@prometheus-ags/prometheus-entity-management 1.0.0 → 1.2.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/CHANGELOG.md +40 -0
- package/README.md +55 -3
- package/dist/index.d.mts +738 -408
- package/dist/index.d.ts +738 -408
- package/dist/index.js +1101 -339
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +836 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
var zustand = require('zustand');
|
|
4
4
|
var middleware = require('zustand/middleware');
|
|
5
5
|
var immer = require('zustand/middleware/immer');
|
|
6
|
-
var
|
|
6
|
+
var React6 = require('react');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
8
|
var shallow = require('zustand/react/shallow');
|
|
8
9
|
var reactTable = require('@tanstack/react-table');
|
|
9
10
|
var lucideReact = require('lucide-react');
|
|
10
11
|
var clsx = require('clsx');
|
|
11
12
|
var tailwindMerge = require('tailwind-merge');
|
|
12
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
13
13
|
|
|
14
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var React6__default = /*#__PURE__*/_interopDefault(React6);
|
|
17
17
|
|
|
18
18
|
// src/graph.ts
|
|
19
19
|
var EMPTY_IDS = [];
|
|
@@ -23,6 +23,11 @@ var EMPTY_ENTITY_STATE = {
|
|
|
23
23
|
error: null,
|
|
24
24
|
stale: false
|
|
25
25
|
};
|
|
26
|
+
var EMPTY_SYNC_METADATA = {
|
|
27
|
+
synced: true,
|
|
28
|
+
origin: "server",
|
|
29
|
+
updatedAt: null
|
|
30
|
+
};
|
|
26
31
|
var EMPTY_LIST_STATE = {
|
|
27
32
|
ids: EMPTY_IDS,
|
|
28
33
|
total: null,
|
|
@@ -41,6 +46,9 @@ var EMPTY_LIST_STATE = {
|
|
|
41
46
|
function defaultEntityState() {
|
|
42
47
|
return { ...EMPTY_ENTITY_STATE };
|
|
43
48
|
}
|
|
49
|
+
function defaultSyncMetadata() {
|
|
50
|
+
return { ...EMPTY_SYNC_METADATA };
|
|
51
|
+
}
|
|
44
52
|
function defaultListState() {
|
|
45
53
|
return { ...EMPTY_LIST_STATE, ids: [] };
|
|
46
54
|
}
|
|
@@ -53,24 +61,33 @@ var useGraphStore = zustand.create()(
|
|
|
53
61
|
entities: {},
|
|
54
62
|
patches: {},
|
|
55
63
|
entityStates: {},
|
|
64
|
+
syncMetadata: {},
|
|
56
65
|
lists: {},
|
|
57
66
|
upsertEntity: (type, id, data) => set((s) => {
|
|
58
67
|
if (!s.entities[type]) s.entities[type] = {};
|
|
59
68
|
s.entities[type][id] = { ...s.entities[type][id] ?? {}, ...data };
|
|
69
|
+
const key = ek(type, id);
|
|
70
|
+
if (!s.syncMetadata[key]) s.syncMetadata[key] = defaultSyncMetadata();
|
|
60
71
|
}),
|
|
61
72
|
upsertEntities: (type, entries) => set((s) => {
|
|
62
73
|
if (!s.entities[type]) s.entities[type] = {};
|
|
63
|
-
for (const { id, data } of entries)
|
|
74
|
+
for (const { id, data } of entries) {
|
|
64
75
|
s.entities[type][id] = { ...s.entities[type][id] ?? {}, ...data };
|
|
76
|
+
const key = ek(type, id);
|
|
77
|
+
if (!s.syncMetadata[key]) s.syncMetadata[key] = defaultSyncMetadata();
|
|
78
|
+
}
|
|
65
79
|
}),
|
|
66
80
|
replaceEntity: (type, id, data) => set((s) => {
|
|
67
81
|
if (!s.entities[type]) s.entities[type] = {};
|
|
68
82
|
s.entities[type][id] = data;
|
|
83
|
+
const key = ek(type, id);
|
|
84
|
+
if (!s.syncMetadata[key]) s.syncMetadata[key] = defaultSyncMetadata();
|
|
69
85
|
}),
|
|
70
86
|
removeEntity: (type, id) => set((s) => {
|
|
71
87
|
delete s.entities[type]?.[id];
|
|
72
88
|
delete s.patches[type]?.[id];
|
|
73
89
|
delete s.entityStates[ek(type, id)];
|
|
90
|
+
delete s.syncMetadata[ek(type, id)];
|
|
74
91
|
}),
|
|
75
92
|
patchEntity: (type, id, patch) => set((s) => {
|
|
76
93
|
if (!s.patches[type]) s.patches[type] = {};
|
|
@@ -102,12 +119,20 @@ var useGraphStore = zustand.create()(
|
|
|
102
119
|
s.entityStates[k].isFetching = false;
|
|
103
120
|
s.entityStates[k].error = null;
|
|
104
121
|
s.entityStates[k].stale = false;
|
|
122
|
+
s.syncMetadata[k] = { ...s.syncMetadata[k] ?? defaultSyncMetadata(), synced: true, origin: "server", updatedAt: Date.now() };
|
|
105
123
|
}),
|
|
106
124
|
setEntityStale: (type, id, stale) => set((s) => {
|
|
107
125
|
const k = ek(type, id);
|
|
108
126
|
if (!s.entityStates[k]) s.entityStates[k] = defaultEntityState();
|
|
109
127
|
s.entityStates[k].stale = stale;
|
|
110
128
|
}),
|
|
129
|
+
setEntitySyncMetadata: (type, id, metadata) => set((s) => {
|
|
130
|
+
const k = ek(type, id);
|
|
131
|
+
s.syncMetadata[k] = { ...s.syncMetadata[k] ?? defaultSyncMetadata(), ...metadata };
|
|
132
|
+
}),
|
|
133
|
+
clearEntitySyncMetadata: (type, id) => set((s) => {
|
|
134
|
+
delete s.syncMetadata[ek(type, id)];
|
|
135
|
+
}),
|
|
111
136
|
setListResult: (key, ids, meta) => set((s) => {
|
|
112
137
|
const ex = s.lists[key] ?? defaultListState();
|
|
113
138
|
s.lists[key] = { ...ex, ...meta, ids, isFetching: false, isFetchingMore: false, error: null, stale: false, lastFetched: Date.now() };
|
|
@@ -179,11 +204,717 @@ var useGraphStore = zustand.create()(
|
|
|
179
204
|
if (!base) return null;
|
|
180
205
|
const patch = s.patches[type]?.[id];
|
|
181
206
|
return patch ? { ...base, ...patch } : base;
|
|
207
|
+
},
|
|
208
|
+
readEntitySnapshot: (type, id) => {
|
|
209
|
+
const s = get();
|
|
210
|
+
const base = s.entities[type]?.[id];
|
|
211
|
+
if (!base) return null;
|
|
212
|
+
const patch = s.patches[type]?.[id];
|
|
213
|
+
const metadata = s.syncMetadata[ek(type, id)] ?? EMPTY_SYNC_METADATA;
|
|
214
|
+
return {
|
|
215
|
+
...patch ? { ...base, ...patch } : base,
|
|
216
|
+
$synced: metadata.synced,
|
|
217
|
+
$origin: metadata.origin,
|
|
218
|
+
$updatedAt: metadata.updatedAt
|
|
219
|
+
};
|
|
182
220
|
}
|
|
183
221
|
}))
|
|
184
222
|
)
|
|
185
223
|
);
|
|
186
224
|
|
|
225
|
+
// src/graph-query.ts
|
|
226
|
+
function queryOnce(opts) {
|
|
227
|
+
const store = useGraphStore.getState();
|
|
228
|
+
const ids = resolveCandidateIds(store, opts);
|
|
229
|
+
let rows = ids.map((id) => store.readEntitySnapshot(opts.type, id)).filter((row) => row !== null);
|
|
230
|
+
if (opts.where) rows = rows.filter(opts.where);
|
|
231
|
+
if (opts.sort) rows = [...rows].sort(opts.sort);
|
|
232
|
+
const projected = rows.map((row) => applySelection(projectRow(row, opts.include, store), opts.select));
|
|
233
|
+
if (opts.id) return projected[0] ?? null;
|
|
234
|
+
return projected;
|
|
235
|
+
}
|
|
236
|
+
var selectGraph = queryOnce;
|
|
237
|
+
function resolveCandidateIds(store, opts) {
|
|
238
|
+
if (opts.id) return [opts.id];
|
|
239
|
+
if (opts.ids) return opts.ids;
|
|
240
|
+
if (opts.listKey) return store.lists[opts.listKey]?.ids ?? [];
|
|
241
|
+
return Object.keys(store.entities[opts.type] ?? {});
|
|
242
|
+
}
|
|
243
|
+
function projectRow(row, include, store) {
|
|
244
|
+
if (!include) return row;
|
|
245
|
+
const projected = { ...row };
|
|
246
|
+
for (const [key, relation] of Object.entries(include)) {
|
|
247
|
+
const related = resolveRelation(row, relation, store);
|
|
248
|
+
projected[key] = related;
|
|
249
|
+
}
|
|
250
|
+
return projected;
|
|
251
|
+
}
|
|
252
|
+
function resolveRelation(entity, relation, store) {
|
|
253
|
+
const include = relation.include;
|
|
254
|
+
switch (relation.via.kind) {
|
|
255
|
+
case "field": {
|
|
256
|
+
const relatedId = entity[relation.via.field];
|
|
257
|
+
if (typeof relatedId !== "string") return null;
|
|
258
|
+
const related = store.readEntitySnapshot(relation.type, relatedId);
|
|
259
|
+
return related ? projectRow(related, include, store) : null;
|
|
260
|
+
}
|
|
261
|
+
case "array": {
|
|
262
|
+
const ids = entity[relation.via.field];
|
|
263
|
+
if (!Array.isArray(ids)) return [];
|
|
264
|
+
return ids.map((id) => typeof id === "string" ? store.readEntitySnapshot(relation.type, id) : null).filter((row) => row !== null).map((row) => projectRow(row, include, store));
|
|
265
|
+
}
|
|
266
|
+
case "list": {
|
|
267
|
+
const key = typeof relation.via.key === "function" ? relation.via.key(entity) : relation.via.key;
|
|
268
|
+
if (!key) return [];
|
|
269
|
+
const ids = store.lists[key]?.ids ?? [];
|
|
270
|
+
return ids.map((id) => store.readEntitySnapshot(relation.type, id)).filter((row) => row !== null).map((row) => projectRow(row, include, store));
|
|
271
|
+
}
|
|
272
|
+
case "resolver": {
|
|
273
|
+
const resolved = relation.via.resolve(entity, store);
|
|
274
|
+
if (Array.isArray(resolved)) {
|
|
275
|
+
return resolved.map((id) => store.readEntitySnapshot(relation.type, id)).filter((row) => row !== null).map((row) => projectRow(row, include, store));
|
|
276
|
+
}
|
|
277
|
+
if (typeof resolved !== "string") return null;
|
|
278
|
+
const related = store.readEntitySnapshot(relation.type, resolved);
|
|
279
|
+
return related ? projectRow(related, include, store) : null;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function applySelection(row, select) {
|
|
284
|
+
if (!select) return row;
|
|
285
|
+
if (typeof select === "function") {
|
|
286
|
+
const result = select(row);
|
|
287
|
+
return result && typeof result === "object" ? result : { value: result };
|
|
288
|
+
}
|
|
289
|
+
const picked = {};
|
|
290
|
+
for (const key of select) {
|
|
291
|
+
if (key in row) picked[key] = row[key];
|
|
292
|
+
}
|
|
293
|
+
return picked;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/graph-actions.ts
|
|
297
|
+
var graphActionListeners = /* @__PURE__ */ new Set();
|
|
298
|
+
var graphActionReplayers = /* @__PURE__ */ new Map();
|
|
299
|
+
function createGraphTransaction() {
|
|
300
|
+
const baseline = cloneGraphData();
|
|
301
|
+
let closed = false;
|
|
302
|
+
const tx = {
|
|
303
|
+
upsertEntity(type, id, data) {
|
|
304
|
+
useGraphStore.getState().upsertEntity(type, id, data);
|
|
305
|
+
return tx;
|
|
306
|
+
},
|
|
307
|
+
replaceEntity(type, id, data) {
|
|
308
|
+
useGraphStore.getState().replaceEntity(type, id, data);
|
|
309
|
+
return tx;
|
|
310
|
+
},
|
|
311
|
+
removeEntity(type, id) {
|
|
312
|
+
useGraphStore.getState().removeEntity(type, id);
|
|
313
|
+
return tx;
|
|
314
|
+
},
|
|
315
|
+
patchEntity(type, id, patch) {
|
|
316
|
+
useGraphStore.getState().patchEntity(type, id, patch);
|
|
317
|
+
return tx;
|
|
318
|
+
},
|
|
319
|
+
clearPatch(type, id) {
|
|
320
|
+
useGraphStore.getState().clearPatch(type, id);
|
|
321
|
+
return tx;
|
|
322
|
+
},
|
|
323
|
+
insertIdInList(key, id, position) {
|
|
324
|
+
useGraphStore.getState().insertIdInList(key, id, position);
|
|
325
|
+
return tx;
|
|
326
|
+
},
|
|
327
|
+
removeIdFromAllLists(type, id) {
|
|
328
|
+
useGraphStore.getState().removeIdFromAllLists(type, id);
|
|
329
|
+
return tx;
|
|
330
|
+
},
|
|
331
|
+
setEntitySyncMetadata(type, id, metadata) {
|
|
332
|
+
useGraphStore.getState().setEntitySyncMetadata(type, id, metadata);
|
|
333
|
+
return tx;
|
|
334
|
+
},
|
|
335
|
+
markEntityPending(type, id, origin = "optimistic") {
|
|
336
|
+
useGraphStore.getState().setEntitySyncMetadata(type, id, {
|
|
337
|
+
synced: false,
|
|
338
|
+
origin,
|
|
339
|
+
updatedAt: Date.now()
|
|
340
|
+
});
|
|
341
|
+
return tx;
|
|
342
|
+
},
|
|
343
|
+
markEntitySynced(type, id, origin = "server") {
|
|
344
|
+
useGraphStore.getState().setEntitySyncMetadata(type, id, {
|
|
345
|
+
synced: true,
|
|
346
|
+
origin,
|
|
347
|
+
updatedAt: Date.now()
|
|
348
|
+
});
|
|
349
|
+
return tx;
|
|
350
|
+
},
|
|
351
|
+
commit() {
|
|
352
|
+
closed = true;
|
|
353
|
+
},
|
|
354
|
+
rollback() {
|
|
355
|
+
if (closed) return;
|
|
356
|
+
useGraphStore.setState(cloneGraphData(baseline));
|
|
357
|
+
closed = true;
|
|
358
|
+
},
|
|
359
|
+
snapshot() {
|
|
360
|
+
return cloneGraphData();
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
return tx;
|
|
364
|
+
}
|
|
365
|
+
function createGraphAction(opts) {
|
|
366
|
+
if (opts.key) {
|
|
367
|
+
graphActionReplayers.set(opts.key, async (record) => {
|
|
368
|
+
const tx = createGraphTransaction();
|
|
369
|
+
try {
|
|
370
|
+
const result = await opts.run(tx, record.input);
|
|
371
|
+
tx.commit();
|
|
372
|
+
return result;
|
|
373
|
+
} catch (error) {
|
|
374
|
+
tx.rollback();
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return async (input) => {
|
|
380
|
+
const tx = createGraphTransaction();
|
|
381
|
+
const record = opts.key ? {
|
|
382
|
+
id: `${opts.key}:${Date.now()}`,
|
|
383
|
+
key: opts.key,
|
|
384
|
+
input: structuredClone(input),
|
|
385
|
+
enqueuedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
386
|
+
} : null;
|
|
387
|
+
try {
|
|
388
|
+
if (record) emitGraphActionEvent({ type: "enqueued", record });
|
|
389
|
+
opts.optimistic?.(tx, input);
|
|
390
|
+
const result = await opts.run(tx, input);
|
|
391
|
+
opts.onSuccess?.(result, input, tx);
|
|
392
|
+
tx.commit();
|
|
393
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
394
|
+
return result;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
tx.rollback();
|
|
397
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
398
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
399
|
+
opts.onError?.(normalized, input);
|
|
400
|
+
throw normalized;
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function subscribeGraphActionEvents(listener) {
|
|
405
|
+
graphActionListeners.add(listener);
|
|
406
|
+
return () => graphActionListeners.delete(listener);
|
|
407
|
+
}
|
|
408
|
+
async function replayRegisteredGraphAction(record) {
|
|
409
|
+
const replayer = graphActionReplayers.get(record.key);
|
|
410
|
+
if (!replayer) throw new Error(`No graph action registered for key "${record.key}"`);
|
|
411
|
+
return replayer(record);
|
|
412
|
+
}
|
|
413
|
+
function cloneGraphData(source = useGraphStore.getState()) {
|
|
414
|
+
return {
|
|
415
|
+
entities: structuredClone(source.entities),
|
|
416
|
+
patches: structuredClone(source.patches),
|
|
417
|
+
entityStates: structuredClone(source.entityStates),
|
|
418
|
+
syncMetadata: structuredClone(source.syncMetadata),
|
|
419
|
+
lists: structuredClone(source.lists)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function emitGraphActionEvent(event) {
|
|
423
|
+
for (const listener of graphActionListeners) listener(event);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/graph-effects.ts
|
|
427
|
+
function createGraphEffect(opts) {
|
|
428
|
+
const getKey = opts.getKey ?? defaultGetKey;
|
|
429
|
+
const isEqual = opts.isEqual ?? defaultIsEqual;
|
|
430
|
+
let initialized = false;
|
|
431
|
+
let previous = /* @__PURE__ */ new Map();
|
|
432
|
+
const evaluate = () => {
|
|
433
|
+
const nextValues = normalizeQueryResult(opts.query());
|
|
434
|
+
const next = /* @__PURE__ */ new Map();
|
|
435
|
+
nextValues.forEach((value, index) => {
|
|
436
|
+
next.set(getKey(value, index), value);
|
|
437
|
+
});
|
|
438
|
+
if (!initialized) {
|
|
439
|
+
initialized = true;
|
|
440
|
+
previous = next;
|
|
441
|
+
if (opts.skipInitial) return;
|
|
442
|
+
}
|
|
443
|
+
for (const [key, value] of next.entries()) {
|
|
444
|
+
const previousValue = previous.get(key);
|
|
445
|
+
if (previousValue === void 0) {
|
|
446
|
+
opts.onEnter?.({ key, value });
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (!isEqual(previousValue, value)) {
|
|
450
|
+
opts.onUpdate?.({ key, value, previousValue });
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
for (const [key, previousValue] of previous.entries()) {
|
|
454
|
+
if (!next.has(key)) opts.onExit?.({ key, previousValue });
|
|
455
|
+
}
|
|
456
|
+
previous = next;
|
|
457
|
+
};
|
|
458
|
+
evaluate();
|
|
459
|
+
const unsubscribe = useGraphStore.subscribe(() => {
|
|
460
|
+
evaluate();
|
|
461
|
+
});
|
|
462
|
+
return {
|
|
463
|
+
dispose: () => {
|
|
464
|
+
unsubscribe();
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function normalizeQueryResult(value) {
|
|
469
|
+
if (value == null) return [];
|
|
470
|
+
return Array.isArray(value) ? value : [value];
|
|
471
|
+
}
|
|
472
|
+
function defaultGetKey(value, index) {
|
|
473
|
+
if (value && typeof value === "object") {
|
|
474
|
+
const record = value;
|
|
475
|
+
if (typeof record.id === "string") return record.id;
|
|
476
|
+
if (typeof record.$key === "string") return record.$key;
|
|
477
|
+
}
|
|
478
|
+
return String(index);
|
|
479
|
+
}
|
|
480
|
+
function defaultIsEqual(previousValue, nextValue) {
|
|
481
|
+
return JSON.stringify(previousValue) === JSON.stringify(nextValue);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/object-path.ts
|
|
485
|
+
function isObject(value) {
|
|
486
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
487
|
+
}
|
|
488
|
+
function getValueAtPath(source, path) {
|
|
489
|
+
if (!path) return source;
|
|
490
|
+
const segments = path.split(".").filter(Boolean);
|
|
491
|
+
let current = source;
|
|
492
|
+
for (const segment of segments) {
|
|
493
|
+
if (!isObject(current) && !Array.isArray(current)) return void 0;
|
|
494
|
+
current = current[segment];
|
|
495
|
+
}
|
|
496
|
+
return current;
|
|
497
|
+
}
|
|
498
|
+
function setValueAtPath(source, path, value) {
|
|
499
|
+
const segments = path.split(".").filter(Boolean);
|
|
500
|
+
if (segments.length === 0) return source;
|
|
501
|
+
const clone = structuredClone(source);
|
|
502
|
+
let current = clone;
|
|
503
|
+
for (let index = 0; index < segments.length - 1; index += 1) {
|
|
504
|
+
const segment = segments[index];
|
|
505
|
+
const next = current[segment];
|
|
506
|
+
if (!isObject(next)) current[segment] = {};
|
|
507
|
+
current = current[segment];
|
|
508
|
+
}
|
|
509
|
+
current[segments[segments.length - 1]] = value;
|
|
510
|
+
return clone;
|
|
511
|
+
}
|
|
512
|
+
function collectDirtyPaths(current, original, prefix = "", acc = /* @__PURE__ */ new Set()) {
|
|
513
|
+
if (isObject(current) && isObject(original)) {
|
|
514
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(current), ...Object.keys(original)]);
|
|
515
|
+
for (const key of keys) {
|
|
516
|
+
const nextPrefix = prefix ? `${prefix}.${key}` : key;
|
|
517
|
+
collectDirtyPaths(current[key], original[key], nextPrefix, acc);
|
|
518
|
+
}
|
|
519
|
+
return acc;
|
|
520
|
+
}
|
|
521
|
+
if (JSON.stringify(current) !== JSON.stringify(original) && prefix) acc.add(prefix);
|
|
522
|
+
return acc;
|
|
523
|
+
}
|
|
524
|
+
var schemaRegistry = /* @__PURE__ */ new Map();
|
|
525
|
+
function registerEntityJsonSchema(config) {
|
|
526
|
+
const key = registryKey(config.entityType, config.field, config.schemaId);
|
|
527
|
+
schemaRegistry.set(key, config);
|
|
528
|
+
}
|
|
529
|
+
function registerRuntimeSchema(config) {
|
|
530
|
+
registerEntityJsonSchema(config);
|
|
531
|
+
}
|
|
532
|
+
function getEntityJsonSchema(opts) {
|
|
533
|
+
const exact = schemaRegistry.get(registryKey(opts.entityType, opts.field, opts.schemaId));
|
|
534
|
+
if (exact) return exact;
|
|
535
|
+
if (opts.field) {
|
|
536
|
+
const byField = schemaRegistry.get(registryKey(opts.entityType, opts.field));
|
|
537
|
+
if (byField) return byField;
|
|
538
|
+
}
|
|
539
|
+
if (opts.schemaId) {
|
|
540
|
+
const byId = schemaRegistry.get(registryKey(opts.entityType, void 0, opts.schemaId));
|
|
541
|
+
if (byId) return byId;
|
|
542
|
+
}
|
|
543
|
+
for (const schema of schemaRegistry.values()) {
|
|
544
|
+
if (schema.entityType !== opts.entityType) continue;
|
|
545
|
+
if (opts.field && schema.field !== opts.field) continue;
|
|
546
|
+
return schema;
|
|
547
|
+
}
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
function useSchemaEntityFields(opts) {
|
|
551
|
+
return React6.useMemo(() => {
|
|
552
|
+
const schema = opts.schema ?? getEntityJsonSchema(opts)?.schema;
|
|
553
|
+
if (!schema) return [];
|
|
554
|
+
return buildEntityFieldsFromSchema({ schema, rootField: opts.rootField ?? opts.field });
|
|
555
|
+
}, [opts.entityType, opts.field, opts.rootField, opts.schemaId, opts.schema]);
|
|
556
|
+
}
|
|
557
|
+
function buildEntityFieldsFromSchema(opts) {
|
|
558
|
+
return buildSchemaFields(opts.schema, opts.rootField ?? "", "");
|
|
559
|
+
}
|
|
560
|
+
function exportGraphSnapshotWithSchemas(opts) {
|
|
561
|
+
return JSON.stringify(
|
|
562
|
+
{
|
|
563
|
+
scope: opts.scope,
|
|
564
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
565
|
+
data: opts.data,
|
|
566
|
+
schemas: opts.schemas.filter(Boolean)
|
|
567
|
+
},
|
|
568
|
+
null,
|
|
569
|
+
opts.pretty === false ? 0 : 2
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
function escapeHtml(input) {
|
|
573
|
+
return input.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
574
|
+
}
|
|
575
|
+
function renderMarkdownToHtml(value) {
|
|
576
|
+
const escaped = escapeHtml(value);
|
|
577
|
+
const blocks = escaped.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
|
|
578
|
+
return blocks.map((block) => renderMarkdownBlock(block)).join("");
|
|
579
|
+
}
|
|
580
|
+
function MarkdownFieldRenderer({ value, className }) {
|
|
581
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
582
|
+
"div",
|
|
583
|
+
{
|
|
584
|
+
className,
|
|
585
|
+
dangerouslySetInnerHTML: { __html: renderMarkdownToHtml(value ?? "") }
|
|
586
|
+
}
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
function MarkdownFieldEditor({
|
|
590
|
+
value,
|
|
591
|
+
onChange,
|
|
592
|
+
placeholder
|
|
593
|
+
}) {
|
|
594
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
595
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
596
|
+
"textarea",
|
|
597
|
+
{
|
|
598
|
+
value,
|
|
599
|
+
onChange: (event) => onChange(event.target.value),
|
|
600
|
+
placeholder,
|
|
601
|
+
className: "w-full min-h-[120px] rounded-md border bg-muted/50 px-3 py-2 text-sm resize-y focus:outline-none focus:ring-1 focus:ring-ring transition-colors"
|
|
602
|
+
}
|
|
603
|
+
),
|
|
604
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border bg-background px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownFieldRenderer, { value, className: "prose prose-sm max-w-none" }) })
|
|
605
|
+
] });
|
|
606
|
+
}
|
|
607
|
+
function createMarkdownDetailRenderer(field) {
|
|
608
|
+
return (value, entity) => /* @__PURE__ */ jsxRuntime.jsx(MarkdownFieldRenderer, { value: String(value ?? getValueAtPath(entity, field) ?? ""), className: "prose prose-sm max-w-none" });
|
|
609
|
+
}
|
|
610
|
+
function buildSchemaFields(schema, pathPrefix, schemaPathPrefix) {
|
|
611
|
+
if (schema.type === "object" && schema.properties) {
|
|
612
|
+
const entries = Object.entries(schema.properties).sort(([, left], [, right]) => {
|
|
613
|
+
const l = left["x-display-order"] ?? Number.MAX_SAFE_INTEGER;
|
|
614
|
+
const r = right["x-display-order"] ?? Number.MAX_SAFE_INTEGER;
|
|
615
|
+
return l - r;
|
|
616
|
+
});
|
|
617
|
+
return entries.flatMap(([key, childSchema]) => {
|
|
618
|
+
if (childSchema["x-hidden"]) return [];
|
|
619
|
+
const field = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
620
|
+
const schemaPath = schemaPathPrefix ? `${schemaPathPrefix}.${key}` : key;
|
|
621
|
+
if (childSchema.type === "object" && childSchema.properties) {
|
|
622
|
+
return buildSchemaFields(childSchema, field, schemaPath);
|
|
623
|
+
}
|
|
624
|
+
return [schemaField(field, schemaPath, childSchema, schema.required?.includes(key) ?? false)];
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
return [];
|
|
628
|
+
}
|
|
629
|
+
function schemaField(field, schemaPath, schema, required) {
|
|
630
|
+
const type = inferFieldType(schema);
|
|
631
|
+
const descriptor = {
|
|
632
|
+
field,
|
|
633
|
+
label: schema.title ?? humanize(field.split(".").pop() ?? field),
|
|
634
|
+
type,
|
|
635
|
+
required,
|
|
636
|
+
hint: schema.description,
|
|
637
|
+
schemaPath,
|
|
638
|
+
schema,
|
|
639
|
+
componentHint: schema["x-a2ui-component"]
|
|
640
|
+
};
|
|
641
|
+
if (schema.enum) {
|
|
642
|
+
descriptor.options = schema.enum.map((value) => ({
|
|
643
|
+
value: String(value),
|
|
644
|
+
label: String(value)
|
|
645
|
+
}));
|
|
646
|
+
}
|
|
647
|
+
if (type === "markdown") {
|
|
648
|
+
descriptor.render = createMarkdownDetailRenderer(field);
|
|
649
|
+
}
|
|
650
|
+
return descriptor;
|
|
651
|
+
}
|
|
652
|
+
function inferFieldType(schema) {
|
|
653
|
+
const forced = schema["x-field-type"];
|
|
654
|
+
if (forced === "markdown") return "markdown";
|
|
655
|
+
if (schema.format === "markdown") return "markdown";
|
|
656
|
+
if (schema.enum) return "enum";
|
|
657
|
+
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
658
|
+
switch (type) {
|
|
659
|
+
case "boolean":
|
|
660
|
+
return "boolean";
|
|
661
|
+
case "integer":
|
|
662
|
+
case "number":
|
|
663
|
+
return "number";
|
|
664
|
+
case "string":
|
|
665
|
+
if (schema.format === "email") return "email";
|
|
666
|
+
if (schema.format === "uri" || schema.format === "url") return "url";
|
|
667
|
+
if (schema.format === "date" || schema.format === "date-time") return "date";
|
|
668
|
+
return "text";
|
|
669
|
+
case "array":
|
|
670
|
+
case "object":
|
|
671
|
+
return "json";
|
|
672
|
+
default:
|
|
673
|
+
return "text";
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
function registryKey(entityType, field, schemaId) {
|
|
677
|
+
return `${entityType}::${field ?? "*"}::${schemaId ?? "*"}`;
|
|
678
|
+
}
|
|
679
|
+
function humanize(value) {
|
|
680
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
681
|
+
}
|
|
682
|
+
function renderMarkdownBlock(block) {
|
|
683
|
+
if (block.startsWith("# ")) return `<h1>${renderInlineMarkdown(block.slice(2))}</h1>`;
|
|
684
|
+
if (block.startsWith("## ")) return `<h2>${renderInlineMarkdown(block.slice(3))}</h2>`;
|
|
685
|
+
return `<p>${renderInlineMarkdown(block).replaceAll("\n", "<br/>")}</p>`;
|
|
686
|
+
}
|
|
687
|
+
function renderInlineMarkdown(block) {
|
|
688
|
+
return block.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/ai-interop.ts
|
|
692
|
+
function exportGraphSnapshot(opts) {
|
|
693
|
+
const payload = {
|
|
694
|
+
scope: opts.scope,
|
|
695
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
696
|
+
data: opts.data
|
|
697
|
+
};
|
|
698
|
+
return JSON.stringify(payload, null, opts.pretty === false ? 0 : 2);
|
|
699
|
+
}
|
|
700
|
+
function createGraphTool(handler) {
|
|
701
|
+
return (input) => handler(input, {
|
|
702
|
+
store: useGraphStore.getState(),
|
|
703
|
+
queryOnce,
|
|
704
|
+
exportGraphSnapshot
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
function createSchemaGraphTool(handler) {
|
|
708
|
+
return (input) => handler(input, {
|
|
709
|
+
store: useGraphStore.getState(),
|
|
710
|
+
queryOnce,
|
|
711
|
+
exportGraphSnapshot,
|
|
712
|
+
getEntityJsonSchema,
|
|
713
|
+
exportGraphSnapshotWithSchemas
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
var DEFAULT_STORAGE_KEY = "prometheus:graph";
|
|
717
|
+
var useGraphSyncStatusStore = zustand.create((set) => ({
|
|
718
|
+
status: {
|
|
719
|
+
phase: "idle",
|
|
720
|
+
isOnline: true,
|
|
721
|
+
isSynced: true,
|
|
722
|
+
pendingActions: 0,
|
|
723
|
+
lastHydratedAt: null,
|
|
724
|
+
lastPersistedAt: null,
|
|
725
|
+
storageKey: null,
|
|
726
|
+
error: null
|
|
727
|
+
},
|
|
728
|
+
setStatus: (status) => set((state) => ({
|
|
729
|
+
status: {
|
|
730
|
+
...state.status,
|
|
731
|
+
...status
|
|
732
|
+
}
|
|
733
|
+
}))
|
|
734
|
+
}));
|
|
735
|
+
var pendingActions = /* @__PURE__ */ new Map();
|
|
736
|
+
function useGraphSyncStatus() {
|
|
737
|
+
return useGraphSyncStatusStore((state) => state.status);
|
|
738
|
+
}
|
|
739
|
+
async function persistGraphToStorage(opts) {
|
|
740
|
+
const payload = {
|
|
741
|
+
version: 1,
|
|
742
|
+
snapshot: cloneGraphSnapshot(),
|
|
743
|
+
pendingActions: opts.pendingActions ?? Array.from(pendingActions.values())
|
|
744
|
+
};
|
|
745
|
+
const json = JSON.stringify(payload);
|
|
746
|
+
await opts.storage.set(opts.key, json);
|
|
747
|
+
const persistedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
748
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
749
|
+
lastPersistedAt: persistedAt,
|
|
750
|
+
storageKey: opts.key,
|
|
751
|
+
pendingActions: payload.pendingActions.length
|
|
752
|
+
});
|
|
753
|
+
return {
|
|
754
|
+
ok: true,
|
|
755
|
+
key: opts.key,
|
|
756
|
+
bytes: json.length,
|
|
757
|
+
persistedAt
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
async function hydrateGraphFromStorage(opts) {
|
|
761
|
+
const raw = await opts.storage.get(opts.key);
|
|
762
|
+
if (!raw) {
|
|
763
|
+
return {
|
|
764
|
+
ok: false,
|
|
765
|
+
key: opts.key,
|
|
766
|
+
hydratedAt: null,
|
|
767
|
+
entityCounts: {},
|
|
768
|
+
error: "No persisted graph snapshot found"
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
try {
|
|
772
|
+
const parsed = JSON.parse(raw);
|
|
773
|
+
useGraphStore.setState(parsed.snapshot);
|
|
774
|
+
pendingActions.clear();
|
|
775
|
+
for (const action of parsed.pendingActions ?? []) pendingActions.set(action.id, action);
|
|
776
|
+
const hydratedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
777
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
778
|
+
lastHydratedAt: hydratedAt,
|
|
779
|
+
storageKey: opts.key,
|
|
780
|
+
pendingActions: pendingActions.size,
|
|
781
|
+
error: null
|
|
782
|
+
});
|
|
783
|
+
return {
|
|
784
|
+
ok: true,
|
|
785
|
+
key: opts.key,
|
|
786
|
+
hydratedAt,
|
|
787
|
+
entityCounts: Object.fromEntries(
|
|
788
|
+
Object.entries(parsed.snapshot.entities).map(([type, entities]) => [type, Object.keys(entities).length])
|
|
789
|
+
),
|
|
790
|
+
pendingActions: Array.from(pendingActions.values())
|
|
791
|
+
};
|
|
792
|
+
} catch (error) {
|
|
793
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
794
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
795
|
+
phase: "error",
|
|
796
|
+
error: message,
|
|
797
|
+
storageKey: opts.key
|
|
798
|
+
});
|
|
799
|
+
return {
|
|
800
|
+
ok: false,
|
|
801
|
+
key: opts.key,
|
|
802
|
+
hydratedAt: null,
|
|
803
|
+
entityCounts: {},
|
|
804
|
+
error: message
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function startLocalFirstGraph(opts) {
|
|
809
|
+
const key = opts.key ?? DEFAULT_STORAGE_KEY;
|
|
810
|
+
const persistDebounceMs = opts.persistDebounceMs ?? 50;
|
|
811
|
+
const statusStore = useGraphSyncStatusStore.getState();
|
|
812
|
+
statusStore.setStatus({
|
|
813
|
+
phase: "hydrating",
|
|
814
|
+
storageKey: key,
|
|
815
|
+
isOnline: opts.onlineSource?.getIsOnline() ?? getDefaultOnlineSource().getIsOnline(),
|
|
816
|
+
isSynced: pendingActions.size === 0,
|
|
817
|
+
error: null
|
|
818
|
+
});
|
|
819
|
+
let persistTimer = null;
|
|
820
|
+
const schedulePersist = () => {
|
|
821
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
822
|
+
persistTimer = setTimeout(() => {
|
|
823
|
+
void persistGraphToStorage({ storage: opts.storage, key });
|
|
824
|
+
}, persistDebounceMs);
|
|
825
|
+
};
|
|
826
|
+
const graphUnsub = useGraphStore.subscribe(() => {
|
|
827
|
+
schedulePersist();
|
|
828
|
+
});
|
|
829
|
+
const actionUnsub = subscribeGraphActionEvents((event) => {
|
|
830
|
+
if (event.type === "enqueued") pendingActions.set(event.record.id, event.record);
|
|
831
|
+
if (event.type === "settled") pendingActions.delete(event.record.id);
|
|
832
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
833
|
+
pendingActions: pendingActions.size,
|
|
834
|
+
isSynced: pendingActions.size === 0
|
|
835
|
+
});
|
|
836
|
+
schedulePersist();
|
|
837
|
+
});
|
|
838
|
+
const onlineSource = opts.onlineSource ?? getDefaultOnlineSource();
|
|
839
|
+
const onlineUnsub = onlineSource.subscribe((online) => {
|
|
840
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
841
|
+
isOnline: online,
|
|
842
|
+
phase: online ? "ready" : "offline"
|
|
843
|
+
});
|
|
844
|
+
});
|
|
845
|
+
const ready = (async () => {
|
|
846
|
+
const hydrated = await hydrateGraphFromStorage({ storage: opts.storage, key });
|
|
847
|
+
if (opts.replayPendingActions && hydrated.ok && pendingActions.size > 0) {
|
|
848
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
849
|
+
phase: "syncing",
|
|
850
|
+
isSynced: false
|
|
851
|
+
});
|
|
852
|
+
for (const action of Array.from(pendingActions.values())) {
|
|
853
|
+
await replayRegisteredGraphAction(action);
|
|
854
|
+
pendingActions.delete(action.id);
|
|
855
|
+
}
|
|
856
|
+
await persistGraphToStorage({ storage: opts.storage, key });
|
|
857
|
+
}
|
|
858
|
+
const online = onlineSource.getIsOnline();
|
|
859
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
860
|
+
phase: online ? "ready" : "offline",
|
|
861
|
+
isOnline: online,
|
|
862
|
+
isSynced: pendingActions.size === 0,
|
|
863
|
+
pendingActions: pendingActions.size
|
|
864
|
+
});
|
|
865
|
+
})();
|
|
866
|
+
return {
|
|
867
|
+
ready,
|
|
868
|
+
dispose() {
|
|
869
|
+
graphUnsub();
|
|
870
|
+
actionUnsub();
|
|
871
|
+
onlineUnsub();
|
|
872
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
873
|
+
},
|
|
874
|
+
async persistNow() {
|
|
875
|
+
await persistGraphToStorage({ storage: opts.storage, key });
|
|
876
|
+
},
|
|
877
|
+
hydrate() {
|
|
878
|
+
return hydrateGraphFromStorage({ storage: opts.storage, key });
|
|
879
|
+
},
|
|
880
|
+
getStatus() {
|
|
881
|
+
return useGraphSyncStatusStore.getState().status;
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function cloneGraphSnapshot() {
|
|
886
|
+
const state = useGraphStore.getState();
|
|
887
|
+
return {
|
|
888
|
+
entities: structuredClone(state.entities),
|
|
889
|
+
patches: structuredClone(state.patches),
|
|
890
|
+
entityStates: structuredClone(state.entityStates),
|
|
891
|
+
syncMetadata: structuredClone(state.syncMetadata),
|
|
892
|
+
lists: structuredClone(state.lists)
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
function getDefaultOnlineSource() {
|
|
896
|
+
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
897
|
+
return {
|
|
898
|
+
getIsOnline: () => window.navigator.onLine,
|
|
899
|
+
subscribe: (listener) => {
|
|
900
|
+
const onlineHandler = () => listener(true);
|
|
901
|
+
const offlineHandler = () => listener(false);
|
|
902
|
+
window.addEventListener("online", onlineHandler);
|
|
903
|
+
window.addEventListener("offline", offlineHandler);
|
|
904
|
+
return () => {
|
|
905
|
+
window.removeEventListener("online", onlineHandler);
|
|
906
|
+
window.removeEventListener("offline", offlineHandler);
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
return {
|
|
912
|
+
getIsOnline: () => true,
|
|
913
|
+
subscribe: () => () => {
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
|
|
187
918
|
// src/engine.ts
|
|
188
919
|
function serializeKey(key) {
|
|
189
920
|
return JSON.stringify(key, (_, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort()) : v);
|
|
@@ -420,7 +1151,7 @@ function subscriberCountServerSnapshot() {
|
|
|
420
1151
|
return 0;
|
|
421
1152
|
}
|
|
422
1153
|
function useGraphDevTools() {
|
|
423
|
-
const subscriberCount =
|
|
1154
|
+
const subscriberCount = React6.useSyncExternalStore(
|
|
424
1155
|
subscribeSubscriberStats,
|
|
425
1156
|
getActiveSubscriberCount,
|
|
426
1157
|
subscriberCountServerSnapshot
|
|
@@ -429,7 +1160,7 @@ function useGraphDevTools() {
|
|
|
429
1160
|
const patches = zustand.useStore(useGraphStore, (state) => state.patches);
|
|
430
1161
|
const entityStates = zustand.useStore(useGraphStore, (state) => state.entityStates);
|
|
431
1162
|
const listsState = zustand.useStore(useGraphStore, (state) => state.lists);
|
|
432
|
-
const graphPart =
|
|
1163
|
+
const graphPart = React6.useMemo(
|
|
433
1164
|
() => collectGraphDevStats(entities, patches, entityStates, listsState),
|
|
434
1165
|
[entities, patches, entityStates, listsState]
|
|
435
1166
|
);
|
|
@@ -445,26 +1176,23 @@ function ensureListeners() {
|
|
|
445
1176
|
function useEntity(opts) {
|
|
446
1177
|
const { type, id, staleTime = getEngineOptions().defaultStaleTime, enabled = true } = opts;
|
|
447
1178
|
ensureListeners();
|
|
448
|
-
const fetchRef =
|
|
1179
|
+
const fetchRef = React6.useRef(opts.fetch);
|
|
449
1180
|
fetchRef.current = opts.fetch;
|
|
450
|
-
const normalizeRef =
|
|
1181
|
+
const normalizeRef = React6.useRef(opts.normalize);
|
|
451
1182
|
normalizeRef.current = opts.normalize;
|
|
452
1183
|
const data = zustand.useStore(useGraphStore, shallow.useShallow((state) => {
|
|
453
1184
|
if (!id) return null;
|
|
454
|
-
|
|
455
|
-
if (!base) return null;
|
|
456
|
-
const patch = state.patches[type]?.[id];
|
|
457
|
-
return patch ? { ...base, ...patch } : base;
|
|
1185
|
+
return state.readEntitySnapshot(type, id);
|
|
458
1186
|
}));
|
|
459
|
-
const entityState = zustand.useStore(useGraphStore,
|
|
1187
|
+
const entityState = zustand.useStore(useGraphStore, React6.useCallback(
|
|
460
1188
|
(state) => state.entityStates[`${type}:${id}`] ?? EMPTY_ENTITY_STATE,
|
|
461
1189
|
[type, id]
|
|
462
1190
|
));
|
|
463
|
-
const doFetch =
|
|
1191
|
+
const doFetch = React6.useCallback(() => {
|
|
464
1192
|
if (!id || !enabled) return;
|
|
465
1193
|
fetchEntity({ type, id, fetch: fetchRef.current, normalize: normalizeRef.current }, getEngineOptions());
|
|
466
1194
|
}, [id, enabled, type]);
|
|
467
|
-
|
|
1195
|
+
React6.useEffect(() => {
|
|
468
1196
|
if (!id || !enabled) return;
|
|
469
1197
|
const token = registerSubscriber(`${type}:${id}`);
|
|
470
1198
|
const state = useGraphStore.getState();
|
|
@@ -474,7 +1202,7 @@ function useEntity(opts) {
|
|
|
474
1202
|
if (!hasData || isStale) doFetch();
|
|
475
1203
|
return () => unregisterSubscriber(`${type}:${id}`, token);
|
|
476
1204
|
}, [id, type, enabled, staleTime, doFetch]);
|
|
477
|
-
|
|
1205
|
+
React6.useEffect(() => {
|
|
478
1206
|
if (entityState.stale && id && enabled && !entityState.isFetching) doFetch();
|
|
479
1207
|
}, [entityState.stale, id, enabled, entityState.isFetching, doFetch]);
|
|
480
1208
|
return { data, isLoading: !data && entityState.isFetching, isFetching: entityState.isFetching, error: entityState.error, isStale: entityState.stale, refetch: doFetch };
|
|
@@ -482,49 +1210,44 @@ function useEntity(opts) {
|
|
|
482
1210
|
function useEntityList(opts) {
|
|
483
1211
|
const { type, queryKey, staleTime = getEngineOptions().defaultStaleTime, enabled = true, mode = "replace" } = opts;
|
|
484
1212
|
ensureListeners();
|
|
485
|
-
const key =
|
|
486
|
-
const fetchRef =
|
|
1213
|
+
const key = React6.useMemo(() => serializeKey(queryKey), [queryKey]);
|
|
1214
|
+
const fetchRef = React6.useRef(opts.fetch);
|
|
487
1215
|
fetchRef.current = opts.fetch;
|
|
488
|
-
const normalizeRef =
|
|
1216
|
+
const normalizeRef = React6.useRef(opts.normalize);
|
|
489
1217
|
normalizeRef.current = opts.normalize;
|
|
490
|
-
const listState = zustand.useStore(useGraphStore,
|
|
1218
|
+
const listState = zustand.useStore(useGraphStore, React6.useCallback((state) => state.lists[key] ?? EMPTY_LIST_STATE, [key]));
|
|
491
1219
|
const items = zustand.useStore(
|
|
492
1220
|
useGraphStore,
|
|
493
1221
|
shallow.useShallow((state) => {
|
|
494
1222
|
const ids = state.lists[key]?.ids ?? EMPTY_IDS;
|
|
495
|
-
return ids.map((id) =>
|
|
496
|
-
const base = state.entities[type]?.[id];
|
|
497
|
-
if (!base) return null;
|
|
498
|
-
const patch = state.patches[type]?.[id];
|
|
499
|
-
return patch ? { ...base, ...patch } : base;
|
|
500
|
-
}).filter((x) => x !== null);
|
|
1223
|
+
return ids.map((id) => state.readEntitySnapshot(type, id)).filter((x) => x !== null);
|
|
501
1224
|
})
|
|
502
1225
|
);
|
|
503
|
-
const doFetch =
|
|
1226
|
+
const doFetch = React6.useCallback((params = {}) => {
|
|
504
1227
|
if (!enabled) return;
|
|
505
1228
|
fetchList({ type, queryKey, mode, fetch: fetchRef.current, normalize: normalizeRef.current }, params, getEngineOptions(), false);
|
|
506
1229
|
}, [enabled, type, queryKey, mode]);
|
|
507
|
-
const fetchNextPage =
|
|
1230
|
+
const fetchNextPage = React6.useCallback(() => {
|
|
508
1231
|
if (!listState.hasNextPage || listState.isFetchingMore || !enabled) return;
|
|
509
1232
|
fetchList({ type, queryKey, mode, fetch: fetchRef.current, normalize: normalizeRef.current }, { cursor: listState.nextCursor ?? void 0, page: (listState.currentPage ?? 0) + 1, pageSize: listState.pageSize ?? void 0 }, getEngineOptions(), true);
|
|
510
1233
|
}, [listState.hasNextPage, listState.isFetchingMore, listState.nextCursor, listState.currentPage, listState.pageSize, enabled, type, queryKey, mode]);
|
|
511
|
-
|
|
1234
|
+
React6.useEffect(() => {
|
|
512
1235
|
if (!enabled) return;
|
|
513
1236
|
const state = useGraphStore.getState();
|
|
514
1237
|
const existing = state.lists[key];
|
|
515
1238
|
const isStale = !existing?.lastFetched || existing.stale || Date.now() - (existing.lastFetched ?? 0) > staleTime;
|
|
516
1239
|
if (!existing || isStale) doFetch({ page: 1, pageSize: listState.pageSize ?? void 0 });
|
|
517
1240
|
}, [key, enabled, staleTime, doFetch, listState.pageSize]);
|
|
518
|
-
|
|
1241
|
+
React6.useEffect(() => {
|
|
519
1242
|
if (listState.stale && enabled && !listState.isFetching) doFetch();
|
|
520
1243
|
}, [listState.stale, enabled, listState.isFetching, doFetch]);
|
|
521
1244
|
return { items, ids: listState.ids, isLoading: listState.ids.length === 0 && listState.isFetching, isFetching: listState.isFetching, isFetchingMore: listState.isFetchingMore, error: listState.error, hasNextPage: listState.hasNextPage, hasPrevPage: listState.hasPrevPage, total: listState.total, currentPage: listState.currentPage, fetchNextPage, refetch: doFetch };
|
|
522
1245
|
}
|
|
523
1246
|
function useEntityMutation(opts) {
|
|
524
|
-
const [state, setState] =
|
|
525
|
-
const optsRef =
|
|
1247
|
+
const [state, setState] = React6.useState({ isPending: false, isSuccess: false, isError: false, error: null });
|
|
1248
|
+
const optsRef = React6.useRef(opts);
|
|
526
1249
|
optsRef.current = opts;
|
|
527
|
-
const mutate =
|
|
1250
|
+
const mutate = React6.useCallback(async (input) => {
|
|
528
1251
|
const { type, mutate: apiFn, normalize, optimistic, invalidateLists, invalidateEntities, onSuccess, onError } = optsRef.current;
|
|
529
1252
|
setState({ isPending: true, isSuccess: false, isError: false, error: null });
|
|
530
1253
|
let rollback = null;
|
|
@@ -534,18 +1257,28 @@ function useEntityMutation(opts) {
|
|
|
534
1257
|
const { id, patch } = opt;
|
|
535
1258
|
const store = useGraphStore.getState();
|
|
536
1259
|
const previous = { ...store.patches[type]?.[id] };
|
|
1260
|
+
const previousSync = store.syncMetadata[`${type}:${id}`];
|
|
537
1261
|
store.patchEntity(type, id, patch);
|
|
538
|
-
|
|
1262
|
+
store.setEntitySyncMetadata(type, id, { synced: false, origin: "optimistic", updatedAt: Date.now() });
|
|
1263
|
+
rollback = () => {
|
|
1264
|
+
const currentStore = useGraphStore.getState();
|
|
1265
|
+
if (Object.keys(previous).length > 0) currentStore.patchEntity(type, id, previous);
|
|
1266
|
+
else currentStore.clearPatch(type, id);
|
|
1267
|
+
if (previousSync) currentStore.setEntitySyncMetadata(type, id, previousSync);
|
|
1268
|
+
else currentStore.clearEntitySyncMetadata(type, id);
|
|
1269
|
+
};
|
|
539
1270
|
}
|
|
540
1271
|
}
|
|
541
1272
|
try {
|
|
542
1273
|
const result = await apiFn(input);
|
|
543
1274
|
if (normalize) {
|
|
544
1275
|
const { id, data } = normalize(result, input);
|
|
545
|
-
useGraphStore.getState()
|
|
1276
|
+
const store = useGraphStore.getState();
|
|
1277
|
+
store.upsertEntity(type, id, data);
|
|
1278
|
+
store.setEntitySyncMetadata(type, id, { synced: true, origin: "server", updatedAt: Date.now() });
|
|
546
1279
|
if (optimistic) {
|
|
547
1280
|
const opt = optimistic(input);
|
|
548
|
-
if (opt)
|
|
1281
|
+
if (opt) store.clearPatch(type, opt.id);
|
|
549
1282
|
}
|
|
550
1283
|
}
|
|
551
1284
|
if (invalidateLists) for (const k of invalidateLists) useGraphStore.getState().invalidateLists(k);
|
|
@@ -561,23 +1294,23 @@ function useEntityMutation(opts) {
|
|
|
561
1294
|
return null;
|
|
562
1295
|
}
|
|
563
1296
|
}, []);
|
|
564
|
-
const trigger =
|
|
1297
|
+
const trigger = React6.useCallback((input) => {
|
|
565
1298
|
void mutate(input);
|
|
566
1299
|
}, [mutate]);
|
|
567
|
-
const reset =
|
|
1300
|
+
const reset = React6.useCallback(() => setState({ isPending: false, isSuccess: false, isError: false, error: null }), []);
|
|
568
1301
|
return { mutate, trigger, reset, state };
|
|
569
1302
|
}
|
|
570
1303
|
function useEntityAugment(type, id) {
|
|
571
|
-
const patch = zustand.useStore(useGraphStore,
|
|
572
|
-
const augment =
|
|
1304
|
+
const patch = zustand.useStore(useGraphStore, React6.useCallback((state) => id ? state.patches[type]?.[id] ?? null : null, [type, id]));
|
|
1305
|
+
const augment = React6.useCallback((fields) => {
|
|
573
1306
|
if (!id) return;
|
|
574
1307
|
useGraphStore.getState().patchEntity(type, id, fields);
|
|
575
1308
|
}, [type, id]);
|
|
576
|
-
const unaugment =
|
|
1309
|
+
const unaugment = React6.useCallback((keys) => {
|
|
577
1310
|
if (!id) return;
|
|
578
1311
|
useGraphStore.getState().unpatchEntity(type, id, keys);
|
|
579
1312
|
}, [type, id]);
|
|
580
|
-
const clear =
|
|
1313
|
+
const clear = React6.useCallback(() => {
|
|
581
1314
|
if (!id) return;
|
|
582
1315
|
useGraphStore.getState().clearPatch(type, id);
|
|
583
1316
|
}, [type, id]);
|
|
@@ -670,7 +1403,7 @@ function useSuspenseEntity(opts) {
|
|
|
670
1403
|
};
|
|
671
1404
|
}
|
|
672
1405
|
function useSuspenseEntityList(opts) {
|
|
673
|
-
const key =
|
|
1406
|
+
const key = React6.useMemo(() => serializeKey(opts.queryKey), [opts.queryKey]);
|
|
674
1407
|
const result = useEntityList(opts);
|
|
675
1408
|
if (result.isLoading) throw getListSuspensePromise(key);
|
|
676
1409
|
if (result.error != null && result.items.length === 0) {
|
|
@@ -1008,17 +1741,17 @@ function hasCustomPredicates(filter) {
|
|
|
1008
1741
|
var EMPTY_ENTITY_BUCKET = {};
|
|
1009
1742
|
function useEntityView(opts) {
|
|
1010
1743
|
const { type, baseQueryKey, mode: forcedMode, remoteFetch, remoteDebounce = 300, staleTime = getEngineOptions().defaultStaleTime, enabled = true, initialIds, initialTotal } = opts;
|
|
1011
|
-
const optsRef =
|
|
1744
|
+
const optsRef = React6.useRef(opts);
|
|
1012
1745
|
optsRef.current = opts;
|
|
1013
|
-
const [liveView, setLiveView] =
|
|
1014
|
-
const liveViewRef =
|
|
1746
|
+
const [liveView, setLiveView] = React6.useState(opts.view);
|
|
1747
|
+
const liveViewRef = React6.useRef(liveView);
|
|
1015
1748
|
liveViewRef.current = liveView;
|
|
1016
|
-
const [isRemoteFetching, setIsRemoteFetching] =
|
|
1017
|
-
const [remoteError, setRemoteError] =
|
|
1018
|
-
const [remoteResultKey, setRemoteResultKey] =
|
|
1019
|
-
const debounceTimer =
|
|
1020
|
-
const baseKey =
|
|
1021
|
-
const seededRef =
|
|
1749
|
+
const [isRemoteFetching, setIsRemoteFetching] = React6.useState(false);
|
|
1750
|
+
const [remoteError, setRemoteError] = React6.useState(null);
|
|
1751
|
+
const [remoteResultKey, setRemoteResultKey] = React6.useState(null);
|
|
1752
|
+
const debounceTimer = React6.useRef(null);
|
|
1753
|
+
const baseKey = React6.useMemo(() => serializeKey(baseQueryKey), [baseQueryKey]);
|
|
1754
|
+
const seededRef = React6.useRef(false);
|
|
1022
1755
|
if (!seededRef.current && initialIds && initialIds.length > 0) {
|
|
1023
1756
|
seededRef.current = true;
|
|
1024
1757
|
const store = useGraphStore.getState();
|
|
@@ -1028,14 +1761,14 @@ function useEntityView(opts) {
|
|
|
1028
1761
|
}
|
|
1029
1762
|
const listState = zustand.useStore(
|
|
1030
1763
|
useGraphStore,
|
|
1031
|
-
|
|
1764
|
+
React6.useCallback((state) => state.lists[baseKey] ?? null, [baseKey])
|
|
1032
1765
|
);
|
|
1033
|
-
const remoteListState = zustand.useStore(useGraphStore,
|
|
1034
|
-
const { isComplete } =
|
|
1766
|
+
const remoteListState = zustand.useStore(useGraphStore, React6.useCallback((state) => remoteResultKey ? state.lists[remoteResultKey] ?? null : null, [remoteResultKey]));
|
|
1767
|
+
const { isComplete } = React6.useMemo(() => {
|
|
1035
1768
|
if (!listState) return { isComplete: false };
|
|
1036
1769
|
return checkCompleteness(listState.ids.length, listState.total, listState.hasNextPage);
|
|
1037
1770
|
}, [listState]);
|
|
1038
|
-
const completenessMode =
|
|
1771
|
+
const completenessMode = React6.useMemo(() => {
|
|
1039
1772
|
if (forcedMode) return forcedMode;
|
|
1040
1773
|
if (liveView.filter && hasCustomPredicates(liveView.filter)) return "local";
|
|
1041
1774
|
if (isComplete) return "local";
|
|
@@ -1047,12 +1780,7 @@ function useEntityView(opts) {
|
|
|
1047
1780
|
shallow.useShallow((state) => {
|
|
1048
1781
|
const list = state.lists[baseKey] ?? EMPTY_LIST_STATE;
|
|
1049
1782
|
const sourceIds = completenessMode !== "remote" && remoteResultKey ? state.lists[remoteResultKey]?.ids ?? EMPTY_IDS : list.ids;
|
|
1050
|
-
const getEntity = (id) =>
|
|
1051
|
-
const base = state.entities[type]?.[id];
|
|
1052
|
-
if (!base) return null;
|
|
1053
|
-
const patch = state.patches[type]?.[id];
|
|
1054
|
-
return patch ? { ...base, ...patch } : base;
|
|
1055
|
-
};
|
|
1783
|
+
const getEntity = (id) => state.readEntitySnapshot(type, id);
|
|
1056
1784
|
return applyView(
|
|
1057
1785
|
sourceIds,
|
|
1058
1786
|
getEntity,
|
|
@@ -1065,15 +1793,10 @@ function useEntityView(opts) {
|
|
|
1065
1793
|
const items = zustand.useStore(
|
|
1066
1794
|
useGraphStore,
|
|
1067
1795
|
shallow.useShallow(
|
|
1068
|
-
(state) => localViewIds.map((id) =>
|
|
1069
|
-
const base = state.entities[type]?.[id];
|
|
1070
|
-
if (!base) return null;
|
|
1071
|
-
const patch = state.patches[type]?.[id];
|
|
1072
|
-
return patch ? { ...base, ...patch } : base;
|
|
1073
|
-
}).filter((item) => item !== null)
|
|
1796
|
+
(state) => localViewIds.map((id) => state.readEntitySnapshot(type, id)).filter((item) => item !== null)
|
|
1074
1797
|
)
|
|
1075
1798
|
);
|
|
1076
|
-
const fireRemoteFetch =
|
|
1799
|
+
const fireRemoteFetch = React6.useCallback(async (view, cursor) => {
|
|
1077
1800
|
const { remoteFetch: rf, normalize: norm, baseQueryKey: bqk } = optsRef.current;
|
|
1078
1801
|
if (!rf) return;
|
|
1079
1802
|
const params = { rest: toRestParams(view), graphql: toGraphQLVariables(view), sql: toSQLClauses(view), view };
|
|
@@ -1097,7 +1820,7 @@ function useEntityView(opts) {
|
|
|
1097
1820
|
setIsRemoteFetching(false);
|
|
1098
1821
|
}
|
|
1099
1822
|
}, [type]);
|
|
1100
|
-
|
|
1823
|
+
React6.useEffect(() => {
|
|
1101
1824
|
if (!enabled || completenessMode === "local" || !remoteFetch) return;
|
|
1102
1825
|
const searchQuery = liveView.search?.query ?? "";
|
|
1103
1826
|
const minChars = liveView.search?.minChars ?? 2;
|
|
@@ -1108,14 +1831,14 @@ function useEntityView(opts) {
|
|
|
1108
1831
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
1109
1832
|
};
|
|
1110
1833
|
}, [liveView, completenessMode, enabled, remoteFetch, remoteDebounce, fireRemoteFetch]);
|
|
1111
|
-
|
|
1834
|
+
React6.useEffect(() => {
|
|
1112
1835
|
if (!enabled) return;
|
|
1113
1836
|
const state = useGraphStore.getState();
|
|
1114
1837
|
const existing = state.lists[baseKey];
|
|
1115
1838
|
const isStale = !existing?.lastFetched || existing.stale || Date.now() - (existing.lastFetched ?? 0) > staleTime;
|
|
1116
1839
|
if (!existing || isStale) fireRemoteFetch(liveViewRef.current);
|
|
1117
1840
|
}, [baseKey, enabled, staleTime, fireRemoteFetch]);
|
|
1118
|
-
|
|
1841
|
+
React6.useEffect(() => {
|
|
1119
1842
|
const unsub = useGraphStore.subscribe((state) => state.entities[type] ?? EMPTY_ENTITY_BUCKET, (newEntities, prevEntities) => {
|
|
1120
1843
|
const view = liveViewRef.current;
|
|
1121
1844
|
const store = useGraphStore.getState();
|
|
@@ -1125,17 +1848,11 @@ function useEntityView(opts) {
|
|
|
1125
1848
|
const isPresent = id in newEntities;
|
|
1126
1849
|
if (!isPresent) continue;
|
|
1127
1850
|
const entity = newEntities[id];
|
|
1128
|
-
const
|
|
1129
|
-
const merged = patch ? { ...entity, ...patch } : entity;
|
|
1851
|
+
const merged = store.readEntitySnapshot(type, id) ?? entity;
|
|
1130
1852
|
const matches = (!view.filter || matchesFilter(merged, view.filter)) && (!view.search?.query || matchesSearch(merged, view.search.query, view.search.fields));
|
|
1131
1853
|
if (matches && !list.ids.includes(id)) {
|
|
1132
1854
|
if (view.sort && view.sort.length > 0) {
|
|
1133
|
-
const idx = findInsertionIndex(merged, list.ids, (eid) =>
|
|
1134
|
-
const b = store.entities[type]?.[eid];
|
|
1135
|
-
if (!b) return null;
|
|
1136
|
-
const p = store.patches[type]?.[eid];
|
|
1137
|
-
return p ? { ...b, ...p } : b;
|
|
1138
|
-
}, view.sort);
|
|
1855
|
+
const idx = findInsertionIndex(merged, list.ids, (eid) => store.readEntitySnapshot(type, eid), view.sort);
|
|
1139
1856
|
store.insertIdInList(baseKey, id, idx);
|
|
1140
1857
|
} else store.insertIdInList(baseKey, id, "start");
|
|
1141
1858
|
}
|
|
@@ -1143,16 +1860,16 @@ function useEntityView(opts) {
|
|
|
1143
1860
|
});
|
|
1144
1861
|
return unsub;
|
|
1145
1862
|
}, [type, baseKey]);
|
|
1146
|
-
const setView =
|
|
1147
|
-
const setFilter =
|
|
1148
|
-
const setSort =
|
|
1149
|
-
const setSearch =
|
|
1150
|
-
const clearView =
|
|
1151
|
-
const fetchNextPage =
|
|
1863
|
+
const setView = React6.useCallback((partial) => setLiveView((prev) => ({ ...prev, ...partial })), []);
|
|
1864
|
+
const setFilter = React6.useCallback((filter) => setLiveView((prev) => ({ ...prev, filter: filter ?? void 0 })), []);
|
|
1865
|
+
const setSort = React6.useCallback((sort) => setLiveView((prev) => ({ ...prev, sort: sort ?? void 0 })), []);
|
|
1866
|
+
const setSearch = React6.useCallback((query) => setLiveView((prev) => ({ ...prev, search: prev.search ? { ...prev.search, query } : { query, fields: [] } })), []);
|
|
1867
|
+
const clearView = React6.useCallback(() => setLiveView({}), []);
|
|
1868
|
+
const fetchNextPage = React6.useCallback(() => {
|
|
1152
1869
|
if (completenessMode === "local" || isRemoteFetching) return;
|
|
1153
1870
|
fireRemoteFetch(liveViewRef.current, remoteListState?.nextCursor ?? void 0);
|
|
1154
1871
|
}, [completenessMode, isRemoteFetching, remoteListState?.nextCursor, fireRemoteFetch]);
|
|
1155
|
-
const refetch =
|
|
1872
|
+
const refetch = React6.useCallback(() => fireRemoteFetch(liveViewRef.current), [fireRemoteFetch]);
|
|
1156
1873
|
const viewTotal = remoteListState?.total ?? (isComplete ? localViewIds.length : listState?.total ?? null);
|
|
1157
1874
|
return {
|
|
1158
1875
|
items,
|
|
@@ -1178,15 +1895,15 @@ function useEntityView(opts) {
|
|
|
1178
1895
|
}
|
|
1179
1896
|
|
|
1180
1897
|
// src/crud/relations.ts
|
|
1181
|
-
var
|
|
1898
|
+
var schemaRegistry2 = /* @__PURE__ */ new Map();
|
|
1182
1899
|
function registerSchema(schema) {
|
|
1183
|
-
|
|
1900
|
+
schemaRegistry2.set(schema.type, schema);
|
|
1184
1901
|
}
|
|
1185
1902
|
function getSchema(type) {
|
|
1186
|
-
return
|
|
1903
|
+
return schemaRegistry2.get(type) ?? null;
|
|
1187
1904
|
}
|
|
1188
1905
|
function cascadeInvalidation(ctx) {
|
|
1189
|
-
const schema =
|
|
1906
|
+
const schema = schemaRegistry2.get(ctx.type);
|
|
1190
1907
|
if (!schema) return;
|
|
1191
1908
|
const store = useGraphStore.getState();
|
|
1192
1909
|
if (schema.globalListKeys) for (const key of schema.globalListKeys) store.invalidateLists(key);
|
|
@@ -1213,7 +1930,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1213
1930
|
}
|
|
1214
1931
|
}
|
|
1215
1932
|
}
|
|
1216
|
-
for (const [, otherSchema] of
|
|
1933
|
+
for (const [, otherSchema] of schemaRegistry2) {
|
|
1217
1934
|
if (!otherSchema.relations) continue;
|
|
1218
1935
|
for (const [, rel] of Object.entries(otherSchema.relations)) {
|
|
1219
1936
|
if (rel.targetType !== ctx.type) continue;
|
|
@@ -1222,7 +1939,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1222
1939
|
}
|
|
1223
1940
|
}
|
|
1224
1941
|
function readRelations(type, entity) {
|
|
1225
|
-
const schema =
|
|
1942
|
+
const schema = schemaRegistry2.get(type);
|
|
1226
1943
|
if (!schema?.relations) return {};
|
|
1227
1944
|
const store = useGraphStore.getState();
|
|
1228
1945
|
const result = {};
|
|
@@ -1252,15 +1969,15 @@ function readRelations(type, entity) {
|
|
|
1252
1969
|
// src/crud/use-entity-crud.ts
|
|
1253
1970
|
function useEntityCRUD(opts) {
|
|
1254
1971
|
const { type, listQueryKey, listFetch, normalize, detailFetch, onCreate, onUpdate, onDelete, createDefaults = {}, initialView = {}, selectAfterCreate = true, clearSelectionAfterDelete = true } = opts;
|
|
1255
|
-
const optsRef =
|
|
1972
|
+
const optsRef = React6.useRef(opts);
|
|
1256
1973
|
optsRef.current = opts;
|
|
1257
|
-
const [mode, setMode] =
|
|
1258
|
-
const [selectedId, setSelectedId] =
|
|
1259
|
-
const select =
|
|
1974
|
+
const [mode, setMode] = React6.useState("list");
|
|
1975
|
+
const [selectedId, setSelectedId] = React6.useState(null);
|
|
1976
|
+
const select = React6.useCallback((id) => {
|
|
1260
1977
|
setSelectedId(id);
|
|
1261
1978
|
setMode(id ? "detail" : "list");
|
|
1262
1979
|
}, []);
|
|
1263
|
-
const openDetail =
|
|
1980
|
+
const openDetail = React6.useCallback((id) => {
|
|
1264
1981
|
setSelectedId(id);
|
|
1265
1982
|
setMode("detail");
|
|
1266
1983
|
}, []);
|
|
@@ -1276,28 +1993,25 @@ function useEntityCRUD(opts) {
|
|
|
1276
1993
|
normalize: (raw) => raw,
|
|
1277
1994
|
enabled: !!selectedId
|
|
1278
1995
|
});
|
|
1279
|
-
const relations =
|
|
1280
|
-
const [editBuffer, setEditBuffer] =
|
|
1281
|
-
const [isSaving, setIsSaving] =
|
|
1282
|
-
const [saveError, setSaveError] =
|
|
1283
|
-
|
|
1996
|
+
const relations = React6.useMemo(() => detail ? readRelations(type, detail) : {}, [type, detail]);
|
|
1997
|
+
const [editBuffer, setEditBuffer] = React6.useState({});
|
|
1998
|
+
const [isSaving, setIsSaving] = React6.useState(false);
|
|
1999
|
+
const [saveError, setSaveError] = React6.useState(null);
|
|
2000
|
+
React6.useEffect(() => {
|
|
1284
2001
|
if (detail) setEditBuffer({ ...detail });
|
|
1285
2002
|
}, [selectedId]);
|
|
1286
|
-
const setField =
|
|
1287
|
-
const setFields =
|
|
1288
|
-
const resetBuffer =
|
|
2003
|
+
const setField = React6.useCallback((field, value) => setEditBuffer((prev) => setValueAtPath(prev, String(field), value)), []);
|
|
2004
|
+
const setFields = React6.useCallback((fields) => setEditBuffer((prev) => ({ ...prev, ...fields })), []);
|
|
2005
|
+
const resetBuffer = React6.useCallback(() => {
|
|
1289
2006
|
const current = selectedId ? useGraphStore.getState().readEntity(type, selectedId) : null;
|
|
1290
2007
|
setEditBuffer(current ? { ...current } : {});
|
|
1291
2008
|
}, [type, selectedId]);
|
|
1292
|
-
const dirty =
|
|
2009
|
+
const dirty = React6.useMemo(() => {
|
|
1293
2010
|
if (!detail) return { changed: /* @__PURE__ */ new Set(), isDirty: false };
|
|
1294
|
-
const changed =
|
|
1295
|
-
for (const key of Object.keys(editBuffer)) {
|
|
1296
|
-
if (JSON.stringify(editBuffer[key]) !== JSON.stringify(detail[key])) changed.add(key);
|
|
1297
|
-
}
|
|
2011
|
+
const changed = collectDirtyPaths(editBuffer, detail);
|
|
1298
2012
|
return { changed, isDirty: changed.size > 0 };
|
|
1299
2013
|
}, [editBuffer, detail]);
|
|
1300
|
-
const startEdit =
|
|
2014
|
+
const startEdit = React6.useCallback((id) => {
|
|
1301
2015
|
const targetId = id ?? selectedId;
|
|
1302
2016
|
if (targetId) {
|
|
1303
2017
|
setSelectedId(targetId);
|
|
@@ -1306,32 +2020,40 @@ function useEntityCRUD(opts) {
|
|
|
1306
2020
|
}
|
|
1307
2021
|
setMode("edit");
|
|
1308
2022
|
}, [selectedId, type]);
|
|
1309
|
-
const cancelEdit =
|
|
2023
|
+
const cancelEdit = React6.useCallback(() => {
|
|
1310
2024
|
resetBuffer();
|
|
1311
2025
|
setMode(selectedId ? "detail" : "list");
|
|
1312
2026
|
setSaveError(null);
|
|
1313
2027
|
}, [resetBuffer, selectedId]);
|
|
1314
|
-
const applyOptimistic =
|
|
2028
|
+
const applyOptimistic = React6.useCallback(() => {
|
|
1315
2029
|
if (!selectedId) return;
|
|
1316
|
-
useGraphStore.getState()
|
|
2030
|
+
const store = useGraphStore.getState();
|
|
2031
|
+
store.patchEntity(type, selectedId, editBuffer);
|
|
2032
|
+
store.setEntitySyncMetadata(type, selectedId, { synced: false, origin: "optimistic", updatedAt: Date.now() });
|
|
1317
2033
|
}, [type, selectedId, editBuffer]);
|
|
1318
|
-
const save =
|
|
2034
|
+
const save = React6.useCallback(async () => {
|
|
1319
2035
|
if (!selectedId || !onUpdate) return null;
|
|
1320
2036
|
setIsSaving(true);
|
|
1321
2037
|
setSaveError(null);
|
|
1322
|
-
const
|
|
1323
|
-
|
|
2038
|
+
const store = useGraphStore.getState();
|
|
2039
|
+
const previous = store.readEntity(type, selectedId);
|
|
2040
|
+
const previousSync = store.syncMetadata[`${type}:${selectedId}`];
|
|
2041
|
+
store.upsertEntity(type, selectedId, editBuffer);
|
|
2042
|
+
store.setEntitySyncMetadata(type, selectedId, { synced: false, origin: "optimistic", updatedAt: Date.now() });
|
|
1324
2043
|
try {
|
|
1325
2044
|
const result = await onUpdate(selectedId, editBuffer);
|
|
1326
2045
|
const { id, data } = normalize(result);
|
|
1327
|
-
|
|
1328
|
-
|
|
2046
|
+
store.replaceEntity(type, id, data);
|
|
2047
|
+
store.clearPatch(type, id);
|
|
2048
|
+
store.setEntitySyncMetadata(type, id, { synced: true, origin: "server", updatedAt: Date.now() });
|
|
1329
2049
|
cascadeInvalidation({ type, id: selectedId, previous, next: data, op: "update" });
|
|
1330
2050
|
setMode("detail");
|
|
1331
2051
|
optsRef.current.onUpdateSuccess?.(result);
|
|
1332
2052
|
return result;
|
|
1333
2053
|
} catch (err) {
|
|
1334
|
-
if (previous)
|
|
2054
|
+
if (previous) store.replaceEntity(type, selectedId, previous);
|
|
2055
|
+
if (previousSync) store.setEntitySyncMetadata(type, selectedId, previousSync);
|
|
2056
|
+
else store.clearEntitySyncMetadata(type, selectedId);
|
|
1335
2057
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1336
2058
|
setSaveError(error.message);
|
|
1337
2059
|
optsRef.current.onError?.("update", error);
|
|
@@ -1340,37 +2062,39 @@ function useEntityCRUD(opts) {
|
|
|
1340
2062
|
setIsSaving(false);
|
|
1341
2063
|
}
|
|
1342
2064
|
}, [selectedId, type, editBuffer, normalize]);
|
|
1343
|
-
const [createBuffer, setCreateBuffer] =
|
|
1344
|
-
const [isCreating, setIsCreating] =
|
|
1345
|
-
const [createError, setCreateError] =
|
|
1346
|
-
const setCreateField =
|
|
1347
|
-
const setCreateFields =
|
|
1348
|
-
const resetCreateBuffer =
|
|
1349
|
-
const startCreate =
|
|
2065
|
+
const [createBuffer, setCreateBuffer] = React6.useState({ ...createDefaults });
|
|
2066
|
+
const [isCreating, setIsCreating] = React6.useState(false);
|
|
2067
|
+
const [createError, setCreateError] = React6.useState(null);
|
|
2068
|
+
const setCreateField = React6.useCallback((field, value) => setCreateBuffer((prev) => setValueAtPath(prev, String(field), value)), []);
|
|
2069
|
+
const setCreateFields = React6.useCallback((fields) => setCreateBuffer((prev) => ({ ...prev, ...fields })), []);
|
|
2070
|
+
const resetCreateBuffer = React6.useCallback(() => setCreateBuffer({ ...optsRef.current.createDefaults ?? {} }), []);
|
|
2071
|
+
const startCreate = React6.useCallback(() => {
|
|
1350
2072
|
resetCreateBuffer();
|
|
1351
2073
|
setCreateError(null);
|
|
1352
2074
|
setMode("create");
|
|
1353
2075
|
}, [resetCreateBuffer]);
|
|
1354
|
-
const cancelCreate =
|
|
2076
|
+
const cancelCreate = React6.useCallback(() => {
|
|
1355
2077
|
resetCreateBuffer();
|
|
1356
2078
|
setMode("list");
|
|
1357
2079
|
setCreateError(null);
|
|
1358
2080
|
}, [resetCreateBuffer]);
|
|
1359
|
-
const
|
|
2081
|
+
const create3 = React6.useCallback(async () => {
|
|
1360
2082
|
if (!onCreate) return null;
|
|
1361
2083
|
setIsCreating(true);
|
|
1362
2084
|
setCreateError(null);
|
|
1363
2085
|
const tempId = `__temp__${Date.now()}`;
|
|
1364
2086
|
const optimisticData = { ...createBuffer, id: tempId, _optimistic: true };
|
|
1365
|
-
useGraphStore.getState()
|
|
1366
|
-
|
|
2087
|
+
const store = useGraphStore.getState();
|
|
2088
|
+
store.upsertEntity(type, tempId, optimisticData);
|
|
2089
|
+
store.setEntitySyncMetadata(type, tempId, { synced: false, origin: "optimistic", updatedAt: Date.now() });
|
|
2090
|
+
store.insertIdInList(serializeKey(listQueryKey), tempId, "start");
|
|
1367
2091
|
try {
|
|
1368
2092
|
const result = await onCreate(createBuffer);
|
|
1369
2093
|
const { id: realId, data } = normalize(result);
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
2094
|
+
store.removeEntity(type, tempId);
|
|
2095
|
+
store.upsertEntity(type, realId, data);
|
|
2096
|
+
store.setEntityFetched(type, realId);
|
|
2097
|
+
store.setEntitySyncMetadata(type, realId, { synced: true, origin: "server", updatedAt: Date.now() });
|
|
1374
2098
|
for (const key of Object.keys(store.lists)) {
|
|
1375
2099
|
const list2 = store.lists[key];
|
|
1376
2100
|
const idx = list2.ids.indexOf(tempId);
|
|
@@ -1388,8 +2112,8 @@ function useEntityCRUD(opts) {
|
|
|
1388
2112
|
optsRef.current.onCreateSuccess?.(result);
|
|
1389
2113
|
return result;
|
|
1390
2114
|
} catch (err) {
|
|
1391
|
-
|
|
1392
|
-
|
|
2115
|
+
store.removeEntity(type, tempId);
|
|
2116
|
+
store.removeIdFromAllLists(type, tempId);
|
|
1393
2117
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1394
2118
|
setCreateError(error.message);
|
|
1395
2119
|
optsRef.current.onError?.("create", error);
|
|
@@ -1398,9 +2122,9 @@ function useEntityCRUD(opts) {
|
|
|
1398
2122
|
setIsCreating(false);
|
|
1399
2123
|
}
|
|
1400
2124
|
}, [type, createBuffer, normalize, listQueryKey, selectAfterCreate, resetCreateBuffer]);
|
|
1401
|
-
const [isDeleting, setIsDeleting] =
|
|
1402
|
-
const [deleteError, setDeleteError] =
|
|
1403
|
-
const deleteEntity =
|
|
2125
|
+
const [isDeleting, setIsDeleting] = React6.useState(false);
|
|
2126
|
+
const [deleteError, setDeleteError] = React6.useState(null);
|
|
2127
|
+
const deleteEntity = React6.useCallback(async (id) => {
|
|
1404
2128
|
const targetId = id ?? selectedId;
|
|
1405
2129
|
if (!targetId || !onDelete) return;
|
|
1406
2130
|
setIsDeleting(true);
|
|
@@ -1428,7 +2152,7 @@ function useEntityCRUD(opts) {
|
|
|
1428
2152
|
setIsDeleting(false);
|
|
1429
2153
|
}
|
|
1430
2154
|
}, [type, selectedId, listQueryKey, clearSelectionAfterDelete]);
|
|
1431
|
-
return { mode, setMode, list, selectedId, select, openDetail, detail: detail ?? null, detailIsLoading, detailError: detailError ?? null, relations, editBuffer, setField, setFields, resetBuffer, dirty, startEdit, cancelEdit, save, isSaving, saveError, applyOptimistic, createBuffer, setCreateField, setCreateFields, resetCreateBuffer, startCreate, cancelCreate, create:
|
|
2155
|
+
return { mode, setMode, list, selectedId, select, openDetail, detail: detail ?? null, detailIsLoading, detailError: detailError ?? null, relations, editBuffer, setField, setFields, resetBuffer, dirty, startEdit, cancelEdit, save, isSaving, saveError, applyOptimistic, createBuffer, setCreateField, setCreateFields, resetCreateBuffer, startCreate, cancelCreate, create: create3, isCreating, createError, deleteEntity, isDeleting, deleteError, isEditing: mode === "edit" || mode === "create" };
|
|
1432
2156
|
}
|
|
1433
2157
|
|
|
1434
2158
|
// src/adapters/realtime-manager.ts
|
|
@@ -2059,8 +2783,8 @@ function createElectricAdapter(opts) {
|
|
|
2059
2783
|
};
|
|
2060
2784
|
}
|
|
2061
2785
|
function useLocalFirst(adapter) {
|
|
2062
|
-
const [isSynced, setIsSynced] =
|
|
2063
|
-
|
|
2786
|
+
const [isSynced, setIsSynced] = React6.useState(adapter.isSynced());
|
|
2787
|
+
React6.useEffect(() => {
|
|
2064
2788
|
const u1 = adapter.onSyncComplete(() => setIsSynced(true));
|
|
2065
2789
|
const u2 = getRealtimeManager().register(adapter, []);
|
|
2066
2790
|
return () => {
|
|
@@ -2068,15 +2792,15 @@ function useLocalFirst(adapter) {
|
|
|
2068
2792
|
u2();
|
|
2069
2793
|
};
|
|
2070
2794
|
}, [adapter]);
|
|
2071
|
-
const query =
|
|
2072
|
-
const execute =
|
|
2795
|
+
const query = React6.useCallback(async (sql, params) => (await adapter.query(sql, params)).rows, [adapter]);
|
|
2796
|
+
const execute = React6.useCallback((sql, params) => adapter.execute(sql, params), [adapter]);
|
|
2073
2797
|
return { isSynced, query, execute };
|
|
2074
2798
|
}
|
|
2075
2799
|
function usePGliteQuery(opts) {
|
|
2076
2800
|
const { adapter, type, sql, params, idColumn = "id", normalize, deps = [] } = opts;
|
|
2077
|
-
const [isLoading, setIsLoading] =
|
|
2078
|
-
const [error, setError] =
|
|
2079
|
-
|
|
2801
|
+
const [isLoading, setIsLoading] = React6.useState(true);
|
|
2802
|
+
const [error, setError] = React6.useState(null);
|
|
2803
|
+
React6.useEffect(() => {
|
|
2080
2804
|
let cancelled = false;
|
|
2081
2805
|
setIsLoading(true);
|
|
2082
2806
|
adapter.query(sql, params).then((r) => {
|
|
@@ -2189,20 +2913,17 @@ function createGQLClient(cfg) {
|
|
|
2189
2913
|
}
|
|
2190
2914
|
function useGQLEntity(opts) {
|
|
2191
2915
|
const { type, id, staleTime = getEngineOptions().defaultStaleTime, enabled = true } = opts;
|
|
2192
|
-
const optsRef =
|
|
2916
|
+
const optsRef = React6.useRef(opts);
|
|
2193
2917
|
optsRef.current = opts;
|
|
2194
2918
|
const data = zustand.useStore(useGraphStore, shallow.useShallow((s) => {
|
|
2195
2919
|
if (!id) return null;
|
|
2196
|
-
|
|
2197
|
-
if (!base) return null;
|
|
2198
|
-
const patch = s.patches[type]?.[id];
|
|
2199
|
-
return patch ? { ...base, ...patch } : base;
|
|
2920
|
+
return s.readEntitySnapshot(type, id);
|
|
2200
2921
|
}));
|
|
2201
|
-
const entityState = zustand.useStore(useGraphStore,
|
|
2922
|
+
const entityState = zustand.useStore(useGraphStore, React6.useCallback(
|
|
2202
2923
|
(s) => s.entityStates[`${type}:${id}`] ?? EMPTY_ENTITY_STATE,
|
|
2203
2924
|
[type, id]
|
|
2204
2925
|
));
|
|
2205
|
-
const doFetch =
|
|
2926
|
+
const doFetch = React6.useCallback(() => {
|
|
2206
2927
|
if (!id || !enabled) return;
|
|
2207
2928
|
const { client, document: document2, variables, descriptor, sideDescriptors, onSuccess, onError } = optsRef.current;
|
|
2208
2929
|
useGraphStore.getState().setEntityFetching(type, id, true);
|
|
@@ -2219,7 +2940,7 @@ function useGQLEntity(opts) {
|
|
|
2219
2940
|
onError?.(e);
|
|
2220
2941
|
});
|
|
2221
2942
|
}, [id, type, enabled]);
|
|
2222
|
-
|
|
2943
|
+
React6.useEffect(() => {
|
|
2223
2944
|
if (!id || !enabled) return;
|
|
2224
2945
|
const token = registerSubscriber(`${type}:${id}`);
|
|
2225
2946
|
const s = useGraphStore.getState();
|
|
@@ -2227,30 +2948,25 @@ function useGQLEntity(opts) {
|
|
|
2227
2948
|
if (!s.entities[type]?.[id] || !ex?.lastFetched || ex.stale || Date.now() - (ex.lastFetched ?? 0) > staleTime) doFetch();
|
|
2228
2949
|
return () => unregisterSubscriber(`${type}:${id}`, token);
|
|
2229
2950
|
}, [id, type, enabled, staleTime, doFetch]);
|
|
2230
|
-
|
|
2951
|
+
React6.useEffect(() => {
|
|
2231
2952
|
if (entityState.stale && id && enabled && !entityState.isFetching) doFetch();
|
|
2232
2953
|
}, [entityState.stale, id, enabled, entityState.isFetching, doFetch]);
|
|
2233
2954
|
return { data, isLoading: !data && entityState.isFetching, isFetching: entityState.isFetching, error: entityState.error, isStale: entityState.stale, refetch: doFetch };
|
|
2234
2955
|
}
|
|
2235
2956
|
function useGQLList(opts) {
|
|
2236
2957
|
const { type, queryKey, staleTime = getEngineOptions().defaultStaleTime, enabled = true, mode = "replace" } = opts;
|
|
2237
|
-
const optsRef =
|
|
2958
|
+
const optsRef = React6.useRef(opts);
|
|
2238
2959
|
optsRef.current = opts;
|
|
2239
|
-
const key =
|
|
2240
|
-
const listState = zustand.useStore(useGraphStore,
|
|
2960
|
+
const key = React6.useMemo(() => serializeKey(queryKey), [queryKey]);
|
|
2961
|
+
const listState = zustand.useStore(useGraphStore, React6.useCallback((s) => s.lists[key] ?? EMPTY_LIST_STATE, [key]));
|
|
2241
2962
|
const items = zustand.useStore(
|
|
2242
2963
|
useGraphStore,
|
|
2243
2964
|
shallow.useShallow((s) => {
|
|
2244
2965
|
const ids = s.lists[key]?.ids ?? EMPTY_IDS;
|
|
2245
|
-
return ids.map((id) =>
|
|
2246
|
-
const base = s.entities[type]?.[id];
|
|
2247
|
-
if (!base) return null;
|
|
2248
|
-
const p = s.patches[type]?.[id];
|
|
2249
|
-
return p ? { ...base, ...p } : base;
|
|
2250
|
-
}).filter((x) => x !== null);
|
|
2966
|
+
return ids.map((id) => s.readEntitySnapshot(type, id)).filter((x) => x !== null);
|
|
2251
2967
|
})
|
|
2252
2968
|
);
|
|
2253
|
-
const doFetch =
|
|
2969
|
+
const doFetch = React6.useCallback((cursor, append = false) => {
|
|
2254
2970
|
if (!enabled) return;
|
|
2255
2971
|
const { client, document: document2, variables, descriptor, sideDescriptors, getItems, getPagination } = optsRef.current;
|
|
2256
2972
|
const store = useGraphStore.getState();
|
|
@@ -2273,25 +2989,25 @@ function useGQLList(opts) {
|
|
|
2273
2989
|
else useGraphStore.getState().setListResult(key, ids, meta);
|
|
2274
2990
|
}).catch((e) => useGraphStore.getState().setListError(key, e.message));
|
|
2275
2991
|
}, [key, enabled, mode]);
|
|
2276
|
-
|
|
2992
|
+
React6.useEffect(() => {
|
|
2277
2993
|
if (!enabled) return;
|
|
2278
2994
|
const ex = useGraphStore.getState().lists[key];
|
|
2279
2995
|
if (!ex || ex.stale || !ex.lastFetched || Date.now() - ex.lastFetched > staleTime) doFetch();
|
|
2280
2996
|
}, [key, enabled, staleTime, doFetch]);
|
|
2281
|
-
|
|
2997
|
+
React6.useEffect(() => {
|
|
2282
2998
|
if (listState.stale && enabled && !listState.isFetching) doFetch();
|
|
2283
2999
|
}, [listState.stale, enabled, listState.isFetching, doFetch]);
|
|
2284
|
-
const fetchNextPage =
|
|
3000
|
+
const fetchNextPage = React6.useCallback(() => {
|
|
2285
3001
|
if (!listState.hasNextPage || listState.isFetchingMore) return;
|
|
2286
3002
|
doFetch(listState.nextCursor ?? void 0, true);
|
|
2287
3003
|
}, [listState.hasNextPage, listState.isFetchingMore, listState.nextCursor, doFetch]);
|
|
2288
3004
|
return { items, ids: listState.ids, isLoading: listState.ids.length === 0 && listState.isFetching, isFetching: listState.isFetching, isFetchingMore: listState.isFetchingMore, error: listState.error, hasNextPage: listState.hasNextPage, total: listState.total, currentPage: listState.currentPage, fetchNextPage, refetch: () => doFetch() };
|
|
2289
3005
|
}
|
|
2290
3006
|
function useGQLMutation(opts) {
|
|
2291
|
-
const optsRef =
|
|
3007
|
+
const optsRef = React6.useRef(opts);
|
|
2292
3008
|
optsRef.current = opts;
|
|
2293
|
-
const [state, setState] =
|
|
2294
|
-
const mutate =
|
|
3009
|
+
const [state, setState] = React6.useState({ isPending: false, isSuccess: false, isError: false, error: null });
|
|
3010
|
+
const mutate = React6.useCallback(async (variables) => {
|
|
2295
3011
|
const { client, document: document2, descriptors, optimistic, invalidateLists, onSuccess, onError } = optsRef.current;
|
|
2296
3012
|
setState({ isPending: true, isSuccess: false, isError: false, error: null });
|
|
2297
3013
|
try {
|
|
@@ -2307,17 +3023,17 @@ function useGQLMutation(opts) {
|
|
|
2307
3023
|
return null;
|
|
2308
3024
|
}
|
|
2309
3025
|
}, []);
|
|
2310
|
-
const trigger =
|
|
3026
|
+
const trigger = React6.useCallback((v) => {
|
|
2311
3027
|
void mutate(v);
|
|
2312
3028
|
}, [mutate]);
|
|
2313
3029
|
return { mutate, trigger, state };
|
|
2314
3030
|
}
|
|
2315
3031
|
function useGQLSubscription(opts) {
|
|
2316
3032
|
const { document: document2, variables, enabled = true } = opts;
|
|
2317
|
-
const [status, setStatus] =
|
|
2318
|
-
const optsRef =
|
|
3033
|
+
const [status, setStatus] = React6.useState({ connected: false, error: null });
|
|
3034
|
+
const optsRef = React6.useRef(opts);
|
|
2319
3035
|
optsRef.current = opts;
|
|
2320
|
-
|
|
3036
|
+
React6.useEffect(() => {
|
|
2321
3037
|
const { client, wsClient, descriptors, onData, onError } = optsRef.current;
|
|
2322
3038
|
if (!enabled) return;
|
|
2323
3039
|
const unsub = client.subscribe({ document: document2, variables, descriptors, wsClient, onData: (d) => {
|
|
@@ -2336,7 +3052,7 @@ function cn(...inputs) {
|
|
|
2336
3052
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
2337
3053
|
}
|
|
2338
3054
|
function InlineCellEditor({ initialValue, onCommit, onCancel, className }) {
|
|
2339
|
-
const [value, setValue] =
|
|
3055
|
+
const [value, setValue] = React6.useState(initialValue);
|
|
2340
3056
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2341
3057
|
"input",
|
|
2342
3058
|
{
|
|
@@ -2366,22 +3082,22 @@ function InlineCellEditor({ initialValue, onCommit, onCancel, className }) {
|
|
|
2366
3082
|
}
|
|
2367
3083
|
function EntityTable({ viewResult, columns, getRowId = (r) => String(r.id), selectedId, onRowClick, onCellEdit, onBulkAction, paginationMode = "loadMore", pageSize = 50, searchPlaceholder = "Search\u2026", searchFields, toolbarChildren, showToolbar = true, emptyState, className }) {
|
|
2368
3084
|
const { items, isLoading, isFetching, isRemoteFetching, isShowingLocalPending, hasNextPage, fetchNextPage, isFetchingMore, viewTotal, setSort, setSearch, refetch } = viewResult;
|
|
2369
|
-
const [sorting, setSorting] =
|
|
2370
|
-
const [rowSelection, setRowSelection] =
|
|
2371
|
-
const [colVis, setColVis] =
|
|
2372
|
-
const [search, setSearchLocal] =
|
|
2373
|
-
const [editingCell, setEditingCell] =
|
|
2374
|
-
const [page, setPage] =
|
|
2375
|
-
const handleSort =
|
|
3085
|
+
const [sorting, setSorting] = React6.useState([]);
|
|
3086
|
+
const [rowSelection, setRowSelection] = React6.useState({});
|
|
3087
|
+
const [colVis, setColVis] = React6.useState({});
|
|
3088
|
+
const [search, setSearchLocal] = React6.useState("");
|
|
3089
|
+
const [editingCell, setEditingCell] = React6.useState(null);
|
|
3090
|
+
const [page, setPage] = React6.useState(1);
|
|
3091
|
+
const handleSort = React6.useCallback((updater) => {
|
|
2376
3092
|
const next = typeof updater === "function" ? updater(sorting) : updater;
|
|
2377
3093
|
setSorting(next);
|
|
2378
3094
|
setSort(next.length ? next.map((s) => ({ field: s.id, direction: s.desc ? "desc" : "asc" })) : null);
|
|
2379
3095
|
}, [sorting, setSort]);
|
|
2380
|
-
const handleSearch =
|
|
3096
|
+
const handleSearch = React6.useCallback((v) => {
|
|
2381
3097
|
setSearchLocal(v);
|
|
2382
3098
|
setSearch(v);
|
|
2383
3099
|
}, [setSearch]);
|
|
2384
|
-
const pagedItems =
|
|
3100
|
+
const pagedItems = React6.useMemo(() => paginationMode === "pages" ? items.slice((page - 1) * pageSize, page * pageSize) : items, [items, paginationMode, page, pageSize]);
|
|
2385
3101
|
const totalPages = Math.ceil(items.length / pageSize);
|
|
2386
3102
|
const table = reactTable.useReactTable({
|
|
2387
3103
|
data: pagedItems,
|
|
@@ -2484,7 +3200,7 @@ function EntityTable({ viewResult, columns, getRowId = (r) => String(r.id), sele
|
|
|
2484
3200
|
] });
|
|
2485
3201
|
}
|
|
2486
3202
|
function Sheet({ open, onClose, title, subtitle, children, footer, width = "w-[480px]" }) {
|
|
2487
|
-
|
|
3203
|
+
React6__default.default.useEffect(() => {
|
|
2488
3204
|
const h = (e) => {
|
|
2489
3205
|
if (e.key === "Escape") onClose();
|
|
2490
3206
|
};
|
|
@@ -2520,6 +3236,8 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2520
3236
|
return /* @__PURE__ */ jsxRuntime.jsx("input", { type: "number", value: String(value ?? ""), onChange: (e) => onChange(e.target.valueAsNumber), placeholder: descriptor.placeholder, className: base });
|
|
2521
3237
|
case "textarea":
|
|
2522
3238
|
return /* @__PURE__ */ jsxRuntime.jsx("textarea", { value: String(value ?? ""), onChange: (e) => onChange(e.target.value), placeholder: descriptor.placeholder, className: "w-full min-h-[80px] rounded-md border bg-muted/50 px-3 py-2 text-sm resize-none focus:outline-none focus:ring-1 focus:ring-ring transition-colors" });
|
|
3239
|
+
case "markdown":
|
|
3240
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MarkdownFieldEditor, { value: String(value ?? ""), onChange: (nextValue) => onChange(nextValue), placeholder: descriptor.placeholder });
|
|
2523
3241
|
case "date":
|
|
2524
3242
|
return /* @__PURE__ */ jsxRuntime.jsx("input", { type: "date", value: value ? new Date(value).toISOString().split("T")[0] : "", onChange: (e) => onChange(e.target.value ? new Date(e.target.value).toISOString() : null), className: base });
|
|
2525
3243
|
case "boolean":
|
|
@@ -2539,12 +3257,35 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2539
3257
|
!value && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select\u2026" }),
|
|
2540
3258
|
(descriptor.options ?? []).map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
2541
3259
|
] });
|
|
3260
|
+
case "json":
|
|
3261
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3262
|
+
"textarea",
|
|
3263
|
+
{
|
|
3264
|
+
value: value != null ? JSON.stringify(value, null, 2) : "",
|
|
3265
|
+
onChange: (event) => {
|
|
3266
|
+
const nextValue = event.target.value;
|
|
3267
|
+
try {
|
|
3268
|
+
onChange(nextValue ? JSON.parse(nextValue) : null);
|
|
3269
|
+
} catch {
|
|
3270
|
+
onChange(nextValue);
|
|
3271
|
+
}
|
|
3272
|
+
},
|
|
3273
|
+
placeholder: descriptor.placeholder,
|
|
3274
|
+
className: "w-full min-h-[120px] rounded-md border bg-muted/50 px-3 py-2 text-sm font-mono resize-y focus:outline-none focus:ring-1 focus:ring-ring transition-colors"
|
|
3275
|
+
}
|
|
3276
|
+
);
|
|
2542
3277
|
default:
|
|
2543
3278
|
return /* @__PURE__ */ jsxRuntime.jsx("input", { value: String(value ?? ""), onChange: (e) => onChange(e.target.value), className: base });
|
|
2544
3279
|
}
|
|
2545
3280
|
}
|
|
3281
|
+
function FieldReadonlyValue({ descriptor, value, entity }) {
|
|
3282
|
+
if (descriptor.render) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: descriptor.render(value, entity) });
|
|
3283
|
+
if (descriptor.type === "markdown") return /* @__PURE__ */ jsxRuntime.jsx(MarkdownFieldRenderer, { value: String(value ?? ""), className: "prose prose-sm max-w-none py-1" });
|
|
3284
|
+
if (descriptor.type === "json") return /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs py-1 whitespace-pre-wrap break-words", children: JSON.stringify(value ?? null, null, 2) });
|
|
3285
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm py-1", children: value != null && value !== "" ? String(value) : "\u2014" });
|
|
3286
|
+
}
|
|
2546
3287
|
function EntityDetailSheet({ crud, fields, title = "Details", description, children, showEditButton = true, showDeleteButton = true, deleteConfirmMessage = "This action cannot be undone." }) {
|
|
2547
|
-
const [confirmDelete, setConfirmDelete] =
|
|
3288
|
+
const [confirmDelete, setConfirmDelete] = React6__default.default.useState(false);
|
|
2548
3289
|
const open = crud.mode === "detail" && !!crud.selectedId;
|
|
2549
3290
|
const entity = crud.detail;
|
|
2550
3291
|
const resolvedTitle = entity && typeof title === "function" ? title(entity) : String(title);
|
|
@@ -2568,8 +3309,7 @@ function EntityDetailSheet({ crud, fields, title = "Details", description, child
|
|
|
2568
3309
|
entity && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2569
3310
|
fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2570
3311
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wide mb-1", children: f.label }),
|
|
2571
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2572
|
-
}, entity, readonly: true })
|
|
3312
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldReadonlyValue, { descriptor: f, value: getValueAtPath(entity, f.field), entity })
|
|
2573
3313
|
] }, f.field)),
|
|
2574
3314
|
children && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2575
3315
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t my-1" }),
|
|
@@ -2639,13 +3379,14 @@ function EntityFormSheet({ crud, fields, createTitle = "Create", editTitle = "Ed
|
|
|
2639
3379
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 rounded-md bg-destructive/10 border border-destructive/20 text-xs text-destructive", children: error }),
|
|
2640
3380
|
visibleFields.map((f) => {
|
|
2641
3381
|
const isDirty = !isCreate && crud.dirty.changed.has(f.field);
|
|
3382
|
+
const currentValue = getValueAtPath(buf, f.field);
|
|
2642
3383
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
2643
3384
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: cn("text-xs font-medium", isDirty ? "text-primary" : "text-muted-foreground"), children: [
|
|
2644
3385
|
f.label,
|
|
2645
3386
|
f.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-0.5", children: "*" }),
|
|
2646
3387
|
isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1.5 text-[10px] font-normal opacity-70", children: "modified" })
|
|
2647
3388
|
] }),
|
|
2648
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldControl, { descriptor: f, value:
|
|
3389
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldControl, { descriptor: f, value: currentValue, onChange: (v) => setField(f.field, v), entity: buf, readonly: f.readonlyOnEdit && isEdit }),
|
|
2649
3390
|
f.hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: f.hint })
|
|
2650
3391
|
] }, f.field);
|
|
2651
3392
|
})
|
|
@@ -3303,43 +4044,43 @@ function buildHeaderGroups(columns, table) {
|
|
|
3303
4044
|
function useTable(options) {
|
|
3304
4045
|
const { data, columns: columnDefs } = options;
|
|
3305
4046
|
const ini = options.initialState;
|
|
3306
|
-
const [sorting, _setSorting] =
|
|
4047
|
+
const [sorting, _setSorting] = React6.useState(
|
|
3307
4048
|
options.state?.sorting ?? ini?.sorting ?? []
|
|
3308
4049
|
);
|
|
3309
|
-
const [columnFilters, _setColumnFilters] =
|
|
4050
|
+
const [columnFilters, _setColumnFilters] = React6.useState(
|
|
3310
4051
|
options.state?.columnFilters ?? ini?.columnFilters ?? []
|
|
3311
4052
|
);
|
|
3312
|
-
const [globalFilter, _setGlobalFilter] =
|
|
4053
|
+
const [globalFilter, _setGlobalFilter] = React6.useState(
|
|
3313
4054
|
options.state?.globalFilter ?? ini?.globalFilter ?? ""
|
|
3314
4055
|
);
|
|
3315
|
-
const [rowSelection, _setRowSelection] =
|
|
4056
|
+
const [rowSelection, _setRowSelection] = React6.useState(
|
|
3316
4057
|
options.state?.rowSelection ?? ini?.rowSelection ?? {}
|
|
3317
4058
|
);
|
|
3318
|
-
const [columnVisibility, _setColumnVisibility] =
|
|
4059
|
+
const [columnVisibility, _setColumnVisibility] = React6.useState(
|
|
3319
4060
|
options.state?.columnVisibility ?? ini?.columnVisibility ?? {}
|
|
3320
4061
|
);
|
|
3321
|
-
const [columnOrder, _setColumnOrder] =
|
|
4062
|
+
const [columnOrder, _setColumnOrder] = React6.useState(
|
|
3322
4063
|
options.state?.columnOrder ?? ini?.columnOrder ?? []
|
|
3323
4064
|
);
|
|
3324
|
-
const [columnPinning, _setColumnPinning] =
|
|
4065
|
+
const [columnPinning, _setColumnPinning] = React6.useState(
|
|
3325
4066
|
options.state?.columnPinning ?? ini?.columnPinning ?? { left: [], right: [] }
|
|
3326
4067
|
);
|
|
3327
|
-
const [columnSizing, _setColumnSizing] =
|
|
4068
|
+
const [columnSizing, _setColumnSizing] = React6.useState(
|
|
3328
4069
|
options.state?.columnSizing ?? ini?.columnSizing ?? {}
|
|
3329
4070
|
);
|
|
3330
|
-
const [columnSizingInfo, _setColumnSizingInfo] =
|
|
4071
|
+
const [columnSizingInfo, _setColumnSizingInfo] = React6.useState(
|
|
3331
4072
|
options.state?.columnSizingInfo ?? ini?.columnSizingInfo ?? defaultState.columnSizingInfo
|
|
3332
4073
|
);
|
|
3333
|
-
const [expanded, _setExpanded] =
|
|
4074
|
+
const [expanded, _setExpanded] = React6.useState(
|
|
3334
4075
|
options.state?.expanded ?? ini?.expanded ?? {}
|
|
3335
4076
|
);
|
|
3336
|
-
const [grouping, _setGrouping] =
|
|
4077
|
+
const [grouping, _setGrouping] = React6.useState(
|
|
3337
4078
|
options.state?.grouping ?? ini?.grouping ?? []
|
|
3338
4079
|
);
|
|
3339
|
-
const [pagination, _setPagination] =
|
|
4080
|
+
const [pagination, _setPagination] = React6.useState(
|
|
3340
4081
|
options.state?.pagination ?? ini?.pagination ?? { pageIndex: 0, pageSize: 10 }
|
|
3341
4082
|
);
|
|
3342
|
-
const state =
|
|
4083
|
+
const state = React6.useMemo(
|
|
3343
4084
|
() => ({
|
|
3344
4085
|
sorting: options.state?.sorting ?? sorting,
|
|
3345
4086
|
columnFilters: options.state?.columnFilters ?? columnFilters,
|
|
@@ -3370,63 +4111,63 @@ function useTable(options) {
|
|
|
3370
4111
|
pagination
|
|
3371
4112
|
]
|
|
3372
4113
|
);
|
|
3373
|
-
const stateRef =
|
|
4114
|
+
const stateRef = React6.useRef(state);
|
|
3374
4115
|
stateRef.current = state;
|
|
3375
|
-
const setSorting =
|
|
4116
|
+
const setSorting = React6.useCallback((updater) => {
|
|
3376
4117
|
options.onSortingChange?.(updater);
|
|
3377
4118
|
if (!options.state?.sorting) _setSorting((prev) => resolveUpdater(updater, prev));
|
|
3378
4119
|
}, [options.onSortingChange, options.state?.sorting]);
|
|
3379
|
-
const setColumnFilters =
|
|
4120
|
+
const setColumnFilters = React6.useCallback((updater) => {
|
|
3380
4121
|
options.onColumnFiltersChange?.(updater);
|
|
3381
4122
|
if (!options.state?.columnFilters) _setColumnFilters((prev) => resolveUpdater(updater, prev));
|
|
3382
4123
|
if (options.autoResetPageIndex !== false) {
|
|
3383
4124
|
_setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
3384
4125
|
}
|
|
3385
4126
|
}, [options.onColumnFiltersChange, options.state?.columnFilters, options.autoResetPageIndex]);
|
|
3386
|
-
const setGlobalFilter =
|
|
4127
|
+
const setGlobalFilter = React6.useCallback((value) => {
|
|
3387
4128
|
options.onGlobalFilterChange?.(value);
|
|
3388
4129
|
if (!options.state?.globalFilter) _setGlobalFilter(value);
|
|
3389
4130
|
if (options.autoResetPageIndex !== false) {
|
|
3390
4131
|
_setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
3391
4132
|
}
|
|
3392
4133
|
}, [options.onGlobalFilterChange, options.state?.globalFilter, options.autoResetPageIndex]);
|
|
3393
|
-
const setRowSelection =
|
|
4134
|
+
const setRowSelection = React6.useCallback((updater) => {
|
|
3394
4135
|
options.onRowSelectionChange?.(updater);
|
|
3395
4136
|
if (!options.state?.rowSelection) _setRowSelection((prev) => resolveUpdater(updater, prev));
|
|
3396
4137
|
}, [options.onRowSelectionChange, options.state?.rowSelection]);
|
|
3397
|
-
const setColumnVisibility =
|
|
4138
|
+
const setColumnVisibility = React6.useCallback((updater) => {
|
|
3398
4139
|
options.onColumnVisibilityChange?.(updater);
|
|
3399
4140
|
if (!options.state?.columnVisibility) _setColumnVisibility((prev) => resolveUpdater(updater, prev));
|
|
3400
4141
|
}, [options.onColumnVisibilityChange, options.state?.columnVisibility]);
|
|
3401
|
-
const setColumnOrder =
|
|
4142
|
+
const setColumnOrder = React6.useCallback((updater) => {
|
|
3402
4143
|
options.onColumnOrderChange?.(updater);
|
|
3403
4144
|
if (!options.state?.columnOrder) _setColumnOrder((prev) => resolveUpdater(updater, prev));
|
|
3404
4145
|
}, [options.onColumnOrderChange, options.state?.columnOrder]);
|
|
3405
|
-
const setColumnPinning =
|
|
4146
|
+
const setColumnPinning = React6.useCallback((updater) => {
|
|
3406
4147
|
options.onColumnPinningChange?.(updater);
|
|
3407
4148
|
if (!options.state?.columnPinning) _setColumnPinning((prev) => resolveUpdater(updater, prev));
|
|
3408
4149
|
}, [options.onColumnPinningChange, options.state?.columnPinning]);
|
|
3409
|
-
const setColumnSizing =
|
|
4150
|
+
const setColumnSizing = React6.useCallback((updater) => {
|
|
3410
4151
|
options.onColumnSizingChange?.(updater);
|
|
3411
4152
|
if (!options.state?.columnSizing) _setColumnSizing((prev) => resolveUpdater(updater, prev));
|
|
3412
4153
|
}, [options.onColumnSizingChange, options.state?.columnSizing]);
|
|
3413
|
-
const setColumnSizingInfo =
|
|
4154
|
+
const setColumnSizingInfo = React6.useCallback((updater) => {
|
|
3414
4155
|
options.onColumnSizingInfoChange?.(updater);
|
|
3415
4156
|
if (!options.state?.columnSizingInfo) _setColumnSizingInfo((prev) => resolveUpdater(updater, prev));
|
|
3416
4157
|
}, [options.onColumnSizingInfoChange, options.state?.columnSizingInfo]);
|
|
3417
|
-
const setExpanded =
|
|
4158
|
+
const setExpanded = React6.useCallback((updater) => {
|
|
3418
4159
|
options.onExpandedChange?.(updater);
|
|
3419
4160
|
if (!options.state?.expanded) _setExpanded((prev) => resolveUpdater(updater, prev));
|
|
3420
4161
|
}, [options.onExpandedChange, options.state?.expanded]);
|
|
3421
|
-
const setGrouping =
|
|
4162
|
+
const setGrouping = React6.useCallback((updater) => {
|
|
3422
4163
|
options.onGroupingChange?.(updater);
|
|
3423
4164
|
if (!options.state?.grouping) _setGrouping((prev) => resolveUpdater(updater, prev));
|
|
3424
4165
|
}, [options.onGroupingChange, options.state?.grouping]);
|
|
3425
|
-
const setPagination =
|
|
4166
|
+
const setPagination = React6.useCallback((updater) => {
|
|
3426
4167
|
options.onPaginationChange?.(updater);
|
|
3427
4168
|
if (!options.state?.pagination) _setPagination((prev) => resolveUpdater(updater, prev));
|
|
3428
4169
|
}, [options.onPaginationChange, options.state?.pagination]);
|
|
3429
|
-
const stateSetters =
|
|
4170
|
+
const stateSetters = React6.useMemo(() => ({
|
|
3430
4171
|
setSorting,
|
|
3431
4172
|
setColumnFilters,
|
|
3432
4173
|
setGlobalFilter,
|
|
@@ -3453,13 +4194,13 @@ function useTable(options) {
|
|
|
3453
4194
|
setGrouping,
|
|
3454
4195
|
setPagination
|
|
3455
4196
|
]);
|
|
3456
|
-
const getState =
|
|
3457
|
-
const coreRowModelRef =
|
|
3458
|
-
const emptyCoreRowModel =
|
|
4197
|
+
const getState = React6.useCallback(() => state, [state]);
|
|
4198
|
+
const coreRowModelRef = React6.useRef(null);
|
|
4199
|
+
const emptyCoreRowModel = React6.useMemo(
|
|
3459
4200
|
() => ({ rows: [], flatRows: [], rowsById: {} }),
|
|
3460
4201
|
[]
|
|
3461
4202
|
);
|
|
3462
|
-
const rowModelTable =
|
|
4203
|
+
const rowModelTable = React6.useMemo(
|
|
3463
4204
|
() => ({
|
|
3464
4205
|
options,
|
|
3465
4206
|
getState: () => stateRef.current,
|
|
@@ -3469,11 +4210,11 @@ function useTable(options) {
|
|
|
3469
4210
|
}),
|
|
3470
4211
|
[options, setRowSelection, setExpanded, emptyCoreRowModel]
|
|
3471
4212
|
);
|
|
3472
|
-
const columns =
|
|
4213
|
+
const columns = React6.useMemo(
|
|
3473
4214
|
() => buildColumns(columnDefs, { getState, ...stateSetters }, stateSetters),
|
|
3474
4215
|
[columnDefs, getState, stateSetters]
|
|
3475
4216
|
);
|
|
3476
|
-
const orderedColumns =
|
|
4217
|
+
const orderedColumns = React6.useMemo(() => {
|
|
3477
4218
|
if (state.columnOrder.length === 0) return columns;
|
|
3478
4219
|
const ordered = [];
|
|
3479
4220
|
const remaining = [...columns];
|
|
@@ -3487,28 +4228,28 @@ function useTable(options) {
|
|
|
3487
4228
|
ordered.push(...remaining);
|
|
3488
4229
|
return ordered;
|
|
3489
4230
|
}, [columns, state.columnOrder]);
|
|
3490
|
-
const visibleColumns =
|
|
4231
|
+
const visibleColumns = React6.useMemo(
|
|
3491
4232
|
() => orderedColumns.filter((c) => c.getIsVisible()),
|
|
3492
4233
|
[orderedColumns]
|
|
3493
4234
|
);
|
|
3494
|
-
const leftPinnedColumns =
|
|
4235
|
+
const leftPinnedColumns = React6.useMemo(
|
|
3495
4236
|
() => visibleColumns.filter((c) => c.getIsPinned() === "left"),
|
|
3496
4237
|
[visibleColumns]
|
|
3497
4238
|
);
|
|
3498
|
-
const rightPinnedColumns =
|
|
4239
|
+
const rightPinnedColumns = React6.useMemo(
|
|
3499
4240
|
() => visibleColumns.filter((c) => c.getIsPinned() === "right"),
|
|
3500
4241
|
[visibleColumns]
|
|
3501
4242
|
);
|
|
3502
|
-
const centerColumns =
|
|
4243
|
+
const centerColumns = React6.useMemo(
|
|
3503
4244
|
() => visibleColumns.filter((c) => c.getIsPinned() === false),
|
|
3504
4245
|
[visibleColumns]
|
|
3505
4246
|
);
|
|
3506
|
-
const coreRowModel =
|
|
4247
|
+
const coreRowModel = React6.useMemo(() => {
|
|
3507
4248
|
const cm = getCoreRowModel2(data, columns, rowModelTable);
|
|
3508
4249
|
coreRowModelRef.current = cm;
|
|
3509
4250
|
return cm;
|
|
3510
4251
|
}, [data, columns, rowModelTable]);
|
|
3511
|
-
const filteredRowModel =
|
|
4252
|
+
const filteredRowModel = React6.useMemo(() => {
|
|
3512
4253
|
if (options.manualFiltering) return coreRowModel;
|
|
3513
4254
|
return getFilteredRowModel(
|
|
3514
4255
|
coreRowModel,
|
|
@@ -3518,32 +4259,32 @@ function useTable(options) {
|
|
|
3518
4259
|
options.globalFilterFn
|
|
3519
4260
|
);
|
|
3520
4261
|
}, [coreRowModel, state.columnFilters, state.globalFilter, columns, options.manualFiltering, options.globalFilterFn]);
|
|
3521
|
-
const sortedRowModel =
|
|
4262
|
+
const sortedRowModel = React6.useMemo(() => {
|
|
3522
4263
|
if (options.manualSorting) return filteredRowModel;
|
|
3523
4264
|
return getSortedRowModel2(filteredRowModel, state.sorting, columns);
|
|
3524
4265
|
}, [filteredRowModel, state.sorting, columns, options.manualSorting]);
|
|
3525
|
-
const groupedRowModel =
|
|
4266
|
+
const groupedRowModel = React6.useMemo(() => {
|
|
3526
4267
|
if (options.manualGrouping || state.grouping.length === 0) return sortedRowModel;
|
|
3527
4268
|
return getGroupedRowModel(sortedRowModel, state.grouping, columns, rowModelTable);
|
|
3528
4269
|
}, [sortedRowModel, state.grouping, columns, options.manualGrouping, rowModelTable]);
|
|
3529
|
-
const expandedRowModel =
|
|
4270
|
+
const expandedRowModel = React6.useMemo(
|
|
3530
4271
|
() => getExpandedRowModel(groupedRowModel, state.expanded),
|
|
3531
4272
|
[groupedRowModel, state.expanded]
|
|
3532
4273
|
);
|
|
3533
4274
|
const prePaginationRowModel = expandedRowModel;
|
|
3534
|
-
const paginatedRowModel =
|
|
4275
|
+
const paginatedRowModel = React6.useMemo(() => {
|
|
3535
4276
|
if (options.manualPagination) return prePaginationRowModel;
|
|
3536
4277
|
return getPaginatedRowModel(prePaginationRowModel, state.pagination);
|
|
3537
4278
|
}, [prePaginationRowModel, state.pagination, options.manualPagination]);
|
|
3538
|
-
const selectedRowModel =
|
|
4279
|
+
const selectedRowModel = React6.useMemo(
|
|
3539
4280
|
() => getSelectedRowModel(coreRowModel, state.rowSelection),
|
|
3540
4281
|
[coreRowModel, state.rowSelection]
|
|
3541
4282
|
);
|
|
3542
|
-
const pageCount =
|
|
4283
|
+
const pageCount = React6.useMemo(() => {
|
|
3543
4284
|
if (options.pageCount != null) return options.pageCount;
|
|
3544
4285
|
return Math.ceil(prePaginationRowModel.rows.length / state.pagination.pageSize);
|
|
3545
4286
|
}, [options.pageCount, prePaginationRowModel, state.pagination.pageSize]);
|
|
3546
|
-
const table =
|
|
4287
|
+
const table = React6.useMemo(() => {
|
|
3547
4288
|
const inst = {
|
|
3548
4289
|
options,
|
|
3549
4290
|
getState: () => state,
|
|
@@ -3846,9 +4587,9 @@ function createSelectionStore() {
|
|
|
3846
4587
|
function useSelectionStore(store, selector) {
|
|
3847
4588
|
return zustand.useStore(store, selector);
|
|
3848
4589
|
}
|
|
3849
|
-
var SelectionContext =
|
|
4590
|
+
var SelectionContext = React6__default.default.createContext(null);
|
|
3850
4591
|
function useSelectionContext() {
|
|
3851
|
-
const store =
|
|
4592
|
+
const store = React6__default.default.useContext(SelectionContext);
|
|
3852
4593
|
if (!store) throw new Error("useSelectionContext must be used within a SelectionContext.Provider");
|
|
3853
4594
|
return store;
|
|
3854
4595
|
}
|
|
@@ -4574,18 +5315,18 @@ function generateId() {
|
|
|
4574
5315
|
function useTablePresets(tableId, options = {}) {
|
|
4575
5316
|
const { adapter, realtimeMode = "auto-apply", enabled = true } = options;
|
|
4576
5317
|
const resolvedAdapter = adapter ?? new MemoryAdapter();
|
|
4577
|
-
const adapterRef =
|
|
5318
|
+
const adapterRef = React6.useRef(resolvedAdapter);
|
|
4578
5319
|
adapterRef.current = resolvedAdapter;
|
|
4579
|
-
const storeRef =
|
|
5320
|
+
const storeRef = React6.useRef(createPresetStore(realtimeMode));
|
|
4580
5321
|
const store = storeRef.current;
|
|
4581
|
-
const [isLoading, setIsLoading] =
|
|
4582
|
-
const [isSubscribed, setIsSubscribed] =
|
|
4583
|
-
|
|
5322
|
+
const [isLoading, setIsLoading] = React6.useState(false);
|
|
5323
|
+
const [isSubscribed, setIsSubscribed] = React6.useState(false);
|
|
5324
|
+
React6.useEffect(() => {
|
|
4584
5325
|
if (!enabled) return;
|
|
4585
5326
|
setIsLoading(true);
|
|
4586
5327
|
store.getState().loadPresets(tableId, adapterRef.current).finally(() => setIsLoading(false));
|
|
4587
5328
|
}, [tableId, enabled, store]);
|
|
4588
|
-
|
|
5329
|
+
React6.useEffect(() => {
|
|
4589
5330
|
if (!enabled) return;
|
|
4590
5331
|
const currentAdapter = adapterRef.current;
|
|
4591
5332
|
if (!currentAdapter.subscribe) {
|
|
@@ -4600,19 +5341,19 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4600
5341
|
}, [tableId, enabled, store]);
|
|
4601
5342
|
const slice = zustand.useStore(store, (s) => s.presets[tableId] ?? s.getTablePresets(tableId));
|
|
4602
5343
|
const allPendingChanges = zustand.useStore(store, (s) => s.pendingChanges);
|
|
4603
|
-
const pendingChanges =
|
|
5344
|
+
const pendingChanges = React6.useMemo(
|
|
4604
5345
|
() => allPendingChanges.filter((e) => e.tableId === tableId),
|
|
4605
5346
|
[allPendingChanges, tableId]
|
|
4606
5347
|
);
|
|
4607
|
-
const activeFilterPreset =
|
|
5348
|
+
const activeFilterPreset = React6.useMemo(
|
|
4608
5349
|
() => slice.filters.find((p) => p.id === slice.activeFilterId) ?? null,
|
|
4609
5350
|
[slice.filters, slice.activeFilterId]
|
|
4610
5351
|
);
|
|
4611
|
-
const activeColumnPreset =
|
|
5352
|
+
const activeColumnPreset = React6.useMemo(
|
|
4612
5353
|
() => slice.columns.find((p) => p.id === slice.activeColumnId) ?? null,
|
|
4613
5354
|
[slice.columns, slice.activeColumnId]
|
|
4614
5355
|
);
|
|
4615
|
-
const applyFilterPreset =
|
|
5356
|
+
const applyFilterPreset = React6.useCallback(
|
|
4616
5357
|
(id) => {
|
|
4617
5358
|
store.getState().applyFilterPreset(tableId, id);
|
|
4618
5359
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4623,7 +5364,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4623
5364
|
},
|
|
4624
5365
|
[tableId, slice.activeColumnId, slice.activeViewMode, store]
|
|
4625
5366
|
);
|
|
4626
|
-
const applyColumnPreset =
|
|
5367
|
+
const applyColumnPreset = React6.useCallback(
|
|
4627
5368
|
(id) => {
|
|
4628
5369
|
store.getState().applyColumnPreset(tableId, id);
|
|
4629
5370
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4634,7 +5375,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4634
5375
|
},
|
|
4635
5376
|
[tableId, slice.activeFilterId, slice.activeViewMode, store]
|
|
4636
5377
|
);
|
|
4637
|
-
const setViewMode =
|
|
5378
|
+
const setViewMode = React6.useCallback(
|
|
4638
5379
|
(mode) => {
|
|
4639
5380
|
store.getState().setViewMode(tableId, mode);
|
|
4640
5381
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4645,7 +5386,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4645
5386
|
},
|
|
4646
5387
|
[tableId, slice.activeFilterId, slice.activeColumnId, store]
|
|
4647
5388
|
);
|
|
4648
|
-
const saveFilterPreset =
|
|
5389
|
+
const saveFilterPreset = React6.useCallback(
|
|
4649
5390
|
async (preset) => {
|
|
4650
5391
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4651
5392
|
const full = {
|
|
@@ -4658,7 +5399,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4658
5399
|
},
|
|
4659
5400
|
[tableId, store]
|
|
4660
5401
|
);
|
|
4661
|
-
const updateFilterPreset =
|
|
5402
|
+
const updateFilterPreset = React6.useCallback(
|
|
4662
5403
|
async (id, patch) => {
|
|
4663
5404
|
const existing = slice.filters.find((p) => p.id === id);
|
|
4664
5405
|
if (!existing) return;
|
|
@@ -4672,7 +5413,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4672
5413
|
},
|
|
4673
5414
|
[tableId, slice.filters, store]
|
|
4674
5415
|
);
|
|
4675
|
-
const saveColumnPreset =
|
|
5416
|
+
const saveColumnPreset = React6.useCallback(
|
|
4676
5417
|
async (preset) => {
|
|
4677
5418
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4678
5419
|
const full = {
|
|
@@ -4685,7 +5426,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4685
5426
|
},
|
|
4686
5427
|
[tableId, store]
|
|
4687
5428
|
);
|
|
4688
|
-
const updateColumnPreset =
|
|
5429
|
+
const updateColumnPreset = React6.useCallback(
|
|
4689
5430
|
async (id, patch) => {
|
|
4690
5431
|
const existing = slice.columns.find((p) => p.id === id);
|
|
4691
5432
|
if (!existing) return;
|
|
@@ -4699,25 +5440,25 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4699
5440
|
},
|
|
4700
5441
|
[tableId, slice.columns, store]
|
|
4701
5442
|
);
|
|
4702
|
-
const deleteFilterPreset =
|
|
5443
|
+
const deleteFilterPreset = React6.useCallback(
|
|
4703
5444
|
async (id) => {
|
|
4704
5445
|
await store.getState().deleteFilterPreset(tableId, id, adapterRef.current);
|
|
4705
5446
|
},
|
|
4706
5447
|
[tableId, store]
|
|
4707
5448
|
);
|
|
4708
|
-
const deleteColumnPreset =
|
|
5449
|
+
const deleteColumnPreset = React6.useCallback(
|
|
4709
5450
|
async (id) => {
|
|
4710
5451
|
await store.getState().deleteColumnPreset(tableId, id, adapterRef.current);
|
|
4711
5452
|
},
|
|
4712
5453
|
[tableId, store]
|
|
4713
5454
|
);
|
|
4714
|
-
const acknowledgePendingChange =
|
|
5455
|
+
const acknowledgePendingChange = React6.useCallback(
|
|
4715
5456
|
(index) => {
|
|
4716
5457
|
store.getState().acknowledgePendingChange(index);
|
|
4717
5458
|
},
|
|
4718
5459
|
[store]
|
|
4719
5460
|
);
|
|
4720
|
-
const dismissPendingChanges =
|
|
5461
|
+
const dismissPendingChanges = React6.useCallback(() => {
|
|
4721
5462
|
store.getState().dismissPendingChanges(tableId);
|
|
4722
5463
|
}, [tableId, store]);
|
|
4723
5464
|
return {
|
|
@@ -4742,7 +5483,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4742
5483
|
isSubscribed
|
|
4743
5484
|
};
|
|
4744
5485
|
}
|
|
4745
|
-
var TableStorageContext =
|
|
5486
|
+
var TableStorageContext = React6.createContext({
|
|
4746
5487
|
adapter: new MemoryAdapter(),
|
|
4747
5488
|
realtimeMode: "auto-apply"
|
|
4748
5489
|
});
|
|
@@ -4751,19 +5492,19 @@ function TableStorageProvider({
|
|
|
4751
5492
|
realtimeMode = "auto-apply",
|
|
4752
5493
|
children
|
|
4753
5494
|
}) {
|
|
4754
|
-
const value =
|
|
5495
|
+
const value = React6.useMemo(
|
|
4755
5496
|
() => ({ adapter, realtimeMode }),
|
|
4756
5497
|
[adapter, realtimeMode]
|
|
4757
5498
|
);
|
|
4758
5499
|
return /* @__PURE__ */ jsxRuntime.jsx(TableStorageContext.Provider, { value, children });
|
|
4759
5500
|
}
|
|
4760
5501
|
function useTableStorageAdapter() {
|
|
4761
|
-
return
|
|
5502
|
+
return React6.useContext(TableStorageContext).adapter;
|
|
4762
5503
|
}
|
|
4763
5504
|
function useTableRealtimeMode() {
|
|
4764
|
-
return
|
|
5505
|
+
return React6.useContext(TableStorageContext).realtimeMode;
|
|
4765
5506
|
}
|
|
4766
|
-
var Table =
|
|
5507
|
+
var Table = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4767
5508
|
"table",
|
|
4768
5509
|
{
|
|
4769
5510
|
ref,
|
|
@@ -4772,11 +5513,11 @@ var Table = React5__default.default.forwardRef(({ className, ...props }, ref) =>
|
|
|
4772
5513
|
}
|
|
4773
5514
|
) }));
|
|
4774
5515
|
Table.displayName = "Table";
|
|
4775
|
-
var TableHeader =
|
|
5516
|
+
var TableHeader = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("bg-muted/60", className), ...props }));
|
|
4776
5517
|
TableHeader.displayName = "TableHeader";
|
|
4777
|
-
var TableBody =
|
|
5518
|
+
var TableBody = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("bg-background", className), ...props }));
|
|
4778
5519
|
TableBody.displayName = "TableBody";
|
|
4779
|
-
var TableFooter =
|
|
5520
|
+
var TableFooter = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4780
5521
|
"tfoot",
|
|
4781
5522
|
{
|
|
4782
5523
|
ref,
|
|
@@ -4785,7 +5526,7 @@ var TableFooter = React5__default.default.forwardRef(({ className, ...props }, r
|
|
|
4785
5526
|
}
|
|
4786
5527
|
));
|
|
4787
5528
|
TableFooter.displayName = "TableFooter";
|
|
4788
|
-
var TableRow =
|
|
5529
|
+
var TableRow = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4789
5530
|
"tr",
|
|
4790
5531
|
{
|
|
4791
5532
|
ref,
|
|
@@ -4797,7 +5538,7 @@ var TableRow = React5__default.default.forwardRef(({ className, ...props }, ref)
|
|
|
4797
5538
|
}
|
|
4798
5539
|
));
|
|
4799
5540
|
TableRow.displayName = "TableRow";
|
|
4800
|
-
var TableHead =
|
|
5541
|
+
var TableHead = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4801
5542
|
"th",
|
|
4802
5543
|
{
|
|
4803
5544
|
ref,
|
|
@@ -4809,7 +5550,7 @@ var TableHead = React5__default.default.forwardRef(({ className, ...props }, ref
|
|
|
4809
5550
|
}
|
|
4810
5551
|
));
|
|
4811
5552
|
TableHead.displayName = "TableHead";
|
|
4812
|
-
var TableCell =
|
|
5553
|
+
var TableCell = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4813
5554
|
"td",
|
|
4814
5555
|
{
|
|
4815
5556
|
ref,
|
|
@@ -4821,7 +5562,7 @@ var TableCell = React5__default.default.forwardRef(({ className, ...props }, ref
|
|
|
4821
5562
|
}
|
|
4822
5563
|
));
|
|
4823
5564
|
TableCell.displayName = "TableCell";
|
|
4824
|
-
var TableCaption =
|
|
5565
|
+
var TableCaption = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4825
5566
|
"caption",
|
|
4826
5567
|
{
|
|
4827
5568
|
ref,
|
|
@@ -4884,11 +5625,11 @@ function InlineCellEditor2({
|
|
|
4884
5625
|
inputId,
|
|
4885
5626
|
ariaLabel
|
|
4886
5627
|
}) {
|
|
4887
|
-
const [value, setValue] =
|
|
4888
|
-
const inputRef =
|
|
4889
|
-
const selectRef =
|
|
5628
|
+
const [value, setValue] = React6.useState(initialValue);
|
|
5629
|
+
const inputRef = React6.useRef(null);
|
|
5630
|
+
const selectRef = React6.useRef(null);
|
|
4890
5631
|
const filterType = columnDef.meta?.entityMeta?.filterType ?? "text";
|
|
4891
|
-
|
|
5632
|
+
React6.useEffect(() => {
|
|
4892
5633
|
if (filterType === "enum") {
|
|
4893
5634
|
selectRef.current?.focus();
|
|
4894
5635
|
return;
|
|
@@ -4897,7 +5638,7 @@ function InlineCellEditor2({
|
|
|
4897
5638
|
inputRef.current?.focus();
|
|
4898
5639
|
inputRef.current?.select();
|
|
4899
5640
|
}, [filterType]);
|
|
4900
|
-
const handleKeyDown =
|
|
5641
|
+
const handleKeyDown = React6.useCallback(
|
|
4901
5642
|
(e) => {
|
|
4902
5643
|
if (e.key === "Enter") {
|
|
4903
5644
|
e.preventDefault();
|
|
@@ -4909,7 +5650,7 @@ function InlineCellEditor2({
|
|
|
4909
5650
|
},
|
|
4910
5651
|
[value, onSave, onCancel]
|
|
4911
5652
|
);
|
|
4912
|
-
const handleBlur =
|
|
5653
|
+
const handleBlur = React6.useCallback(() => {
|
|
4913
5654
|
onSave(value);
|
|
4914
5655
|
}, [value, onSave]);
|
|
4915
5656
|
if (filterType === "boolean") {
|
|
@@ -5017,8 +5758,8 @@ function InlineItemEditor({
|
|
|
5017
5758
|
onCancel,
|
|
5018
5759
|
className
|
|
5019
5760
|
}) {
|
|
5020
|
-
const baseId =
|
|
5021
|
-
const [editValues, setEditValues] =
|
|
5761
|
+
const baseId = React6.useId();
|
|
5762
|
+
const [editValues, setEditValues] = React6.useState({});
|
|
5022
5763
|
const editableFields = columns.filter(
|
|
5023
5764
|
(c) => c.meta?.entityMeta?.editable && c.accessorKey
|
|
5024
5765
|
);
|
|
@@ -5119,11 +5860,11 @@ function ActionDropdown({
|
|
|
5119
5860
|
actions,
|
|
5120
5861
|
className
|
|
5121
5862
|
}) {
|
|
5122
|
-
const [isOpen, setIsOpen] =
|
|
5123
|
-
const [confirmAction, setConfirmAction] =
|
|
5124
|
-
const menuRef =
|
|
5863
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
5864
|
+
const [confirmAction, setConfirmAction] = React6.useState(null);
|
|
5865
|
+
const menuRef = React6.useRef(null);
|
|
5125
5866
|
const visibleActions = actions.filter((a) => !a.hidden?.(item));
|
|
5126
|
-
|
|
5867
|
+
React6.useEffect(() => {
|
|
5127
5868
|
function handleClick(e) {
|
|
5128
5869
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
5129
5870
|
setIsOpen(false);
|
|
@@ -5195,7 +5936,7 @@ function ActionButtonRow({
|
|
|
5195
5936
|
const visibleActions = actions.filter((a) => !a.hidden?.(item));
|
|
5196
5937
|
const inline = visibleActions.slice(0, maxVisible);
|
|
5197
5938
|
const overflow = visibleActions.slice(maxVisible);
|
|
5198
|
-
const [confirmAction, setConfirmAction] =
|
|
5939
|
+
const [confirmAction, setConfirmAction] = React6.useState(null);
|
|
5199
5940
|
function executeAction(action) {
|
|
5200
5941
|
if (action.confirm) {
|
|
5201
5942
|
setConfirmAction(action);
|
|
@@ -5363,10 +6104,10 @@ function DataTable({
|
|
|
5363
6104
|
getRowId,
|
|
5364
6105
|
className
|
|
5365
6106
|
}) {
|
|
5366
|
-
const [editingCell, setEditingCell] =
|
|
6107
|
+
const [editingCell, setEditingCell] = React6.useState(null);
|
|
5367
6108
|
const headerGroups = table.getHeaderGroups();
|
|
5368
6109
|
const rowModel = table.getRowModel();
|
|
5369
|
-
const handleCellDoubleClick =
|
|
6110
|
+
const handleCellDoubleClick = React6.useCallback(
|
|
5370
6111
|
(rowId, columnId, columnDef) => {
|
|
5371
6112
|
if (!enableInlineEdit) return;
|
|
5372
6113
|
if (!columnDef.meta?.entityMeta?.editable) return;
|
|
@@ -5374,7 +6115,7 @@ function DataTable({
|
|
|
5374
6115
|
},
|
|
5375
6116
|
[enableInlineEdit]
|
|
5376
6117
|
);
|
|
5377
|
-
const handleInlineSave =
|
|
6118
|
+
const handleInlineSave = React6.useCallback(
|
|
5378
6119
|
async (row, columnId, value) => {
|
|
5379
6120
|
const field = columnId;
|
|
5380
6121
|
await onInlineSave?.(row.original, field, value);
|
|
@@ -5551,7 +6292,7 @@ function GalleryView({
|
|
|
5551
6292
|
galleryColumns,
|
|
5552
6293
|
className
|
|
5553
6294
|
}) {
|
|
5554
|
-
const [editingId, setEditingId] =
|
|
6295
|
+
const [editingId, setEditingId] = React6.useState(null);
|
|
5555
6296
|
const breakpointClasses = galleryColumns ? buildBreakpointClasses(galleryColumns) : "";
|
|
5556
6297
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5557
6298
|
"div",
|
|
@@ -5615,7 +6356,7 @@ function GalleryCard({
|
|
|
5615
6356
|
(s) => selectionStore ? s.isMultiSelectMode : false
|
|
5616
6357
|
);
|
|
5617
6358
|
const storeToggle = useSelectionStore(selStore, (s) => s.toggle);
|
|
5618
|
-
const toggle =
|
|
6359
|
+
const toggle = React6.useCallback(
|
|
5619
6360
|
(id) => {
|
|
5620
6361
|
if (selectionStore) storeToggle(id);
|
|
5621
6362
|
},
|
|
@@ -5776,7 +6517,7 @@ function ListView({
|
|
|
5776
6517
|
getRowId,
|
|
5777
6518
|
className
|
|
5778
6519
|
}) {
|
|
5779
|
-
const [editingId, setEditingId] =
|
|
6520
|
+
const [editingId, setEditingId] = React6.useState(null);
|
|
5780
6521
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("divide-y rounded-md border", className), children: rows.map((row) => {
|
|
5781
6522
|
const id = getRowId?.(row.original) ?? row.id;
|
|
5782
6523
|
const isEditing = editingId === id;
|
|
@@ -5829,7 +6570,7 @@ function ListItem({
|
|
|
5829
6570
|
(s) => selectionStore ? s.isMultiSelectMode : false
|
|
5830
6571
|
);
|
|
5831
6572
|
const storeToggle = useSelectionStore(selStore, (s) => s.toggle);
|
|
5832
|
-
const toggle =
|
|
6573
|
+
const toggle = React6.useCallback(
|
|
5833
6574
|
(id) => {
|
|
5834
6575
|
if (selectionStore) storeToggle(id);
|
|
5835
6576
|
},
|
|
@@ -6023,7 +6764,7 @@ function DataTableToolbar({
|
|
|
6023
6764
|
className,
|
|
6024
6765
|
children
|
|
6025
6766
|
}) {
|
|
6026
|
-
const [colVisOpen, setColVisOpen] =
|
|
6767
|
+
const [colVisOpen, setColVisOpen] = React6.useState(false);
|
|
6027
6768
|
const globalFilter = table.getState().globalFilter;
|
|
6028
6769
|
const columnFilters = table.getState().columnFilters;
|
|
6029
6770
|
const hasFilters = columnFilters.length > 0;
|
|
@@ -6191,7 +6932,7 @@ function DataTablePagination({
|
|
|
6191
6932
|
totalCount,
|
|
6192
6933
|
className
|
|
6193
6934
|
}) {
|
|
6194
|
-
const pageSizeId =
|
|
6935
|
+
const pageSizeId = React6.useId();
|
|
6195
6936
|
if (mode === "none") return null;
|
|
6196
6937
|
const state = table.getState();
|
|
6197
6938
|
const count = totalCount ?? table.getPrePaginationRowModel().rows.length;
|
|
@@ -6340,7 +7081,7 @@ function ChevronsRightIcon({ className }) {
|
|
|
6340
7081
|
] });
|
|
6341
7082
|
}
|
|
6342
7083
|
function EmptyState({ config, isFiltered = false, className }) {
|
|
6343
|
-
if (
|
|
7084
|
+
if (React6__default.default.isValidElement(config)) {
|
|
6344
7085
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: config });
|
|
6345
7086
|
}
|
|
6346
7087
|
const cfg = config ?? {};
|
|
@@ -6390,7 +7131,7 @@ function MultiSelectBar({
|
|
|
6390
7131
|
}) {
|
|
6391
7132
|
const selectedIdsSet = useSelectionStore(store, (s) => s.selectedIds);
|
|
6392
7133
|
const selectedCount = selectedIdsSet.size;
|
|
6393
|
-
const selectedIds =
|
|
7134
|
+
const selectedIds = React6.useMemo(() => Array.from(selectedIdsSet), [selectedIdsSet]);
|
|
6394
7135
|
const deselectAll = useSelectionStore(store, (s) => s.deselectAll);
|
|
6395
7136
|
useSelectionStore(store, (s) => s.selectAll);
|
|
6396
7137
|
if (selectedCount === 0) return null;
|
|
@@ -6468,11 +7209,11 @@ function PresetPicker({
|
|
|
6468
7209
|
pendingChangesCount = 0,
|
|
6469
7210
|
className
|
|
6470
7211
|
}) {
|
|
6471
|
-
const [isOpen, setIsOpen] =
|
|
6472
|
-
const [activeTab, setActiveTab] =
|
|
6473
|
-
const popoverRef =
|
|
6474
|
-
const triggerRef =
|
|
6475
|
-
|
|
7212
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
7213
|
+
const [activeTab, setActiveTab] = React6.useState("filters");
|
|
7214
|
+
const popoverRef = React6.useRef(null);
|
|
7215
|
+
const triggerRef = React6.useRef(null);
|
|
7216
|
+
React6.useEffect(() => {
|
|
6476
7217
|
function handleClick(e) {
|
|
6477
7218
|
if (popoverRef.current && !popoverRef.current.contains(e.target) && !triggerRef.current?.contains(e.target)) {
|
|
6478
7219
|
setIsOpen(false);
|
|
@@ -6643,7 +7384,7 @@ function PresetItem({
|
|
|
6643
7384
|
onEdit,
|
|
6644
7385
|
onDelete
|
|
6645
7386
|
}) {
|
|
6646
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
7387
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = React6.useState(false);
|
|
6647
7388
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6648
7389
|
"div",
|
|
6649
7390
|
{
|
|
@@ -6755,13 +7496,13 @@ function FilterPresetDialog({
|
|
|
6755
7496
|
preset,
|
|
6756
7497
|
onSave
|
|
6757
7498
|
}) {
|
|
6758
|
-
const nameId =
|
|
6759
|
-
const descriptionId =
|
|
6760
|
-
const [name, setName] =
|
|
6761
|
-
const [description, setDescription] =
|
|
6762
|
-
const [isDefault, setIsDefault] =
|
|
6763
|
-
const [logic, setLogic] =
|
|
6764
|
-
const [clauses, setClauses] =
|
|
7499
|
+
const nameId = React6.useId();
|
|
7500
|
+
const descriptionId = React6.useId();
|
|
7501
|
+
const [name, setName] = React6.useState(preset?.name ?? "");
|
|
7502
|
+
const [description, setDescription] = React6.useState(preset?.description ?? "");
|
|
7503
|
+
const [isDefault, setIsDefault] = React6.useState(preset?.isDefault ?? false);
|
|
7504
|
+
const [logic, setLogic] = React6.useState("and");
|
|
7505
|
+
const [clauses, setClauses] = React6.useState(() => {
|
|
6765
7506
|
if (!preset?.filter) return [];
|
|
6766
7507
|
const filterSpec = preset.filter;
|
|
6767
7508
|
const rawClauses = Array.isArray(filterSpec) ? filterSpec : filterSpec.clauses ?? [];
|
|
@@ -7004,10 +7745,10 @@ function ColumnPresetDialog({
|
|
|
7004
7745
|
preset,
|
|
7005
7746
|
onSave
|
|
7006
7747
|
}) {
|
|
7007
|
-
const [name, setName] =
|
|
7008
|
-
const [description, setDescription] =
|
|
7009
|
-
const [isDefault, setIsDefault] =
|
|
7010
|
-
const [entries, setEntries] =
|
|
7748
|
+
const [name, setName] = React6.useState(preset?.name ?? "");
|
|
7749
|
+
const [description, setDescription] = React6.useState(preset?.description ?? "");
|
|
7750
|
+
const [isDefault, setIsDefault] = React6.useState(preset?.isDefault ?? false);
|
|
7751
|
+
const [entries, setEntries] = React6.useState(() => {
|
|
7011
7752
|
if (preset?.columns) return [...preset.columns];
|
|
7012
7753
|
return columns.map((col, idx) => ({
|
|
7013
7754
|
id: col.accessorKey ?? col.id ?? `col_${idx}`,
|
|
@@ -7017,7 +7758,7 @@ function ColumnPresetDialog({
|
|
|
7017
7758
|
pinned: false
|
|
7018
7759
|
}));
|
|
7019
7760
|
});
|
|
7020
|
-
const [dragIdx, setDragIdx] =
|
|
7761
|
+
const [dragIdx, setDragIdx] = React6.useState(null);
|
|
7021
7762
|
function updateEntry(id, updates) {
|
|
7022
7763
|
setEntries(
|
|
7023
7764
|
(prev) => prev.map((e) => e.id === id ? { ...e, ...updates } : e)
|
|
@@ -7290,15 +8031,15 @@ function EntityListView(props) {
|
|
|
7290
8031
|
onRefresh,
|
|
7291
8032
|
className
|
|
7292
8033
|
} = props;
|
|
7293
|
-
const data =
|
|
8034
|
+
const data = React6.useMemo(
|
|
7294
8035
|
() => viewResult?.items ?? dataProp ?? [],
|
|
7295
8036
|
[viewResult?.items, dataProp]
|
|
7296
8037
|
);
|
|
7297
|
-
const selectionStoreRef =
|
|
8038
|
+
const selectionStoreRef = React6.useRef(null);
|
|
7298
8039
|
if (!selectionStoreRef.current) {
|
|
7299
8040
|
selectionStoreRef.current = createSelectionStore();
|
|
7300
8041
|
}
|
|
7301
|
-
const [viewMode, setViewMode] =
|
|
8042
|
+
const [viewMode, setViewMode] = React6.useState(defaultViewMode);
|
|
7302
8043
|
const adapter = useTableStorageAdapter();
|
|
7303
8044
|
const realtimeMode = useTableRealtimeMode();
|
|
7304
8045
|
const presets = useTablePresets(tableId ?? "__no_table_id__", {
|
|
@@ -7306,10 +8047,10 @@ function EntityListView(props) {
|
|
|
7306
8047
|
realtimeMode,
|
|
7307
8048
|
enabled: enablePresets && !!tableId
|
|
7308
8049
|
});
|
|
7309
|
-
const [filterDialogOpen, setFilterDialogOpen] =
|
|
7310
|
-
const [columnDialogOpen, setColumnDialogOpen] =
|
|
7311
|
-
const [editingFilterPreset, setEditingFilterPreset] =
|
|
7312
|
-
const [editingColumnPreset, setEditingColumnPreset] =
|
|
8050
|
+
const [filterDialogOpen, setFilterDialogOpen] = React6.useState(false);
|
|
8051
|
+
const [columnDialogOpen, setColumnDialogOpen] = React6.useState(false);
|
|
8052
|
+
const [editingFilterPreset, setEditingFilterPreset] = React6.useState(null);
|
|
8053
|
+
const [editingColumnPreset, setEditingColumnPreset] = React6.useState(null);
|
|
7313
8054
|
const table = useTable({
|
|
7314
8055
|
data,
|
|
7315
8056
|
columns,
|
|
@@ -7330,7 +8071,7 @@ function EntityListView(props) {
|
|
|
7330
8071
|
const prePagRows = table.getPrePaginationRowModel();
|
|
7331
8072
|
const isEmpty = data.length === 0;
|
|
7332
8073
|
const isFilteredEmpty = !isEmpty && prePagRows.rows.length === 0;
|
|
7333
|
-
const handleViewModeChange =
|
|
8074
|
+
const handleViewModeChange = React6.useCallback(
|
|
7334
8075
|
(mode) => {
|
|
7335
8076
|
setViewMode(mode);
|
|
7336
8077
|
if (enablePresets && tableId) {
|
|
@@ -7339,19 +8080,19 @@ function EntityListView(props) {
|
|
|
7339
8080
|
},
|
|
7340
8081
|
[enablePresets, tableId, presets]
|
|
7341
8082
|
);
|
|
7342
|
-
const handleInlineSaveTable =
|
|
8083
|
+
const handleInlineSaveTable = React6.useCallback(
|
|
7343
8084
|
(item, field, value) => {
|
|
7344
8085
|
onInlineEdit?.(item, field, value);
|
|
7345
8086
|
},
|
|
7346
8087
|
[onInlineEdit]
|
|
7347
8088
|
);
|
|
7348
|
-
const handleInlineSaveItem =
|
|
8089
|
+
const handleInlineSaveItem = React6.useCallback(
|
|
7349
8090
|
(item, changes) => {
|
|
7350
8091
|
onInlineSave?.(item, changes);
|
|
7351
8092
|
},
|
|
7352
8093
|
[onInlineSave]
|
|
7353
8094
|
);
|
|
7354
|
-
const handleBatchAction =
|
|
8095
|
+
const handleBatchAction = React6.useCallback(
|
|
7355
8096
|
(actionId, selectedIds) => {
|
|
7356
8097
|
if (!onBatchAction) return;
|
|
7357
8098
|
const selectedItems = data.filter((item) => {
|
|
@@ -7500,12 +8241,12 @@ function DataTableFilter({
|
|
|
7500
8241
|
column,
|
|
7501
8242
|
className
|
|
7502
8243
|
}) {
|
|
7503
|
-
const [isOpen, setIsOpen] =
|
|
7504
|
-
const popoverRef =
|
|
7505
|
-
const triggerRef =
|
|
8244
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
8245
|
+
const popoverRef = React6.useRef(null);
|
|
8246
|
+
const triggerRef = React6.useRef(null);
|
|
7506
8247
|
const filterType = column.columnDef.meta?.entityMeta?.filterType ?? "text";
|
|
7507
8248
|
const isFiltered = column.getIsFiltered();
|
|
7508
|
-
|
|
8249
|
+
React6.useEffect(() => {
|
|
7509
8250
|
function handleClick(e) {
|
|
7510
8251
|
if (popoverRef.current && !popoverRef.current.contains(e.target) && !triggerRef.current?.contains(e.target)) {
|
|
7511
8252
|
setIsOpen(false);
|
|
@@ -7563,7 +8304,7 @@ function FilterControl({
|
|
|
7563
8304
|
}
|
|
7564
8305
|
}
|
|
7565
8306
|
function TextFilter({ column }) {
|
|
7566
|
-
const id =
|
|
8307
|
+
const id = React6.useId();
|
|
7567
8308
|
const value = column.getFilterValue() ?? "";
|
|
7568
8309
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7569
8310
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "text-xs font-medium", children: "Contains" }),
|
|
@@ -7590,8 +8331,8 @@ function TextFilter({ column }) {
|
|
|
7590
8331
|
] });
|
|
7591
8332
|
}
|
|
7592
8333
|
function NumberFilter({ column }) {
|
|
7593
|
-
const minId =
|
|
7594
|
-
const maxId =
|
|
8334
|
+
const minId = React6.useId();
|
|
8335
|
+
const maxId = React6.useId();
|
|
7595
8336
|
const value = column.getFilterValue() ?? [void 0, void 0];
|
|
7596
8337
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7597
8338
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: "Range" }),
|
|
@@ -7695,8 +8436,8 @@ function EnumFilter({ column }) {
|
|
|
7695
8436
|
] });
|
|
7696
8437
|
}
|
|
7697
8438
|
function DateFilter({ column }) {
|
|
7698
|
-
const startId =
|
|
7699
|
-
const endId =
|
|
8439
|
+
const startId = React6.useId();
|
|
8440
|
+
const endId = React6.useId();
|
|
7700
8441
|
const value = column.getFilterValue() ?? [void 0, void 0];
|
|
7701
8442
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7702
8443
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: "Date range" }),
|
|
@@ -7740,13 +8481,13 @@ function selectionColumn2() {
|
|
|
7740
8481
|
enableFiltering: false,
|
|
7741
8482
|
enableHiding: false,
|
|
7742
8483
|
enableResizing: false,
|
|
7743
|
-
header: ({ table }) =>
|
|
8484
|
+
header: ({ table }) => React6__default.default.createElement("input", {
|
|
7744
8485
|
type: "checkbox",
|
|
7745
8486
|
checked: table.getIsAllPageRowsSelected(),
|
|
7746
8487
|
onChange: table.getToggleAllPageRowsSelectedHandler(),
|
|
7747
8488
|
className: "h-4 w-4 rounded border-primary text-primary focus:ring-ring"
|
|
7748
8489
|
}),
|
|
7749
|
-
cell: ({ row }) =>
|
|
8490
|
+
cell: ({ row }) => React6__default.default.createElement("input", {
|
|
7750
8491
|
type: "checkbox",
|
|
7751
8492
|
checked: row.getIsSelected(),
|
|
7752
8493
|
onChange: row.getToggleSelectedHandler(),
|
|
@@ -7882,7 +8623,7 @@ function enumColumn2(options) {
|
|
|
7882
8623
|
const opt = options.options.find((o) => o.value === val);
|
|
7883
8624
|
if (!opt) return val;
|
|
7884
8625
|
if (opt.badgeClassName) {
|
|
7885
|
-
return
|
|
8626
|
+
return React6__default.default.createElement(
|
|
7886
8627
|
"span",
|
|
7887
8628
|
{
|
|
7888
8629
|
className: `inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium capitalize ${opt.badgeClassName}`
|
|
@@ -7890,7 +8631,7 @@ function enumColumn2(options) {
|
|
|
7890
8631
|
opt.label
|
|
7891
8632
|
);
|
|
7892
8633
|
}
|
|
7893
|
-
return
|
|
8634
|
+
return React6__default.default.createElement(
|
|
7894
8635
|
"span",
|
|
7895
8636
|
{
|
|
7896
8637
|
className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
@@ -7947,6 +8688,8 @@ exports.GalleryView = GalleryView;
|
|
|
7947
8688
|
exports.InlineCellEditor = InlineCellEditor;
|
|
7948
8689
|
exports.InlineItemEditor = InlineItemEditor;
|
|
7949
8690
|
exports.ListView = ListView;
|
|
8691
|
+
exports.MarkdownFieldEditor = MarkdownFieldEditor;
|
|
8692
|
+
exports.MarkdownFieldRenderer = MarkdownFieldRenderer;
|
|
7950
8693
|
exports.MemoryAdapter = MemoryAdapter;
|
|
7951
8694
|
exports.MultiSelectBar = MultiSelectBar;
|
|
7952
8695
|
exports.PresetPicker = PresetPicker;
|
|
@@ -7971,6 +8714,7 @@ exports.ZustandPersistAdapter = ZustandPersistAdapter;
|
|
|
7971
8714
|
exports.actionsColumn = actionsColumn;
|
|
7972
8715
|
exports.applyView = applyView;
|
|
7973
8716
|
exports.booleanColumn = booleanColumn;
|
|
8717
|
+
exports.buildEntityFieldsFromSchema = buildEntityFieldsFromSchema;
|
|
7974
8718
|
exports.cascadeInvalidation = cascadeInvalidation;
|
|
7975
8719
|
exports.checkCompleteness = checkCompleteness;
|
|
7976
8720
|
exports.compareEntities = compareEntities;
|
|
@@ -7978,10 +8722,15 @@ exports.configureEngine = configureEngine;
|
|
|
7978
8722
|
exports.createConvexAdapter = createConvexAdapter;
|
|
7979
8723
|
exports.createElectricAdapter = createElectricAdapter;
|
|
7980
8724
|
exports.createGQLClient = createGQLClient;
|
|
8725
|
+
exports.createGraphAction = createGraphAction;
|
|
8726
|
+
exports.createGraphEffect = createGraphEffect;
|
|
7981
8727
|
exports.createGraphQLSubscriptionAdapter = createGraphQLSubscriptionAdapter;
|
|
8728
|
+
exports.createGraphTool = createGraphTool;
|
|
8729
|
+
exports.createGraphTransaction = createGraphTransaction;
|
|
7982
8730
|
exports.createPresetStore = createPresetStore;
|
|
7983
8731
|
exports.createPrismaEntityConfig = createPrismaEntityConfig;
|
|
7984
8732
|
exports.createRow = createRow;
|
|
8733
|
+
exports.createSchemaGraphTool = createSchemaGraphTool;
|
|
7985
8734
|
exports.createSelectionStore = createSelectionStore;
|
|
7986
8735
|
exports.createSupabaseRealtimeAdapter = createSupabaseRealtimeAdapter;
|
|
7987
8736
|
exports.createWebSocketAdapter = createWebSocketAdapter;
|
|
@@ -7991,10 +8740,13 @@ exports.deleteAction = deleteAction;
|
|
|
7991
8740
|
exports.editAction = editAction;
|
|
7992
8741
|
exports.enumColumn = enumColumn;
|
|
7993
8742
|
exports.executeGQL = executeGQL;
|
|
8743
|
+
exports.exportGraphSnapshot = exportGraphSnapshot;
|
|
8744
|
+
exports.exportGraphSnapshotWithSchemas = exportGraphSnapshotWithSchemas;
|
|
7994
8745
|
exports.fetchEntity = fetchEntity;
|
|
7995
8746
|
exports.fetchList = fetchList;
|
|
7996
8747
|
exports.flattenClauses = flattenClauses;
|
|
7997
8748
|
exports.getCoreRowModel = getCoreRowModel2;
|
|
8749
|
+
exports.getEntityJsonSchema = getEntityJsonSchema;
|
|
7998
8750
|
exports.getExpandedRowModel = getExpandedRowModel;
|
|
7999
8751
|
exports.getFacetedMinMaxValues = getFacetedMinMaxValues;
|
|
8000
8752
|
exports.getFacetedRowModel = getFacetedRowModel;
|
|
@@ -8007,10 +8759,12 @@ exports.getSchema = getSchema;
|
|
|
8007
8759
|
exports.getSelectedRowModel = getSelectedRowModel;
|
|
8008
8760
|
exports.getSortedRowModel = getSortedRowModel2;
|
|
8009
8761
|
exports.hasCustomPredicates = hasCustomPredicates;
|
|
8762
|
+
exports.hydrateGraphFromStorage = hydrateGraphFromStorage;
|
|
8010
8763
|
exports.matchesFilter = matchesFilter;
|
|
8011
8764
|
exports.matchesSearch = matchesSearch;
|
|
8012
8765
|
exports.normalizeGQLResponse = normalizeGQLResponse;
|
|
8013
8766
|
exports.numberColumn = numberColumn;
|
|
8767
|
+
exports.persistGraphToStorage = persistGraphToStorage;
|
|
8014
8768
|
exports.prismaRelationsToSchema = prismaRelationsToSchema;
|
|
8015
8769
|
exports.pureActionsColumn = actionsColumn2;
|
|
8016
8770
|
exports.pureBooleanColumn = booleanColumn2;
|
|
@@ -8019,12 +8773,18 @@ exports.pureEnumColumn = enumColumn2;
|
|
|
8019
8773
|
exports.pureNumberColumn = numberColumn2;
|
|
8020
8774
|
exports.pureSelectionColumn = selectionColumn2;
|
|
8021
8775
|
exports.pureTextColumn = textColumn2;
|
|
8776
|
+
exports.queryOnce = queryOnce;
|
|
8022
8777
|
exports.readRelations = readRelations;
|
|
8778
|
+
exports.registerEntityJsonSchema = registerEntityJsonSchema;
|
|
8779
|
+
exports.registerRuntimeSchema = registerRuntimeSchema;
|
|
8023
8780
|
exports.registerSchema = registerSchema;
|
|
8781
|
+
exports.renderMarkdownToHtml = renderMarkdownToHtml;
|
|
8024
8782
|
exports.resetRealtimeManager = resetRealtimeManager;
|
|
8783
|
+
exports.selectGraph = selectGraph;
|
|
8025
8784
|
exports.selectionColumn = selectionColumn;
|
|
8026
8785
|
exports.serializeKey = serializeKey;
|
|
8027
8786
|
exports.startGarbageCollector = startGarbageCollector;
|
|
8787
|
+
exports.startLocalFirstGraph = startLocalFirstGraph;
|
|
8028
8788
|
exports.stopGarbageCollector = stopGarbageCollector;
|
|
8029
8789
|
exports.textColumn = textColumn;
|
|
8030
8790
|
exports.toGraphQLVariables = toGraphQLVariables;
|
|
@@ -8045,8 +8805,10 @@ exports.useGQLMutation = useGQLMutation;
|
|
|
8045
8805
|
exports.useGQLSubscription = useGQLSubscription;
|
|
8046
8806
|
exports.useGraphDevTools = useGraphDevTools;
|
|
8047
8807
|
exports.useGraphStore = useGraphStore;
|
|
8808
|
+
exports.useGraphSyncStatus = useGraphSyncStatus;
|
|
8048
8809
|
exports.useLocalFirst = useLocalFirst;
|
|
8049
8810
|
exports.usePGliteQuery = usePGliteQuery;
|
|
8811
|
+
exports.useSchemaEntityFields = useSchemaEntityFields;
|
|
8050
8812
|
exports.useSelectionContext = useSelectionContext;
|
|
8051
8813
|
exports.useSelectionStore = useSelectionStore;
|
|
8052
8814
|
exports.useSuspenseEntity = useSuspenseEntity;
|