jcloud/dashboard/src2/views/site/SiteOverviewDomains.vue

396 lines
10 KiB
Vue

<template>
<Card
title="Domains"
:subtitle="
domains.data && domains.data.length
? 'Domains pointing to your site'
: 'No domains pointing to your site'
"
>
<template #actions>
<Button
@click="showDialog = true"
:disabled="site.status === 'Suspended'"
>
Add Domain
</Button>
</template>
<div class="divide-y" v-if="domains.data">
<div v-for="d in domains.data" :key="d.name">
<div class="py-2">
<div class="flex items-center">
<div class="flex w-2/3 text-base font-medium">
<a
class="text-blue-500"
:href="'https://' + d.domain"
target="_blank"
v-if="d.status === 'Active'"
>
{{ d.domain }}
</a>
<span v-else>{{ d.domain }}</span>
<div
class="flex"
v-if="d.redirect_to_primary == 1 && d.status == 'Active'"
>
<FeatherIcon name="arrow-right" class="mx-1 w-4" />
<a
class="text-blue-500"
:href="'https://' + d.domain"
target="_blank"
v-if="d.status === 'Active'"
>
{{ site.host_name }}
</a>
</div>
</div>
<div class="ml-auto flex items-center space-x-2">
<Badge
v-if="d.status == 'Active' && d.primary"
:label="'Primary'"
/>
<Badge v-else-if="d.status != 'Active'" :label="d.status" />
<Button
v-if="d.status == 'Broken' && d.retry_count <= 5"
:loading="$resources.retryAddDomain.loading"
@click="
$resources.retryAddDomain.submit({
name: site.name,
domain: d.domain
})
"
>
Retry
</Button>
<Button v-if="$resources.removeDomain.loading" :loading="true">
Removing domain
</Button>
<Dropdown v-else :options="actionItems(d)">
<template v-slot="{ open }">
<Button icon="more-horizontal" />
</template>
</Dropdown>
</div>
</div>
<ErrorMessage
v-if="d.status == 'Broken'"
error="We encountered an error while adding the domain."
/>
<ErrorMessage :message="$resources.removeDomain.error" />
<ErrorMessage :message="$resources.setHostName.error" />
</div>
</div>
</div>
<Dialog v-model="showDialog" :options="{ title: 'Add Domain' }">
<template v-slot:body-content>
<div class="space-y-4">
<p class="text-base">
To add a custom domain, you must already own it. If you don't have
one, buy it and come back here.
</p>
<FormControl
placeholder="www.example.com"
v-model="newDomain"
:readonly="dnsVerified"
/>
<div v-if="newDomain && !dnsVerified" class="space-y-2 text-base">
<p>Create one of the following DNS records</p>
<p class="px-2">
<span class="font-semibold text-gray-700">CNAME</span> record from
<span class="font-semibold text-gray-700">{{ newDomain }}</span>
to
<span class="font-semibold text-gray-700">{{ site.name }}</span>
</p>
<p class="px-2">
<span class="font-semibold text-gray-700">A</span> record from
<span class="font-semibold text-gray-700">{{ newDomain }}</span>
to
<span class="font-semibold text-gray-700">{{ site.ip }}</span>
</p>
</div>
<div v-if="dnsResult && !dnsResult.matched" class="space-y-2">
<p class="text-base">
Received following DNS query responses for
<span class="font-semibold text-gray-700">{{ newDomain }}</span
>.
</p>
<div
v-if="newDomain && dnsResult.CNAME && !dnsResult.CNAME.matched"
class="space-y-2"
>
<p class="text-base">
<span class="font-semibold text-gray-700">CNAME</span>
</p>
<div
class="flex flex-row items-center justify-between rounded-lg border-2 p-2"
>
<p
class="select-all overflow-hidden font-mono text-sm text-gray-800"
>
{{ dnsResult.CNAME.answer }}
</p>
</div>
</div>
<div
v-if="newDomain && dnsResult.A && !dnsResult.A.matched"
class="space-y-2"
>
<p class="text-base">
<span class="font-semibold text-gray-700">A</span>
</p>
<div
class="flex flex-row items-center justify-between rounded-lg border-2 p-2"
>
<p
class="select-all overflow-hidden font-mono text-sm text-gray-800"
>
{{ dnsResult.A.answer }}
</p>
</div>
</div>
</div>
<p class="flex text-base" v-if="dnsVerified === false">
<FeatherIcon
name="x"
class="mr-2 h-5 w-5 rounded-full bg-red-100 p-1 text-red-500"
/>
DNS Verification Failed
</p>
<p class="flex text-base" v-if="dnsVerified === true">
<FeatherIcon
name="check"
class="mr-2 h-5 w-5 rounded-full bg-green-100 p-1 text-green-500"
/>
DNS records successfully verified. Click on Add Domain.
</p>
<ErrorMessage :message="$resources.checkDNS.error" />
<ErrorMessage :message="$resources.addDomain.error" />
<ErrorMessage :message="$resources.retryAddDomain.error" />
</div>
</template>
<template #actions>
<Button
v-if="!dnsVerified"
class="mt-2 w-full"
variant="solid"
:loading="$resources.checkDNS.loading"
@click="
$resources.checkDNS.submit({
name: site.name,
domain: newDomain
})
"
>
Verify DNS
</Button>
<Button
v-if="dnsVerified"
class="mt-2 w-full"
variant="solid"
:loading="$resources.addDomain.loading"
@click="
$resources.addDomain.submit({
name: site.name,
domain: newDomain
})
"
>
Add Domain
</Button>
</template>
</Dialog>
</Card>
</template>
<script>
import { notify } from '@/utils/toast';
export default {
name: 'SiteOverviewDomains',
props: ['site'],
data() {
return {
showDialog: false,
newDomain: null
};
},
resources: {
domains() {
return {
url: 'jcloud.api.site.domains',
params: { name: this.site?.name },
auto: true
};
},
checkDNS: {
url: 'jcloud.api.site.check_dns',
validate() {
if (!this.newDomain) return 'Domain cannot be empty';
}
},
addDomain: {
url: 'jcloud.api.site.add_domain',
onSuccess() {
this.$resources.checkDNS.reset();
this.$resources.domains.reload();
this.showDialog = false;
}
},
removeDomain: {
url: 'jcloud.api.site.remove_domain',
onSuccess() {
this.$resources.domains.reload();
}
},
retryAddDomain: {
url: 'jcloud.api.site.retry_add_domain',
onSuccess() {
this.$resources.domains.fetch();
}
},
setHostName: {
url: 'jcloud.api.site.set_host_name',
onSuccess() {
this.$resources.domains.reload();
}
},
setupRedirect: {
url: 'jcloud.api.site.set_redirect',
onSuccess() {
this.$resources.domains.reload();
}
},
removeRedirect: {
url: 'jcloud.api.site.unset_redirect',
onSuccess() {
this.$resources.domains.reload();
}
}
},
computed: {
domains() {
return this.$resources.domains;
},
dnsVerified() {
return this.dnsResult?.matched;
},
dnsResult() {
return this.$resources.checkDNS.data;
},
primaryDomain() {
return this.$resources.domains.data.filter(d => d.primary)[0].domain;
}
},
watch: {
newDomain() {
this.$resources.checkDNS.reset();
}
},
methods: {
actionItems(domain) {
return [
{
label: 'Remove',
onClick: () => this.confirmRemoveDomain(domain.domain)
},
{
label: 'Set Primary',
condition: () => domain.status == 'Active' && !domain.primary,
onClick: () => this.confirmSetPrimary(domain.domain)
},
{
label: 'Redirect to Primary',
condition: () =>
domain.status == 'Active' &&
!domain.primary &&
!domain.redirect_to_primary,
onClick: () => this.confirmSetupRedirect(domain.domain)
},
{
label: 'Remove Redirect',
condition: () =>
domain.status == 'Active' &&
!domain.primary &&
domain.redirect_to_primary,
onClick: () => this.confirmRemoveRedirect(domain.domain)
}
].filter(d => (d.condition ? d.condition() : true));
},
confirmRemoveDomain(domain) {
this.$confirm({
title: 'Remove Domain',
message: `Are you sure you want to remove the domain <b>${domain}</b>?`,
actionLabel: 'Remove',
actionColor: 'red',
action: closeDialog => {
closeDialog();
this.$resources.removeDomain.submit({
name: this.site.name,
domain: domain
});
}
});
},
confirmSetPrimary(domain) {
let workingRedirects = false;
this.$resources.domains.data.forEach(d => {
if (d.redirect_to_primary) {
workingRedirects = true;
}
});
if (workingRedirects) {
notify({
title: 'Please Remove all Active Redirects',
color: 'red',
icon: 'x'
});
} else {
this.$confirm({
title: 'Set as Primary Domain',
message: `Setting as primary will make <b>${domain}</b> the primary URL for your site. Do you want to continue?`,
actionLabel: 'Set Primary',
action: closeDialog => {
closeDialog();
this.$resources.setHostName.submit({
name: this.site.name,
domain: domain
});
}
});
}
},
confirmSetupRedirect(domain) {
this.$confirm({
title: 'Redirect to Primary Domain',
message: `Redirect to Primary will redirect <b>${domain}</b> to <b>${this.primaryDomain}</b>. Do you want to continue?`,
actionLabel: 'Redirect to Primary',
action: closeDialog => {
closeDialog();
this.$resources.setupRedirect.submit({
name: this.site.name,
domain: domain
});
}
});
},
confirmRemoveRedirect(domain) {
this.$confirm({
title: 'Remove Redirect',
message: `Remove Redirect will remove previously set up redirect from <b>${domain}</b> to <b>${this.primaryDomain}</b>. Do you want to continue?`,
actionLabel: 'Remove Redirect',
action: closeDialog => {
closeDialog();
this.$resources.removeRedirect.submit({
name: this.site.name,
domain: domain
});
}
});
}
}
};
</script>