192 lines
7.8 KiB
Svelte
192 lines
7.8 KiB
Svelte
<script lang="ts">
|
|
import { createSvelteTable, FlexRender } from "@components/ui/data-table";
|
|
import { columns } from "./columns";
|
|
import { getCoreRowModel, getPaginationRowModel, type PaginationState } from "@tanstack/table-core";
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@components/ui/table";
|
|
import { auditLog } from "@components/repo/auditlog";
|
|
import { now, ZonedDateTime } from "@internationalized/date";
|
|
import { AuditLogEntrySchema, type AuditLogEntry } from "@components/types/auditlog";
|
|
import { Button } from "@components/ui/button";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger } from "@components/ui/select";
|
|
import { Input } from "@components/ui/input";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
|
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command";
|
|
import { Check } from "lucide-svelte";
|
|
import { cn } from "@components/utils";
|
|
import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
|
|
import PlayerSelector from "@components/ui/PlayerSelector.svelte";
|
|
|
|
let debounceTimer: NodeJS.Timeout;
|
|
const debounce = <T,>(value: T, func: (value: T) => void) => {
|
|
clearTimeout(debounceTimer);
|
|
debounceTimer = setTimeout(() => {
|
|
func(value);
|
|
}, 300);
|
|
};
|
|
|
|
let actionText = $state("");
|
|
let serverText = $state("");
|
|
let fullText = $state("");
|
|
let actors = $state<number[]>([]);
|
|
let actionTypes = $state<string[]>([]);
|
|
let timeGreater = $state<ZonedDateTime>(now("Europe/Berlin").subtract({ months: 1 }));
|
|
let timeLess = $state<ZonedDateTime>(now("Europe/Berlin"));
|
|
let serverOwner = $state<number[]>([]);
|
|
let velocity = $state(false);
|
|
let sorting = $state("DESC");
|
|
|
|
let pagination = $state<PaginationState>({
|
|
pageIndex: 0,
|
|
pageSize: 25,
|
|
});
|
|
|
|
let data = $state<AuditLogEntry[]>([]);
|
|
let rows = $state(0);
|
|
|
|
$effect(() => {
|
|
$auditLog
|
|
.get(
|
|
actionText || undefined,
|
|
serverText || undefined,
|
|
fullText || undefined,
|
|
actors.length > 0 ? actors : undefined,
|
|
actionTypes.length > 0 ? actionTypes : undefined,
|
|
timeGreater ? timeGreater.toDate().getTime() : undefined,
|
|
timeLess ? timeLess.toDate().getTime() : undefined,
|
|
serverOwner.length > 0 ? serverOwner : undefined,
|
|
velocity,
|
|
pagination.pageIndex,
|
|
pagination.pageSize,
|
|
sorting || undefined
|
|
)
|
|
.then((res) => {
|
|
data = res.entries;
|
|
rows = res.rows;
|
|
});
|
|
});
|
|
|
|
const table = createSvelteTable({
|
|
get data() {
|
|
return data;
|
|
},
|
|
columns,
|
|
state: {
|
|
get pagination() {
|
|
return pagination;
|
|
},
|
|
},
|
|
onPaginationChange: (updater) => {
|
|
if (typeof updater === "function") {
|
|
pagination = updater(pagination);
|
|
} else {
|
|
pagination = updater;
|
|
}
|
|
},
|
|
getCoreRowModel: getCoreRowModel(),
|
|
getPaginationRowModel: getPaginationRowModel(),
|
|
manualPagination: true,
|
|
get rowCount() {
|
|
return rows;
|
|
},
|
|
});
|
|
|
|
let playerSearch = $state("");
|
|
let ownerSearch = $state("");
|
|
</script>
|
|
|
|
<div class="p-4">
|
|
<div class="rounded border mb-4 p-2 flex lg:flex-row flex-col">
|
|
<Input
|
|
class="w-48 mr-2"
|
|
placeholder="Suchen..."
|
|
value={fullText}
|
|
onchange={(e) =>
|
|
debounce(e.currentTarget.value, (v) => {
|
|
fullText = v;
|
|
})}
|
|
oninput={(e) =>
|
|
debounce(e.currentTarget.value, (v) => {
|
|
fullText = v;
|
|
})}
|
|
/>
|
|
<Select type="multiple" value={actionTypes} onValueChange={(e) => (actionTypes = e)}>
|
|
<SelectTrigger class="w-48 mr-2" placeholder="Aktionstypen auswählen...">Aktionstypen ({actionTypes.length})</SelectTrigger>
|
|
<SelectContent>
|
|
{#each ["JOIN", "LEAVE", "COMMAND", "SENSITIVE_COMMAND", "CHAT", "GUI_OPEN", "GUI_CLOSE", "GUI_CLICK"] as option}
|
|
<SelectItem value={option}>{option}</SelectItem>
|
|
{/each}
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
<div class="mr-2">
|
|
<PlayerSelector bind:value={actors} multiple placeholder="Spieler Filter" />
|
|
</div>
|
|
<div class="mr-2">
|
|
<PlayerSelector bind:value={serverOwner} multiple placeholder="Server Owner" />
|
|
</div>
|
|
<div class="mr-2">
|
|
<DateTimePicker bind:value={timeGreater} />
|
|
</div>
|
|
<div class="mr-2">
|
|
<DateTimePicker bind:value={timeLess} />
|
|
</div>
|
|
<Select type="single" value={sorting} onValueChange={(e) => (sorting = e)}>
|
|
<SelectTrigger class="w-48 mr-2">{sorting === "ASC" ? "Aufsteigend" : "Absteigend"}</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="ASC">Aufsteigend</SelectItem>
|
|
<SelectItem value="DESC">Absteigend</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div class="rounded border">
|
|
<Table>
|
|
<TableHeader>
|
|
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
|
<TableRow>
|
|
{#each headerGroup.headers as header (header.id)}
|
|
<TableHead colspan={header.colSpan}>
|
|
{#if !header.isPlaceholder}
|
|
<FlexRender content={header.column.columnDef.header} context={header.getContext()} />
|
|
{/if}
|
|
</TableHead>
|
|
{/each}
|
|
</TableRow>
|
|
{/each}
|
|
</TableHeader>
|
|
<TableBody>
|
|
{#each table.getRowModel().rows as row (row.id)}
|
|
<TableRow>
|
|
{#each row.getVisibleCells() as cell (cell.id)}
|
|
<TableCell class="p-2 align-top">
|
|
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
|
</TableCell>
|
|
{/each}
|
|
</TableRow>
|
|
{:else}
|
|
<TableRow>
|
|
<TableCell colspan={columns.length} class="h-24 text-center">Keine Einträge gefunden.</TableCell>
|
|
</TableRow>
|
|
{/each}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end space-x-2 py-4">
|
|
<div>
|
|
<Select type="single" value={pagination.pageSize.toString()} onValueChange={(e) => (pagination = { pageSize: +e, pageIndex: 0 })}>
|
|
<SelectTrigger>{pagination.pageSize}</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="5">5</SelectItem>
|
|
<SelectItem value="10">10</SelectItem>
|
|
<SelectItem value="25">25</SelectItem>
|
|
<SelectItem value="50">50</SelectItem>
|
|
<SelectItem value="100">100</SelectItem>
|
|
<SelectItem value="200">200</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<Button variant="outline" size="sm" onclick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>Previous</Button>
|
|
<Button variant="outline" size="sm" onclick={() => table.nextPage()} disabled={!table.getCanNextPage()}>Next</Button>
|
|
</div>
|
|
</div>
|