mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-12 19:28:20 +00:00
Compare commits
14 commits
84488b3e63
...
ab8430824f
Author | SHA1 | Date | |
---|---|---|---|
ab8430824f | |||
0c27dffef9 | |||
f8752f99af | |||
185c1e723d | |||
1bf33e54b3 | |||
439d105858 | |||
efa043ed35 | |||
f1d7b57a21 | |||
3eb13e20d2 | |||
8e9d29327d | |||
60fabb254f | |||
1af5af41cc | |||
b360bdf978 | |||
43454b1641 |
16 changed files with 126 additions and 54 deletions
|
@ -3,33 +3,25 @@ const props = withDefaults(defineProps<{
|
||||||
data: any[],
|
data: any[],
|
||||||
component?: string,
|
component?: string,
|
||||||
componentProp?: '',
|
componentProp?: '',
|
||||||
ellipsis?: number
|
ellipsis?: number,
|
||||||
|
empty?: string
|
||||||
}>(), {
|
}>(), {
|
||||||
data: () => [],
|
data: () => [],
|
||||||
component: '',
|
component: '',
|
||||||
componentProp: '',
|
componentProp: '',
|
||||||
ellipsis: 2,
|
ellipsis: 10,
|
||||||
|
empty: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="pillbar">
|
<div v-if="props.data.length != 0" class="pillstack">
|
||||||
<div v-for="(item, index) of props.data.slice(0, ellipsis)" :key="index" class="pill">
|
<div v-for="(item, index) of props.data.slice(0, ellipsis)" :key="index" class="pill">
|
||||||
<component v-bind="{[props.componentProp]: item}" :is="props.component" v-if="props.component !== ''"/>
|
<component v-bind="{[props.componentProp]: item}" :is="props.component" v-if="props.component !== ''"/>
|
||||||
<template v-else>{{ item }}</template>
|
<template v-else>{{ item }}</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="props.data.length >= props.ellipsis" class="pill">...</div>
|
<div v-if="props.data.length >= props.ellipsis" class="pill">...</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
{{ props.empty }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
|
||||||
.pillbar {
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
.pill {
|
|
||||||
border: 1px solid var(--cl-fg);
|
|
||||||
padding: 0.25rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
19
client/src/components/display/ElementDisplay.vue
Normal file
19
client/src/components/display/ElementDisplay.vue
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
data: any,
|
||||||
|
component?: string,
|
||||||
|
componentProp?: '',
|
||||||
|
}>(), {
|
||||||
|
data: '',
|
||||||
|
component: '',
|
||||||
|
componentProp: '',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div v-if="data" class="pillbar">
|
||||||
|
<div class="pill">
|
||||||
|
<component v-bind="{[props.componentProp]: props.data}" :is="props.component" v-if="props.component !== ''"/>
|
||||||
|
<template v-else>{{ props.data }}</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
12
client/src/components/display/EnumTypeDisplay.vue
Normal file
12
client/src/components/display/EnumTypeDisplay.vue
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { variantOf } from '~/util';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
data: object | string,
|
||||||
|
}>(), {
|
||||||
|
data: '',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
{{ variantOf(props.data) }}
|
||||||
|
</template>
|
|
@ -108,7 +108,10 @@ function dragDropRow() {
|
||||||
data.splice(draggedRow, 1);
|
data.splice(draggedRow, 1);
|
||||||
data.splice(draggedOverRow, 0, row);
|
data.splice(draggedOverRow, 0, row);
|
||||||
data = data;
|
data = data;
|
||||||
emit('draggedRow', draggedRow, draggedOverRow);
|
// Don't emit if we are at the same spot
|
||||||
|
if (draggedRow !== draggedOverRow){
|
||||||
|
emit('draggedRow', draggedRow, draggedOverRow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset Drag & Remove Selection
|
// Reset Drag & Remove Selection
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Index, MaybeIndex, equals } from '../../util';
|
import { Index, MaybeIndex, equals, variantOf } from '../../util';
|
||||||
import { Fields } from './NicerForm.vue';
|
import { Fields } from './NicerForm.vue';
|
||||||
|
|
||||||
export type Variant = {
|
export type Variant = {
|
||||||
|
@ -34,7 +34,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// Local Variables for Two-Way bindings
|
// Local Variables for Two-Way bindings
|
||||||
let modelValue: MaybeEnumValue = $ref(null);
|
let modelValue = $ref(null as MaybeEnumValue);
|
||||||
// Sync from v-model
|
// Sync from v-model
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
watch(() => props.modelValue, (val) => {
|
watch(() => props.modelValue, (val) => {
|
||||||
|
@ -49,8 +49,14 @@ onMounted(() => {
|
||||||
}, { deep: true, immediate: true });
|
}, { deep: true, immediate: true });
|
||||||
});
|
});
|
||||||
// Sync to v-model
|
// Sync to v-model
|
||||||
watch($$(modelValue), (val) => {
|
watch($$(modelValue), (val, oldVal) => {
|
||||||
if (equals(val, props.modelValue)) return;
|
if (equals(val, props.modelValue)) return;
|
||||||
|
const [oldVariant, newVariant] = [variantOf(oldVal), variantOf(val)];
|
||||||
|
// Wipe variant values if variant definitions change
|
||||||
|
if (typeof val === 'object'
|
||||||
|
&& val && newVariant && oldVariant
|
||||||
|
&& !equals(props.variants[newVariant].fields, props.variants[oldVariant].fields))
|
||||||
|
val[newVariant] = formValue = {};
|
||||||
emit('update:modelValue', typeof val === 'string' ? val : Object.assign({}, val));
|
emit('update:modelValue', typeof val === 'string' ? val : Object.assign({}, val));
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
|
||||||
|
|
|
@ -121,3 +121,20 @@ tbody tr:hover, th:hover {
|
||||||
tbody tr.selected {
|
tbody tr.selected {
|
||||||
background-color: var(--cl-table-sl)
|
background-color: var(--cl-table-sl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pillbar {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pillstack {
|
||||||
|
align-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill {
|
||||||
|
border: 1px solid var(--cl-fg);
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
|
import ElementDisplay from '~/components/display/ElementDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let rules = $ref([]);
|
let rules = $ref([]);
|
||||||
|
@ -9,11 +11,11 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Source', path: 'source_addresses' },
|
{ heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Destination', path: 'destination_addresses' },
|
{ heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Service', path: 'services' },
|
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Translated Address', path: 'dnat_address' },
|
{ heading: 'Translated Address', path: 'dnat_address', component: markRaw(ElementDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Translated Service', path: 'dnat_service' },
|
{ heading: 'Translated Service', path: 'dnat_service', component: markRaw(ElementDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Counter', path: 'counter' },
|
{ heading: 'Counter', path: 'counter' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
@ -59,7 +61,7 @@ onMounted(async() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<TableView v-model:selection="selection" v-model:data="rules" title="DNAT Rules" :columns="columns" :loading="loading" :table-props="{sort:true, sortSelf: true, draggable: true}" @dragged-row="draggedRow">
|
<TableView v-model:selection="selection" v-model:data="rules" title="DNAT Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
|
||||||
<button @click="load">Refresh</button>
|
<button @click="load">Refresh</button>
|
||||||
<router-link class="button" to="/firewall/destination_nat_rules/edit">Create</router-link>
|
<router-link class="button" to="/firewall/destination_nat_rules/edit">Create</router-link>
|
||||||
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/destination_nat_rules/edit/' + selection[0]">Edit</router-link>
|
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/destination_nat_rules/edit/' + selection[0]">Edit</router-link>
|
||||||
|
|
|
@ -15,6 +15,7 @@ const columns = [
|
||||||
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Verdict', path: 'verdict' },
|
{ heading: 'Verdict', path: 'verdict' },
|
||||||
{ heading: 'Counter', path: 'counter' },
|
{ heading: 'Counter', path: 'counter' },
|
||||||
|
{ heading: 'Log', path: 'log' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ onMounted(async() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<TableView v-model:selection="selection" v-model:data="rules" title="Forward Rules" :columns="columns" :loading="loading" :table-props="{sort:true, sortSelf: true, draggable: true}" @dragged-row="draggedRow">
|
<TableView v-model:selection="selection" v-model:data="rules" title="Forward Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
|
||||||
<button @click="load">Refresh</button>
|
<button @click="load">Refresh</button>
|
||||||
<router-link class="button" to="/firewall/forward_rules/edit">Create</router-link>
|
<router-link class="button" to="/firewall/forward_rules/edit">Create</router-link>
|
||||||
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/forward_rules/edit/' + selection[0]">Edit</router-link>
|
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/forward_rules/edit/' + selection[0]">Edit</router-link>
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
|
import ElementDisplay from '~/components/display/ElementDisplay.vue';
|
||||||
|
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
|
||||||
|
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let rules = $ref([]);
|
let rules = $ref([]);
|
||||||
|
@ -9,11 +13,12 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Source', path: 'source_addresses' },
|
{ heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Destination', path: 'destination_addresses' },
|
{ heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Service', path: 'services' },
|
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Translated Address', path: 'snat_type.snat.address' },
|
{ heading: 'Type', path: 'snat_type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Translated Service', path: 'snat_type.snat.service' },
|
{ heading: 'Translated Address', path: 'snat_type.snat.address', component: markRaw(ElementDisplay), componentProp: 'data' },
|
||||||
|
{ heading: 'Translated Service', path: 'snat_type.snat.service', component: markRaw(ElementDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Counter', path: 'counter' },
|
{ heading: 'Counter', path: 'counter' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
@ -59,7 +64,7 @@ onMounted(async() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<TableView v-model:selection="selection" v-model:data="rules" title="SNAT Rules" :columns="columns" :loading="loading" :table-props="{sort:true, sortSelf: true, draggable: true}" @dragged-row="draggedRow">
|
<TableView v-model:selection="selection" v-model:data="rules" title="SNAT Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
|
||||||
<button @click="load">Refresh</button>
|
<button @click="load">Refresh</button>
|
||||||
<router-link class="button" to="/firewall/source_nat_rules/edit">Create</router-link>
|
<router-link class="button" to="/firewall/source_nat_rules/edit">Create</router-link>
|
||||||
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/source_nat_rules/edit/' + selection[0]">Edit</router-link>
|
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/source_nat_rules/edit/' + selection[0]">Edit</router-link>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
|
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let interfaces = $ref({});
|
let interfaces = $ref({});
|
||||||
|
@ -9,10 +11,15 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Type', path: 'type' },
|
{ heading: 'Alias', path: 'alias' },
|
||||||
{ heading: 'Members', path: 'members' },
|
{ heading: 'Type', path: 'interface_type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Addressing Mode', path: 'addressing_mode' },
|
{ heading: 'Addressing Mode', path: 'addressing_mode', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Address', path: 'address' },
|
{ heading: 'Address', path: 'addressing_mode.static.address' },
|
||||||
|
{ heading: 'Vlan Parent', path: 'interface_type.vlan.parent' },
|
||||||
|
{ heading: 'Vlan ID', path: 'interface_type.vlan.id' },
|
||||||
|
{ heading: 'Bond Members', path: 'interface_type.bond.members', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
|
{ heading: 'Bridge Members', path: 'interface_type.bridge.members', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const displayData = $computed(() => {
|
const displayData = $computed(() => {
|
||||||
|
@ -21,7 +28,8 @@ const displayData = $computed(() => {
|
||||||
for (const index in interfaces) {
|
for (const index in interfaces) {
|
||||||
data.push({
|
data.push({
|
||||||
name: interfaces[index].name,
|
name: interfaces[index].name,
|
||||||
type: interfaces[index].type,
|
alias: interfaces[index].alias,
|
||||||
|
interface_type: interfaces[index].interface_type,
|
||||||
addressing_mode: interfaces[index].addressing_mode,
|
addressing_mode: interfaces[index].addressing_mode,
|
||||||
address: interfaces[index].address,
|
address: interfaces[index].address,
|
||||||
comment: interfaces[index].comment,
|
comment: interfaces[index].comment,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let addresses = $ref([]);
|
let addresses = $ref([]);
|
||||||
|
@ -9,7 +10,7 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Type', path: 'type' },
|
{ heading: 'Type', path: 'type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Value', path: 'value' },
|
{ heading: 'Value', path: 'value' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
@ -33,7 +34,7 @@ const displayData = $computed(() => {
|
||||||
data.push({
|
data.push({
|
||||||
name: addresses[index].name,
|
name: addresses[index].name,
|
||||||
value: getAddressValue(addresses[index]),
|
value: getAddressValue(addresses[index]),
|
||||||
type: addresses[index].type,
|
type: addresses[index].address_type,
|
||||||
comment: addresses[index].comment,
|
comment: addresses[index].comment,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,7 @@ const displayData = $computed(() => {
|
||||||
|
|
||||||
function getAddressValue(s: any): string {
|
function getAddressValue(s: any): string {
|
||||||
let value: string;
|
let value: string;
|
||||||
switch (s.type) {
|
switch (s.address_type) {
|
||||||
case 'host':
|
case 'host':
|
||||||
value = s.host;
|
value = s.host;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let services = $ref({});
|
let services = $ref({});
|
||||||
|
@ -9,7 +10,7 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Type', path: 'type' },
|
{ heading: 'Type', path: 'type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Value', path: 'value' },
|
{ heading: 'Value', path: 'value' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let servers = $ref([]);
|
let servers = $ref([]);
|
||||||
|
@ -9,6 +10,7 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Interface', path: 'interface' },
|
{ heading: 'Interface', path: 'interface' },
|
||||||
|
{ heading: 'Pool', path: 'pool', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let interfaces = $ref({});
|
let interfaces = $ref({});
|
||||||
|
@ -10,7 +11,7 @@ let selection = $ref([] as number[]);
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Listen Port', path: 'listen_port' },
|
{ heading: 'Listen Port', path: 'listen_port' },
|
||||||
{ heading: 'Peers', path: 'peers' },
|
{ heading: 'Peers', path: 'peers', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { apiCall } from '../../api';
|
import { apiCall } from '../../api';
|
||||||
import getPlugins from '../../plugins';
|
import getPlugins from '../../plugins';
|
||||||
|
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
|
||||||
const p = getPlugins();
|
const p = getPlugins();
|
||||||
|
|
||||||
let peers = $ref({});
|
let peers = $ref({});
|
||||||
|
@ -9,7 +10,7 @@ let selection = $ref([] as number[]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ heading: 'Name', path: 'name' },
|
{ heading: 'Name', path: 'name' },
|
||||||
{ heading: 'Allowed IPs', path: 'allowed_ips' },
|
{ heading: 'Allowed IPs', path: 'allowed_ips', component: markRaw(ArrayDisplay), componentProp: 'data' },
|
||||||
{ heading: 'Endpoint', path: 'endpoint' },
|
{ heading: 'Endpoint', path: 'endpoint' },
|
||||||
{ heading: 'Persistent Keepalive', path: 'persistent_keepalive' },
|
{ heading: 'Persistent Keepalive', path: 'persistent_keepalive' },
|
||||||
{ heading: 'Comment', path: 'comment' },
|
{ heading: 'Comment', path: 'comment' },
|
||||||
|
|
|
@ -16,6 +16,7 @@ export function isNullish(value: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function variantOf(enumValue: any) {
|
export function variantOf(enumValue: any) {
|
||||||
|
if (enumValue === null) return null;
|
||||||
if (typeof enumValue === 'string') return enumValue;
|
if (typeof enumValue === 'string') return enumValue;
|
||||||
else return Object.entries(enumValue)[0][0];
|
else return Object.entries(enumValue)[0][0];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue