@svadmin/core 0.27.0 → 0.27.1
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 +8 -8
- package/src/adapters/casl.ts +1 -0
- package/src/auth-hooks.svelte.ts +1 -1
- package/src/data-transfer.svelte.ts +1 -1
- package/src/form-hooks.svelte.ts +8 -8
- package/src/helpers-pure.ts +1 -1
- package/src/helpers.ts +0 -1
- package/src/hooks.svelte.ts +4 -5
- package/src/live-sse.ts +1 -1
- package/src/live-websocket.ts +1 -1
- package/src/mutation-hooks.svelte.ts +12 -11
- package/src/permissions.svelte.ts +1 -1
- package/src/query-hooks.svelte.ts +4 -4
- package/src/routing-hooks.svelte.ts +2 -1
- package/src/table-hooks.svelte.ts +3 -2
- package/src/table-state.svelte.ts +3 -2
- package/src/task-hooks.svelte.ts +2 -2
- package/src/theme.svelte.ts +3 -3
- package/src/toast.svelte.ts +1 -0
- package/src/types.ts +3 -2
- package/src/unsaved-changes.svelte.ts +4 -3
- package/src/useParsed.svelte.ts +2 -0
- package/src/utility-hooks.svelte.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/core",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"author": "zuohuadong",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
},
|
|
10
10
|
"main": "src/index.ts",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@happy-dom/global-registrator": "^20.
|
|
13
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
12
|
+
"@happy-dom/global-registrator": "^20.10.0",
|
|
13
|
+
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
14
14
|
"@testing-library/dom": "^10.4.1",
|
|
15
15
|
"@testing-library/svelte": "^5.3.1",
|
|
16
16
|
"@testing-library/user-event": "^14.6.1",
|
|
17
|
-
"@types/bun": "^1.3.
|
|
18
|
-
"@types/jsdom": "^28.0.
|
|
19
|
-
"happy-dom": "^20.
|
|
20
|
-
"jsdom": "^29.
|
|
21
|
-
"vitest": "^4.1.
|
|
17
|
+
"@types/bun": "^1.3.14",
|
|
18
|
+
"@types/jsdom": "^28.0.3",
|
|
19
|
+
"happy-dom": "^20.10.0",
|
|
20
|
+
"jsdom": "^29.1.1",
|
|
21
|
+
"vitest": "^4.1.8"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"svelte": "^5.0.0",
|
package/src/adapters/casl.ts
CHANGED
package/src/auth-hooks.svelte.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getDataProviderForResource } from './context.svelte';
|
|
2
2
|
import { useParsed } from './useParsed.svelte';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Sort, Filter, BaseRecord } from './types';
|
|
4
4
|
|
|
5
5
|
export interface UseExportOptions<TData extends BaseRecord = BaseRecord> {
|
|
6
6
|
resource?: string;
|
package/src/form-hooks.svelte.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
1
2
|
import { useQueryClient } from '@tanstack/svelte-query';
|
|
2
3
|
import { useParsed } from './useParsed.svelte';
|
|
3
4
|
import { getAdminOptions } from './options.svelte';
|
|
@@ -17,8 +18,8 @@ import { deepMerge, invalidateByScopes } from './mutation-hooks.svelte';
|
|
|
17
18
|
|
|
18
19
|
export interface UseFormOptions<
|
|
19
20
|
TVariables extends Record<string, unknown> = Record<string, unknown>,
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
_TData extends BaseRecord = BaseRecord,
|
|
22
|
+
_TError = HttpError,
|
|
22
23
|
> {
|
|
23
24
|
resource?: KnownResources;
|
|
24
25
|
action?: 'create' | 'edit' | 'clone' | 'show';
|
|
@@ -44,7 +45,7 @@ export interface UseFormOptions<
|
|
|
44
45
|
/** Called every time a field value changes. */
|
|
45
46
|
onChange?: (event: { field: string; value: unknown; values: TVariables }) => void;
|
|
46
47
|
/** Called before mutation. Return false or call cancel() to prevent submission. */
|
|
47
|
-
onSubmit?: (ctx: { values: TVariables; action: 'create' | 'edit' | 'clone' | 'show'; cancel: () => void }) =>
|
|
48
|
+
onSubmit?: (ctx: { values: TVariables; action: 'create' | 'edit' | 'clone' | 'show'; cancel: () => void }) => boolean | undefined;
|
|
48
49
|
|
|
49
50
|
// ─── Meta ─────────────────────────────────────────────────────
|
|
50
51
|
meta?: Record<string, unknown>;
|
|
@@ -85,7 +86,7 @@ export interface UseFormOptions<
|
|
|
85
86
|
|
|
86
87
|
export interface UseFormReturn<
|
|
87
88
|
TVariables extends Record<string, unknown> = Record<string, unknown>,
|
|
88
|
-
|
|
89
|
+
_TData extends BaseRecord = BaseRecord,
|
|
89
90
|
> {
|
|
90
91
|
// ─── Form values (single source of truth) ─────────────────────
|
|
91
92
|
/** Reactive form values. Read/write directly. */
|
|
@@ -213,8 +214,7 @@ export function useForm<
|
|
|
213
214
|
function setFieldError(field: string, message: string) { errors = { ...errors, [field]: message }; }
|
|
214
215
|
function clearErrors() { errors = {}; }
|
|
215
216
|
function clearFieldError(field: string) {
|
|
216
|
-
const
|
|
217
|
-
delete next[field];
|
|
217
|
+
const { [field]: _, ...next } = errors;
|
|
218
218
|
errors = next;
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -270,7 +270,7 @@ export function useForm<
|
|
|
270
270
|
const query = createQuery(() => ({
|
|
271
271
|
queryKey: [options.dataProviderName, resource, 'one', currentId, queryMeta],
|
|
272
272
|
queryFn: async () => {
|
|
273
|
-
const result = await provider.getOne<BaseRecord>({ resource, id: currentId
|
|
273
|
+
const result = await provider.getOne<BaseRecord>({ resource, id: currentId as string, meta: queryMeta });
|
|
274
274
|
return result;
|
|
275
275
|
},
|
|
276
276
|
enabled: (queryOptions?.enabled ?? true) && (action === 'edit' || action === 'clone' || action === 'show') && currentId != null,
|
|
@@ -345,7 +345,7 @@ export function useForm<
|
|
|
345
345
|
const updateMut = createMutation<{ data: TData }, unknown, TVariables>(() => ({
|
|
346
346
|
...options.updateMutationOptions,
|
|
347
347
|
mutationFn: async (variables: TVariables) => {
|
|
348
|
-
const targetId = currentId
|
|
348
|
+
const targetId = currentId as string;
|
|
349
349
|
const targetResource = resource;
|
|
350
350
|
const targetMeta = mutationMeta;
|
|
351
351
|
if (mutationMode === 'undoable') {
|
package/src/helpers-pure.ts
CHANGED
package/src/helpers.ts
CHANGED
package/src/hooks.svelte.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
1
2
|
// @svadmin/core — Core Data and Hook APIs (Modularized for v0.2.29+)
|
|
2
3
|
|
|
3
4
|
// ─── Re-exports from modular hook files ─────────────────────────────
|
|
@@ -30,13 +31,11 @@ import { invalidateByScopes, publishLiveEvent } from './mutation-hooks.svelte';
|
|
|
30
31
|
import type { NotificationConfig, OvertimeOptions, LiveSubscriptionParams } from './hook-utils.svelte';
|
|
31
32
|
import type { BaseRecord, HttpError, Pagination, Sort, Filter, DataProvider, KnownResources } from './types';
|
|
32
33
|
import type { LiveMode, LiveEvent } from './live.svelte';
|
|
33
|
-
import { useList } from './query-hooks.svelte';
|
|
34
|
-
import type { UseListOptions } from './query-hooks.svelte';
|
|
35
34
|
import { audit } from './audit';
|
|
36
35
|
|
|
37
36
|
// ─── useInfiniteList ────────────────────────────────────────────────
|
|
38
37
|
|
|
39
|
-
export interface UseInfiniteListOptions<
|
|
38
|
+
export interface UseInfiniteListOptions<_TData extends BaseRecord = BaseRecord, _TError = HttpError> {
|
|
40
39
|
resource?: KnownResources;
|
|
41
40
|
pagination?: Pagination;
|
|
42
41
|
sorters?: Sort[];
|
|
@@ -113,7 +112,7 @@ export function useInfiniteList<TData extends BaseRecord = BaseRecord, TError =
|
|
|
113
112
|
|
|
114
113
|
// ─── useSelect ──────────────────────────────────────────────────────
|
|
115
114
|
|
|
116
|
-
export interface UseSelectOptions<TData extends BaseRecord = BaseRecord,
|
|
115
|
+
export interface UseSelectOptions<TData extends BaseRecord = BaseRecord, _TOption = { label: string; value: string | number }> {
|
|
117
116
|
resource: KnownResources;
|
|
118
117
|
optionLabel?: string | ((item: TData) => string);
|
|
119
118
|
optionValue?: string | ((item: TData) => string | number);
|
|
@@ -231,7 +230,7 @@ export function useSelect<TData extends BaseRecord = BaseRecord, TOption = { lab
|
|
|
231
230
|
|
|
232
231
|
// ─── useCustom ──────────────────────────────────────────────────────
|
|
233
232
|
|
|
234
|
-
export interface UseCustomOptions<
|
|
233
|
+
export interface UseCustomOptions<_TData = unknown, _TError = HttpError> {
|
|
235
234
|
url: string;
|
|
236
235
|
method: 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
237
236
|
config?: { payload?: unknown; query?: Record<string, unknown>; headers?: Record<string, string>; sorters?: Sort[]; filters?: Filter[] };
|
package/src/live-sse.ts
CHANGED
|
@@ -123,7 +123,7 @@ export function createSSELiveProvider(options: SSELiveProviderOptions): LiveProv
|
|
|
123
123
|
subscribers.set(resource, new Set());
|
|
124
124
|
isNewResource = true;
|
|
125
125
|
}
|
|
126
|
-
subscribers.get(resource)
|
|
126
|
+
subscribers.get(resource)?.add(callback);
|
|
127
127
|
|
|
128
128
|
if (!eventSource && typeof EventSource !== 'undefined') {
|
|
129
129
|
connect();
|
package/src/live-websocket.ts
CHANGED
|
@@ -121,7 +121,7 @@ export function createWebSocketLiveProvider(options: WebSocketLiveProviderOption
|
|
|
121
121
|
if (!subscribers.has(resource)) {
|
|
122
122
|
subscribers.set(resource, new Set());
|
|
123
123
|
}
|
|
124
|
-
subscribers.get(resource)
|
|
124
|
+
subscribers.get(resource)?.add(callback);
|
|
125
125
|
lastParams.set(resource, liveParams);
|
|
126
126
|
|
|
127
127
|
// Ensure connection is open
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import { createMutation, useQueryClient } from '@tanstack/svelte-query';
|
|
2
3
|
import { getAdminOptions } from './options.svelte';
|
|
3
4
|
import { getDataProviderForResource, getResource, getLiveProvider } from './context.svelte';
|
|
4
5
|
import { useParsed } from './useParsed.svelte';
|
|
5
6
|
import { audit } from './audit';
|
|
6
7
|
import { UndoError } from './types';
|
|
7
|
-
import type { BaseRecord, HttpError,
|
|
8
|
+
import type { BaseRecord, HttpError, KnownResources } from './types';
|
|
8
9
|
import { checkError, createOvertimeTracker, fireSuccessNotification, fireErrorNotification } from './hook-utils.svelte';
|
|
9
10
|
import type { NotificationConfig, OvertimeOptions } from './hook-utils.svelte';
|
|
10
11
|
import { toast } from './toast.svelte';
|
|
@@ -132,14 +133,14 @@ export function useCreate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
132
133
|
// Invalidation in onSuccess for create (refine pattern — no optimistic data to reconcile on error)
|
|
133
134
|
invalidateByScopes(queryClient, resName, params.invalidates, ['list', 'many'], undefined, params.dataProviderName);
|
|
134
135
|
if (typeof options.mutationOptions?.onSuccess === 'function') {
|
|
135
|
-
(options.mutationOptions.onSuccess as
|
|
136
|
+
(options.mutationOptions.onSuccess as (...a: unknown[]) => unknown)(data, params, context);
|
|
136
137
|
}
|
|
137
138
|
},
|
|
138
139
|
onError: (error, params, context) => {
|
|
139
140
|
checkError(error);
|
|
140
141
|
fireErrorNotification(params.errorNotification, 'Create failed', error, params.resource ?? defaultResource);
|
|
141
142
|
if (typeof options.mutationOptions?.onError === 'function') {
|
|
142
|
-
(options.mutationOptions.onError as
|
|
143
|
+
(options.mutationOptions.onError as (...a: unknown[]) => unknown)(error, params, context);
|
|
143
144
|
}
|
|
144
145
|
},
|
|
145
146
|
}));
|
|
@@ -242,7 +243,7 @@ export function useUpdate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
242
243
|
|
|
243
244
|
if (updater.list !== false) {
|
|
244
245
|
queryClient.setQueriesData({ predicate: (q) => dp(q) && q.queryKey[1] === resName && q.queryKey[2] === 'list' }, (old: unknown) => {
|
|
245
|
-
if (typeof updater.list === 'function') return updater.list
|
|
246
|
+
if (typeof updater.list === 'function') return updater.list(old, params.variables, targetId);
|
|
246
247
|
if (!old || typeof old !== 'object' || !('data' in old)) return old;
|
|
247
248
|
const o = old as { data: Record<string, unknown>[] };
|
|
248
249
|
return { ...o, data: o.data.map((item) => String(item[pk]) === String(targetId) ? deepMerge(item, params.variables) : item) };
|
|
@@ -251,7 +252,7 @@ export function useUpdate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
251
252
|
|
|
252
253
|
if (updater.many !== false) {
|
|
253
254
|
queryClient.setQueriesData({ predicate: (q) => dp(q) && q.queryKey[1] === resName && q.queryKey[2] === 'many' }, (old: unknown) => {
|
|
254
|
-
if (typeof updater.many === 'function') return updater.many
|
|
255
|
+
if (typeof updater.many === 'function') return updater.many(old, params.variables, targetId);
|
|
255
256
|
if (!old || typeof old !== 'object' || !('data' in old)) return old;
|
|
256
257
|
const o = old as { data: Record<string, unknown>[] };
|
|
257
258
|
return { ...o, data: o.data.map((item) => String(item[pk]) === String(targetId) ? deepMerge(item, params.variables) : item) };
|
|
@@ -268,7 +269,7 @@ export function useUpdate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
268
269
|
audit({ action: 'update', resource: resName, recordId: String(targetId) });
|
|
269
270
|
publishLiveEvent(resName, 'updated', targetId != null ? [targetId] : undefined);
|
|
270
271
|
if (typeof options.mutationOptions?.onSuccess === 'function') {
|
|
271
|
-
(options.mutationOptions.onSuccess as
|
|
272
|
+
(options.mutationOptions.onSuccess as (...a: unknown[]) => unknown)(data, params, extractedCtx);
|
|
272
273
|
}
|
|
273
274
|
},
|
|
274
275
|
onSettled: (_data, error, params) => {
|
|
@@ -277,7 +278,7 @@ export function useUpdate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
277
278
|
const targetId = params.id ?? defaultId;
|
|
278
279
|
invalidateByScopes(queryClient, resName, params.invalidates, ['list', 'many', 'detail'], targetId != null ? targetId : undefined, params.dataProviderName);
|
|
279
280
|
if (typeof options.mutationOptions?.onSettled === 'function') {
|
|
280
|
-
(options.mutationOptions.onSettled as
|
|
281
|
+
(options.mutationOptions.onSettled as (...a: unknown[]) => unknown)(_data, error, params, undefined);
|
|
281
282
|
}
|
|
282
283
|
},
|
|
283
284
|
onError: (error, params, context: unknown) => {
|
|
@@ -292,7 +293,7 @@ export function useUpdate<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
292
293
|
const extractedCtx = ctx?._svadmin_ctx ? ctx.userContext : context;
|
|
293
294
|
fireErrorNotification(params.errorNotification, 'Update failed', error, params.resource ?? defaultResource);
|
|
294
295
|
if (typeof options.mutationOptions?.onError === 'function') {
|
|
295
|
-
(options.mutationOptions.onError as
|
|
296
|
+
(options.mutationOptions.onError as (...a: unknown[]) => unknown)(error, params, extractedCtx);
|
|
296
297
|
}
|
|
297
298
|
},
|
|
298
299
|
}));
|
|
@@ -409,7 +410,7 @@ export function useDelete<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
409
410
|
audit({ action: 'delete', resource: resName, recordId: String(targetId) });
|
|
410
411
|
publishLiveEvent(resName, 'deleted', targetId != null ? [targetId] : undefined);
|
|
411
412
|
if (typeof options.mutationOptions?.onSuccess === 'function') {
|
|
412
|
-
(options.mutationOptions.onSuccess as
|
|
413
|
+
(options.mutationOptions.onSuccess as (...a: unknown[]) => unknown)(data, params, extractedCtx);
|
|
413
414
|
}
|
|
414
415
|
},
|
|
415
416
|
onSettled: (_data, error, params) => {
|
|
@@ -418,7 +419,7 @@ export function useDelete<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
418
419
|
const targetId = params.id ?? defaultId;
|
|
419
420
|
invalidateByScopes(queryClient, resName, params.invalidates, ['list', 'many'], targetId != null ? targetId : undefined, params.dataProviderName);
|
|
420
421
|
if (typeof options.mutationOptions?.onSettled === 'function') {
|
|
421
|
-
(options.mutationOptions.onSettled as
|
|
422
|
+
(options.mutationOptions.onSettled as (...a: unknown[]) => unknown)(_data, error, params, undefined);
|
|
422
423
|
}
|
|
423
424
|
},
|
|
424
425
|
onError: (error, params, context: unknown) => {
|
|
@@ -433,7 +434,7 @@ export function useDelete<TData extends BaseRecord = BaseRecord, TError = HttpEr
|
|
|
433
434
|
const extractedCtx = ctx?._svadmin_ctx ? ctx.userContext : context;
|
|
434
435
|
fireErrorNotification(params.errorNotification, 'Delete failed', error, params.resource ?? defaultResource);
|
|
435
436
|
if (typeof options.mutationOptions?.onError === 'function') {
|
|
436
|
-
(options.mutationOptions.onError as
|
|
437
|
+
(options.mutationOptions.onError as (...a: unknown[]) => unknown)(error, params, extractedCtx);
|
|
437
438
|
}
|
|
438
439
|
},
|
|
439
440
|
}));
|
|
@@ -93,7 +93,7 @@ export async function canAccessAsync(resourceOrBatch: string | CanParams[], acti
|
|
|
93
93
|
return provider.can(resourceOrBatch);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
return provider.can({ resource: resourceOrBatch, action: action
|
|
96
|
+
return provider.can({ resource: resourceOrBatch, action: action as string, params }) as Promise<CanResult>;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// ─── Feature Gate ─────────────────────────────────────────────
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createQuery
|
|
1
|
+
import { createQuery } from '@tanstack/svelte-query';
|
|
2
2
|
import { getAdminOptions } from './options.svelte';
|
|
3
3
|
import { getDataProviderForResource, getDataProvider, getLiveProvider } from './context.svelte';
|
|
4
4
|
import { useParsed } from './useParsed.svelte';
|
|
@@ -57,7 +57,7 @@ function cloneQueryKeyPart<T>(value: T): T {
|
|
|
57
57
|
return value;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export interface UseListOptions<
|
|
60
|
+
export interface UseListOptions<_TData extends BaseRecord = BaseRecord, _TError = HttpError> {
|
|
61
61
|
resource?: KnownResources;
|
|
62
62
|
pagination?: Pagination;
|
|
63
63
|
sorters?: Sort[];
|
|
@@ -146,7 +146,7 @@ export function useList<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
146
146
|
|
|
147
147
|
// ─── useOne ────────────────────────────────────────────────────
|
|
148
148
|
|
|
149
|
-
export interface UseOneOptions<
|
|
149
|
+
export interface UseOneOptions<_TData extends BaseRecord = BaseRecord, _TError = HttpError> {
|
|
150
150
|
resource?: KnownResources;
|
|
151
151
|
id?: string | number;
|
|
152
152
|
meta?: Record<string, unknown>;
|
|
@@ -256,7 +256,7 @@ export function useShow<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
256
256
|
|
|
257
257
|
// ─── useMany ───────────────────────────────────────────────────
|
|
258
258
|
|
|
259
|
-
export interface UseManyOptions<
|
|
259
|
+
export interface UseManyOptions<_TData extends BaseRecord = BaseRecord, _TError = HttpError> {
|
|
260
260
|
resource: KnownResources;
|
|
261
261
|
ids: (string | number)[];
|
|
262
262
|
meta?: Record<string, unknown>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
2
|
+
import { navigate } from './router';
|
|
2
3
|
import { getResource, getResources, getRouterProvider } from './context.svelte';
|
|
3
4
|
import { useParsed } from './useParsed.svelte';
|
|
4
5
|
|
|
@@ -7,7 +7,7 @@ import type { UseListOptions, MaybeGetter } from './query-hooks.svelte';
|
|
|
7
7
|
|
|
8
8
|
export type FilterSetMode = 'merge' | 'replace';
|
|
9
9
|
|
|
10
|
-
export interface UseTableOptions<TQueryFnData extends BaseRecord = BaseRecord, TError = HttpError,
|
|
10
|
+
export interface UseTableOptions<TQueryFnData extends BaseRecord = BaseRecord, TError = HttpError, _TSearchVariables = Record<string, unknown>> extends Omit<UseListOptions<TQueryFnData, TError>, 'pagination' | 'sorters' | 'filters'> {
|
|
11
11
|
resource?: KnownResources;
|
|
12
12
|
pagination?: Pagination;
|
|
13
13
|
sorters?: {
|
|
@@ -80,7 +80,7 @@ export function useTable<
|
|
|
80
80
|
|
|
81
81
|
const tableQueryInfo = useList<TQueryFnData, TError>(() => {
|
|
82
82
|
const currentOpts = getOptions();
|
|
83
|
-
const { meta, syncWithLocation, dataProviderName, pagination: _p, sorters: _s, filters: _f, ...restOptions } = currentOpts;
|
|
83
|
+
const { meta, syncWithLocation: _swl, dataProviderName, pagination: _p, sorters: _s, filters: _f, ...restOptions } = currentOpts;
|
|
84
84
|
return {
|
|
85
85
|
resource: currentOpts.resource ?? parsed.resource ?? '',
|
|
86
86
|
pagination: queryPagination,
|
|
@@ -209,6 +209,7 @@ export function useTable<
|
|
|
209
209
|
if (vb == null && va != null) return -1;
|
|
210
210
|
if (va == null && vb == null) continue;
|
|
211
211
|
|
|
212
|
+
// eslint-disable-next-line no-useless-assignment
|
|
212
213
|
let cmp = 0;
|
|
213
214
|
if (typeof va === 'number' && typeof vb === 'number') cmp = va - vb;
|
|
214
215
|
else if (va instanceof Date && vb instanceof Date) cmp = va.getTime() - vb.getTime();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
1
2
|
// TableState — Svelte 5 Class State Pattern for table data management
|
|
2
3
|
// Reactive class that encapsulates all table state with fine-grained $state/$derived
|
|
3
4
|
|
|
@@ -94,7 +95,7 @@ export class TableState<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
94
95
|
this.currentFilters = initFilters;
|
|
95
96
|
|
|
96
97
|
// Create query
|
|
97
|
-
const _this = this;
|
|
98
|
+
const _this = this; // eslint-disable-line @typescript-eslint/no-this-alias
|
|
98
99
|
const { meta, syncWithLocation: _s, dataProviderName, pagination: _p, sorters: _sr, filters: _f, ...restOptions } = options;
|
|
99
100
|
this._queryResult = useList<TData, TError>({
|
|
100
101
|
resource,
|
|
@@ -226,7 +227,7 @@ export class TableState<TData extends BaseRecord = BaseRecord, TError = HttpErro
|
|
|
226
227
|
get clientData(): TData[] {
|
|
227
228
|
if (this.paginationMode === 'server') return [];
|
|
228
229
|
const allData = this.data;
|
|
229
|
-
|
|
230
|
+
const sorted = [...allData];
|
|
230
231
|
const activeSorters = this.sortersMode === 'off' ? this.effectiveSorters : [];
|
|
231
232
|
if (activeSorters.length > 0) {
|
|
232
233
|
sorted.sort((a, b) => {
|
package/src/task-hooks.svelte.ts
CHANGED
|
@@ -74,7 +74,7 @@ export function useSubmitTask<
|
|
|
74
74
|
return { mutation, get overtime() { return overtime; } };
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
export interface UseTaskOptions<TTask extends TaskRecord = TaskRecord,
|
|
77
|
+
export interface UseTaskOptions<TTask extends TaskRecord = TaskRecord, _TError = HttpError> {
|
|
78
78
|
taskId?: string;
|
|
79
79
|
taskProvider?: TaskProvider<TTask>;
|
|
80
80
|
queryOptions?: {
|
|
@@ -138,7 +138,7 @@ export function useTask<TTask extends TaskRecord = TaskRecord, TError = HttpErro
|
|
|
138
138
|
}) as typeof query & { overtime: typeof overtime };
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
export interface UseTaskListOptions<TTask extends TaskRecord = TaskRecord,
|
|
141
|
+
export interface UseTaskListOptions<TTask extends TaskRecord = TaskRecord, _TError = HttpError> {
|
|
142
142
|
params?: Record<string, unknown>;
|
|
143
143
|
dlq?: boolean;
|
|
144
144
|
taskProvider?: TaskProvider<TTask>;
|
package/src/theme.svelte.ts
CHANGED
|
@@ -255,7 +255,7 @@ export function configureTheme(config: ThemeConfig): void {
|
|
|
255
255
|
if (preset) {
|
|
256
256
|
colorTheme = preset.name as ColorTheme;
|
|
257
257
|
if (typeof window !== 'undefined') {
|
|
258
|
-
try { localStorage.setItem(COLOR_STORAGE_KEY, preset.name); } catch {}
|
|
258
|
+
try { localStorage.setItem(COLOR_STORAGE_KEY, preset.name); } catch { /* intentional */}
|
|
259
259
|
}
|
|
260
260
|
applyColorTheme(preset.name as ColorTheme);
|
|
261
261
|
applyColorPreset(preset);
|
|
@@ -369,7 +369,7 @@ export function getTheme(): ThemeMode {
|
|
|
369
369
|
export function setTheme(newMode: ThemeMode): void {
|
|
370
370
|
mode = newMode;
|
|
371
371
|
if (typeof window !== 'undefined') {
|
|
372
|
-
try { localStorage.setItem(STORAGE_KEY, newMode); } catch {}
|
|
372
|
+
try { localStorage.setItem(STORAGE_KEY, newMode); } catch { /* intentional */}
|
|
373
373
|
}
|
|
374
374
|
applyTheme(newMode);
|
|
375
375
|
// Re-apply color preset — light/dark CSS variable overrides differ
|
|
@@ -416,7 +416,7 @@ export function getColorTheme(): ColorTheme {
|
|
|
416
416
|
export function setColorTheme(ct: ColorTheme): void {
|
|
417
417
|
colorTheme = ct;
|
|
418
418
|
if (typeof window !== 'undefined') {
|
|
419
|
-
try { localStorage.setItem(COLOR_STORAGE_KEY, ct); } catch {}
|
|
419
|
+
try { localStorage.setItem(COLOR_STORAGE_KEY, ct); } catch { /* intentional */}
|
|
420
420
|
}
|
|
421
421
|
applyColorTheme(ct);
|
|
422
422
|
const preset = builtinPresets[ct];
|
package/src/toast.svelte.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -256,7 +256,7 @@ export interface TaskSubscription {
|
|
|
256
256
|
export interface TaskHandle<TTask extends TaskRecord = TaskRecord> {
|
|
257
257
|
id?: string;
|
|
258
258
|
wait(): Promise<TTask>;
|
|
259
|
-
subscribe?(callback: (task: TTask) => void): TaskSubscription | (() => void) |
|
|
259
|
+
subscribe?(callback: (task: TTask) => void): TaskSubscription | (() => void) | undefined;
|
|
260
260
|
cancel?(): Promise<unknown>;
|
|
261
261
|
retry?(): Promise<unknown>;
|
|
262
262
|
}
|
|
@@ -273,7 +273,7 @@ export interface TaskProvider<TTask extends TaskRecord = TaskRecord> {
|
|
|
273
273
|
listDlq?(params?: Record<string, unknown>): Promise<TaskListResult<TTask>>;
|
|
274
274
|
cancel?(taskId: string): Promise<unknown>;
|
|
275
275
|
retry?(taskId: string): Promise<unknown>;
|
|
276
|
-
subscribe?(taskId: string, callback: (task: TTask) => void): TaskSubscription | (() => void) |
|
|
276
|
+
subscribe?(taskId: string, callback: (task: TTask) => void): TaskSubscription | (() => void) | undefined;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
// ─── AuthProvider ─────────────────────────────────────────────
|
|
@@ -448,6 +448,7 @@ export interface FieldDefinition {
|
|
|
448
448
|
* // list.data → { id: string; name: string; email: string }[]
|
|
449
449
|
* ```
|
|
450
450
|
*/
|
|
451
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
451
452
|
export interface ResourceTypeMap {}
|
|
452
453
|
|
|
453
454
|
/** When ResourceTypeMap is empty → string; otherwise → registered keys */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
1
2
|
// UnsavedChangesNotifier — guards against accidental navigation with dirty forms
|
|
2
3
|
// Supports: browser tab close, hash-based SPA routing, and framework router interception
|
|
3
4
|
|
|
@@ -14,7 +15,7 @@ export function resetUnsavedChanges(): void {
|
|
|
14
15
|
dirty = false;
|
|
15
16
|
_unsavedChangesCleanup?.();
|
|
16
17
|
_unsavedChangesCleanup = null;
|
|
17
|
-
|
|
18
|
+
__navigationGuard = null;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export function getUnsavedChanges(): boolean {
|
|
@@ -30,7 +31,7 @@ interface NavigationGuard {
|
|
|
30
31
|
(opts: { cancel: () => void }): void;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
let
|
|
34
|
+
let __navigationGuard: NavigationGuard | null = null;
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Register a framework-level navigation guard.
|
|
@@ -51,7 +52,7 @@ let _navigationGuard: NavigationGuard | null = null;
|
|
|
51
52
|
* and pass a `beforeNavigate` callback.
|
|
52
53
|
*/
|
|
53
54
|
export function registerNavigationGuard(guard: NavigationGuard): void {
|
|
54
|
-
|
|
55
|
+
__navigationGuard = guard;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
/**
|
package/src/useParsed.svelte.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
1
2
|
import { useForm, type UseFormOptions, type UseFormReturn } from './form-hooks.svelte';
|
|
2
3
|
import { useQueryClient } from '@tanstack/svelte-query';
|
|
3
4
|
import { useParsed } from './useParsed.svelte';
|
|
4
5
|
import { getResource, getResources } from './context.svelte';
|
|
5
6
|
import { getAdminOptions } from './options.svelte';
|
|
6
|
-
import { navigate } from './router';
|
|
7
7
|
import { t } from './i18n.svelte';
|
|
8
8
|
import type { BaseRecord, HttpError, Filter, KnownResources, ResourceDefinition } from './types';
|
|
9
9
|
import { useList, type UseListOptions } from './query-hooks.svelte';
|
|
@@ -162,7 +162,7 @@ export function useBreadcrumb() {
|
|
|
162
162
|
|
|
163
163
|
// ─── useRelation ───────────────────────────────────────────
|
|
164
164
|
|
|
165
|
-
export interface UseRelationOptions<
|
|
165
|
+
export interface UseRelationOptions<_TData extends BaseRecord = BaseRecord, _TError = HttpError> {
|
|
166
166
|
resource: KnownResources;
|
|
167
167
|
id?: string | number;
|
|
168
168
|
pagination?: { current?: number; pageSize?: number };
|