2023-09-02 00:15:19 +08:00
|
|
|
import { useI18n } from '@solid-primitives/i18n'
|
2023-09-17 12:37:10 +08:00
|
|
|
import { makePersisted } from '@solid-primitives/storage'
|
|
|
|
import {
|
|
|
|
IconSettings,
|
|
|
|
IconSortAscending,
|
|
|
|
IconSortDescending,
|
|
|
|
} from '@tabler/icons-solidjs'
|
|
|
|
import { rankItem } from '@tanstack/match-sorter-utils'
|
2023-09-01 22:07:02 +08:00
|
|
|
import {
|
|
|
|
ColumnDef,
|
2023-09-17 12:37:10 +08:00
|
|
|
FilterFn,
|
|
|
|
SortingState,
|
2023-09-01 22:07:02 +08:00
|
|
|
createSolidTable,
|
|
|
|
flexRender,
|
|
|
|
getCoreRowModel,
|
2023-09-17 12:37:10 +08:00
|
|
|
getFilteredRowModel,
|
|
|
|
getSortedRowModel,
|
2023-09-01 22:07:02 +08:00
|
|
|
} from '@tanstack/solid-table'
|
2023-09-17 12:37:10 +08:00
|
|
|
import { For, Index, createEffect, createMemo, createSignal } from 'solid-js'
|
2023-09-05 20:53:00 +08:00
|
|
|
import { twMerge } from 'tailwind-merge'
|
2023-09-15 23:43:55 +08:00
|
|
|
import { Button, LogsSettingsModal } from '~/components'
|
|
|
|
import { LOG_LEVEL, MODAL } from '~/constants'
|
|
|
|
import { logsTableSize, tableSizeClassName, useWsRequest } from '~/signals'
|
2023-09-14 18:31:52 +08:00
|
|
|
import { logLevel, logMaxRows } from '~/signals/config'
|
2023-09-01 22:07:02 +08:00
|
|
|
import { Log } from '~/types'
|
|
|
|
|
|
|
|
type LogWithSeq = Log & { seq: number }
|
2023-08-24 04:20:53 +08:00
|
|
|
|
2023-09-17 12:37:10 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-08-29 14:44:49 +08:00
|
|
|
export default () => {
|
2023-09-02 00:15:19 +08:00
|
|
|
const [t] = useI18n()
|
2023-09-10 19:03:26 +08:00
|
|
|
let seq = 1
|
2023-09-01 22:07:02 +08:00
|
|
|
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
2023-08-24 04:20:53 +08:00
|
|
|
|
2023-09-14 16:49:39 +08:00
|
|
|
const logsData = useWsRequest<Log>('logs', { level: logLevel() })
|
2023-08-24 04:20:53 +08:00
|
|
|
|
|
|
|
createEffect(() => {
|
2023-09-06 19:33:07 +08:00
|
|
|
const data = logsData()
|
2023-08-24 04:20:53 +08:00
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-09-16 15:38:42 +08:00
|
|
|
setLogs((logs) => [{ ...data, seq }, ...logs].slice(0, logMaxRows()))
|
2023-09-01 22:07:02 +08:00
|
|
|
|
|
|
|
seq++
|
|
|
|
})
|
|
|
|
|
2023-09-17 12:37:10 +08:00
|
|
|
const [globalFilter, setGlobalFilter] = createSignal('')
|
|
|
|
|
|
|
|
const [sorting, setSorting] = makePersisted(createSignal<SortingState>([]), {
|
|
|
|
name: 'logsTableSorting',
|
|
|
|
storage: localStorage,
|
|
|
|
})
|
|
|
|
|
|
|
|
const columns = createMemo<ColumnDef<LogWithSeq>[]>(() => [
|
2023-09-01 22:07:02 +08:00
|
|
|
{
|
2023-09-08 21:22:34 +08:00
|
|
|
header: t('sequence'),
|
2023-09-01 22:07:02 +08:00
|
|
|
accessorFn: (row) => row.seq,
|
|
|
|
},
|
|
|
|
{
|
2023-09-08 21:22:34 +08:00
|
|
|
header: t('type'),
|
2023-09-17 12:37:10 +08:00
|
|
|
accessorFn: (row) => row.type,
|
2023-09-10 01:10:56 +08:00
|
|
|
cell: ({ row }) => {
|
2023-09-14 16:49:39 +08:00
|
|
|
const type = row.original.type as LOG_LEVEL
|
2023-09-10 01:10:56 +08:00
|
|
|
|
|
|
|
let className = ''
|
|
|
|
|
|
|
|
switch (type) {
|
2023-09-14 16:49:39 +08:00
|
|
|
case LOG_LEVEL.Error:
|
2023-09-10 01:10:56 +08:00
|
|
|
className = 'text-error'
|
|
|
|
break
|
2023-09-14 16:49:39 +08:00
|
|
|
case LOG_LEVEL.Warning:
|
2023-09-10 01:10:56 +08:00
|
|
|
className = 'text-warning'
|
|
|
|
break
|
2023-09-14 16:49:39 +08:00
|
|
|
case LOG_LEVEL.Info:
|
2023-09-10 01:10:56 +08:00
|
|
|
className = 'text-info'
|
|
|
|
break
|
2023-09-14 16:49:39 +08:00
|
|
|
case LOG_LEVEL.Debug:
|
|
|
|
className = 'text-success'
|
|
|
|
break
|
2023-09-10 01:10:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return <span class={className}>{`[${row.original.type}]`}</span>
|
|
|
|
},
|
2023-09-01 22:07:02 +08:00
|
|
|
},
|
|
|
|
{
|
2023-09-08 21:22:34 +08:00
|
|
|
header: t('payload'),
|
2023-09-01 22:07:02 +08:00
|
|
|
accessorFn: (row) => row.payload,
|
|
|
|
},
|
2023-09-17 12:37:10 +08:00
|
|
|
])
|
2023-09-01 22:07:02 +08:00
|
|
|
|
|
|
|
const table = createSolidTable({
|
2023-09-17 12:37:10 +08:00
|
|
|
filterFns: {
|
|
|
|
fuzzy: fuzzyFilter,
|
|
|
|
},
|
|
|
|
state: {
|
|
|
|
get globalFilter() {
|
|
|
|
return globalFilter()
|
|
|
|
},
|
|
|
|
get sorting() {
|
|
|
|
return sorting()
|
|
|
|
},
|
|
|
|
},
|
2023-09-01 22:07:02 +08:00
|
|
|
get data() {
|
2023-09-17 12:37:10 +08:00
|
|
|
return logs()
|
2023-09-01 22:07:02 +08:00
|
|
|
},
|
2023-09-17 12:37:10 +08:00
|
|
|
sortDescFirst: true,
|
|
|
|
columns: columns(),
|
|
|
|
onGlobalFilterChange: setGlobalFilter,
|
|
|
|
onSortingChange: setSorting,
|
|
|
|
globalFilterFn: fuzzyFilter,
|
|
|
|
getFilteredRowModel: getFilteredRowModel(),
|
|
|
|
getSortedRowModel: getSortedRowModel(),
|
2023-09-01 22:07:02 +08:00
|
|
|
getCoreRowModel: getCoreRowModel(),
|
2023-08-24 04:20:53 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
return (
|
2023-09-17 12:40:24 +08:00
|
|
|
<div class="flex h-full flex-col gap-2">
|
2023-09-15 23:43:55 +08:00
|
|
|
<div class="join w-full">
|
|
|
|
<input
|
|
|
|
type="search"
|
|
|
|
class="input join-item input-primary input-sm flex-1 flex-shrink-0 sm:input-md"
|
|
|
|
placeholder={t('search')}
|
2023-09-17 12:37:10 +08:00
|
|
|
onInput={(e) => setGlobalFilter(e.target.value)}
|
2023-09-15 23:43:55 +08:00
|
|
|
/>
|
|
|
|
|
|
|
|
<Button
|
|
|
|
class="join-item btn-sm sm:btn-md"
|
|
|
|
onClick={() => {
|
|
|
|
const modal = document.querySelector(
|
|
|
|
`#${MODAL.LOGS_SETTINGS}`,
|
|
|
|
) as HTMLDialogElement | null
|
|
|
|
|
|
|
|
modal?.showModal()
|
|
|
|
}}
|
2023-09-22 16:05:36 +08:00
|
|
|
icon={<IconSettings />}
|
|
|
|
/>
|
2023-09-15 23:43:55 +08:00
|
|
|
</div>
|
2023-08-24 04:20:53 +08:00
|
|
|
|
2023-09-05 00:20:19 +08:00
|
|
|
<div class="overflow-x-auto whitespace-nowrap rounded-md bg-base-300">
|
2023-09-06 03:08:18 +08:00
|
|
|
<table
|
2023-09-06 10:37:25 +08:00
|
|
|
class={twMerge(
|
2023-09-15 23:43:55 +08:00
|
|
|
tableSizeClassName(logsTableSize()),
|
2023-09-06 10:37:25 +08:00
|
|
|
'table relative rounded-none',
|
|
|
|
)}
|
2023-09-06 03:08:18 +08:00
|
|
|
>
|
2023-09-05 00:20:19 +08:00
|
|
|
<thead class="sticky top-0 z-10">
|
2023-09-10 19:03:26 +08:00
|
|
|
<Index each={table.getHeaderGroups()}>
|
|
|
|
{(keyedHeaderGroup) => {
|
|
|
|
const headerGroup = keyedHeaderGroup()
|
|
|
|
|
|
|
|
return (
|
|
|
|
<tr>
|
|
|
|
<Index each={headerGroup.headers}>
|
|
|
|
{(keyedHeader) => {
|
|
|
|
const header = keyedHeader()
|
|
|
|
|
|
|
|
return (
|
2023-09-17 12:37:10 +08:00
|
|
|
<th class="bg-base-200">
|
|
|
|
<div class="flex items-center">
|
|
|
|
<div
|
|
|
|
class={twMerge(
|
|
|
|
header.column.getCanSort() &&
|
|
|
|
'cursor-pointer select-none',
|
|
|
|
'flex-1',
|
|
|
|
)}
|
|
|
|
onClick={header.column.getToggleSortingHandler()}
|
|
|
|
>
|
|
|
|
{flexRender(
|
|
|
|
header.column.columnDef.header,
|
|
|
|
header.getContext(),
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{{
|
|
|
|
asc: <IconSortAscending />,
|
|
|
|
desc: <IconSortDescending />,
|
|
|
|
}[header.column.getIsSorted() as string] ?? null}
|
2023-09-10 19:03:26 +08:00
|
|
|
</div>
|
|
|
|
</th>
|
|
|
|
)
|
|
|
|
}}
|
|
|
|
</Index>
|
|
|
|
</tr>
|
|
|
|
)
|
|
|
|
}}
|
|
|
|
</Index>
|
2023-09-01 22:07:02 +08:00
|
|
|
</thead>
|
|
|
|
|
|
|
|
<tbody>
|
|
|
|
<For each={table.getRowModel().rows}>
|
|
|
|
{(row) => (
|
2023-09-17 21:18:23 +08:00
|
|
|
<tr class="hover:!bg-primary hover:text-primary-content">
|
2023-09-01 22:07:02 +08:00
|
|
|
<For each={row.getVisibleCells()}>
|
|
|
|
{(cell) => (
|
2023-09-17 21:18:23 +08:00
|
|
|
<td class="py-2">
|
2023-09-01 22:07:02 +08:00
|
|
|
{flexRender(
|
|
|
|
cell.column.columnDef.cell,
|
|
|
|
cell.getContext(),
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</tr>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
2023-08-24 04:20:53 +08:00
|
|
|
</div>
|
2023-09-15 23:43:55 +08:00
|
|
|
|
|
|
|
<LogsSettingsModal />
|
2023-08-24 04:20:53 +08:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|