Skip to content

Commit 6b0e50a

Browse files
committed
Added page scoped filter cached, reworked org switcher.
1 parent 53024c7 commit 6b0e50a

File tree

6 files changed

+75
-61
lines changed

6 files changed

+75
-61
lines changed

src/Exceptionless.Web/ClientApp/src/lib/features/events/components/filters/helpers.svelte.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import type { IFilter } from '$comp/faceted-filter';
22

33
import { organization } from '$features/organizations/context.svelte';
4-
import { SvelteMap } from 'svelte/reactivity';
54

65
import { DateFilter, KeywordFilter, type ProjectFilter, type StringFilter } from './models.svelte';
76

87
let filterCacheVersion = $state(1);
98
export function filterCacheVersionNumber() {
109
return filterCacheVersion;
1110
}
12-
const filterCache = new SvelteMap<null | string, IFilter[]>();
11+
const filterCache = new Map<null | string, IFilter[]>();
1312

1413
export function applyTimeFilter(filters: IFilter[], time: null | string): IFilter[] {
1514
const dateFilterIndex = filters.findIndex((f) => f.key === 'date-date');
@@ -25,8 +24,13 @@ export function applyTimeFilter(filters: IFilter[], time: null | string): IFilte
2524
return filters;
2625
}
2726

27+
export function buildFilterCacheKey(organization: string | undefined, scope: string, filter: null | string): string {
28+
return `${organization ?? ''}:${scope}:${filter ?? ''}`;
29+
}
30+
2831
export function clearFilterCache() {
2932
filterCache.clear();
33+
filterCacheVersion = 1;
3034
}
3135

3236
export function filterChanged(filters: IFilter[], addedOrUpdated: IFilter): IFilter[] {
@@ -47,8 +51,7 @@ export function filterRemoved(filters: IFilter[], removed?: IFilter): IFilter[]
4751
return filters.filter((f) => f.id !== removed.id);
4852
}
4953

50-
export function getFiltersFromCache(filter: null | string): IFilter[] {
51-
const cacheKey = filter ?? '';
54+
export function getFiltersFromCache(cacheKey: string, filter: null | string): IFilter[] {
5255
if (filterCache.has(cacheKey)) {
5356
const filters = filterCache.get(cacheKey)?.map((f) => f.clone()) ?? [];
5457
return filters;
@@ -140,8 +143,15 @@ export function toFilter(filters: IFilter[]): string {
140143
.trim();
141144
}
142145

143-
export function updateFilterCache(filter: null | string, filters: IFilter[]) {
144-
filterCache.set(filter ?? '', filters);
146+
export function updateFilterCache(cacheKey: string, filters: IFilter[]) {
147+
// Prevent unbounded growth
148+
if (filterCache.size >= 100) {
149+
const oldestKey = filterCache.keys().next().value;
150+
filterCache.delete(oldestKey as string);
151+
}
152+
153+
filterCache.delete(cacheKey);
154+
filterCache.set(cacheKey, filters);
145155
filterCacheVersion += 1;
146156
}
147157

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
11
import { PersistedState } from 'runed';
22

33
export const organization = new PersistedState<string | undefined>('organization', undefined);
4-
5-
export function dispatchSwitchOrganizationEvent() {
6-
document.dispatchEvent(
7-
new CustomEvent('switch-organization', {
8-
bubbles: true,
9-
detail: organization.current
10-
})
11-
);
12-
}

src/Exceptionless.Web/ClientApp/src/routes/(app)/+layout.svelte

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { accessToken, gotoLogin } from '$features/auth/index.svelte';
77
import { invalidatePersistentEventQueries } from '$features/events/api.svelte';
88
import { getOrganizationQuery, invalidateOrganizationQueries } from '$features/organizations/api.svelte';
9-
import { dispatchSwitchOrganizationEvent, organization } from '$features/organizations/context.svelte';
9+
import { organization } from '$features/organizations/context.svelte';
1010
import { invalidateProjectQueries } from '$features/projects/api.svelte';
1111
import { invalidateStackQueries } from '$features/stacks/api.svelte';
1212
import { getMeQuery, invalidateUserQueries } from '$features/users/api.svelte';
@@ -163,13 +163,11 @@
163163
if (organizationsResponse.data.length === 0) {
164164
// TODO: Redirect to create organization page.
165165
organization.current = undefined;
166-
dispatchSwitchOrganizationEvent();
167166
return;
168167
}
169168
170169
if (!organizationsResponse.data.find((org) => org.id === organization.current)) {
171170
organization.current = organizationsResponse.data[0]!.id;
172-
dispatchSwitchOrganizationEvent();
173171
}
174172
});
175173
@@ -187,13 +185,7 @@
187185
class="pt-2"
188186
isLoading={organizationsResponse.isLoading}
189187
organizations={organizationsResponse.data}
190-
bind:selected={
191-
() => organization.current,
192-
(v) => {
193-
organization.current = v;
194-
dispatchSwitchOrganizationEvent();
195-
}
196-
}
188+
bind:selected={organization.current}
197189
/>
198190
{/snippet}
199191

src/Exceptionless.Web/ClientApp/src/routes/(app)/+page.svelte

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
import type { EventSummaryModel, SummaryTemplateKeys } from '$features/events/components/summary/index';
33
4+
import { page } from '$app/state';
45
import AutomaticRefreshIndicatorButton from '$comp/automatic-refresh-indicator-button.svelte';
56
import * as DataTable from '$comp/data-table';
67
import * as FacetedFilter from '$comp/faceted-filter';
@@ -11,7 +12,7 @@
1112
import { type DateFilter, StatusFilter } from '$features/events/components/filters';
1213
import {
1314
applyTimeFilter,
14-
clearFilterCache,
15+
buildFilterCacheKey,
1516
filterCacheVersionNumber,
1617
filterChanged,
1718
filterRemoved,
@@ -49,7 +50,11 @@
4950
time: 'last week'
5051
};
5152
52-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
53+
function filterCacheKey(filter: null | string): string {
54+
return buildFilterCacheKey(organization.current, page.url.pathname, filter);
55+
}
56+
57+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
5358
const params = queryParamsState({
5459
default: DEFAULT_PARAMS,
5560
pushHistory: true,
@@ -60,18 +65,21 @@
6065
}
6166
});
6267
63-
function onSwitchOrganization() {
64-
clearFilterCache();
65-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
66-
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
67-
Object.assign(params, DEFAULT_PARAMS);
68-
}
68+
watch(
69+
() => organization.current,
70+
() => {
71+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
72+
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
73+
Object.assign(params, DEFAULT_PARAMS);
74+
},
75+
{ lazy: true }
76+
);
6977
70-
let filters = $state(applyTimeFilter(getFiltersFromCache(params.filter), params.time));
78+
let filters = $state(applyTimeFilter(getFiltersFromCache(filterCacheKey(params.filter), params.filter), params.time));
7179
watch(
7280
[() => params.filter, () => params.time, () => filterCacheVersionNumber()],
7381
([filter, time]) => {
74-
filters = applyTimeFilter(getFiltersFromCache(filter), time);
82+
filters = applyTimeFilter(getFiltersFromCache(filterCacheKey(filter), filter), time);
7583
},
7684
{ lazy: true }
7785
);
@@ -93,7 +101,7 @@
93101
function updateFilters(updatedFilters: FacetedFilter.IFilter[]): void {
94102
const filter = toFilter(updatedFilters.filter((f) => f.type !== 'date'));
95103
96-
updateFilterCache(filter, updatedFilters);
104+
updateFilterCache(filterCacheKey(filter), updatedFilters);
97105
params.time = (updatedFilters.find((f) => f.type === 'date') as DateFilter)?.value as string;
98106
params.filter = filter;
99107
}
@@ -153,7 +161,6 @@
153161
}
154162
155163
useEventListener(document, 'refresh', () => loadData());
156-
useEventListener(document, 'switch-organization', onSwitchOrganization);
157164
useEventListener(document, 'PersistentEventChanged', async (event) => await onPersistentEventChanged((event as CustomEvent).detail));
158165
159166
$effect(() => {

src/Exceptionless.Web/ClientApp/src/routes/(app)/issues/+page.svelte

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
import type { EventSummaryModel, SummaryTemplateKeys } from '$features/events/components/summary/index';
33
4+
import { page } from '$app/state';
45
import AutomaticRefreshIndicatorButton from '$comp/automatic-refresh-indicator-button.svelte';
56
import * as DataTable from '$comp/data-table';
67
import * as FacetedFilter from '$comp/faceted-filter';
@@ -12,7 +13,7 @@
1213
import { type DateFilter, StatusFilter, TypeFilter } from '$features/events/components/filters';
1314
import {
1415
applyTimeFilter,
15-
clearFilterCache,
16+
buildFilterCacheKey,
1617
filterCacheVersionNumber,
1718
filterChanged,
1819
filterRemoved,
@@ -63,7 +64,11 @@
6364
time: 'last week'
6465
};
6566
66-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
67+
function filterCacheKey(filter: null | string): string {
68+
return buildFilterCacheKey(organization.current, page.url.pathname, filter);
69+
}
70+
71+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
6772
const params = queryParamsState({
6873
default: DEFAULT_PARAMS,
6974
pushHistory: true,
@@ -74,18 +79,21 @@
7479
}
7580
});
7681
77-
function onSwitchOrganization() {
78-
clearFilterCache();
79-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
80-
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
81-
Object.assign(params, DEFAULT_PARAMS);
82-
}
82+
watch(
83+
() => organization.current,
84+
() => {
85+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
86+
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
87+
Object.assign(params, DEFAULT_PARAMS);
88+
},
89+
{ lazy: true }
90+
);
8391
84-
let filters = $state(applyTimeFilter(getFiltersFromCache(params.filter), params.time));
92+
let filters = $state(applyTimeFilter(getFiltersFromCache(filterCacheKey(params.filter), params.filter), params.time));
8593
watch(
8694
[() => params.filter, () => params.time, () => filterCacheVersionNumber()],
8795
([filter, time]) => {
88-
filters = applyTimeFilter(getFiltersFromCache(filter), time);
96+
filters = applyTimeFilter(getFiltersFromCache(filterCacheKey(filter), filter), time);
8997
},
9098
{ lazy: true }
9199
);
@@ -110,7 +118,7 @@
110118
function updateFilters(updatedFilters: FacetedFilter.IFilter[]): void {
111119
const filter = toFilter(updatedFilters.filter((f) => f.type !== 'date'));
112120
113-
updateFilterCache(filter, updatedFilters);
121+
updateFilterCache(filterCacheKey(filter), updatedFilters);
114122
params.time = (updatedFilters.find((f) => f.type === 'date') as DateFilter)?.value as string;
115123
params.filter = filter;
116124
}
@@ -170,7 +178,6 @@
170178
}
171179
172180
useEventListener(document, 'refresh', async () => await loadData());
173-
useEventListener(document, 'switch-organization', onSwitchOrganization);
174181
useEventListener(document, 'StackChanged', async (event) => await onStackChanged((event as CustomEvent).detail));
175182
176183
$effect(() => {

src/Exceptionless.Web/ClientApp/src/routes/(app)/stream/+page.svelte

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
import type { EventSummaryModel, SummaryTemplateKeys } from '$features/events/components/summary/index';
33
4+
import { page } from '$app/state';
45
import * as DataTable from '$comp/data-table';
56
import DelayedRender from '$comp/delayed-render.svelte';
67
import ErrorMessage from '$comp/error-message.svelte';
@@ -11,7 +12,7 @@
1112
import EventsDrawer from '$features/events/components/events-drawer.svelte';
1213
import { StatusFilter } from '$features/events/components/filters';
1314
import {
14-
clearFilterCache,
15+
buildFilterCacheKey,
1516
filterCacheVersionNumber,
1617
filterChanged,
1718
filterRemoved,
@@ -45,7 +46,11 @@
4546
limit: DEFAULT_LIMIT
4647
};
4748
48-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
49+
function filterCacheKey(filter: null | string): string {
50+
return buildFilterCacheKey(organization.current, page.url.pathname, filter);
51+
}
52+
53+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
4954
const params = queryParamsState({
5055
default: DEFAULT_PARAMS,
5156
pushHistory: true,
@@ -55,18 +60,21 @@
5560
}
5661
});
5762
58-
function onSwitchOrganization() {
59-
clearFilterCache();
60-
updateFilterCache(DEFAULT_PARAMS.filter, DEFAULT_FILTERS);
61-
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
62-
Object.assign(params, DEFAULT_PARAMS);
63-
}
63+
watch(
64+
() => organization.current,
65+
() => {
66+
updateFilterCache(filterCacheKey(DEFAULT_PARAMS.filter), DEFAULT_FILTERS);
67+
//params.$reset(); // Work around for https://github.com/beynar/kit-query-params/issues/7
68+
Object.assign(params, DEFAULT_PARAMS);
69+
},
70+
{ lazy: true }
71+
);
6472
65-
let filters = $state(getFiltersFromCache(params.filter));
73+
let filters = $state(getFiltersFromCache(filterCacheKey(params.filter), params.filter));
6674
watch(
6775
[() => params.filter, () => filterCacheVersionNumber()],
6876
([filter]) => {
69-
filters = getFiltersFromCache(filter);
77+
filters = getFiltersFromCache(filterCacheKey(filter), filter);
7078
},
7179
{ lazy: true }
7280
);
@@ -90,7 +98,7 @@
9098
9199
function updateFilters(updatedFilters: FacetedFilter.IFilter[]): void {
92100
const filter = toFilter(updatedFilters);
93-
updateFilterCache(filter, updatedFilters);
101+
updateFilterCache(filterCacheKey(filter), updatedFilters);
94102
params.filter = filter;
95103
}
96104
@@ -167,7 +175,6 @@
167175
}
168176
169177
useEventListener(document, 'refresh', async () => await loadData());
170-
useEventListener(document, 'switch-organization', onSwitchOrganization);
171178
useEventListener(document, 'PersistentEventChanged', (event) => onPersistentEventChanged((event as CustomEvent).detail));
172179
173180
$effect(() => {

0 commit comments

Comments
 (0)