|
2 | 2 | import type { Snippet } from 'svelte';
|
3 | 3 |
|
4 | 4 | import * as DataTable from '$comp/data-table';
|
5 |
| - import { getKeywordFilter, getOrganizationFilter, getProjectFilter, getStackFilter, type IFilter } from "$comp/filters/filters.svelte"; |
6 |
| - import { ChangeType, type WebSocketMessageValue } from '$features/websockets/models'; |
7 |
| - import { DEFAULT_LIMIT } from '$shared/api'; |
8 |
| - import { type FetchClientResponse, useFetchClient } from '@exceptionless/fetchclient'; |
9 |
| - import { createTable } from '@tanstack/svelte-table'; |
10 |
| - import { useEventListener } from 'runed'; |
11 |
| - import { debounce } from 'throttle-debounce'; |
| 5 | + import { type Table } from '@tanstack/svelte-table'; |
12 | 6 |
|
13 |
| - import type { GetEventsMode } from '../../api.svelte'; |
14 | 7 | import type { EventSummaryModel, SummaryTemplateKeys } from '../summary/index';
|
15 | 8 |
|
16 |
| - import { getTableContext } from './options.svelte'; |
17 |
| -
|
18 | 9 | interface Props {
|
19 |
| - filter: string; |
20 |
| - filters: IFilter[]; |
21 | 10 | limit: number;
|
22 |
| - mode?: GetEventsMode; |
23 |
| - pageFilter?: string; |
24 | 11 | rowclick?: (row: EventSummaryModel<SummaryTemplateKeys>) => void;
|
25 |
| - time: string; |
| 12 | + table: Table<EventSummaryModel<SummaryTemplateKeys>>; |
26 | 13 | toolbarChildren?: Snippet;
|
27 | 14 | }
|
28 | 15 |
|
29 |
| - let { filter, filters, limit = $bindable(DEFAULT_LIMIT), mode = 'summary', pageFilter = undefined, rowclick, time, toolbarChildren }: Props = $props(); |
30 |
| - const context = getTableContext<EventSummaryModel<SummaryTemplateKeys>>({ limit, mode }); |
31 |
| - const table = createTable(context.options); |
32 |
| -
|
33 |
| - const client = useFetchClient(); |
34 |
| - let response: FetchClientResponse<EventSummaryModel<SummaryTemplateKeys>[]>; |
35 |
| -
|
36 |
| - $effect(() => { |
37 |
| - limit = Number(context.limit); |
38 |
| - loadData(); |
39 |
| - }); |
40 |
| -
|
41 |
| - async function loadData() { |
42 |
| - if (client.loading) { |
43 |
| - return; |
44 |
| - } |
45 |
| -
|
46 |
| - response = await client.getJSON<EventSummaryModel<SummaryTemplateKeys>[]>('events', { |
47 |
| - params: { |
48 |
| - ...context.parameters, |
49 |
| - filter: [pageFilter, filter].filter(Boolean).join(' '), |
50 |
| - time |
51 |
| - } |
52 |
| - }); |
53 |
| -
|
54 |
| - if (response.ok) { |
55 |
| - context.data = response.data || []; |
56 |
| - context.meta = response.meta; |
57 |
| - table.resetRowSelection(); |
58 |
| - } |
59 |
| - } |
60 |
| - const debouncedLoadData = debounce(10000, loadData); |
61 |
| -
|
62 |
| - async function onPersistentEvent(message: WebSocketMessageValue<'PersistentEventChanged'>) { |
63 |
| - const shouldRefresh = () => { |
64 |
| - if (!filter) { |
65 |
| - return true; |
66 |
| - } |
67 |
| -
|
68 |
| - const { id, organization_id, project_id, stack_id } = message; |
69 |
| - if (id) { |
70 |
| - // Check to see if any records on the page match |
71 |
| - if (mode === "summary" && table.options.data.some((doc) => doc.id === id)) { |
72 |
| - return true; |
73 |
| - } |
74 |
| -
|
75 |
| - // This could match any kind of lucene query (even must not filtering) |
76 |
| - const keywordFilter = getKeywordFilter(filters); |
77 |
| - if (keywordFilter && !keywordFilter.isEmpty()) { |
78 |
| - if (keywordFilter.value!.includes(id)) { |
79 |
| - return true; |
80 |
| - } |
81 |
| - } |
82 |
| - } |
83 |
| -
|
84 |
| - if (stack_id) { |
85 |
| - // Check to see if any records on the page match |
86 |
| - if (mode !== "summary" && table.options.data.some((doc) => doc.id === stack_id)) { |
87 |
| - return true; |
88 |
| - } |
89 |
| -
|
90 |
| - const stackFilter = getStackFilter(filters); |
91 |
| - if (stackFilter && !stackFilter.isEmpty()) { |
92 |
| - return stackFilter.value === stack_id; |
93 |
| - } |
94 |
| - } |
95 |
| -
|
96 |
| - if (project_id) { |
97 |
| - const projectFilter = getProjectFilter(filters); |
98 |
| - if (projectFilter && !projectFilter.isEmpty()) { |
99 |
| - return projectFilter.value.includes(project_id); |
100 |
| - } |
101 |
| - } |
102 |
| -
|
103 |
| - if (organization_id) { |
104 |
| - const organizationFilter = getOrganizationFilter(filters); |
105 |
| - if (organizationFilter && !organizationFilter.isEmpty()) { |
106 |
| - return organizationFilter.value === organization_id; |
107 |
| - } |
108 |
| - } |
109 |
| -
|
110 |
| - return true; |
111 |
| - }; |
112 |
| -
|
113 |
| - switch (message.change_type) { |
114 |
| - case ChangeType.Added: |
115 |
| - case ChangeType.Saved: |
116 |
| - if (shouldRefresh()) { |
117 |
| - await debouncedLoadData(); |
118 |
| - } |
119 |
| -
|
120 |
| - break; |
121 |
| - case ChangeType.Removed: |
122 |
| - if (shouldRefresh()) { |
123 |
| - if (message.id && mode === "summary") { |
124 |
| - table.options.data = table.options.data.filter((doc) => doc.id !== message.id); |
125 |
| - } |
126 |
| -
|
127 |
| - await debouncedLoadData(); |
128 |
| - } |
129 |
| -
|
130 |
| - break; |
131 |
| - } |
132 |
| - } |
133 |
| -
|
134 |
| - useEventListener(document, 'refresh', async () => await loadData()); |
135 |
| - useEventListener(document, 'PersistentEventChanged', async (event) => await onPersistentEvent((event as CustomEvent).detail)); |
| 16 | + let { limit = $bindable(), rowclick, table, toolbarChildren }: Props = $props(); |
136 | 17 | </script>
|
137 | 18 |
|
138 | 19 | <DataTable.Root>
|
|
143 | 24 | </DataTable.Toolbar>
|
144 | 25 | <DataTable.Body {rowclick} {table}></DataTable.Body>
|
145 | 26 | <DataTable.Pagination {table}>
|
146 |
| - <DataTable.PageSize bind:value={context.limit} {table}></DataTable.PageSize> |
| 27 | + <DataTable.PageSize bind:value={limit} {table}></DataTable.PageSize> |
147 | 28 | </DataTable.Pagination>
|
148 | 29 | </DataTable.Root>
|
0 commit comments