mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-11 02:48:21 +00:00
add table selection, rework column definitions
This commit is contained in:
parent
0f306a7705
commit
3847a89594
2 changed files with 85 additions and 9 deletions
|
@ -1,15 +1,33 @@
|
|||
<script setup lang="ts">
|
||||
import { useKeyModifier } from '@vueuse/core';
|
||||
|
||||
const shiftState = $(useKeyModifier('Shift'));
|
||||
const ctrlState = $(useKeyModifier('Control'));
|
||||
|
||||
const props = defineModel<{
|
||||
columns?: Record<string, string>,
|
||||
columns?: {
|
||||
heading: string,
|
||||
path: string,
|
||||
component?: Component,
|
||||
}[],
|
||||
data?: Record<string, any>[],
|
||||
sort?: boolean,
|
||||
sortSelf?: boolean,
|
||||
sortBy?: string,
|
||||
sortDesc?: boolean,
|
||||
}>();
|
||||
let { columns, data, sortSelf, sortBy, sortDesc } = $(props);
|
||||
let { columns, data, sort, sortSelf, sortBy, sortDesc } = $(props);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'rowAction', index: number): void,
|
||||
(event: 'selectionChanged'): void
|
||||
}>();
|
||||
|
||||
let selection = $ref([] as number[]);
|
||||
|
||||
const displayData = $computed(() => (sortSelf && sortBy !== '')
|
||||
? data?.sort((a, b) => {
|
||||
selection = [];
|
||||
let result;
|
||||
if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1;
|
||||
else if (a[sortBy ?? ''] === b[sortBy ?? '']) result = 0;
|
||||
|
@ -21,35 +39,84 @@ const displayData = $computed(() => (sortSelf && sortBy !== '')
|
|||
: data);
|
||||
|
||||
function toggleSorting(columnName: string) {
|
||||
if (!sort) return;
|
||||
if (columnName === sortBy) sortDesc = !sortDesc;
|
||||
else {
|
||||
sortDesc = false;
|
||||
sortBy = columnName;
|
||||
}
|
||||
}
|
||||
|
||||
function rowSelection(index: number) {
|
||||
if (shiftState) {
|
||||
let last = selection[selection.length-1];
|
||||
let start = index;
|
||||
let end = last;
|
||||
if (last < start) {
|
||||
start = last;
|
||||
end = index;
|
||||
}
|
||||
for (let i = start; i < end; i++ ) {
|
||||
if (!selection.includes(i)) {
|
||||
selection = [...selection, i];
|
||||
}
|
||||
}
|
||||
} else if (ctrlState) {
|
||||
if (selection.includes(index)) {
|
||||
// remove if already exists
|
||||
selection.splice(selection.indexOf(index), 1);
|
||||
} else {
|
||||
selection = [...selection, index];
|
||||
}
|
||||
} else {
|
||||
if (selection.includes(index)) {
|
||||
selection = [];
|
||||
} else {
|
||||
selection = [index];
|
||||
}
|
||||
}
|
||||
emit("selectionChanged");
|
||||
}
|
||||
|
||||
function atPath(value: any, path: string): any {
|
||||
for (const segment of path.split(".")) {
|
||||
value = value[segment];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="[name, heading] in Object.entries(columns ?? {})" :key="name" @click="toggleSorting(name)">
|
||||
<th v-for="{heading, path} of columns" :key="path" @click="() => toggleSorting(path)">
|
||||
<div class="flex-row">
|
||||
{{ heading }}
|
||||
<i-mdi-arrow-down v-if="name === sortBy && sortDesc"/>
|
||||
<i-mdi-arrow-up v-else-if="name === sortBy"/>
|
||||
<template v-if="sort">
|
||||
<i-mdi-arrow-down v-if="path === sortBy && sortDesc"/>
|
||||
<i-mdi-arrow-up v-else-if="path === sortBy"/>
|
||||
</template>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- eslint-disable-next-line vue/require-v-for-key -->
|
||||
<tr v-for="row of displayData">
|
||||
<td v-for="[column] in Object.entries(columns ?? {})" :key="column" v-text="row[column]"/>
|
||||
<tr v-for="(row, index) in displayData" :key="index"
|
||||
@click="() => rowSelection(index)"
|
||||
@dblclick="() => emit('rowAction', index)"
|
||||
:class="{'selected': selection.includes(index)}">
|
||||
<td v-for="{path, component} of columns" :key="path">
|
||||
{{ component ? "" : atPath(row, path) }}
|
||||
<component v-if="component" :is="component"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.selected {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
|
@ -2,6 +2,15 @@
|
|||
import { apiCall } from "../../api";
|
||||
|
||||
let rules = $ref([]);
|
||||
const columns = [
|
||||
{heading: 'Name', path: 'name'},
|
||||
{heading: 'Source', path: 'match.source_addresses'},
|
||||
{heading: 'Destination', path: 'match.destination_addresses'},
|
||||
{heading: 'Service', path: 'match.services'},
|
||||
{heading: 'Verdict', path: 'verdict'},
|
||||
{heading: 'Counter', path: 'counter'},
|
||||
{heading: 'Comment', path: 'comment'},
|
||||
];
|
||||
|
||||
async function loadRules(){
|
||||
let res = await apiCall("Firewall.GetForwardRules", {});
|
||||
|
@ -24,6 +33,6 @@ onMounted(async() => {
|
|||
<PageHeader title="Forward Rules">
|
||||
<button @click="loadRules">Load Rules</button>
|
||||
</PageHeader>
|
||||
<NiceTable :columns="{name: 'Name', verdict: 'Verdict'}" :sort-self="false" v-model:data="rules"/>
|
||||
<NiceTable :columns="columns" v-model:data="rules"/>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Reference in a new issue