Compare commits

..

No commits in common. "ab8430824f94fbe11fa78312326fe882476b6c70" and "84488b3e63441c33ae9eca1ee945d6dcb7af6115" have entirely different histories.

16 changed files with 54 additions and 126 deletions

View file

@ -3,25 +3,33 @@ const props = withDefaults(defineProps<{
data: any[],
component?: string,
componentProp?: '',
ellipsis?: number,
empty?: string
ellipsis?: number
}>(), {
data: () => [],
component: '',
componentProp: '',
ellipsis: 10,
empty: '',
ellipsis: 2,
});
</script>
<template>
<div v-if="props.data.length != 0" class="pillstack">
<div class="pillbar">
<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 !== ''"/>
<template v-else>{{ item }}</template>
</div>
<div v-if="props.data.length >= props.ellipsis" class="pill">...</div>
</div>
<div v-else>
{{ props.empty }}
</div>
</template>
<style scoped>
.pillbar {
flex-direction: row;
flex-wrap: wrap;
gap: 0.25rem;
}
.pill {
border: 1px solid var(--cl-fg);
padding: 0.25rem;
}
</style>

View file

@ -1,19 +0,0 @@
<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>

View file

@ -1,12 +0,0 @@
<script setup lang="ts">
import { variantOf } from '~/util';
const props = withDefaults(defineProps<{
data: object | string,
}>(), {
data: '',
});
</script>
<template>
{{ variantOf(props.data) }}
</template>

View file

@ -108,10 +108,7 @@ function dragDropRow() {
data.splice(draggedRow, 1);
data.splice(draggedOverRow, 0, row);
data = data;
// Don't emit if we are at the same spot
if (draggedRow !== draggedOverRow){
emit('draggedRow', draggedRow, draggedOverRow);
}
emit('draggedRow', draggedRow, draggedOverRow);
}
// Reset Drag & Remove Selection
@ -163,4 +160,4 @@ function dragDropRow() {
.dragged-over-after { border-bottom: 0.25rem solid var(--cl-fg); }
tr { cursor: grab; }
</style>
</style>

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { Index, MaybeIndex, equals, variantOf } from '../../util';
import { Index, MaybeIndex, equals } from '../../util';
import { Fields } from './NicerForm.vue';
export type Variant = {
@ -34,7 +34,7 @@ const emit = defineEmits<{
}>();
// Local Variables for Two-Way bindings
let modelValue = $ref(null as MaybeEnumValue);
let modelValue: MaybeEnumValue = $ref(null);
// Sync from v-model
onMounted(() => {
watch(() => props.modelValue, (val) => {
@ -49,14 +49,8 @@ onMounted(() => {
}, { deep: true, immediate: true });
});
// Sync to v-model
watch($$(modelValue), (val, oldVal) => {
watch($$(modelValue), (val) => {
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));
}, { deep: true });
@ -94,4 +88,4 @@ watchEffect(() => {
border: 1px solid var(--cl-fg);
padding: calc(0.25rem - 1px);
}
</style>
</style>

View file

@ -120,21 +120,4 @@ tbody tr:hover, th:hover {
tbody tr.selected {
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;
}

View file

@ -1,8 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
import ElementDisplay from '~/components/display/ElementDisplay.vue';
const p = getPlugins();
let rules = $ref([]);
@ -11,11 +9,11 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Translated Address', path: 'dnat_address', component: markRaw(ElementDisplay), componentProp: 'data' },
{ heading: 'Translated Service', path: 'dnat_service', component: markRaw(ElementDisplay), componentProp: 'data' },
{ heading: 'Source', path: 'source_addresses' },
{ heading: 'Destination', path: 'destination_addresses' },
{ heading: 'Service', path: 'services' },
{ heading: 'Translated Address', path: 'dnat_address' },
{ heading: 'Translated Service', path: 'dnat_service' },
{ heading: 'Counter', path: 'counter' },
{ heading: 'Comment', path: 'comment' },
];
@ -61,11 +59,11 @@ onMounted(async() => {
<template>
<div>
<TableView v-model:selection="selection" v-model:data="rules" title="DNAT Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
<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">
<button @click="load">Refresh</button>
<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>
<button :disabled="selection.length != 1" @click="deleteRule">Delete</button>
</TableView>
</div>
</template>
</template>

View file

@ -15,7 +15,6 @@ const columns = [
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Verdict', path: 'verdict' },
{ heading: 'Counter', path: 'counter' },
{ heading: 'Log', path: 'log' },
{ heading: 'Comment', path: 'comment' },
];
@ -60,11 +59,11 @@ onMounted(async() => {
<template>
<div>
<TableView v-model:selection="selection" v-model:data="rules" title="Forward Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
<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">
<button @click="load">Refresh</button>
<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>
<button :disabled="selection.length != 1" @click="deleteRule">Delete</button>
</TableView>
</div>
</template>
</template>

View file

@ -1,10 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
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();
let rules = $ref([]);
@ -13,12 +9,11 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Type', path: 'snat_type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
{ 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: 'Source', path: 'source_addresses' },
{ heading: 'Destination', path: 'destination_addresses' },
{ heading: 'Service', path: 'services' },
{ heading: 'Translated Address', path: 'snat_type.snat.address' },
{ heading: 'Translated Service', path: 'snat_type.snat.service' },
{ heading: 'Counter', path: 'counter' },
{ heading: 'Comment', path: 'comment' },
];
@ -64,11 +59,11 @@ onMounted(async() => {
<template>
<div>
<TableView v-model:selection="selection" v-model:data="rules" title="SNAT Rules" :columns="columns" :loading="loading" :table-props="{draggable: true}" @dragged-row="draggedRow">
<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">
<button @click="load">Refresh</button>
<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>
<button :disabled="selection.length != 1" @click="deleteRule">Delete</button>
</TableView>
</div>
</template>
</template>

View file

@ -1,8 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
const p = getPlugins();
let interfaces = $ref({});
@ -11,15 +9,10 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Alias', path: 'alias' },
{ heading: 'Type', path: 'interface_type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
{ heading: 'Addressing Mode', path: 'addressing_mode', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
{ 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' },
{ heading: 'Type', path: 'type' },
{ heading: 'Members', path: 'members' },
{ heading: 'Addressing Mode', path: 'addressing_mode' },
{ heading: 'Address', path: 'address' },
];
const displayData = $computed(() => {
@ -28,8 +21,7 @@ const displayData = $computed(() => {
for (const index in interfaces) {
data.push({
name: interfaces[index].name,
alias: interfaces[index].alias,
interface_type: interfaces[index].interface_type,
type: interfaces[index].type,
addressing_mode: interfaces[index].addressing_mode,
address: interfaces[index].address,
comment: interfaces[index].comment,
@ -77,4 +69,4 @@ onMounted(async() => {
<button :disabled="selection.length != 1" @click="editInterface">Edit</button>
<button :disabled="selection.length != 1" @click="deleteInterface">Delete</button>
</TableView>
</template>
</template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
const p = getPlugins();
let addresses = $ref([]);
@ -10,7 +9,7 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Type', path: 'type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
{ heading: 'Type', path: 'type' },
{ heading: 'Value', path: 'value' },
{ heading: 'Comment', path: 'comment' },
];
@ -34,7 +33,7 @@ const displayData = $computed(() => {
data.push({
name: addresses[index].name,
value: getAddressValue(addresses[index]),
type: addresses[index].address_type,
type: addresses[index].type,
comment: addresses[index].comment,
});
}
@ -43,7 +42,7 @@ const displayData = $computed(() => {
function getAddressValue(s: any): string {
let value: string;
switch (s.address_type) {
switch (s.type) {
case 'host':
value = s.host;
break;
@ -89,4 +88,4 @@ onMounted(async() => {
<button :disabled="selection.length != 1" @click="editAddress">Edit</button>
<button :disabled="selection.length != 1" @click="deleteAddress">Delete</button>
</TableView>
</template>
</template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import EnumTypeDisplay from '~/components/display/EnumTypeDisplay.vue';
const p = getPlugins();
let services = $ref({});
@ -10,7 +9,7 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Type', path: 'type', component: markRaw(EnumTypeDisplay), componentProp: 'data' },
{ heading: 'Type', path: 'type' },
{ heading: 'Value', path: 'value' },
{ heading: 'Comment', path: 'comment' },
];
@ -92,4 +91,4 @@ onMounted(async() => {
<button :disabled="selection.length != 1" @click="editService">Edit</button>
<button :disabled="selection.length != 1" @click="deleteService">Delete</button>
</TableView>
</template>
</template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
const p = getPlugins();
let servers = $ref([]);
@ -10,7 +9,6 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Interface', path: 'interface' },
{ heading: 'Pool', path: 'pool', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Comment', path: 'comment' },
];
@ -50,4 +48,4 @@ onMounted(async() => {
<button :disabled="selection.length != 1" @click="deleteRule">Delete</button>
</TableView>
</div>
</template>
</template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
const p = getPlugins();
let interfaces = $ref({});
@ -11,7 +10,7 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Listen Port', path: 'listen_port' },
{ heading: 'Peers', path: 'peers', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Peers', path: 'peers' },
{ heading: 'Comment', path: 'comment' },
];
@ -69,4 +68,4 @@ onMounted(async() => {
<button :disabled="selection.length != 1" @click="editInterface">Edit</button>
<button :disabled="selection.length != 1" @click="deleteInterface">Delete</button>
</TableView>
</template>
</template>

View file

@ -1,7 +1,6 @@
<script setup lang="ts">
import { apiCall } from '../../api';
import getPlugins from '../../plugins';
import ArrayDisplay from '~/components/display/ArrayDisplay.vue';
const p = getPlugins();
let peers = $ref({});
@ -10,7 +9,7 @@ let selection = $ref([] as number[]);
const columns = [
{ heading: 'Name', path: 'name' },
{ heading: 'Allowed IPs', path: 'allowed_ips', component: markRaw(ArrayDisplay), componentProp: 'data' },
{ heading: 'Allowed IPs', path: 'allowed_ips' },
{ heading: 'Endpoint', path: 'endpoint' },
{ heading: 'Persistent Keepalive', path: 'persistent_keepalive' },
{ heading: 'Comment', path: 'comment' },

View file

@ -16,7 +16,6 @@ export function isNullish(value: any) {
}
export function variantOf(enumValue: any) {
if (enumValue === null) return null;
if (typeof enumValue === 'string') return enumValue;
else return Object.entries(enumValue)[0][0];
}