@svadmin/core 0.23.1 → 0.23.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +20 -3
- package/src/adapters/casbin.ts +1 -1
- package/src/adapters/casl.ts +1 -1
- package/src/audit.ts +12 -11
- package/src/auth-hooks.svelte.ts +25 -2
- package/src/chatProvider.svelte.ts +20 -3
- package/src/context.svelte.ts +17 -1
- package/src/data-transfer.svelte.ts +23 -11
- package/src/form-hooks.svelte.ts +71 -27
- package/src/form-hooks.test.svelte.ts +83 -0
- package/src/helpers-pure.ts +13 -6
- package/src/helpers.test.ts +2 -2
- package/src/helpers.ts +4 -0
- package/src/hook-utils.svelte.ts +40 -20
- package/src/hooks.svelte.ts +43 -50
- package/src/i18n.svelte.ts +3 -0
- package/src/index.ts +10 -8
- package/src/inferencer-openapi.ts +5 -3
- package/src/inferencer.ts +6 -4
- package/src/live-sse.ts +20 -17
- package/src/live-websocket.ts +1 -0
- package/src/live.svelte.ts +19 -11
- package/src/mutation-hooks.svelte.ts +39 -25
- package/src/mutation-hooks.test.svelte.ts +114 -0
- package/src/notification.svelte.ts +6 -6
- package/src/options.svelte.ts +1 -1
- package/src/{permissions.ts → permissions.svelte.ts} +1 -1
- package/src/permissions.test.ts +32 -80
- package/src/query-hooks.svelte.ts +18 -9
- package/src/query-hooks.test.svelte.ts +65 -0
- package/src/query-keys.ts +3 -4
- package/src/reactive-hooks.test.svelte.ts +26 -0
- package/src/router-provider.test.ts +3 -0
- package/src/router-provider.ts +13 -9
- package/src/router.ts +11 -0
- package/src/routing-hooks.svelte.ts +16 -13
- package/src/routing-hooks.test.svelte.ts +55 -0
- package/src/table-hooks.svelte.ts +46 -1
- package/src/table-hooks.test.svelte.ts +57 -0
- package/src/table-state.svelte.ts +17 -12
- package/src/theme.svelte.ts +25 -6
- package/src/toast.svelte.ts +8 -0
- package/src/unsaved-changes.svelte.ts +14 -6
- package/src/url-sync.ts +2 -1
- package/src/useCan.ts +2 -2
- package/src/useParsed.svelte.ts +15 -5
- package/src/utility-hooks.svelte.ts +5 -2
|
@@ -138,7 +138,7 @@ export function useTable<
|
|
|
138
138
|
if (newPage !== pagination.current) {
|
|
139
139
|
pagination = { ...pagination, current: newPage };
|
|
140
140
|
}
|
|
141
|
-
const newPageSize = urlState.pageSize ??
|
|
141
|
+
const newPageSize = urlState.pageSize ?? getOptions().pagination?.pageSize ?? getAdminOptions().defaultPageSize ?? 10;
|
|
142
142
|
if (newPageSize !== pagination.pageSize) {
|
|
143
143
|
pagination = { ...pagination, pageSize: newPageSize };
|
|
144
144
|
}
|
|
@@ -220,6 +220,51 @@ export function useTable<
|
|
|
220
220
|
return 0;
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
|
+
const activeFilters = filtersMode === 'off' ? effectiveFilters : [];
|
|
224
|
+
if (activeFilters.length > 0) {
|
|
225
|
+
function matchesFilter(item: Record<string, unknown>, f: Filter): boolean {
|
|
226
|
+
if (!('field' in f)) {
|
|
227
|
+
if (f.operator === 'and') return f.value.every(sub => matchesFilter(item, sub));
|
|
228
|
+
if (f.operator === 'or') return f.value.length === 0 || f.value.some(sub => matchesFilter(item, sub));
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const val = item[f.field];
|
|
232
|
+
const fv = f.value;
|
|
233
|
+
switch (f.operator) {
|
|
234
|
+
case 'null': return val == null;
|
|
235
|
+
case 'nnull': return val != null;
|
|
236
|
+
default: break;
|
|
237
|
+
}
|
|
238
|
+
if (fv == null || fv === '') return true;
|
|
239
|
+
switch (f.operator) {
|
|
240
|
+
case 'eq': return val == fv;
|
|
241
|
+
case 'ne': return val != fv;
|
|
242
|
+
case 'lt': return typeof val === 'number' && typeof fv === 'number' && val < fv;
|
|
243
|
+
case 'gt': return typeof val === 'number' && typeof fv === 'number' && val > fv;
|
|
244
|
+
case 'lte': return typeof val === 'number' && typeof fv === 'number' && val <= fv;
|
|
245
|
+
case 'gte': return typeof val === 'number' && typeof fv === 'number' && val >= fv;
|
|
246
|
+
case 'in': return !Array.isArray(fv) || fv.length === 0 || fv.includes(val);
|
|
247
|
+
case 'nin': return !Array.isArray(fv) || fv.length === 0 || !fv.includes(val);
|
|
248
|
+
case 'contains': return typeof val === 'string' && typeof fv === 'string' && val.includes(fv);
|
|
249
|
+
case 'ncontains': return typeof val === 'string' && typeof fv === 'string' && !val.includes(fv);
|
|
250
|
+
case 'startswith': return typeof val === 'string' && typeof fv === 'string' && val.startsWith(fv);
|
|
251
|
+
case 'endswith': return typeof val === 'string' && typeof fv === 'string' && val.endsWith(fv);
|
|
252
|
+
case 'between': {
|
|
253
|
+
if (!Array.isArray(fv) || fv.length !== 2) return true;
|
|
254
|
+
return typeof val === 'number' && val >= (fv[0] as number) && val <= (fv[1] as number);
|
|
255
|
+
}
|
|
256
|
+
case 'nbetween': {
|
|
257
|
+
if (!Array.isArray(fv) || fv.length !== 2) return true;
|
|
258
|
+
return typeof val === 'number' && (val < (fv[0] as number) || val > (fv[1] as number));
|
|
259
|
+
}
|
|
260
|
+
default: return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
sorted = sorted.filter((item) => {
|
|
264
|
+
const rec = item as Record<string, unknown>;
|
|
265
|
+
return activeFilters.every(f => matchesFilter(rec, f));
|
|
266
|
+
});
|
|
267
|
+
}
|
|
223
268
|
if (paginationMode === 'off') return sorted;
|
|
224
269
|
const start = ((pagination.current ?? 1) - 1) * (pagination.pageSize ?? 10);
|
|
225
270
|
const end = start + (pagination.pageSize ?? 10);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { useTable } from './table-hooks.svelte';
|
|
3
|
+
import { flushSync } from 'svelte';
|
|
4
|
+
import { QueryClient } from '@tanstack/svelte-query';
|
|
5
|
+
|
|
6
|
+
vi.mock('./context.svelte', () => ({
|
|
7
|
+
useDataProvider: () => ({
|
|
8
|
+
getList: vi.fn().mockResolvedValue({ data: [], total: 0 })
|
|
9
|
+
}),
|
|
10
|
+
useResource: () => ({ name: 'posts' }),
|
|
11
|
+
getResource: (name: string) => ({ name, primaryKey: 'id' }),
|
|
12
|
+
useRouterContext: () => ({ navigate: vi.fn(), url: '/', parsedParams: { current: 1, pageSize: 10 } }),
|
|
13
|
+
useTranslate: () => (key: string) => key,
|
|
14
|
+
getSyncWithLocation: () => false,
|
|
15
|
+
useNotification: () => ({ open: vi.fn(), close: vi.fn() }),
|
|
16
|
+
getLiveProvider: () => undefined
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock('@tanstack/svelte-query', async (importOriginal) => {
|
|
20
|
+
const actual = await importOriginal();
|
|
21
|
+
return {
|
|
22
|
+
...actual as any,
|
|
23
|
+
useQueryClient: () => new QueryClient(),
|
|
24
|
+
createQuery: () => ({
|
|
25
|
+
data: { data: [{ id: 1, title: 'Row' }], total: 1 },
|
|
26
|
+
isPending: false,
|
|
27
|
+
isFetching: false,
|
|
28
|
+
error: null
|
|
29
|
+
})
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('useTable - Headless Svelte 5 Compatibility', () => {
|
|
34
|
+
|
|
35
|
+
it('binds useTable logic internally and updates pagination flawlessly via $state', () => {
|
|
36
|
+
let table: ReturnType<typeof useTable>;
|
|
37
|
+
|
|
38
|
+
const cleanup = $effect.root(() => {
|
|
39
|
+
table = useTable({ resource: 'posts' });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
flushSync();
|
|
43
|
+
|
|
44
|
+
expect(table!.query).toBeDefined();
|
|
45
|
+
expect(table!.query?.data?.data[0].title).toBe('Row');
|
|
46
|
+
expect(table!.current).toBe(1);
|
|
47
|
+
|
|
48
|
+
// Trigger mutable state
|
|
49
|
+
table!.setPage(2);
|
|
50
|
+
|
|
51
|
+
flushSync();
|
|
52
|
+
|
|
53
|
+
expect(table!.current).toBe(2);
|
|
54
|
+
|
|
55
|
+
cleanup();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -182,6 +182,7 @@ export class TableState<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
182
182
|
|
|
183
183
|
setSorters(newSorters: Sort[]) {
|
|
184
184
|
this.currentSorters = newSorters;
|
|
185
|
+
this.pagination = { ...this.pagination, current: 1 };
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
toggleSort(field: string) {
|
|
@@ -193,6 +194,7 @@ export class TableState<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
193
194
|
} else {
|
|
194
195
|
this.currentSorters = [];
|
|
195
196
|
}
|
|
197
|
+
this.pagination = { ...this.pagination, current: 1 };
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
setFilters(newFilters: Filter[], mode?: FilterSetMode) {
|
|
@@ -221,25 +223,28 @@ export class TableState<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
221
223
|
this.pagination = { ...this.pagination, current: 1 };
|
|
222
224
|
}
|
|
223
225
|
|
|
224
|
-
/** For client-side pagination mode */
|
|
225
226
|
get clientData(): TData[] {
|
|
226
|
-
if (this.paginationMode
|
|
227
|
+
if (this.paginationMode === 'server') return [];
|
|
227
228
|
const allData = this.data;
|
|
228
|
-
const start = (this.current - 1) * this.pageSize;
|
|
229
|
-
const end = start + this.pageSize;
|
|
230
229
|
let sorted = [...allData];
|
|
231
|
-
const activeSorters = this.sortersMode === 'off' ? this.effectiveSorters :
|
|
230
|
+
const activeSorters = this.sortersMode === 'off' ? this.effectiveSorters : [];
|
|
232
231
|
if (activeSorters.length > 0) {
|
|
233
|
-
const { field, order } = activeSorters[0];
|
|
234
232
|
sorted.sort((a, b) => {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
233
|
+
for (const { field, order } of activeSorters) {
|
|
234
|
+
const va = (a as Record<string, unknown>)[field];
|
|
235
|
+
const vb = (b as Record<string, unknown>)[field];
|
|
236
|
+
if (va == null && vb == null) continue;
|
|
237
|
+
if (va == null) return 1;
|
|
238
|
+
if (vb == null) return -1;
|
|
239
|
+
const cmp = va < vb ? -1 : va > vb ? 1 : 0;
|
|
240
|
+
if (cmp !== 0) return order === 'desc' ? -cmp : cmp;
|
|
241
|
+
}
|
|
242
|
+
return 0;
|
|
241
243
|
});
|
|
242
244
|
}
|
|
245
|
+
if (this.paginationMode === 'off') return sorted;
|
|
246
|
+
const start = (this.current - 1) * this.pageSize;
|
|
247
|
+
const end = start + this.pageSize;
|
|
243
248
|
return sorted.slice(start, end);
|
|
244
249
|
}
|
|
245
250
|
}
|
package/src/theme.svelte.ts
CHANGED
|
@@ -248,15 +248,19 @@ let themeConfig: ThemeConfig = {};
|
|
|
248
248
|
* automatically via AdminApp's themeConfig prop.
|
|
249
249
|
*/
|
|
250
250
|
export function configureTheme(config: ThemeConfig): void {
|
|
251
|
-
themeConfig = { ...config };
|
|
252
|
-
// Re-apply the current theme with new strategy
|
|
251
|
+
themeConfig = { ...themeConfig, ...config };
|
|
253
252
|
applyTheme(mode);
|
|
254
|
-
// Apply color preset first (lower priority)
|
|
255
253
|
if (config.colorPreset) {
|
|
256
254
|
const preset = resolvePreset(config.colorPreset);
|
|
257
|
-
if (preset)
|
|
255
|
+
if (preset) {
|
|
256
|
+
colorTheme = preset.name as ColorTheme;
|
|
257
|
+
if (typeof window !== 'undefined') {
|
|
258
|
+
try { localStorage.setItem(COLOR_STORAGE_KEY, preset.name); } catch {}
|
|
259
|
+
}
|
|
260
|
+
applyColorTheme(preset.name as ColorTheme);
|
|
261
|
+
applyColorPreset(preset);
|
|
262
|
+
}
|
|
258
263
|
}
|
|
259
|
-
// Then apply manual CSS overrides (higher priority)
|
|
260
264
|
if (config.cssOverrides) {
|
|
261
265
|
applyCssOverrides(config.cssOverrides);
|
|
262
266
|
}
|
|
@@ -415,7 +419,22 @@ export function setColorTheme(ct: ColorTheme): void {
|
|
|
415
419
|
try { localStorage.setItem(COLOR_STORAGE_KEY, ct); } catch {}
|
|
416
420
|
}
|
|
417
421
|
applyColorTheme(ct);
|
|
418
|
-
// Apply the preset's CSS variable overrides for the current resolved theme
|
|
419
422
|
const preset = builtinPresets[ct];
|
|
420
423
|
if (preset) applyColorPreset(preset);
|
|
421
424
|
}
|
|
425
|
+
|
|
426
|
+
export function resetTheme(): void {
|
|
427
|
+
mode = getStoredTheme();
|
|
428
|
+
colorTheme = getStoredColorTheme();
|
|
429
|
+
themeConfig = {};
|
|
430
|
+
if (typeof document !== 'undefined') {
|
|
431
|
+
for (const key of activePresetVars) {
|
|
432
|
+
document.documentElement.style.removeProperty(key);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
activePresetVars = [];
|
|
436
|
+
applyTheme(mode);
|
|
437
|
+
applyColorTheme(colorTheme);
|
|
438
|
+
const preset = builtinPresets[colorTheme];
|
|
439
|
+
if (preset) applyColorPreset(preset);
|
|
440
|
+
}
|
package/src/toast.svelte.ts
CHANGED
|
@@ -56,6 +56,14 @@ export function removeToast(id: number): void {
|
|
|
56
56
|
toasts = toasts.filter(t => t.id !== id);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
export function resetToast(): void {
|
|
60
|
+
for (const timer of undoableTimers.values()) clearTimeout(timer);
|
|
61
|
+
undoableTimers.clear();
|
|
62
|
+
queue = [];
|
|
63
|
+
promiseQueue = [];
|
|
64
|
+
toasts = [];
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
export const toast = {
|
|
60
68
|
success: (msg: string, duration?: number, opts?: { key?: string }) => addToast('success', msg, duration, opts),
|
|
61
69
|
error: (msg: string, duration?: number, opts?: { key?: string }) => addToast('error', msg, duration ?? 5000, opts),
|
|
@@ -2,14 +2,21 @@
|
|
|
2
2
|
// Supports: browser tab close, hash-based SPA routing, and framework router interception
|
|
3
3
|
|
|
4
4
|
import { t } from './i18n.svelte';
|
|
5
|
+
import { syncGlobalPath } from './useParsed.svelte';
|
|
5
6
|
|
|
6
7
|
let dirty = $state(false);
|
|
7
8
|
|
|
8
|
-
/** Mark whether the current form has unsaved changes */
|
|
9
9
|
export function setUnsavedChanges(value: boolean) {
|
|
10
10
|
dirty = value;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export function resetUnsavedChanges(): void {
|
|
14
|
+
dirty = false;
|
|
15
|
+
_unsavedChangesCleanup?.();
|
|
16
|
+
_unsavedChangesCleanup = null;
|
|
17
|
+
_navigationGuard = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
export function getUnsavedChanges(): boolean {
|
|
14
21
|
return dirty;
|
|
15
22
|
}
|
|
@@ -68,12 +75,14 @@ export function registerNavigationGuard(guard: NavigationGuard): void {
|
|
|
68
75
|
* initUnsavedChangesNotifier();
|
|
69
76
|
* ```
|
|
70
77
|
*/
|
|
78
|
+
let _unsavedChangesCleanup: (() => void) | null = null;
|
|
79
|
+
|
|
71
80
|
export function initUnsavedChangesNotifier(options?: {
|
|
72
81
|
beforeNavigate?: (callback: (nav: { cancel: () => void }) => void) => void;
|
|
73
82
|
}) {
|
|
74
83
|
if (typeof window === 'undefined') return;
|
|
84
|
+
_unsavedChangesCleanup?.();
|
|
75
85
|
|
|
76
|
-
// 1. Browser tab close / refresh
|
|
77
86
|
const onBeforeUnload = (e: BeforeUnloadEvent) => {
|
|
78
87
|
if (!dirty) return;
|
|
79
88
|
e.preventDefault();
|
|
@@ -81,7 +90,6 @@ export function initUnsavedChangesNotifier(options?: {
|
|
|
81
90
|
};
|
|
82
91
|
window.addEventListener('beforeunload', onBeforeUnload);
|
|
83
92
|
|
|
84
|
-
// 2. Framework router (SvelteKit, etc.)
|
|
85
93
|
if (options?.beforeNavigate) {
|
|
86
94
|
options.beforeNavigate(({ cancel }) => {
|
|
87
95
|
if (dirty) {
|
|
@@ -94,12 +102,12 @@ export function initUnsavedChangesNotifier(options?: {
|
|
|
94
102
|
});
|
|
95
103
|
}
|
|
96
104
|
|
|
97
|
-
// 3. Hash-based fallback for SPAs without a framework router
|
|
98
105
|
const onHashChange = (e: HashChangeEvent) => {
|
|
99
106
|
if (!dirty) return;
|
|
100
107
|
if (!confirm(t('common.unsavedChanges'))) {
|
|
101
108
|
if (e.oldURL) {
|
|
102
109
|
history.replaceState(null, '', new URL(e.oldURL).hash || '#');
|
|
110
|
+
syncGlobalPath();
|
|
103
111
|
}
|
|
104
112
|
} else {
|
|
105
113
|
dirty = false;
|
|
@@ -107,9 +115,9 @@ export function initUnsavedChangesNotifier(options?: {
|
|
|
107
115
|
};
|
|
108
116
|
window.addEventListener('hashchange', onHashChange);
|
|
109
117
|
|
|
110
|
-
|
|
111
|
-
return () => {
|
|
118
|
+
_unsavedChangesCleanup = () => {
|
|
112
119
|
window.removeEventListener('beforeunload', onBeforeUnload);
|
|
113
120
|
window.removeEventListener('hashchange', onHashChange);
|
|
114
121
|
};
|
|
122
|
+
return _unsavedChangesCleanup;
|
|
115
123
|
}
|
package/src/url-sync.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Filter } from './types';
|
|
2
2
|
import { getRouterProvider } from './context.svelte';
|
|
3
|
+
import { getAdminOptions } from './options.svelte';
|
|
3
4
|
|
|
4
5
|
export interface URLState {
|
|
5
6
|
page?: number;
|
|
@@ -57,7 +58,7 @@ export function writeURLState(state: URLState): void {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
if ('pageSize' in state) {
|
|
60
|
-
if (state.pageSize && state.pageSize !== 10) params['pageSize'] = String(state.pageSize);
|
|
61
|
+
if (state.pageSize && state.pageSize !== (getAdminOptions().defaultPageSize ?? 10)) params['pageSize'] = String(state.pageSize);
|
|
61
62
|
else delete params['pageSize'];
|
|
62
63
|
}
|
|
63
64
|
|
package/src/useCan.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// useCan — reactive permission check hook with TanStack Query integration
|
|
2
2
|
|
|
3
3
|
import { createQuery } from '@tanstack/svelte-query';
|
|
4
|
-
import { canAccessAsync, getAccessControlProvider } from './permissions';
|
|
5
|
-
import type { Action, CanResult } from './permissions';
|
|
4
|
+
import { canAccessAsync, getAccessControlProvider } from './permissions.svelte';
|
|
5
|
+
import type { Action, CanResult } from './permissions.svelte';
|
|
6
6
|
|
|
7
7
|
export interface UseCanOptions {
|
|
8
8
|
resource: string;
|
package/src/useParsed.svelte.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// useParsed — parse current URL hash into structured route info
|
|
2
2
|
|
|
3
|
-
import { currentPath } from './router';
|
|
3
|
+
import { currentPath, registerRouterSync } from './router';
|
|
4
4
|
import { getResources } from './context.svelte';
|
|
5
5
|
|
|
6
6
|
interface ParsedRoute {
|
|
@@ -12,12 +12,22 @@ interface ParsedRoute {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
let globalPath = $state('/');
|
|
15
|
+
|
|
16
|
+
export function resetGlobalPath(): void {
|
|
17
|
+
globalPath = typeof window !== 'undefined' ? currentPath() : '/';
|
|
18
|
+
}
|
|
19
|
+
export function syncGlobalPath(): void {
|
|
20
|
+
if (typeof window !== 'undefined') globalPath = currentPath();
|
|
21
|
+
}
|
|
22
|
+
registerRouterSync(syncGlobalPath);
|
|
23
|
+
|
|
15
24
|
if (typeof window !== 'undefined') {
|
|
16
|
-
// Initialize
|
|
17
25
|
globalPath = currentPath();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
if (!(window as any).__svadminParsedInit) {
|
|
27
|
+
(window as any).__svadminParsedInit = true;
|
|
28
|
+
window.addEventListener('hashchange', () => { globalPath = currentPath(); });
|
|
29
|
+
window.addEventListener('popstate', () => { globalPath = currentPath(); });
|
|
30
|
+
}
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
/**
|
|
@@ -56,8 +56,11 @@ export function useModalForm<
|
|
|
56
56
|
visible = false;
|
|
57
57
|
formState.reset();
|
|
58
58
|
if (options.autoSave?.invalidateOnClose) {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const dpN = options.dataProviderName;
|
|
60
|
+
const dp = (q: { queryKey: readonly unknown[] }) => q.queryKey[0] === dpN;
|
|
61
|
+
queryClient.invalidateQueries({ predicate: (q) => dp(q) && q.queryKey[1] === formState.resource && (q.queryKey[2] === 'list' || q.queryKey[2] === 'infiniteList' || q.queryKey[2] === 'select') });
|
|
62
|
+
queryClient.invalidateQueries({ predicate: (q) => dp(q) && q.queryKey[1] === formState.resource && q.queryKey[2] === 'many' });
|
|
63
|
+
queryClient.invalidateQueries({ predicate: (q) => dp(q) && q.queryKey[1] === formState.resource && q.queryKey[2] === 'one' });
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|