168 lines
6.2 KiB
Vue
168 lines
6.2 KiB
Vue
<script setup>
|
|
|
|
import { ref, onMounted, useTemplateRef } from 'vue';
|
|
import { Button, Dialog, SingleSelect, FormGroup, TextInput, ClipboardAction } from '@cloudron/pankow';
|
|
import Section from '../components/Section.vue';
|
|
import NetworkModel from '../models/NetworkModel.js';
|
|
|
|
const networkModel = NetworkModel.create();
|
|
|
|
// keep in sync with sysinfo.js
|
|
const providers = [
|
|
{ name: 'Disabled', value: 'noop' },
|
|
{ name: 'Public IP', value: 'generic' },
|
|
{ name: 'Static IP address', value: 'fixed' },
|
|
{ name: 'Network interface', value: 'network-interface' }
|
|
];
|
|
|
|
function prettyIpProviderName(provider) {
|
|
switch (provider) {
|
|
case 'noop': return 'Disabled';
|
|
case 'generic': return 'Public IP';
|
|
case 'fixed': return 'Static IP address';
|
|
case 'network-interface': return 'Network interface';
|
|
default: return 'Unknown';
|
|
}
|
|
}
|
|
|
|
const provider = ref('');
|
|
const address = ref('');
|
|
const detectedAddress = ref('');
|
|
const interfaceName = ref('');
|
|
const dialog = useTemplateRef('dialog');
|
|
const editError = ref({});
|
|
const editBusy = ref(false);
|
|
const editProvider = ref('');
|
|
const editAddress = ref('');
|
|
const editInterfaceName = ref('');
|
|
|
|
const form = useTemplateRef('form');
|
|
const isFormValid = ref(false);
|
|
function checkValidity() {
|
|
isFormValid.value = form.value ? form.value.checkValidity() : false;
|
|
|
|
if (isFormValid.value) {
|
|
if (editProvider.value === 'fixed' && !editAddress.value) isFormValid.value = false;
|
|
if (editProvider.value === 'network-interface' && !editInterfaceName.value) isFormValid.value = false;
|
|
}
|
|
}
|
|
|
|
async function refresh() {
|
|
let [error, result] = await networkModel.getIpv6Config();
|
|
if (error) return console.error(error);
|
|
|
|
provider.value = result.provider;
|
|
address.value = result.ip;
|
|
interfaceName.value = result.ifname;
|
|
|
|
[error, result] = await networkModel.getIpv6();
|
|
if (error) return console.error(error);
|
|
|
|
detectedAddress.value = result;
|
|
}
|
|
|
|
function onConfigure() {
|
|
editBusy.value = false;
|
|
editError.value = {};
|
|
editProvider.value = provider.value;
|
|
editAddress.value = address.value || '';
|
|
editInterfaceName.value = interfaceName.value || '';
|
|
|
|
dialog.value.open();
|
|
setTimeout(checkValidity, 100); // update state of the confirm button
|
|
}
|
|
|
|
async function onSubmit() {
|
|
if (!form.value.reportValidity()) return;
|
|
|
|
editBusy.value = true;
|
|
editError.value = {};
|
|
|
|
const [error] = await networkModel.setIpv6Config(editProvider.value, editAddress.value.trim(), editInterfaceName.value.trim());
|
|
if (error) {
|
|
editBusy.value = false;
|
|
if (error.body && error.body.message === 'invalid IPv6') editError.value.ipv4 = error.body.message;
|
|
else if (error.body && error.body.message.indexOf('No interface named') === 0) editError.value.ifname = error.body.message;
|
|
else editError.value.generic = error.body ? error.body.message : 'Internal error';
|
|
return;
|
|
}
|
|
|
|
await refresh();
|
|
|
|
dialog.value.close();
|
|
editBusy.value = false;
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await refresh();
|
|
});
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<Dialog ref="dialog"
|
|
:title="$t('network.configureIpv6.title')"
|
|
:confirm-label="$t('main.dialog.save')"
|
|
:confirm-busy="editBusy"
|
|
:confirm-active="!editBusy && isFormValid"
|
|
:reject-label="$t('main.dialog.cancel')"
|
|
reject-style="secondary"
|
|
@confirm="onSubmit()"
|
|
>
|
|
<div>
|
|
<form novalidate @submit.prevent="onSubmit()" autocomplete="off" ref="form" @input="checkValidity()">
|
|
<fieldset :disabled="editBusy">
|
|
<input style="display: none" type="submit" />
|
|
|
|
<FormGroup>
|
|
<label for="providerInput">{{ $t('network.ip.provider') }} <sup><a href="https://docs.cloudron.io/networking/#ipv4" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
|
|
<SingleSelect id="providerInput" v-model="editProvider" :options="providers" option-key="value" option-label="name" required/>
|
|
<div class="error-label" v-show="editError.generic">{{ editError.generic }}</div>
|
|
</FormGroup>
|
|
|
|
<div v-show="editProvider === 'generic'" style="margin-top: 10px">
|
|
{{ $t('network.configureIp.providerGenericDescription') }} <sup><a href="https://ipv4.api.cloudron.io/api/v1/helper/public_ip" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup>
|
|
</div>
|
|
|
|
<!-- Fixed -->
|
|
<FormGroup v-show="editProvider === 'fixed'">
|
|
<label for="addressInput">{{ $t('network.ipv6.address') }}</label>
|
|
<TextInput id="addressInput" v-model="editAddress" :required="editProvider === 'fixed'" />
|
|
<div class="error-label" v-show="editError.ipv4">{{ editError.ipv4 }}</div>
|
|
</FormGroup>
|
|
|
|
<!-- Network Interface -->
|
|
<FormGroup v-show="editProvider === 'network-interface'">
|
|
<label for="interfaceNameInput">{{ $t('network.ip.interface') }}</label>
|
|
<div description>{{ $t('network.ip.interfaceDescription') }} ip -f inet6 -br addr <ClipboardAction plain value="ip -f inet6 -br addr" /></div>
|
|
<TextInput id="interfaceNameInput" v-model="editInterfaceName" :required="editProvider === 'network-interface'" />
|
|
<div class="error-label" v-show="editError.ifname">{{ editError.ifname }}</div>
|
|
</FormGroup>
|
|
</fieldset>
|
|
</form>
|
|
</div>
|
|
</Dialog>
|
|
|
|
<Section :title="$t('network.ipv6.title')">
|
|
<div>{{ $t('network.ipv6.description') }}</div>
|
|
<br/>
|
|
|
|
<div class="info-row">
|
|
<div class="info-label">{{ $t('network.ip.provider') }}</div>
|
|
<div class="info-value">{{ prettyIpProviderName(provider) }}</div>
|
|
</div>
|
|
<div class="info-row" v-show="provider !== 'noop'">
|
|
<div class="info-label">{{ $t('network.ip.address') }}</div>
|
|
<div class="info-value">{{ address || `${detectedAddress} (${$t('network.ip.detected')})` }}</div>
|
|
</div>
|
|
<div class="info-row" v-show="interfaceName">
|
|
<div class="info-label">{{ $t('network.ip.interface') }}</div>
|
|
<div class="info-value">{{ interfaceName }}</div>
|
|
</div>
|
|
|
|
<Button style="margin-top: 10px" @click="onConfigure()">{{ $t('network.ip.configure') }}</Button>
|
|
</Section>
|
|
</div>
|
|
</template>
|