feat(logs): fuzzy filter, sorting

This commit is contained in:
kunish 2023-09-17 12:37:10 +08:00
parent 5277c7bbc9
commit 67345cf1e3
No known key found for this signature in database
GPG Key ID: 647A12B4F782C430
2 changed files with 77 additions and 25 deletions

View File

@ -261,9 +261,6 @@ export default () => {
get globalFilter() { get globalFilter() {
return globalFilter() return globalFilter()
}, },
get columnFilters() {
return []
},
}, },
get data() { get data() {
return activeTab() === ActiveTab.activeConnections return activeTab() === ActiveTab.activeConnections
@ -420,7 +417,7 @@ export default () => {
<tbody> <tbody>
<For each={table.getRowModel().rows}> <For each={table.getRowModel().rows}>
{(row) => ( {(row) => (
<tr class="h-8 hover:!bg-primary hover:text-primary-content"> <tr class="hover:!bg-primary hover:text-primary-content">
<For each={row.getVisibleCells()}> <For each={row.getVisibleCells()}>
{(cell) => { {(cell) => {
return ( return (

View File

@ -1,12 +1,22 @@
import { useI18n } from '@solid-primitives/i18n' import { useI18n } from '@solid-primitives/i18n'
import { IconSettings } from '@tabler/icons-solidjs' import { makePersisted } from '@solid-primitives/storage'
import {
IconSettings,
IconSortAscending,
IconSortDescending,
} from '@tabler/icons-solidjs'
import { rankItem } from '@tanstack/match-sorter-utils'
import { import {
ColumnDef, ColumnDef,
FilterFn,
SortingState,
createSolidTable, createSolidTable,
flexRender, flexRender,
getCoreRowModel, getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
} from '@tanstack/solid-table' } from '@tanstack/solid-table'
import { For, Index, createEffect, createSignal } from 'solid-js' import { For, Index, createEffect, createMemo, createSignal } from 'solid-js'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { Button, LogsSettingsModal } from '~/components' import { Button, LogsSettingsModal } from '~/components'
import { LOG_LEVEL, MODAL } from '~/constants' import { LOG_LEVEL, MODAL } from '~/constants'
@ -16,10 +26,22 @@ import { Log } from '~/types'
type LogWithSeq = Log & { seq: number } type LogWithSeq = Log & { seq: number }
const fuzzyFilter: FilterFn<LogWithSeq> = (row, columnId, value, addMeta) => {
// Rank the item
const itemRank = rankItem(row.getValue(columnId), value)
// Store the itemRank info
addMeta({
itemRank,
})
// Return if the item should be filtered in/out
return itemRank.passed
}
export default () => { export default () => {
const [t] = useI18n() const [t] = useI18n()
let seq = 1 let seq = 1
const [search, setSearch] = createSignal('')
const [logs, setLogs] = createSignal<LogWithSeq[]>([]) const [logs, setLogs] = createSignal<LogWithSeq[]>([])
const logsData = useWsRequest<Log>('logs', { level: logLevel() }) const logsData = useWsRequest<Log>('logs', { level: logLevel() })
@ -36,13 +58,21 @@ export default () => {
seq++ seq++
}) })
const columns: ColumnDef<LogWithSeq>[] = [ const [globalFilter, setGlobalFilter] = createSignal('')
const [sorting, setSorting] = makePersisted(createSignal<SortingState>([]), {
name: 'logsTableSorting',
storage: localStorage,
})
const columns = createMemo<ColumnDef<LogWithSeq>[]>(() => [
{ {
header: t('sequence'), header: t('sequence'),
accessorFn: (row) => row.seq, accessorFn: (row) => row.seq,
}, },
{ {
header: t('type'), header: t('type'),
accessorFn: (row) => row.type,
cell: ({ row }) => { cell: ({ row }) => {
const type = row.original.type as LOG_LEVEL const type = row.original.type as LOG_LEVEL
@ -70,17 +100,30 @@ export default () => {
header: t('payload'), header: t('payload'),
accessorFn: (row) => row.payload, accessorFn: (row) => row.payload,
}, },
] ])
const table = createSolidTable({ const table = createSolidTable({
get data() { filterFns: {
return search() fuzzy: fuzzyFilter,
? logs().filter((log) =>
log.payload.toLowerCase().includes(search().toLowerCase()),
)
: logs()
}, },
columns, state: {
get globalFilter() {
return globalFilter()
},
get sorting() {
return sorting()
},
},
get data() {
return logs()
},
sortDescFirst: true,
columns: columns(),
onGlobalFilterChange: setGlobalFilter,
onSortingChange: setSorting,
globalFilterFn: fuzzyFilter,
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}) })
@ -91,7 +134,7 @@ export default () => {
type="search" type="search"
class="input join-item input-primary input-sm flex-1 flex-shrink-0 sm:input-md" class="input join-item input-primary input-sm flex-1 flex-shrink-0 sm:input-md"
placeholder={t('search')} placeholder={t('search')}
onInput={(e) => setSearch(e.target.value)} onInput={(e) => setGlobalFilter(e.target.value)}
/> />
<Button <Button
@ -127,14 +170,26 @@ export default () => {
const header = keyedHeader() const header = keyedHeader()
return ( return (
<th class="bg-base-300"> <th class="bg-base-200">
<div> <div class="flex items-center">
{header.isPlaceholder <div
? null class={twMerge(
: flexRender( header.column.getCanSort() &&
header.column.columnDef.header, 'cursor-pointer select-none',
header.getContext(), 'flex-1',
)} )}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</div>
{{
asc: <IconSortAscending />,
desc: <IconSortDescending />,
}[header.column.getIsSorted() as string] ?? null}
</div> </div>
</th> </th>
) )