add table selection, rework column definitions

This commit is contained in:
Samuel Lorch 2023-03-12 20:27:36 +01:00
parent 0f306a7705
commit 3847a89594
2 changed files with 85 additions and 9 deletions

View file

@ -1,15 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import { useKeyModifier } from '@vueuse/core';
const shiftState = $(useKeyModifier('Shift'));
const ctrlState = $(useKeyModifier('Control'));
const props = defineModel<{ const props = defineModel<{
columns?: Record<string, string>, columns?: {
heading: string,
path: string,
component?: Component,
}[],
data?: Record<string, any>[], data?: Record<string, any>[],
sort?: boolean,
sortSelf?: boolean, sortSelf?: boolean,
sortBy?: string, sortBy?: string,
sortDesc?: boolean, 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 !== '') const displayData = $computed(() => (sortSelf && sortBy !== '')
? data?.sort((a, b) => { ? data?.sort((a, b) => {
selection = [];
let result; let result;
if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1; if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1;
else if (a[sortBy ?? ''] === b[sortBy ?? '']) result = 0; else if (a[sortBy ?? ''] === b[sortBy ?? '']) result = 0;
@ -21,35 +39,84 @@ const displayData = $computed(() => (sortSelf && sortBy !== '')
: data); : data);
function toggleSorting(columnName: string) { function toggleSorting(columnName: string) {
if (!sort) return;
if (columnName === sortBy) sortDesc = !sortDesc; if (columnName === sortBy) sortDesc = !sortDesc;
else { else {
sortDesc = false; sortDesc = false;
sortBy = columnName; 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> </script>
<template> <template>
<table> <table>
<thead> <thead>
<tr> <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"> <div class="flex-row">
{{ heading }} {{ heading }}
<i-mdi-arrow-down v-if="name === sortBy && sortDesc"/> <template v-if="sort">
<i-mdi-arrow-up v-else-if="name === sortBy"/> <i-mdi-arrow-down v-if="path === sortBy && sortDesc"/>
<i-mdi-arrow-up v-else-if="path === sortBy"/>
</template>
</div> </div>
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<!-- eslint-disable-next-line vue/require-v-for-key --> <tr v-for="(row, index) in displayData" :key="index"
<tr v-for="row of displayData"> @click="() => rowSelection(index)"
<td v-for="[column] in Object.entries(columns ?? {})" :key="column" v-text="row[column]"/> @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> </tr>
</tbody> </tbody>
</table> </table>
</template> </template>
<style scoped> <style scoped>
.selected {
background-color: red;
}
</style> </style>

View file

@ -2,6 +2,15 @@
import { apiCall } from "../../api"; import { apiCall } from "../../api";
let rules = $ref([]); 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(){ async function loadRules(){
let res = await apiCall("Firewall.GetForwardRules", {}); let res = await apiCall("Firewall.GetForwardRules", {});
@ -24,6 +33,6 @@ onMounted(async() => {
<PageHeader title="Forward Rules"> <PageHeader title="Forward Rules">
<button @click="loadRules">Load Rules</button> <button @click="loadRules">Load Rules</button>
</PageHeader> </PageHeader>
<NiceTable :columns="{name: 'Name', verdict: 'Verdict'}" :sort-self="false" v-model:data="rules"/> <NiceTable :columns="columns" v-model:data="rules"/>
</div> </div>
</template> </template>