app install: Fix status of install button
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import { ref, computed, useTemplateRef, onMounted, inject } from 'vue';
|
import { ref, computed, useTemplateRef, onMounted, inject, watch } from 'vue';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import { Button, Dialog, SingleSelect, FormGroup, TextInput, InputGroup, Spinner } from '@cloudron/pankow';
|
import { Button, Dialog, SingleSelect, FormGroup, TextInput, InputGroup, Spinner } from '@cloudron/pankow';
|
||||||
import { prettyDate, prettyBinarySize, isValidDomain } from '@cloudron/pankow/utils';
|
import { prettyDate, prettyBinarySize } from '@cloudron/pankow/utils';
|
||||||
import AccessControl from './AccessControl.vue';
|
import AccessControl from './AccessControl.vue';
|
||||||
import PortBindings from './PortBindings.vue';
|
import PortBindings from './PortBindings.vue';
|
||||||
import AppsModel from '../models/AppsModel.js';
|
import AppsModel from '../models/AppsModel.js';
|
||||||
@@ -39,23 +39,28 @@ const locationInput = useTemplateRef('locationInput');
|
|||||||
const description = computed(() => marked.parse(manifest.value.description || ''));
|
const description = computed(() => marked.parse(manifest.value.description || ''));
|
||||||
const domains = ref([]);
|
const domains = ref([]);
|
||||||
|
|
||||||
const formValid = computed(() => {
|
const form = ref(null); // assigned via "Function Ref" because it is inside v-if
|
||||||
if (!domain.value) return false;
|
const isFormValid = ref(false);
|
||||||
|
async function checkValidity() {
|
||||||
|
isFormValid.value = form.value ? form.value.checkValidity() : false;
|
||||||
|
|
||||||
if (location.value && !isValidDomain(location.value + '.' + domain.value)) return false;
|
if (isFormValid.value) {
|
||||||
|
if (accessRestrictionOption.value === ACL_OPTIONS.RESTRICTED && (accessRestrictionAcl.value.users.length === 0 && accessRestrictionAcl.value.groups.length === 0)) {
|
||||||
|
isFormValid.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (accessRestrictionOption.value === ACL_OPTIONS.RESTRICTED && (accessRestrictionAcl.value.users.length === 0 && accessRestrictionAcl.value.groups.length === 0)) return false;
|
if (manifest.value.id === PROXY_APP_ID) {
|
||||||
|
try {
|
||||||
if (manifest.value.id === PROXY_APP_ID) {
|
new URL(upstreamUri.value);
|
||||||
try {
|
// eslint-disable-next-line no-unused-vars
|
||||||
new URL(upstreamUri.value);
|
} catch (e) {
|
||||||
// eslint-disable-next-line no-unused-vars
|
isFormValid.value = false;
|
||||||
} catch (e) {
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
watch(form, () => { // trigger form validation when the ref becomes set
|
||||||
|
setTimeout(checkValidity, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
const appMaxCountExceeded = ref(false);
|
const appMaxCountExceeded = ref(false);
|
||||||
@@ -68,7 +73,9 @@ function setStep(newStep) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
step.value = newStep;
|
step.value = newStep;
|
||||||
if (newStep === STEP.INSTALL) setTimeout(() => locationInput.value.$el.focus(), 500);
|
if (newStep === STEP.INSTALL) {
|
||||||
|
setTimeout(() => locationInput.value.$el.focus(), 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// form data
|
// form data
|
||||||
@@ -91,6 +98,8 @@ function onDomainChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit(overwriteDns) {
|
async function onSubmit(overwriteDns) {
|
||||||
|
if (!form.value.reportValidity()) return;
|
||||||
|
|
||||||
formError.value = {};
|
formError.value = {};
|
||||||
busy.value = true;
|
busy.value = true;
|
||||||
|
|
||||||
@@ -309,15 +318,15 @@ defineExpose({
|
|||||||
<div class="error-label" v-if="formError.generic">{{ formError.generic }}</div>
|
<div class="error-label" v-if="formError.generic">{{ formError.generic }}</div>
|
||||||
<div class="error-label" v-if="formError.dnsExists">{{ formError.dnsExists }}</div>
|
<div class="error-label" v-if="formError.dnsExists">{{ formError.dnsExists }}</div>
|
||||||
|
|
||||||
<form @submit.prevent="onSubmit(false)" autocomplete="off">
|
<form :ref="(el) => { form = el; }" @submit.prevent="onSubmit(false)" autocomplete="off" @input="checkValidity()">
|
||||||
<fieldset :disabled="busy">
|
<fieldset :disabled="busy">
|
||||||
<input style="display: none;" type="submit" :disabled="!formValid" />
|
<input style="display: none;" type="submit" :disabled="busy" />
|
||||||
|
|
||||||
<FormGroup :class="{ 'has-error': formError.location }">
|
<FormGroup :class="{ 'has-error': formError.location }">
|
||||||
<label for="location">{{ $t('appstore.installDialog.location') }}</label>
|
<label for="location">{{ $t('appstore.installDialog.location') }}</label>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<TextInput id="location" ref="locationInput" v-model="location" style="flex-grow: 1"/>
|
<TextInput id="location" ref="locationInput" v-model="location" style="flex-grow: 1"/>
|
||||||
<SingleSelect v-model="domain" :options="domains" option-label="label" option-key="domain" @select="onDomainChange()" :search-threshold="10"/>
|
<SingleSelect v-model="domain" :options="domains" option-label="label" option-key="domain" @select="onDomainChange()" :search-threshold="10" required/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
<div class="warning-label" v-show="domainProvider === 'noop' || domainProvider === 'manual'" v-html="$t('appstore.installDialog.manualWarning', { location: ((location ? location + '.' : '') + domain) })"></div>
|
<div class="warning-label" v-show="domainProvider === 'noop' || domainProvider === 'manual'" v-html="$t('appstore.installDialog.manualWarning', { location: ((location ? location + '.' : '') + domain) })"></div>
|
||||||
<div class="error-label" v-if="formError.location">{{ formError.location }}</div>
|
<div class="error-label" v-if="formError.location">{{ formError.location }}</div>
|
||||||
@@ -328,21 +337,21 @@ defineExpose({
|
|||||||
<small>{{ port.description }}</small>
|
<small>{{ port.description }}</small>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
<TextInput :id="'secondaryDomainInput' + key" v-model="port.value" :placeholder="$t('appstore.installDialog.locationPlaceholder')" style="flex-grow: 1"/>
|
<TextInput :id="'secondaryDomainInput' + key" v-model="port.value" :placeholder="$t('appstore.installDialog.locationPlaceholder')" style="flex-grow: 1"/>
|
||||||
<SingleSelect v-model="port.domain" :options="domains" option-label="label" option-key="domain" />
|
<SingleSelect v-model="port.domain" :options="domains" option-label="label" option-key="domain" required/>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup :class="{ 'has-error': formError.upstreamUri }" v-show="manifest.id === PROXY_APP_ID">
|
<FormGroup :class="{ 'has-error': formError.upstreamUri }" v-if="manifest.id === PROXY_APP_ID">
|
||||||
<label for="upstreamUri">Upstream URI</label>
|
<label for="upstreamUri">Upstream URI</label>
|
||||||
<TextInput id="upstreamUri" v-model="upstreamUri" />
|
<TextInput id="upstreamUri" v-model="upstreamUri" required/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<PortBindings v-model:tcp="tcpPorts" v-model:udp="udpPorts" :error="formError" :domain-provider="domainProvider"/>
|
<PortBindings v-model:tcp="tcpPorts" v-model:udp="udpPorts" :error="formError" :domain-provider="domainProvider"/>
|
||||||
<AccessControl v-model:option="accessRestrictionOption" v-model:acl="accessRestrictionAcl" :manifest="manifest" :users="users" :groups="groups" :installation="true"/>
|
<AccessControl v-model:option="accessRestrictionOption" v-model:acl="accessRestrictionAcl" :manifest="manifest" :users="users" :groups="groups" :installation="true"/>
|
||||||
|
|
||||||
<div class="bottom-button-bar">
|
<div class="bottom-button-bar">
|
||||||
<Button v-if="needsOverwriteDns" danger @click="onSubmit(true)" icon="fa-solid fa-circle-down" :disabled="!formValid" :loading="busy">Install {{ manifest.title }} and overwrite DNS</Button>
|
<Button v-if="needsOverwriteDns" danger @click="onSubmit(true)" icon="fa-solid fa-circle-down" :disabled="busy || !isFormValid" :loading="busy">Install {{ manifest.title }} and overwrite DNS</Button>
|
||||||
<Button v-else @click="onSubmit(false)" icon="fa-solid fa-circle-down" :disabled="!formValid" :loading="busy">Install {{ manifest.title }}</Button>
|
<Button v-else @click="onSubmit(false)" icon="fa-solid fa-circle-down" :disabled="busy || !isFormValid" :loading="busy">Install {{ manifest.title }}</Button>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ function onRemoveRedirect(index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
|
if (!form.value.reportValidity()) return;
|
||||||
|
|
||||||
busy.value = true;
|
busy.value = true;
|
||||||
errorMessage.value = '';
|
errorMessage.value = '';
|
||||||
errorObject.value = {};
|
errorObject.value = {};
|
||||||
|
|||||||
Reference in New Issue
Block a user