@svadmin/core 0.49.1 → 0.52.0
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/README.md +32 -0
- package/package.json +21 -4
- package/src/access-control-contract.ts +250 -0
- package/src/adapters/casbin.ts +20 -14
- package/src/adapters/casl.ts +22 -19
- package/src/admin-tool.ts +7 -7
- package/src/audit-contract.ts +105 -0
- package/src/audit.ts +88 -128
- package/src/auth-hooks.svelte.ts +593 -261
- package/src/auth-mutation-contract.ts +143 -0
- package/src/auth-query-contract.ts +97 -0
- package/src/captured-mutation.svelte.ts +45 -0
- package/src/chatProvider.svelte.ts +1 -1
- package/src/command-contract.ts +195 -0
- package/src/context.svelte.ts +217 -205
- package/src/contract-context.svelte.ts +37 -0
- package/src/contract-form.svelte.ts +566 -0
- package/src/create-contract.ts +56 -0
- package/src/create-hooks.svelte.ts +347 -0
- package/src/create-many-contract.ts +90 -0
- package/src/create-many-hooks.svelte.ts +396 -0
- package/src/data-transfer.svelte.ts +1 -215
- package/src/defined-options.ts +50 -0
- package/src/delete-contract.ts +50 -0
- package/src/delete-hooks.svelte.ts +403 -0
- package/src/delete-many-contract.ts +60 -0
- package/src/delete-many-hooks.svelte.ts +402 -0
- package/src/enterprise.ts +4 -4
- package/src/export-format.ts +16 -14
- package/src/export-hooks.svelte.ts +191 -0
- package/src/feature-gate-contract.ts +53 -0
- package/src/hook-utils.svelte.ts +53 -105
- package/src/hooks.svelte.ts +19 -774
- package/src/http.ts +88 -87
- package/src/i18n.svelte.ts +56 -2
- package/src/import-contract.ts +106 -0
- package/src/import-hooks.svelte.ts +310 -0
- package/src/index.ts +77 -28
- package/src/inferencer-graphql.ts +7 -6
- package/src/infinite-query.svelte.ts +228 -0
- package/src/invalidation-contract.ts +26 -0
- package/src/live-sse.ts +91 -127
- package/src/live-subscription.svelte.ts +130 -0
- package/src/live-transport.ts +127 -0
- package/src/live-websocket.ts +85 -118
- package/src/live.svelte.ts +66 -68
- package/src/notification.svelte.ts +17 -15
- package/src/permission-catalog.ts +121 -0
- package/src/permission-hints-contract.ts +48 -0
- package/src/permissions.svelte.ts +112 -59
- package/src/plain-data.ts +61 -0
- package/src/provider-bundle.ts +85 -79
- package/src/provider-response.ts +35 -0
- package/src/query-hooks.svelte.ts +241 -286
- package/src/query-invalidation.ts +172 -0
- package/src/query-keys.ts +221 -110
- package/src/query-session.svelte.ts +216 -0
- package/src/query-snapshot.ts +144 -0
- package/src/reactive-projection.ts +53 -0
- package/src/record-decoder.ts +63 -0
- package/src/resource-binding.svelte.ts +19 -0
- package/src/resource-contract.ts +595 -0
- package/src/resource-mutation-types.ts +30 -0
- package/src/resource-schemas.ts +371 -0
- package/src/resource-transport-config.ts +156 -0
- package/src/route-parsing.ts +11 -11
- package/src/router-provider.ts +64 -59
- package/src/router.ts +8 -3
- package/src/routing-hooks.svelte.ts +90 -62
- package/src/schema-validation.ts +92 -0
- package/src/schema.ts +13 -0
- package/src/select-options.ts +95 -0
- package/src/select-query.svelte.ts +191 -0
- package/src/session-query.svelte.ts +88 -0
- package/src/strict-command-hooks.svelte.ts +333 -0
- package/src/strict-hooks.svelte.ts +198 -0
- package/src/table-hooks.svelte.ts +180 -174
- package/src/table-state.svelte.ts +117 -117
- package/src/task-contract.ts +87 -0
- package/src/task-hooks.svelte.ts +193 -149
- package/src/task-provider.ts +115 -0
- package/src/task-subscription.ts +132 -0
- package/src/theme.svelte.ts +155 -154
- package/src/toast.svelte.ts +38 -37
- package/src/types.ts +55 -103
- package/src/unsafe.ts +7 -0
- package/src/update-contract.ts +65 -0
- package/src/update-hooks.svelte.ts +347 -0
- package/src/update-many-contract.ts +79 -0
- package/src/update-many-hooks.svelte.ts +373 -0
- package/src/url-sync.ts +11 -10
- package/src/useCan.ts +96 -31
- package/src/useParsed.svelte.ts +18 -14
- package/src/useStepsForm.svelte.ts +123 -63
- package/src/utility-hooks.svelte.ts +101 -158
- package/src/form-hooks.svelte.ts +0 -889
- package/src/mutation-hooks.svelte.ts +0 -561
|
@@ -1,182 +1,187 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { definedOptions } from './defined-options';
|
|
2
|
+
import { createListQuery } from './query-hooks.svelte';
|
|
3
|
+
import { decodeBaseRecord, type RecordDecoder } from './record-decoder';
|
|
4
|
+
import { readURLState,writeURLState } from './url-sync';
|
|
5
|
+
import { captureContractContext } from './contract-context.svelte';
|
|
5
6
|
import { getAdminOptions } from './options.svelte';
|
|
6
|
-
import type { Pagination,
|
|
7
|
-
import type { UseListOptions,
|
|
7
|
+
import type { Pagination,Sort,Filter,BaseRecord,HttpError,KnownResources } from './types';
|
|
8
|
+
import type { UseListOptions,MaybeGetter } from './query-hooks.svelte';
|
|
8
9
|
|
|
9
|
-
export type FilterSetMode
|
|
10
|
+
export type FilterSetMode='merge'|'replace';
|
|
10
11
|
|
|
11
|
-
export interface UseTableOptions<TQueryFnData extends BaseRecord
|
|
12
|
+
export interface UseTableOptions<TQueryFnData extends BaseRecord=BaseRecord,TError=HttpError,_TSearchVariables=Record<string,unknown>> extends Omit<UseListOptions<TQueryFnData,TError>,'pagination'|'sorters'|'filters'> {
|
|
12
13
|
resource?: KnownResources;
|
|
13
14
|
pagination?: Pagination;
|
|
14
15
|
sorters?: {
|
|
15
16
|
initial?: Sort[];
|
|
16
17
|
permanent?: Sort[];
|
|
17
|
-
mode?: 'off'
|
|
18
|
+
mode?: 'off'|'server';
|
|
18
19
|
};
|
|
19
20
|
filters?: {
|
|
20
21
|
initial?: Filter[];
|
|
21
22
|
permanent?: Filter[];
|
|
22
|
-
mode?: 'off'
|
|
23
|
+
mode?: 'off'|'server';
|
|
23
24
|
defaultBehavior?: FilterSetMode;
|
|
24
25
|
};
|
|
25
26
|
syncWithLocation?: boolean;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
export function useTable<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
29
|
+
export function useTable(optionsOrGetter: MaybeGetter<UseTableOptions>={}) {
|
|
30
|
+
return createTableQuery(optionsOrGetter, () => decodeBaseRecord);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createTableQuery<TQueryFnData extends BaseRecord>(
|
|
34
|
+
optionsOrGetter: MaybeGetter<UseTableOptions>, getDecoder: () => RecordDecoder<TQueryFnData>,
|
|
35
|
+
) {
|
|
36
|
+
const adminContext=captureContractContext(optionsOrGetter);
|
|
37
|
+
const getOptions=() => typeof optionsOrGetter==='function'? optionsOrGetter():optionsOrGetter;
|
|
38
|
+
|
|
37
39
|
// Use a local derived to compute these since they are used to initialize state
|
|
38
40
|
// Even if options change, init values are only used once, which makes sense for initial state
|
|
39
|
-
const initialOpts
|
|
40
|
-
const syncWithLocation
|
|
41
|
-
|
|
42
|
-
const paginationMode = $derived(getOptions().pagination?.mode ?? 'server');
|
|
43
|
-
const sortersMode = $derived(getOptions().sorters?.mode ?? 'server');
|
|
44
|
-
const filtersMode = $derived(getOptions().filters?.mode ?? 'server');
|
|
45
|
-
const filterDefaultBehavior = $derived(getOptions().filters?.defaultBehavior ?? 'replace');
|
|
41
|
+
const initialOpts=getOptions();
|
|
42
|
+
const syncWithLocation=initialOpts.syncWithLocation??getAdminOptions().syncWithLocation;
|
|
46
43
|
|
|
47
|
-
const
|
|
48
|
-
const
|
|
44
|
+
const paginationMode=$derived(getOptions().pagination?.mode??'server');
|
|
45
|
+
const sortersMode=$derived(getOptions().sorters?.mode??'server');
|
|
46
|
+
const filtersMode=$derived(getOptions().filters?.mode??'server');
|
|
47
|
+
const filterDefaultBehavior=$derived(getOptions().filters?.defaultBehavior??'replace');
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
let initFilters = initialOpts.filters?.initial ?? [];
|
|
49
|
+
const permanentSorters=$derived(getOptions().sorters?.permanent??[]);
|
|
50
|
+
const permanentFilters=$derived(getOptions().filters?.permanent??[]);
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
let initPagination=initialOpts.pagination??{ current: 1,pageSize: 10 };
|
|
53
|
+
let initSorters=initialOpts.sorters?.initial??[];
|
|
54
|
+
let initFilters=initialOpts.filters?.initial??[];
|
|
55
|
+
|
|
56
|
+
if(syncWithLocation&&typeof window!=='undefined') {
|
|
57
|
+
const urlState=readURLState(adminContext);
|
|
58
|
+
if(urlState.page||urlState.pageSize) {
|
|
59
|
+
initPagination=definedOptions({
|
|
60
|
+
current: urlState.page??initPagination.current,
|
|
61
|
+
pageSize: urlState.pageSize??initPagination.pageSize,
|
|
62
|
+
});
|
|
61
63
|
}
|
|
62
|
-
if
|
|
63
|
-
initSorters
|
|
64
|
+
if(urlState.sortField) {
|
|
65
|
+
initSorters=[{ field: urlState.sortField,order: urlState.sortOrder??'asc' }];
|
|
64
66
|
}
|
|
65
|
-
if
|
|
66
|
-
initFilters
|
|
67
|
+
if(urlState.filters) {
|
|
68
|
+
initFilters=urlState.filters;
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
let pagination
|
|
71
|
-
let currentSorters
|
|
72
|
-
let currentFilters
|
|
72
|
+
let pagination=$state<Pagination>(initPagination);
|
|
73
|
+
let currentSorters=$state<Sort[]>(initSorters);
|
|
74
|
+
let currentFilters=$state<Filter[]>(initFilters);
|
|
73
75
|
|
|
74
|
-
const effectiveSorters
|
|
75
|
-
const effectiveFilters
|
|
76
|
+
const effectiveSorters=$derived([...currentSorters,...permanentSorters]);
|
|
77
|
+
const effectiveFilters=$derived([...currentFilters,...permanentFilters]);
|
|
76
78
|
|
|
77
|
-
const querySorters
|
|
78
|
-
const queryFilters
|
|
79
|
-
const queryPagination
|
|
79
|
+
const querySorters=$derived(sortersMode==='server'? effectiveSorters:[]);
|
|
80
|
+
const queryFilters=$derived(filtersMode==='server'? effectiveFilters:[]);
|
|
81
|
+
const queryPagination=$derived(paginationMode==='server'
|
|
80
82
|
? pagination
|
|
81
|
-
:
|
|
83
|
+
:{ current: 1,pageSize: 999999,mode: paginationMode });
|
|
82
84
|
|
|
83
|
-
const tableQueryInfo
|
|
84
|
-
const currentOpts
|
|
85
|
-
const { meta,
|
|
85
|
+
const tableQueryInfo=createListQuery(() => {
|
|
86
|
+
const currentOpts=getOptions();
|
|
87
|
+
const { meta,syncWithLocation: _swl,dataProviderName,pagination: _p,sorters: _s,filters: _f,...restOptions }=currentOpts;
|
|
86
88
|
return {
|
|
87
|
-
resource: currentOpts.resource ?? parsed.resource ?? '',
|
|
88
89
|
pagination: queryPagination,
|
|
89
90
|
sorters: querySorters,
|
|
90
91
|
filters: queryFilters,
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
...definedOptions({
|
|
93
|
+
meta,
|
|
94
|
+
dataProviderName,
|
|
95
|
+
}),
|
|
93
96
|
...restOptions
|
|
94
97
|
};
|
|
95
|
-
});
|
|
98
|
+
}, getDecoder);
|
|
96
99
|
|
|
97
|
-
const query
|
|
98
|
-
const overtime
|
|
100
|
+
const query=tableQueryInfo;
|
|
101
|
+
const overtime=tableQueryInfo.overtime;
|
|
99
102
|
|
|
100
|
-
function setSorters(newSorters: Sort[]) { currentSorters
|
|
101
|
-
function setFilters(newFilters: Filter[],
|
|
102
|
-
const behavior
|
|
103
|
-
if
|
|
104
|
-
const merged
|
|
105
|
-
for
|
|
106
|
-
if
|
|
107
|
-
const idx
|
|
108
|
-
if
|
|
109
|
-
if
|
|
110
|
-
else merged[idx]
|
|
111
|
-
} else if
|
|
103
|
+
function setSorters(newSorters: Sort[]) { currentSorters=newSorters; pagination={ ...pagination,current: 1 }; }
|
|
104
|
+
function setFilters(newFilters: Filter[],mode?: FilterSetMode) {
|
|
105
|
+
const behavior=mode??filterDefaultBehavior;
|
|
106
|
+
if(behavior==='merge') {
|
|
107
|
+
const merged=[...currentFilters];
|
|
108
|
+
for(const nf of newFilters) {
|
|
109
|
+
if(!('field' in nf)) { merged.push(nf); continue; }
|
|
110
|
+
const idx=merged.findIndex(f => 'field' in f&&f.field===nf.field&&f.operator===nf.operator);
|
|
111
|
+
if(idx>=0) {
|
|
112
|
+
if(nf.value===undefined||nf.value===null||nf.value==='') merged.splice(idx,1);
|
|
113
|
+
else merged[idx]=nf;
|
|
114
|
+
} else if(nf.value!==undefined&&nf.value!==null&&nf.value!=='') {
|
|
112
115
|
merged.push(nf);
|
|
113
116
|
}
|
|
114
117
|
}
|
|
115
|
-
currentFilters
|
|
118
|
+
currentFilters=merged;
|
|
116
119
|
} else {
|
|
117
|
-
currentFilters
|
|
120
|
+
currentFilters=newFilters;
|
|
118
121
|
}
|
|
119
|
-
pagination
|
|
122
|
+
pagination={ ...pagination,current: 1 };
|
|
120
123
|
}
|
|
121
124
|
|
|
122
|
-
function setPage(page: number) { pagination
|
|
123
|
-
function setPageSize(size: number) { pagination
|
|
125
|
+
function setPage(page: number) { pagination={ ...pagination,current: page }; }
|
|
126
|
+
function setPageSize(size: number) { pagination={ ...pagination,pageSize: size,current: 1 }; }
|
|
124
127
|
|
|
125
|
-
if
|
|
128
|
+
if(syncWithLocation&&typeof window!=='undefined') {
|
|
126
129
|
$effect(() => {
|
|
127
130
|
writeURLState({
|
|
128
131
|
page: pagination.current,
|
|
129
132
|
pageSize: pagination.pageSize,
|
|
130
133
|
sortField: currentSorters[0]?.field,
|
|
131
134
|
sortOrder: currentSorters[0]?.order,
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
...definedOptions({
|
|
136
|
+
filters: currentFilters
|
|
137
|
+
})
|
|
138
|
+
},adminContext);
|
|
134
139
|
});
|
|
135
140
|
|
|
136
141
|
$effect(() => {
|
|
137
|
-
const handler
|
|
138
|
-
const urlState
|
|
139
|
-
const newPage
|
|
140
|
-
if
|
|
141
|
-
pagination
|
|
142
|
+
const handler=() => {
|
|
143
|
+
const urlState=readURLState(adminContext);
|
|
144
|
+
const newPage=urlState.page??1;
|
|
145
|
+
if(newPage!==pagination.current) {
|
|
146
|
+
pagination={ ...pagination,current: newPage };
|
|
142
147
|
}
|
|
143
|
-
const newPageSize
|
|
144
|
-
if
|
|
145
|
-
pagination
|
|
148
|
+
const newPageSize=urlState.pageSize??getOptions().pagination?.pageSize??getAdminOptions().defaultPageSize??10;
|
|
149
|
+
if(newPageSize!==pagination.pageSize) {
|
|
150
|
+
pagination={ ...pagination,pageSize: newPageSize };
|
|
146
151
|
}
|
|
147
|
-
if
|
|
148
|
-
const newSorter: Sort
|
|
149
|
-
if
|
|
150
|
-
currentSorters
|
|
152
|
+
if(urlState.sortField) {
|
|
153
|
+
const newSorter: Sort={ field: urlState.sortField,order: urlState.sortOrder??'asc' };
|
|
154
|
+
if(JSON.stringify([newSorter])!==JSON.stringify(currentSorters)) {
|
|
155
|
+
currentSorters=[newSorter];
|
|
151
156
|
}
|
|
152
|
-
} else if
|
|
153
|
-
currentSorters
|
|
157
|
+
} else if(currentSorters.length>0) {
|
|
158
|
+
currentSorters=[];
|
|
154
159
|
}
|
|
155
|
-
if
|
|
156
|
-
currentFilters
|
|
157
|
-
} else if
|
|
158
|
-
currentFilters
|
|
160
|
+
if(urlState.filters&&JSON.stringify(urlState.filters)!==JSON.stringify(currentFilters)) {
|
|
161
|
+
currentFilters=urlState.filters;
|
|
162
|
+
} else if(!urlState.filters&¤tFilters.length>0) {
|
|
163
|
+
currentFilters=[];
|
|
159
164
|
}
|
|
160
165
|
};
|
|
161
|
-
window.addEventListener('popstate',
|
|
162
|
-
window.addEventListener('hashchange',
|
|
166
|
+
window.addEventListener('popstate',handler);
|
|
167
|
+
window.addEventListener('hashchange',handler);
|
|
163
168
|
return () => {
|
|
164
|
-
window.removeEventListener('popstate',
|
|
165
|
-
window.removeEventListener('hashchange',
|
|
169
|
+
window.removeEventListener('popstate',handler);
|
|
170
|
+
window.removeEventListener('hashchange',handler);
|
|
166
171
|
};
|
|
167
172
|
});
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
function createLinkForSyncWithLocation(): string {
|
|
171
|
-
const params
|
|
172
|
-
if
|
|
173
|
-
if
|
|
174
|
-
if
|
|
175
|
-
params.set('sort',
|
|
176
|
-
params.set('order',
|
|
176
|
+
const params=new URLSearchParams();
|
|
177
|
+
if(pagination.current) params.set('page',String(pagination.current));
|
|
178
|
+
if(pagination.pageSize) params.set('pageSize',String(pagination.pageSize));
|
|
179
|
+
if(currentSorters[0]) {
|
|
180
|
+
params.set('sort',currentSorters[0].field);
|
|
181
|
+
params.set('order',currentSorters[0].order);
|
|
177
182
|
}
|
|
178
|
-
if
|
|
179
|
-
params.set('filters',
|
|
183
|
+
if(currentFilters.length>0) {
|
|
184
|
+
params.set('filters',JSON.stringify(currentFilters));
|
|
180
185
|
}
|
|
181
186
|
return `?${params.toString()}`;
|
|
182
187
|
}
|
|
@@ -187,91 +192,92 @@ export function useTable<
|
|
|
187
192
|
get pagination() { return pagination; },
|
|
188
193
|
get sorters() { return currentSorters; },
|
|
189
194
|
get filters() { return currentFilters; },
|
|
190
|
-
setSorters,
|
|
195
|
+
setSorters,setFilters,setPage,setPageSize,
|
|
191
196
|
createLinkForSyncWithLocation,
|
|
192
197
|
get totalPages() {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
return Math.ceil(total / (pagination.pageSize ?? 10));
|
|
198
|
+
const total=query.data?.total??0;
|
|
199
|
+
return Math.ceil(total/(pagination.pageSize??10));
|
|
196
200
|
},
|
|
197
|
-
get current() { return pagination.current
|
|
198
|
-
get pageSize() { return pagination.pageSize
|
|
199
|
-
get pageCount() { return Math.ceil((
|
|
201
|
+
get current() { return pagination.current??1; },
|
|
202
|
+
get pageSize() { return pagination.pageSize??10; },
|
|
203
|
+
get pageCount() { return Math.ceil((query.data?.total??0)/(pagination.pageSize??10)); },
|
|
200
204
|
get clientData(): TQueryFnData[] {
|
|
201
|
-
if
|
|
202
|
-
const allData
|
|
203
|
-
let sorted
|
|
204
|
-
const activeSorters
|
|
205
|
-
if
|
|
206
|
-
sorted.sort((a,
|
|
207
|
-
for
|
|
208
|
-
const va
|
|
209
|
-
const vb
|
|
210
|
-
if
|
|
211
|
-
if
|
|
212
|
-
if
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if
|
|
217
|
-
else if
|
|
218
|
-
else
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (cmp !== 0) return order === 'desc' ? -cmp : cmp;
|
|
205
|
+
if(paginationMode==='server') return [];
|
|
206
|
+
const allData=query.data?.data??[];
|
|
207
|
+
let sorted=[...allData];
|
|
208
|
+
const activeSorters=sortersMode==='off'? effectiveSorters:[];
|
|
209
|
+
if(activeSorters.length>0) {
|
|
210
|
+
sorted.sort((a,b) => {
|
|
211
|
+
for(const { field,order } of activeSorters) {
|
|
212
|
+
const va=a[field];
|
|
213
|
+
const vb=b[field];
|
|
214
|
+
if(va==null&&vb!=null) return 1;
|
|
215
|
+
if(vb==null&&va!=null) return -1;
|
|
216
|
+
if(va==null&&vb==null) continue;
|
|
217
|
+
|
|
218
|
+
let cmp: number;
|
|
219
|
+
if(typeof va==='number'&&typeof vb==='number') cmp=va-vb;
|
|
220
|
+
else if(va instanceof Date&&vb instanceof Date) cmp=va.getTime()-vb.getTime();
|
|
221
|
+
else if(typeof va==='string'&&typeof vb==='string'&&!isNaN(Number(va))&&!isNaN(Number(vb))) cmp=Number(va)-Number(vb);
|
|
222
|
+
else cmp=String(va).localeCompare(String(vb));
|
|
223
|
+
|
|
224
|
+
if(cmp!==0) return order==='desc'? -cmp:cmp;
|
|
222
225
|
}
|
|
223
226
|
return 0;
|
|
224
227
|
});
|
|
225
228
|
}
|
|
226
|
-
const activeFilters
|
|
227
|
-
if
|
|
228
|
-
function matchesFilter(item: Record<string,
|
|
229
|
-
if
|
|
230
|
-
if
|
|
231
|
-
if
|
|
229
|
+
const activeFilters=filtersMode==='off'? effectiveFilters:[];
|
|
230
|
+
if(activeFilters.length>0) {
|
|
231
|
+
function matchesFilter(item: Record<string,unknown>,f: Filter): boolean {
|
|
232
|
+
if(!('field' in f)) {
|
|
233
|
+
if(f.operator==='and') return f.value.every(sub => matchesFilter(item,sub));
|
|
234
|
+
if(f.operator==='or') return f.value.length===0||f.value.some(sub => matchesFilter(item,sub));
|
|
232
235
|
return true;
|
|
233
236
|
}
|
|
234
|
-
const val
|
|
235
|
-
const fv
|
|
236
|
-
switch
|
|
237
|
-
case 'null': return val
|
|
238
|
-
case 'nnull': return val
|
|
237
|
+
const val=item[f.field];
|
|
238
|
+
const fv=f.value;
|
|
239
|
+
switch(f.operator) {
|
|
240
|
+
case 'null': return val==null;
|
|
241
|
+
case 'nnull': return val!=null;
|
|
239
242
|
default: break;
|
|
240
243
|
}
|
|
241
|
-
if
|
|
242
|
-
switch
|
|
243
|
-
case 'eq': return val
|
|
244
|
-
case 'ne': return val
|
|
245
|
-
case 'lt': return typeof val
|
|
246
|
-
case 'gt': return typeof val
|
|
247
|
-
case 'lte': return typeof val
|
|
248
|
-
case 'gte': return typeof val
|
|
249
|
-
case 'in': return !Array.isArray(fv)
|
|
250
|
-
case 'nin': return !Array.isArray(fv)
|
|
251
|
-
case 'contains': return typeof val
|
|
252
|
-
case 'ncontains': return typeof val
|
|
253
|
-
case 'startswith': return typeof val
|
|
254
|
-
case 'endswith': return typeof val
|
|
244
|
+
if(fv==null||fv==='') return true;
|
|
245
|
+
switch(f.operator) {
|
|
246
|
+
case 'eq': return val==fv;
|
|
247
|
+
case 'ne': return val!=fv;
|
|
248
|
+
case 'lt': return typeof val==='number'&&typeof fv==='number'&&val<fv;
|
|
249
|
+
case 'gt': return typeof val==='number'&&typeof fv==='number'&&val>fv;
|
|
250
|
+
case 'lte': return typeof val==='number'&&typeof fv==='number'&&val<=fv;
|
|
251
|
+
case 'gte': return typeof val==='number'&&typeof fv==='number'&&val>=fv;
|
|
252
|
+
case 'in': return !Array.isArray(fv)||fv.length===0||fv.includes(val);
|
|
253
|
+
case 'nin': return !Array.isArray(fv)||fv.length===0||!fv.includes(val);
|
|
254
|
+
case 'contains': return typeof val==='string'&&typeof fv==='string'&&val.includes(fv);
|
|
255
|
+
case 'ncontains': return typeof val==='string'&&typeof fv==='string'&&!val.includes(fv);
|
|
256
|
+
case 'startswith': return typeof val==='string'&&typeof fv==='string'&&val.startsWith(fv);
|
|
257
|
+
case 'endswith': return typeof val==='string'&&typeof fv==='string'&&val.endsWith(fv);
|
|
255
258
|
case 'between': {
|
|
256
|
-
if
|
|
257
|
-
|
|
259
|
+
if(!Array.isArray(fv)||fv.length!==2) return true;
|
|
260
|
+
const [min,max]: unknown[]=fv;
|
|
261
|
+
return typeof val==='number'&&typeof min==='number'&&typeof max==='number'
|
|
262
|
+
&&val>=min&&val<=max;
|
|
258
263
|
}
|
|
259
264
|
case 'nbetween': {
|
|
260
|
-
if
|
|
261
|
-
|
|
265
|
+
if(!Array.isArray(fv)||fv.length!==2) return true;
|
|
266
|
+
const [min,max]: unknown[]=fv;
|
|
267
|
+
return typeof val==='number'&&typeof min==='number'&&typeof max==='number'
|
|
268
|
+
&&(val<min||val>max);
|
|
262
269
|
}
|
|
263
270
|
default: return true;
|
|
264
271
|
}
|
|
265
272
|
}
|
|
266
|
-
sorted
|
|
267
|
-
|
|
268
|
-
return activeFilters.every(f => matchesFilter(rec, f));
|
|
273
|
+
sorted=sorted.filter((item) => {
|
|
274
|
+
return activeFilters.every(f => matchesFilter(item,f));
|
|
269
275
|
});
|
|
270
276
|
}
|
|
271
|
-
if
|
|
272
|
-
const start
|
|
273
|
-
const end
|
|
274
|
-
return sorted.slice(start,
|
|
277
|
+
if(paginationMode==='off') return sorted;
|
|
278
|
+
const start=((pagination.current??1)-1)*(pagination.pageSize??10);
|
|
279
|
+
const end=start+(pagination.pageSize??10);
|
|
280
|
+
return sorted.slice(start,end);
|
|
275
281
|
},
|
|
276
282
|
};
|
|
277
283
|
}
|