Finish initial implementation dns setup view
This commit is contained in:
@@ -1,12 +1,19 @@
|
||||
<script setup>
|
||||
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { Spinner, Button, FormGroup, TextInput } from 'pankow';
|
||||
import { ref, onMounted, useTemplateRef } from 'vue';
|
||||
import { Spinner, Button, SingleSelect, FormGroup, TextInput } from 'pankow';
|
||||
import { redirectIfNeeded } from '../utils.js';
|
||||
import CloudronModel from '../models/CloudronModel.js';
|
||||
import ProvisionModel from '../models/ProvisionModel.js';
|
||||
import DomainProviderForm from '../components/DomainProviderForm.vue';
|
||||
|
||||
const cloudronModel = CloudronModel.create();
|
||||
const provisionModel = ProvisionModel.create();
|
||||
|
||||
const ipProviders = [
|
||||
{ name: 'Disabled', value: 'noop' },
|
||||
{ name: 'Public IP', value: 'generic' },
|
||||
{ name: 'Static IP Address', value: 'fixed' },
|
||||
{ name: 'Network Interface', value: 'network-interface' }
|
||||
];
|
||||
|
||||
const formError = ref({});
|
||||
const busy = ref(false);
|
||||
@@ -15,29 +22,114 @@ const waitingForDnsSetup = ref(false);
|
||||
const progressMessage = ref('');
|
||||
const taskMinutesActive = ref(0);
|
||||
const domain = ref('');
|
||||
const instanceId = ref('');
|
||||
const setupToken = ref('');
|
||||
const zoneName = ref('');
|
||||
const provider = ref('');
|
||||
const dnsConfig = ref({});
|
||||
const tlsProvider = ref('');
|
||||
const advancedVisible = ref(false);
|
||||
const tlsProvider = ref('letsencrypt-prod-wildcard');
|
||||
const showAdvanced = ref(false);
|
||||
const ipv4Provider = ref('generic');
|
||||
const ipv4Address = ref('');
|
||||
const ipv4Interface = ref('');
|
||||
const ipv6Provider = ref('generic');
|
||||
const ipv6Address = ref('');
|
||||
const ipv6Interface = ref('');
|
||||
|
||||
const isValid = computed(() => {
|
||||
return true;
|
||||
});
|
||||
const form = useTemplateRef('form');
|
||||
const isFormValid = ref(false);
|
||||
function checkValidity() {
|
||||
if (!provider.value) return false;
|
||||
isFormValid.value = form.value.checkValidity();
|
||||
}
|
||||
|
||||
async function waitForDnsSetup () {
|
||||
waitingForDnsSetup.value = true;
|
||||
formError.value = {};
|
||||
|
||||
const [error, result] = await provisionModel.status();
|
||||
if (error) {
|
||||
setTimeout(waitForDnsSetup, 5000);
|
||||
return console.error(error);
|
||||
}
|
||||
|
||||
if (!result.setup.active) {
|
||||
if (!result.adminFqdn || result.setup.errorMessage) { // setup reset or errored. start over
|
||||
formError.value.dnsWait = result.setup.errorMessage;
|
||||
waitingForDnsSetup.value = false;
|
||||
} else { // proceed to activation
|
||||
window.location.href = 'https://' + result.adminFqdn + '/activation.html' + (window.location.search);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
progressMessage.value = result.setup.message;
|
||||
taskMinutesActive.value = (new Date() - new Date(result.setup.startTime)) / 60000;
|
||||
|
||||
setTimeout(waitForDnsSetup, 5000);
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!isValid.value) return;
|
||||
if (!isFormValid.value) return;
|
||||
|
||||
busy.value = true;
|
||||
formError.value = {};
|
||||
|
||||
const data = {
|
||||
domainConfig: {
|
||||
domain: domain.value,
|
||||
zoneName: zoneName.value,
|
||||
provider: provider.value,
|
||||
config: dnsConfig.value,
|
||||
tlsConfig: {
|
||||
provider: tlsProvider.value
|
||||
},
|
||||
},
|
||||
ipv4Config: {
|
||||
provider: ipv4Provider.value,
|
||||
ip: ipv4Provider.value === 'fixed' ? ipv4Address.value : '',
|
||||
ifname: ipv4Provider.value === 'network-interface' ? ipv4Interface.value : '',
|
||||
},
|
||||
ipv6Config: {
|
||||
provider: ipv6Provider.value,
|
||||
ip: ipv6Provider.value === 'fixed' ? ipv6Address.value : '',
|
||||
ifname: ipv6Provider.value === 'network-interface' ? ipv6Interface.value : '',
|
||||
},
|
||||
providerToken: instanceId.value,
|
||||
setupToken: setupToken.value,
|
||||
};
|
||||
|
||||
const [error] = await provisionModel.setup(data);
|
||||
if (error) {
|
||||
if (error.status === 422) {
|
||||
// TODO what is this special error checking for ami doing here?
|
||||
if (provider.value === 'ami') {
|
||||
formError.value.ami = error.message;
|
||||
} else {
|
||||
formError.value.setup = error.message;
|
||||
}
|
||||
} else {
|
||||
formError.value.generic = error.message;
|
||||
}
|
||||
|
||||
busy.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
waitForDnsSetup();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const [error, result] = await cloudronModel.provisionStatus();
|
||||
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
|
||||
|
||||
const [error, result] = await provisionModel.status();
|
||||
if (error) return console.error(error);
|
||||
|
||||
if (redirectIfNeeded(result, 'setup')) return; // redirected to some other view...
|
||||
|
||||
instanceId.value = search.instanceId;
|
||||
setupToken.value = search.setupToken;
|
||||
|
||||
ready.value = true;
|
||||
});
|
||||
|
||||
@@ -46,98 +138,88 @@ onMounted(async () => {
|
||||
<template>
|
||||
<div class="container" v-if="ready">
|
||||
<Transition name="slide-fade" mode="out-in">
|
||||
<div class="view" v-if="waitingForDnsSetup">
|
||||
<div class="view" v-if="waitingForDnsSetup" style="text-align: center; max-width: unset;">
|
||||
<Spinner class="pankow-spinner-large"/>
|
||||
<h3>{{ progressMessage }} ...</h3>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<p>
|
||||
Please wait while Cloudron is setting up the dashboard.<br/>
|
||||
<div>
|
||||
Please wait while Cloudron is setting up the dashboard.
|
||||
<br/>
|
||||
<br/>
|
||||
You can follow the logs on the server at <code class="clipboard hand" data-clipboard-text="/home/yellowtent/platformdata/logs/box.log" uib-tooltip="{{ clipboardDone ? 'Copied' : 'Click to copy' }}" tooltip-placement="right">/home/yellowtent/platformdata/logs/box.log</code>
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<p v-show="taskMinutesActive >= 4">
|
||||
If setup appears stuck, it can be restarted by running <code class="clipboard hand" data-clipboard-text="systemctl restart box" uib-tooltip="{{ clipboardDone ? 'Copied' : 'Click to copy' }}" tooltip-placement="right">systemctl restart box</code> and reloading this page.
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<span v-show="taskMinutesActive >= 4">If setup appears stuck, it can be restarted by running <code>systemctl restart box</code> and reloading this page.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="view" v-else>
|
||||
<h1>Domain Setup</h1>
|
||||
<h1>Cloudron Domain Setup</h1>
|
||||
|
||||
<form @submit.prevent="onSubmit()">
|
||||
<div class="text-danger" v-if="formError.dnsWait">{{ formError.dnsWait }}</div>
|
||||
<div class="text-danger" v-if="formError.setup">{{ formError.setup }}</div>
|
||||
<div class="text-danger" v-if="formError.generic">{{ formError.generic }}</div>
|
||||
|
||||
<form ref="form" @submit.prevent="onSubmit()" @input="checkValidity()">
|
||||
<fieldset :disabled="busy">
|
||||
<FormGroup>
|
||||
<label for="domainInput">Domain <sup><a href="https://docs.cloudron.io/installation/#domain-setup" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<TextInput id="domainInput" v-model="domain" placeholder="example.com" required />
|
||||
<div class="text-danger" v-show="domain.indexOf('my.') === 0 && domain.length > 3">Are you sure about this domain? The dashboard will be at <b>my.{{ domain }}</b></div>
|
||||
<div>Apps will be installed on subdomains of this domain. The dashboard will be available on the <b>my</b> subdomain. You can add more domains later.</div>
|
||||
<div style="padding-top: 6px;">Apps will be installed on subdomains of this domain. The dashboard will be available on the <b>my</b> subdomain. You can add more domains later.</div>
|
||||
</FormGroup>
|
||||
|
||||
<DomainProviderForm v-model:provider="provider" v-model:dns-config="dnsConfig" v-model:tls-provider="tlsProvider" :domain="domain" />
|
||||
<DomainProviderForm v-model:provider="provider" v-model:dns-config="dnsConfig" v-model:tls-provider="tlsProvider" :domain="domain" :show-advanced="showAdvanced" />
|
||||
|
||||
<div v-show="advancedVisible">
|
||||
<div v-show="showAdvanced">
|
||||
<FormGroup>
|
||||
<label for="zoneNameInput">DNS Zone Name (Optional) <sup><a href="https://docs.cloudron.io/domains/#zone-name" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<TextInput id="zoneNameInput" v-model="zoneName" placeholder="Defaults to TLD" />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<label>Certificate Provider <sup><a href="https://docs.cloudron.io/certificates/#certificate-providers" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<select class="form-control" ng-model="dnsCredentials.tlsConfig.provider" ng-options="a.value as a.name for a in tlsProvider" ng-disabled="dnsCredentials.busy"></select>
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv4 provider -->
|
||||
<FormGroup>
|
||||
<label class="control-label">IPv4 Configuration <sup><a ng-href="https://docs.cloudron.io/networking/#ip-configuration" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<select class="form-control" ng-model="ipv4Config.provider" ng-options="a.value as a.name for a in ipProviders"></select>
|
||||
<SingleSelect v-model="ipv4Provider" :options="ipProviders" option-key="value" option-label="name" />
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv4 Fixed -->
|
||||
<FormGroup ng-show="ipv4Config.provider === 'fixed'">
|
||||
<label class="control-label">IPv4 Address</label>
|
||||
<input type="text" class="form-control" ng-model="ipv4Config.ip" name="ipv4" ng-required="ipv4Config.provider === 'fixed'">
|
||||
<FormGroup v-if="ipv4Provider === 'fixed'">
|
||||
<label for="ipv4AddressInput">IPv4 Address</label>
|
||||
<TextInput id="ipv4AddressInput" v-model="ipv4Address" required />
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv4 Network Interface -->
|
||||
<FormGroup ng-show="ipv4Config.provider === 'network-interface'">
|
||||
<label class="control-label">IPv4 Interface Name</label>
|
||||
<input type="text" class="form-control" ng-model="ipv4Config.ifname" name="ifname4" ng-required="ipv4Config.provider === 'network-interface'">
|
||||
<FormGroup v-if="ipv4Provider === 'network-interface'">
|
||||
<label for="ipv4InterfaceInput">IPv4 Interface Name</label>
|
||||
<TextInput id="ipv4InterfaceInput" v-model="ipv4Interface" required />
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv6 provider -->
|
||||
<FormGroup>
|
||||
<label class="control-label">IPv6 Configuration <sup><a ng-href="https://docs.cloudron.io/networking/#ip-configuration" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
||||
<select class="form-control" ng-model="ipv6Config.provider" ng-options="a.value as a.name for a in ipProviders"></select>
|
||||
<SingleSelect v-model="ipv6Provider" :options="ipProviders" option-key="value" option-label="name" />
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv6 Fixed -->
|
||||
<FormGroup ng-show="ipv6Config.provider === 'fixed'">
|
||||
<label class="control-label">IPv6 Address</label>
|
||||
<input type="text" class="form-control" ng-model="ipv6Config.ip" name="ipv6" ng-required="ipv6Config.provider === 'fixed'">
|
||||
<FormGroup v-if="ipv6Provider === 'fixed'">
|
||||
<label for="ipv6AddressInput">IPv6 Address</label>
|
||||
<TextInput id="ipv6AddressInput" v-model="ipv6Address" required />
|
||||
</FormGroup>
|
||||
|
||||
<!-- IPv6 Network Interface -->
|
||||
<FormGroup ng-show="ipv6Config.provider === 'network-interface'">
|
||||
<label class="control-label">IPv6 Interface Name</label>
|
||||
<input type="text" class="form-control" ng-model="ipv6Config.ifname" name="ifname6" ng-required="ipv6Config.provider === 'network-interface'">
|
||||
<FormGroup v-if="ipv6Provider === 'network-interface'">
|
||||
<label for="ipv6InterfaceInpt">IPv6 Interface Name</label>
|
||||
<TextInput id="ipv6InterfaceInpt" v-model="ipv6Interface" required />
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
<div class="actionable" @click="advancedVisible = false" v-if="advancedVisible">Hide Advanced settings</div>
|
||||
<div class="actionable" @click="advancedVisible = true" v-else>Advanced settings...</div>
|
||||
<div class="actionable" @click="showAdvanced = false" v-if="showAdvanced">Hide Advanced settings</div>
|
||||
<div class="actionable" @click="showAdvanced = true" v-else>Advanced settings...</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<Button @click="onSubmit()" :disabled="busy" :loading="busy">Next</Button>
|
||||
|
||||
<div class="actionable"><small>Looking to <a href="/restore.html">restore?</a></small></div>
|
||||
<Button @click="onSubmit()" style="margin-top: 12px" :disabled="busy || !isFormValid" :loading="busy">Next</Button>
|
||||
<a href="/restore.html" style="margin-left: 10px;">Looking to restore?</a>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
@@ -150,11 +232,17 @@ onMounted(async () => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.view {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user