2023-08-24 04:20:53 +08:00
|
|
|
import { createEventSignal } from '@solid-primitives/event-listener'
|
2023-09-02 00:15:19 +08:00
|
|
|
import { useI18n } from '@solid-primitives/i18n'
|
2023-08-24 04:20:53 +08:00
|
|
|
import { createReconnectingWS } from '@solid-primitives/websocket'
|
2023-09-01 22:07:02 +08:00
|
|
|
import {
|
|
|
|
ColumnDef,
|
|
|
|
createSolidTable,
|
|
|
|
flexRender,
|
|
|
|
getCoreRowModel,
|
|
|
|
} from '@tanstack/solid-table'
|
2023-08-24 04:20:53 +08:00
|
|
|
import { For, createEffect, createSignal } from 'solid-js'
|
2023-08-27 23:30:13 +08:00
|
|
|
import { secret, wsEndpointURL } from '~/signals'
|
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-08-29 14:44:49 +08:00
|
|
|
export default () => {
|
2023-09-02 00:15:19 +08:00
|
|
|
const [t] = useI18n()
|
2023-09-01 22:07:02 +08:00
|
|
|
let seq = 0
|
2023-08-24 04:20:53 +08:00
|
|
|
const [search, setSearch] = createSignal('')
|
2023-09-01 22:07:02 +08:00
|
|
|
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
2023-08-24 04:20:53 +08:00
|
|
|
|
2023-08-27 23:30:13 +08:00
|
|
|
const ws = createReconnectingWS(`${wsEndpointURL()}/logs?token=${secret()}`)
|
2023-08-24 04:20:53 +08:00
|
|
|
|
|
|
|
const messageEvent = createEventSignal<{
|
|
|
|
message: WebSocketEventMap['message']
|
|
|
|
}>(ws, 'message')
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
const data = messageEvent()?.data
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
setLogs((logs) =>
|
2023-09-01 22:07:02 +08:00
|
|
|
[{ ...(JSON.parse(data) as Log), seq }, ...logs].slice(0, 100),
|
2023-08-24 04:20:53 +08:00
|
|
|
)
|
2023-09-01 22:07:02 +08:00
|
|
|
|
|
|
|
seq++
|
|
|
|
})
|
|
|
|
|
|
|
|
const columns: ColumnDef<LogWithSeq>[] = [
|
|
|
|
{
|
|
|
|
accessorKey: 'Sequence',
|
|
|
|
accessorFn: (row) => row.seq,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
accessorKey: 'Type',
|
|
|
|
accessorFn: (row) => row.type,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
accessorKey: 'Payload',
|
|
|
|
accessorFn: (row) => row.payload,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
const table = createSolidTable({
|
|
|
|
get data() {
|
|
|
|
return search()
|
|
|
|
? logs().filter((log) =>
|
|
|
|
log.payload.toLowerCase().includes(search().toLowerCase()),
|
|
|
|
)
|
|
|
|
: logs()
|
|
|
|
},
|
|
|
|
columns,
|
|
|
|
getCoreRowModel: getCoreRowModel(),
|
2023-08-24 04:20:53 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div class="flex flex-col gap-4">
|
|
|
|
<input
|
|
|
|
class="input input-primary"
|
2023-09-02 00:15:19 +08:00
|
|
|
placeholder={t('search')}
|
2023-08-24 04:20:53 +08:00
|
|
|
onInput={(e) => setSearch(e.target.value)}
|
|
|
|
/>
|
|
|
|
|
2023-09-02 02:54:47 +08:00
|
|
|
<div class="overflow-x-auto whitespace-nowrap rounded-md">
|
|
|
|
<table class="table table-zebra-zebra table-xs rounded-none bg-base-200">
|
2023-09-01 22:07:02 +08:00
|
|
|
<thead>
|
|
|
|
<For each={table.getHeaderGroups()}>
|
|
|
|
{(headerGroup) => (
|
|
|
|
<tr>
|
|
|
|
<For each={headerGroup.headers}>
|
|
|
|
{(header) => (
|
|
|
|
<th class="bg-base-300">
|
|
|
|
<div>
|
|
|
|
{header.isPlaceholder
|
|
|
|
? null
|
|
|
|
: flexRender(
|
|
|
|
header.column.columnDef.header,
|
|
|
|
header.getContext(),
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</th>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</tr>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</thead>
|
|
|
|
|
|
|
|
<tbody>
|
|
|
|
<For each={table.getRowModel().rows}>
|
|
|
|
{(row) => (
|
|
|
|
<tr>
|
|
|
|
<For each={row.getVisibleCells()}>
|
|
|
|
{(cell) => (
|
|
|
|
<td>
|
|
|
|
{flexRender(
|
|
|
|
cell.column.columnDef.cell,
|
|
|
|
cell.getContext(),
|
|
|
|
)}
|
|
|
|
</td>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</tr>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
2023-08-24 04:20:53 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|