location: show what DNS is being overwritten in location UI

fixes #858
This commit is contained in:
Girish Ramakrishnan
2026-03-30 13:11:45 +02:00
parent f333148afa
commit 4b851afc6a
10 changed files with 70 additions and 57 deletions
+29 -21
View File
@@ -18,7 +18,7 @@ const busy = ref(false);
const errorMessage = ref('');
const errorObject = ref({});
const overwriteDns = ref(false);
const needsOverwriteDns = ref(false);
const needsOverwriteDns = ref([]);
const domain = ref('');
const subdomain = ref('');
const secondaryDomains = ref({});
@@ -56,6 +56,12 @@ function onAddRedirect() {
const form = useTemplateRef('form');
const isFormValid = ref(false);
function resetDnsOverwrite() {
needsOverwriteDns.value = [];
overwriteDns.value = false;
errorMessage.value = '';
}
function checkValidity() {
isFormValid.value = form.value ? form.value.checkValidity() : false;
@@ -87,7 +93,7 @@ async function onSubmit() {
busy.value = true;
errorMessage.value = '';
errorObject.value = {};
needsOverwriteDns.value = false;
needsOverwriteDns.value = [];
const checkForDomains = [{
domain: domain.value,
@@ -98,6 +104,7 @@ async function onSubmit() {
for (const d of aliases.value) checkForDomains.push({ domain: d.domain, subdomain: d.subdomain });
for (const d of redirects.value) checkForDomains.push({ domain: d.domain, subdomain: d.subdomain });
const conflicting = [];
for (const d of checkForDomains) {
const [error, result] = await domainsModel.checkRecords(d.domain, d.subdomain);
if (error) {
@@ -106,11 +113,14 @@ async function onSubmit() {
return console.error(error);
}
if (result.needsOverwrite && !overwriteDns.value) {
busy.value = false;
needsOverwriteDns.value = true;
return;
}
if (result.needsOverwrite) conflicting.push((d.subdomain ? d.subdomain + '.' : '') + d.domain);
}
if (conflicting.length > 0 && !overwriteDns.value) {
busy.value = false;
needsOverwriteDns.value = conflicting;
errorMessage.value = `DNS records of ${conflicting.join(', ')} already exist`;
return;
}
// only use enabled ports
@@ -207,8 +217,8 @@ onMounted(async () => {
<div style="display: flex; gap: 10px;">
<InputGroup style="flex-grow: 1">
<TextInput style="flex-grow: 1" v-model="subdomain" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="domain" option-key="domain" option-label="label" :search-threshold="10" required/>
<TextInput style="flex-grow: 1" v-model="subdomain" @input="resetDnsOverwrite()" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="domain" option-key="domain" option-label="label" @select="resetDnsOverwrite()" :search-threshold="10" required/>
</InputGroup>
<div class="warning-label" v-if="isNoopOrManual(domain)" v-html="$t('appstore.installDialog.manualWarning', { location: ((subdomain ? subdomain + '.' : '') + domain) })"></div>
<!-- Button just to offset the same margin on the right to align location input when alias or redirects are visible -->
@@ -220,8 +230,8 @@ onMounted(async () => {
<label :for="'secondaryDomainInput' + item.containerPort">{{ item.title }}</label>
<small>{{ item.description }}</small>
<InputGroup style="flex-grow: 1">
<TextInput style="flex-grow: 1" :id="'secondaryDomainInput' + item.containerPort" v-model="item.subdomain" :placeholder="$t('appstore.installDialog.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" :search-threshold="10" required/>
<TextInput style="flex-grow: 1" :id="'secondaryDomainInput' + item.containerPort" v-model="item.subdomain" @input="resetDnsOverwrite()" :placeholder="$t('appstore.installDialog.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" @select="resetDnsOverwrite()" :search-threshold="10" required/>
</InputGroup>
<div class="warning-label" v-if="isNoopOrManual(item.domain)" v-html="$t('appstore.installDialog.manualWarning', { location: ((item.subdomain ? item.subdomain + '.' : '') + item.domain) })"></div>
</FormGroup>
@@ -234,8 +244,8 @@ onMounted(async () => {
<div v-for="(item, index) in aliases" :key="item" style="margin-bottom: 10px">
<div style="display: flex; gap: 10px;">
<InputGroup style="flex-grow: 1">
<TextInput style="flex-grow: 1" v-model="item.subdomain" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" :search-threshold="10"/>
<TextInput style="flex-grow: 1" v-model="item.subdomain" @input="resetDnsOverwrite()" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" @select="resetDnsOverwrite()" :search-threshold="10"/>
</InputGroup>
<Button danger tool :disabled="busy" icon="fa-solid fa-trash" @click="onRemoveAlias(index)"/>
</div>
@@ -253,8 +263,8 @@ onMounted(async () => {
<div v-for="(item, index) in redirects" :key="item" style="margin-bottom: 10px;">
<div style="display: flex; gap: 10px;">
<InputGroup style="flex-grow: 1">
<TextInput style="flex-grow: 1" v-model="item.subdomain" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" :search-threshold="10"/>
<TextInput style="flex-grow: 1" v-model="item.subdomain" @input="resetDnsOverwrite()" :placeholder="$t('app.location.locationPlaceholder')"/>
<SingleSelect :disabled="busy" :options="domains" v-model="item.domain" option-key="domain" option-label="label" @select="resetDnsOverwrite()" :search-threshold="10"/>
</InputGroup>
<Button danger tool :disabled="busy" icon="fa-solid fa-trash" @click="onRemoveRedirect(index)"/>
</div>
@@ -272,13 +282,11 @@ onMounted(async () => {
<br/>
<div class="error-label" v-if="errorMessage">{{ errorMessage }}</div>
<br v-if="errorMessage"/>
<div class="text-danger" v-if="errorMessage">{{ errorMessage }}</div>
<Checkbox v-if="needsOverwriteDns.length" v-model="overwriteDns" :label="$t('app.location.overwriteDns', { domains: needsOverwriteDns.join(', ') })"/>
<br v-if="needsOverwriteDns.length"/>
<Checkbox v-if="needsOverwriteDns" v-model="overwriteDns" :label="$t('app.location.dnsoverwrite')"/>
<br v-if="needsOverwriteDns"/>
<Button @click="onSubmit()" :loading="busy" :disabled="busy || (app.error && app.error.installationState !== ISTATES.PENDING_LOCATION_CHANGE) || app.taskId || !isFormValid">{{ $t('app.location.saveAction') }}</Button>
<Button @click="onSubmit()" :loading="busy" :disabled="busy || (app.error && app.error.installationState !== ISTATES.PENDING_LOCATION_CHANGE) || app.taskId || !isFormValid || (needsOverwriteDns.length > 0 && !overwriteDns)">{{ $t('app.location.saveAction') }}</Button>
</div>
</template>