runeforge 0.0.16 → 0.0.18

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.
@@ -1,344 +1,364 @@
1
1
  <script lang="ts" generics="T extends object = Record<string, unknown>">
2
- import { page } from '$app/state';
3
- import { goto } from '$app/navigation';
4
- import List from './views/List.svelte';
5
- import Read from './views/Read.svelte';
6
- import Create from './views/Create.svelte';
7
- import Update from './views/Update.svelte';
8
- import { AUTO_EXCLUDED } from './utils/constants.js';
9
- import { resolveOptions, resolveFormatter, inferType } from './utils/resolution.js';
10
- import { isFilterable } from '../table/utils.js';
11
- import type { AttributeMetadata } from '../../types/attribute.js';
12
- import type {
13
- ActionConfiguration,
14
- ColumnDefinition,
15
- CustomAction,
16
- FieldDefinition,
17
- } from '../../types/crud.js';
18
- import type {
19
- FilterSnapshot,
20
- PaginatedEnvelope,
21
- ServerPagination,
22
- SortDirection,
23
- TableQuery,
24
- } from '../../types/table.js';
2
+ import { page } from '$app/state';
3
+ import { goto } from '$app/navigation';
4
+ import List from './views/List.svelte';
5
+ import Read from './views/Read.svelte';
6
+ import Create from './views/Create.svelte';
7
+ import Update from './views/Update.svelte';
8
+ import { AUTO_EXCLUDED } from './utils/constants.js';
9
+ import {
10
+ resolveOptions,
11
+ resolveFormatter,
12
+ inferType
13
+ } from './utils/resolution.js';
14
+ import { isFilterable } from '../table/utils.js';
15
+ import type { AttributeMetadata } from '../../types/attribute.js';
16
+ import type {
17
+ ActionConfiguration,
18
+ ColumnDefinition,
19
+ CustomAction,
20
+ CustomBulkAction,
21
+ FieldDefinition,
22
+ SearchConfiguration
23
+ } from '../../types/crud.js';
24
+ import type {
25
+ FilterSnapshot,
26
+ PaginatedEnvelope,
27
+ ServerPagination,
28
+ SortDirection,
29
+ TableQuery
30
+ } from '../../types/table.js';
25
31
 
26
- let {
27
- data = undefined as Record<string, unknown> | undefined,
28
- dataKey = undefined as string | undefined,
29
- idKey = '_id',
30
- labelOne = '',
31
- labelMany = '',
32
- icon,
33
- pageSize = 10,
34
- creation = {} as ActionConfiguration<T>,
35
- update = {} as ActionConfiguration<T>,
36
- read = {} as ActionConfiguration<T>,
37
- deletion = {} as ActionConfiguration<T>,
38
- actions = [] as CustomAction<T>[],
39
- columns = undefined as ColumnDefinition<T>[] | undefined,
40
- fields = undefined as FieldDefinition<T>[] | undefined,
41
- meta = undefined as Partial<Record<string, AttributeMetadata>> | undefined,
42
- form = null as { error?: string } | null,
43
- }: {
44
- data?: Record<string, unknown>;
45
- dataKey?: string;
46
- idKey?: string;
47
- labelOne?: string;
48
- labelMany?: string;
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
- icon?: any;
51
- pageSize?: number;
52
- creation?: ActionConfiguration<T>;
53
- update?: ActionConfiguration<T>;
54
- read?: ActionConfiguration<T>;
55
- deletion?: ActionConfiguration<T>;
56
- actions?: CustomAction<T>[];
57
- columns?: ColumnDefinition<T>[];
58
- fields?: FieldDefinition<T>[];
59
- meta?: Partial<Record<string, AttributeMetadata>>;
60
- form?: { error?: string } | null;
61
- } = $props();
32
+ let {
33
+ data = undefined as Record<string, unknown> | undefined,
34
+ dataKey = undefined as string | undefined,
35
+ idKey = '_id',
36
+ labelOne = '',
37
+ labelMany = '',
38
+ icon,
39
+ pageSize = 10,
40
+ creation = {} as ActionConfiguration<T>,
41
+ update = {} as ActionConfiguration<T>,
42
+ read = {} as ActionConfiguration<T>,
43
+ deletion = {} as ActionConfiguration<T>,
44
+ actions = [] as CustomAction<T>[],
45
+ customBulkActions = [] as CustomBulkAction<T>[],
46
+ search = undefined as SearchConfiguration | undefined,
47
+ columns = undefined as ColumnDefinition<T>[] | undefined,
48
+ fields = undefined as FieldDefinition<T>[] | undefined,
49
+ meta = undefined as Partial<Record<string, AttributeMetadata>> | undefined,
50
+ form = null as { error?: string } | null
51
+ }: {
52
+ data?: Record<string, unknown>;
53
+ dataKey?: string;
54
+ idKey?: string;
55
+ labelOne?: string;
56
+ labelMany?: string;
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ icon?: any;
59
+ pageSize?: number;
60
+ creation?: ActionConfiguration<T>;
61
+ update?: ActionConfiguration<T>;
62
+ read?: ActionConfiguration<T>;
63
+ deletion?: ActionConfiguration<T>;
64
+ actions?: CustomAction<T>[];
65
+ customBulkActions?: CustomBulkAction<T>[];
66
+ search?: SearchConfiguration;
67
+ columns?: ColumnDefinition<T>[];
68
+ fields?: FieldDefinition<T>[];
69
+ meta?: Partial<Record<string, AttributeMetadata>>;
70
+ form?: { error?: string } | null;
71
+ } = $props();
62
72
 
63
- function isEnvelope(value: unknown): value is PaginatedEnvelope<T> {
64
- return (
65
- !!value &&
66
- typeof value === 'object' &&
67
- !Array.isArray(value) &&
68
- Array.isArray((value as Record<string, unknown>).results) &&
69
- typeof (value as Record<string, unknown>).count === 'number'
70
- );
71
- }
73
+ function isEnvelope(value: unknown): value is PaginatedEnvelope<T> {
74
+ return (
75
+ !!value &&
76
+ typeof value === 'object' &&
77
+ !Array.isArray(value) &&
78
+ Array.isArray((value as Record<string, unknown>).results) &&
79
+ typeof (value as Record<string, unknown>).count === 'number'
80
+ );
81
+ }
72
82
 
73
- const rawSlice = $derived(data && dataKey ? data[dataKey] : undefined);
74
- const envelope = $derived(isEnvelope(rawSlice) ? rawSlice : undefined);
75
- const entityData = $derived<T[]>(
76
- envelope ? envelope.results : (Array.isArray(rawSlice) ? (rawSlice as T[]) : [])
77
- );
83
+ const rawSlice = $derived(data && dataKey ? data[dataKey] : undefined);
84
+ const envelope = $derived(isEnvelope(rawSlice) ? rawSlice : undefined);
85
+ const entityData = $derived<T[]>(
86
+ envelope ? envelope.results : Array.isArray(rawSlice) ? (rawSlice as T[]) : []
87
+ );
78
88
 
79
- const serverPagination = $derived<ServerPagination | undefined>(
80
- envelope
81
- ? {
82
- page: envelope.page,
83
- pageSize: envelope.pageSize,
84
- totalPages: Math.max(1, Math.ceil(envelope.count / envelope.pageSize)),
85
- total: envelope.count,
86
- }
87
- : undefined
88
- );
89
+ const serverPagination = $derived<ServerPagination | undefined>(
90
+ envelope
91
+ ? {
92
+ page: envelope.page,
93
+ pageSize: envelope.pageSize,
94
+ totalPages: Math.max(1, Math.ceil(envelope.count / envelope.pageSize)),
95
+ total: envelope.count
96
+ }
97
+ : undefined
98
+ );
89
99
 
90
- const viewParam = $derived(page.url.searchParams.get('view'));
91
- const idParam = $derived(page.url.searchParams.get('id'));
100
+ const viewParam = $derived(page.url.searchParams.get('view'));
101
+ const idParam = $derived(page.url.searchParams.get('id'));
92
102
 
93
- const creating = $derived(viewParam === 'create');
94
- const reading = $derived(idParam !== null && viewParam === null);
95
- const editing = $derived(idParam !== null && viewParam === 'edit');
103
+ const creating = $derived(viewParam === 'create');
104
+ const reading = $derived(idParam !== null && viewParam === null);
105
+ const editing = $derived(idParam !== null && viewParam === 'edit');
96
106
 
97
- const excluded = $derived(new Set([...AUTO_EXCLUDED, idKey]));
107
+ const excluded = $derived(new Set([...AUTO_EXCLUDED, idKey]));
98
108
 
99
- const singleInstance = $derived<T | undefined>(
100
- (Object.values(page.data as Record<string, unknown>).find(
101
- (v) => v !== null && typeof v === 'object' && !Array.isArray(v) && idKey in (v as object)
102
- ) as T | undefined)
103
- );
109
+ const singleInstance = $derived<T | undefined>(
110
+ Object.values(page.data as Record<string, unknown>).find(
111
+ (v) => v !== null && typeof v === 'object' && !Array.isArray(v) && idKey in (v as object)
112
+ ) as T | undefined
113
+ );
104
114
 
105
- let activeAction = $state<{ action: CustomAction<T>; item: T } | null>(null);
115
+ let activeAction = $state<{ action: CustomAction<T>; item: T } | null>(null);
106
116
 
107
- async function navList() { await goto('?'); }
108
- async function navCreate() { await goto('?view=create'); }
109
- async function navRead(item: T) {
110
- await goto(`?id=${encodeURIComponent(String((item as Record<string, unknown>)[idKey] ?? ''))}`);
111
- }
112
- async function navEdit(item: T) {
113
- await goto(`?id=${encodeURIComponent(String((item as Record<string, unknown>)[idKey] ?? ''))}&view=edit`);
114
- }
117
+ async function navList() {
118
+ await goto('?');
119
+ }
120
+ async function navCreate() {
121
+ await goto('?view=create');
122
+ }
123
+ async function navRead(item: T) {
124
+ await goto(`?id=${encodeURIComponent(String((item as Record<string, unknown>)[idKey] ?? ''))}`);
125
+ }
126
+ async function navEdit(item: T) {
127
+ await goto(
128
+ `?id=${encodeURIComponent(String((item as Record<string, unknown>)[idKey] ?? ''))}&view=edit`
129
+ );
130
+ }
115
131
 
116
- const resolvedColumns: ColumnDefinition<T>[] = $derived(
117
- columns ?? (meta
118
- ? (Object.entries(meta) as [string, AttributeMetadata][])
119
- .filter(([, m]) => !m.excludedFromList)
120
- .map(([k, m]) => ({
121
- attribute: k as keyof T & string,
122
- title: m.label ?? k,
123
- type: m.type,
124
- formatter: resolveFormatter(m, data),
125
- component: m.component,
126
- sortable: m.sortable,
127
- filterable: m.filterable,
128
- }))
129
- : entityData.length > 0
130
- ? (Object.keys(entityData[0]) as (keyof T & string)[])
131
- .filter((k) => !excluded.has(k))
132
- .map((k) => ({ attribute: k, title: k }))
133
- : [])
134
- );
132
+ const resolvedColumns: ColumnDefinition<T>[] = $derived(
133
+ columns ??
134
+ (meta
135
+ ? (Object.entries(meta) as [string, AttributeMetadata][])
136
+ .filter(([, m]) => !m.excludedFromList)
137
+ .map(([k, m]) => ({
138
+ attribute: k as keyof T & string,
139
+ title: m.label ?? k,
140
+ type: m.type,
141
+ formatter: resolveFormatter(m, data),
142
+ component: m.component,
143
+ sortable: m.sortable,
144
+ filterable: m.filterable
145
+ }))
146
+ : entityData.length > 0
147
+ ? (Object.keys(entityData[0]) as (keyof T & string)[])
148
+ .filter((k) => !excluded.has(k))
149
+ .map((k) => ({ attribute: k, title: k }))
150
+ : [])
151
+ );
135
152
 
136
- // Server-pagination mode only: GenericCRUD owns `page`/`ordering`/per-column
137
- // filter query params the same way it already owns `view`/`id`, so pagination
138
- // state survives reloads/direct links and `+page.svelte` never has to change.
139
- const orderingParam = $derived(page.url.searchParams.get('ordering'));
140
- const initialSort = $derived(
141
- orderingParam
142
- ? {
143
- column: orderingParam.startsWith('-') ? orderingParam.slice(1) : orderingParam,
144
- direction: (orderingParam.startsWith('-') ? 'desc' : 'asc') as SortDirection,
145
- }
146
- : undefined
147
- );
153
+ // Server-pagination mode only: GenericCRUD owns `page`/`ordering`/per-column
154
+ // filter query params the same way it already owns `view`/`id`, so pagination
155
+ // state survives reloads/direct links and `+page.svelte` never has to change.
156
+ const orderingParam = $derived(page.url.searchParams.get('ordering'));
157
+ const initialSort = $derived(
158
+ orderingParam
159
+ ? {
160
+ column: orderingParam.startsWith('-') ? orderingParam.slice(1) : orderingParam,
161
+ direction: (orderingParam.startsWith('-') ? 'desc' : 'asc') as SortDirection
162
+ }
163
+ : undefined
164
+ );
148
165
 
149
- const initialFilters = $derived.by<Partial<FilterSnapshot> | undefined>(() => {
150
- if (!envelope) return undefined;
151
- const text: Record<string, string> = {};
152
- const values: Record<string, string[]> = {};
153
- const dateRanges: Record<string, { from: string; to: string }> = {};
154
- for (const col of resolvedColumns) {
155
- if (!isFilterable(col)) continue;
156
- const raw = page.url.searchParams.get(col.attribute);
157
- if (raw != null) {
158
- if (col.type === 'boolean') values[col.attribute] = raw.split(',').filter(Boolean);
159
- else text[col.attribute] = raw;
160
- }
161
- const from = page.url.searchParams.get(`${col.attribute}_from`);
162
- const to = page.url.searchParams.get(`${col.attribute}_to`);
163
- if (from || to) dateRanges[col.attribute] = { from: from ?? '', to: to ?? '' };
164
- }
165
- return { text, values, dateRanges };
166
- });
166
+ const initialFilters = $derived.by<Partial<FilterSnapshot> | undefined>(() => {
167
+ if (!envelope) return undefined;
168
+ const text: Record<string, string> = {};
169
+ const values: Record<string, string[]> = {};
170
+ const dateRanges: Record<string, { from: string; to: string }> = {};
171
+ for (const col of resolvedColumns) {
172
+ if (!isFilterable(col)) continue;
173
+ const raw = page.url.searchParams.get(col.attribute);
174
+ if (raw != null) {
175
+ if (col.type === 'boolean') values[col.attribute] = raw.split(',').filter(Boolean);
176
+ else text[col.attribute] = raw;
177
+ }
178
+ const from = page.url.searchParams.get(`${col.attribute}_from`);
179
+ const to = page.url.searchParams.get(`${col.attribute}_to`);
180
+ if (from || to) dateRanges[col.attribute] = { from: from ?? '', to: to ?? '' };
181
+ }
182
+ return { text, values, dateRanges };
183
+ });
167
184
 
168
- async function handlePaginationChange(query: TableQuery) {
169
- // Local, synchronous query-string builder consumed immediately by goto();
170
- // not rendered/reactive state, so plain URLSearchParams is correct here.
171
- // eslint-disable-next-line svelte/prefer-svelte-reactivity
172
- const params = new URLSearchParams(page.url.searchParams);
173
- params.delete('view');
174
- params.delete('id');
185
+ async function handlePaginationChange(query: TableQuery) {
186
+ // Local, synchronous query-string builder consumed immediately by goto();
187
+ // not rendered/reactive state, so plain URLSearchParams is correct here.
188
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity
189
+ const params = new URLSearchParams(page.url.searchParams);
190
+ params.delete('view');
191
+ params.delete('id');
175
192
 
176
- if (query.page > 1) params.set('page', String(query.page));
177
- else params.delete('page');
193
+ if (query.page > 1) params.set('page', String(query.page));
194
+ else params.delete('page');
178
195
 
179
- if (query.ordering) params.set('ordering', query.ordering);
180
- else params.delete('ordering');
196
+ if (query.ordering) params.set('ordering', query.ordering);
197
+ else params.delete('ordering');
181
198
 
182
- for (const col of resolvedColumns) {
183
- params.delete(col.attribute);
184
- params.delete(`${col.attribute}_from`);
185
- params.delete(`${col.attribute}_to`);
186
- }
187
- for (const [k, v] of Object.entries(query.filters.text)) {
188
- if (v) params.set(k, v);
189
- }
190
- for (const [k, vs] of Object.entries(query.filters.values)) {
191
- if (vs.length) params.set(k, vs.join(','));
192
- }
193
- for (const [k, r] of Object.entries(query.filters.dateRanges)) {
194
- if (r.from) params.set(`${k}_from`, r.from);
195
- if (r.to) params.set(`${k}_to`, r.to);
196
- }
199
+ for (const col of resolvedColumns) {
200
+ params.delete(col.attribute);
201
+ params.delete(`${col.attribute}_from`);
202
+ params.delete(`${col.attribute}_to`);
203
+ }
204
+ for (const [k, v] of Object.entries(query.filters.text)) {
205
+ if (v) params.set(k, v);
206
+ }
207
+ for (const [k, vs] of Object.entries(query.filters.values)) {
208
+ if (vs.length) params.set(k, vs.join(','));
209
+ }
210
+ for (const [k, r] of Object.entries(query.filters.dateRanges)) {
211
+ if (r.from) params.set(`${k}_from`, r.from);
212
+ if (r.to) params.set(`${k}_to`, r.to);
213
+ }
197
214
 
198
- const qs = params.toString();
199
- await goto(qs ? `?${qs}` : '?', { keepFocus: true, noScroll: true });
200
- }
215
+ const qs = params.toString();
216
+ await goto(qs ? `?${qs}` : '?', { keepFocus: true, noScroll: true });
217
+ }
201
218
 
202
- const resolvedFields: FieldDefinition<T>[] = $derived(
203
- fields ?? (meta
204
- ? (Object.entries(meta) as [string, AttributeMetadata][])
205
- .filter(([k, m]) => !excluded.has(k) && !m.excludedFromCreate)
206
- .map(([k, m]) => ({
207
- attribute: k as keyof T & string,
208
- title: m.label,
209
- type: m.type ?? inferType(k, undefined),
210
- required: m.required,
211
- autocomplete: m.autocomplete,
212
- placeholder: m.placeholder,
213
- default: m.default,
214
- options: resolveOptions(m, data),
215
- }))
216
- : entityData.length > 0
217
- ? (Object.entries(entityData[0]) as [string, unknown][])
218
- .filter(([k]) => !excluded.has(k))
219
- .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
220
- : [])
221
- );
219
+ const resolvedFields: FieldDefinition<T>[] = $derived(
220
+ fields ??
221
+ (meta
222
+ ? (Object.entries(meta) as [string, AttributeMetadata][])
223
+ .filter(([k, m]) => !excluded.has(k) && !m.excludedFromCreate)
224
+ .map(([k, m]) => ({
225
+ attribute: k as keyof T & string,
226
+ title: m.label,
227
+ type: m.type ?? inferType(k, undefined),
228
+ required: m.required,
229
+ autocomplete: m.autocomplete,
230
+ placeholder: m.placeholder,
231
+ default: m.default,
232
+ options: resolveOptions(m, data)
233
+ }))
234
+ : entityData.length > 0
235
+ ? (Object.entries(entityData[0]) as [string, unknown][])
236
+ .filter(([k]) => !excluded.has(k))
237
+ .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
238
+ : [])
239
+ );
222
240
 
223
- const resolvedReadFields: FieldDefinition<T>[] = $derived(
224
- fields ?? (meta
225
- ? (Object.entries(meta) as [string, AttributeMetadata][])
226
- .filter(([k, m]) => !excluded.has(k) && !m.excludedFromRead)
227
- .map(([k, m]) => ({
228
- attribute: k as keyof T & string,
229
- title: m.label,
230
- type: m.type ?? inferType(k, undefined),
231
- required: m.required,
232
- autocomplete: m.autocomplete,
233
- placeholder: m.placeholder,
234
- default: m.default,
235
- options: resolveOptions(m, data),
236
- }))
237
- : entityData.length > 0
238
- ? (Object.entries(entityData[0]) as [string, unknown][])
239
- .filter(([k]) => !excluded.has(k))
240
- .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
241
- : [])
242
- );
241
+ const resolvedReadFields: FieldDefinition<T>[] = $derived(
242
+ fields ??
243
+ (meta
244
+ ? (Object.entries(meta) as [string, AttributeMetadata][])
245
+ .filter(([k, m]) => !excluded.has(k) && !m.excludedFromRead)
246
+ .map(([k, m]) => ({
247
+ attribute: k as keyof T & string,
248
+ title: m.label,
249
+ type: m.type ?? inferType(k, undefined),
250
+ required: m.required,
251
+ autocomplete: m.autocomplete,
252
+ placeholder: m.placeholder,
253
+ default: m.default,
254
+ options: resolveOptions(m, data)
255
+ }))
256
+ : entityData.length > 0
257
+ ? (Object.entries(entityData[0]) as [string, unknown][])
258
+ .filter(([k]) => !excluded.has(k))
259
+ .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
260
+ : [])
261
+ );
243
262
 
244
- const resolvedUpdateFields: FieldDefinition<T>[] = $derived(
245
- fields ?? (meta
246
- ? (Object.entries(meta) as [string, AttributeMetadata][])
247
- .filter(([k, m]) => !excluded.has(k) && !m.excludedFromUpdate)
248
- .map(([k, m]) => ({
249
- attribute: k as keyof T & string,
250
- title: m.label,
251
- type: m.type ?? inferType(k, undefined),
252
- required: m.required,
253
- autocomplete: m.autocomplete,
254
- placeholder: m.placeholder,
255
- default: m.default,
256
- options: resolveOptions(m, data),
257
- }))
258
- : entityData.length > 0
259
- ? (Object.entries(entityData[0]) as [string, unknown][])
260
- .filter(([k]) => !excluded.has(k))
261
- .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
262
- : [])
263
- );
263
+ const resolvedUpdateFields: FieldDefinition<T>[] = $derived(
264
+ fields ??
265
+ (meta
266
+ ? (Object.entries(meta) as [string, AttributeMetadata][])
267
+ .filter(([k, m]) => !excluded.has(k) && !m.excludedFromUpdate)
268
+ .map(([k, m]) => ({
269
+ attribute: k as keyof T & string,
270
+ title: m.label,
271
+ type: m.type ?? inferType(k, undefined),
272
+ required: m.required,
273
+ autocomplete: m.autocomplete,
274
+ placeholder: m.placeholder,
275
+ default: m.default,
276
+ options: resolveOptions(m, data)
277
+ }))
278
+ : entityData.length > 0
279
+ ? (Object.entries(entityData[0]) as [string, unknown][])
280
+ .filter(([k]) => !excluded.has(k))
281
+ .map(([k, v]) => ({ attribute: k as keyof T & string, type: inferType(k, v) }))
282
+ : [])
283
+ );
264
284
 
265
- const serverError = $derived(
266
- creating || reading || editing || activeAction !== null
267
- ? (form?.error ?? '')
268
- : ''
269
- );
285
+ const serverError = $derived(
286
+ creating || reading || editing || activeAction !== null ? (form?.error ?? '') : ''
287
+ );
270
288
  </script>
271
289
 
272
290
  {#if creating}
273
- <Create
274
- {labelOne}
275
- {labelMany}
276
- {icon}
277
- fields={resolvedFields}
278
- {creation}
279
- {serverError}
280
- onCancel={navList}
281
- onSuccess={navList}
282
- />
291
+ <Create
292
+ {labelOne}
293
+ {labelMany}
294
+ {icon}
295
+ fields={resolvedFields}
296
+ {creation}
297
+ {serverError}
298
+ onCancel={navList}
299
+ onSuccess={navList}
300
+ />
283
301
  {:else if reading}
284
- <Read
285
- {labelOne}
286
- {labelMany}
287
- {icon}
288
- {idKey}
289
- fields={resolvedReadFields}
290
- instance={singleInstance ?? {} as T}
291
- {read}
292
- onCancel={navList}
293
- />
302
+ <Read
303
+ {labelOne}
304
+ {labelMany}
305
+ {icon}
306
+ {idKey}
307
+ fields={resolvedReadFields}
308
+ instance={singleInstance ?? ({} as T)}
309
+ {read}
310
+ onCancel={navList}
311
+ />
294
312
  {:else if editing}
295
- <Update
296
- {labelOne}
297
- {labelMany}
298
- {icon}
299
- {idKey}
300
- fields={resolvedUpdateFields}
301
- instance={singleInstance ?? {} as T}
302
- {update}
303
- {serverError}
304
- onCancel={navList}
305
- onSuccess={navList}
306
- />
313
+ <Update
314
+ {labelOne}
315
+ {labelMany}
316
+ {icon}
317
+ {idKey}
318
+ fields={resolvedUpdateFields}
319
+ instance={singleInstance ?? ({} as T)}
320
+ {update}
321
+ {serverError}
322
+ onCancel={navList}
323
+ onSuccess={navList}
324
+ />
307
325
  {:else}
308
- <List
309
- data={entityData}
310
- {labelOne}
311
- {labelMany}
312
- {icon}
313
- {pageSize}
314
- {idKey}
315
- {creation}
316
- {update}
317
- {read}
318
- {deletion}
319
- {actions}
320
- columns={resolvedColumns}
321
- pagination={serverPagination}
322
- {initialSort}
323
- {initialFilters}
324
- onPaginationChange={handlePaginationChange}
325
- onCreate={navCreate}
326
- onEdit={navEdit}
327
- onView={navRead}
328
- onAction={(action, item) => {
329
- if (action.condition?.(item) ?? true) activeAction = { action, item };
330
- }}
331
- />
326
+ <List
327
+ data={entityData}
328
+ {labelOne}
329
+ {labelMany}
330
+ {icon}
331
+ {pageSize}
332
+ {idKey}
333
+ {creation}
334
+ {update}
335
+ {read}
336
+ {deletion}
337
+ {actions}
338
+ {customBulkActions}
339
+ {search}
340
+ columns={resolvedColumns}
341
+ pagination={serverPagination}
342
+ {initialSort}
343
+ {initialFilters}
344
+ onPaginationChange={handlePaginationChange}
345
+ onCreate={navCreate}
346
+ onEdit={navEdit}
347
+ onView={navRead}
348
+ onAction={(action, item) => {
349
+ if (action.condition?.(item) ?? true) activeAction = { action, item };
350
+ }}
351
+ />
332
352
  {/if}
333
353
 
334
354
  {#if activeAction !== null}
335
- {@const ActionView = activeAction.action.view}
336
- <ActionView
337
- instance={activeAction.item}
338
- label={activeAction.action.label}
339
- endpoint={activeAction.action.endpoint}
340
- {serverError}
341
- onCancel={() => (activeAction = null)}
342
- onSuccess={() => (activeAction = null)}
343
- />
355
+ {@const ActionView = activeAction.action.view}
356
+ <ActionView
357
+ instance={activeAction.item}
358
+ label={activeAction.action.label}
359
+ endpoint={activeAction.action.endpoint}
360
+ {serverError}
361
+ onCancel={() => (activeAction = null)}
362
+ onSuccess={() => (activeAction = null)}
363
+ />
344
364
  {/if}