@prometheus-ags/prometheus-entity-management 1.1.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 +19 -0
- package/README.md +25 -1
- package/dist/index.d.mts +588 -419
- package/dist/index.d.ts +588 -419
- package/dist/index.js +770 -281
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +512 -37
- 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 = [];
|
|
@@ -294,6 +294,8 @@ function applySelection(row, select) {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// src/graph-actions.ts
|
|
297
|
+
var graphActionListeners = /* @__PURE__ */ new Set();
|
|
298
|
+
var graphActionReplayers = /* @__PURE__ */ new Map();
|
|
297
299
|
function createGraphTransaction() {
|
|
298
300
|
const baseline = cloneGraphData();
|
|
299
301
|
let closed = false;
|
|
@@ -361,22 +363,53 @@ function createGraphTransaction() {
|
|
|
361
363
|
return tx;
|
|
362
364
|
}
|
|
363
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
|
+
}
|
|
364
379
|
return async (input) => {
|
|
365
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;
|
|
366
387
|
try {
|
|
388
|
+
if (record) emitGraphActionEvent({ type: "enqueued", record });
|
|
367
389
|
opts.optimistic?.(tx, input);
|
|
368
390
|
const result = await opts.run(tx, input);
|
|
369
391
|
opts.onSuccess?.(result, input, tx);
|
|
370
392
|
tx.commit();
|
|
393
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
371
394
|
return result;
|
|
372
395
|
} catch (error) {
|
|
373
396
|
tx.rollback();
|
|
374
397
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
398
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
375
399
|
opts.onError?.(normalized, input);
|
|
376
400
|
throw normalized;
|
|
377
401
|
}
|
|
378
402
|
};
|
|
379
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
|
+
}
|
|
380
413
|
function cloneGraphData(source = useGraphStore.getState()) {
|
|
381
414
|
return {
|
|
382
415
|
entities: structuredClone(source.entities),
|
|
@@ -386,6 +419,9 @@ function cloneGraphData(source = useGraphStore.getState()) {
|
|
|
386
419
|
lists: structuredClone(source.lists)
|
|
387
420
|
};
|
|
388
421
|
}
|
|
422
|
+
function emitGraphActionEvent(event) {
|
|
423
|
+
for (const listener of graphActionListeners) listener(event);
|
|
424
|
+
}
|
|
389
425
|
|
|
390
426
|
// src/graph-effects.ts
|
|
391
427
|
function createGraphEffect(opts) {
|
|
@@ -445,6 +481,213 @@ function defaultIsEqual(previousValue, nextValue) {
|
|
|
445
481
|
return JSON.stringify(previousValue) === JSON.stringify(nextValue);
|
|
446
482
|
}
|
|
447
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
|
+
|
|
448
691
|
// src/ai-interop.ts
|
|
449
692
|
function exportGraphSnapshot(opts) {
|
|
450
693
|
const payload = {
|
|
@@ -461,6 +704,216 @@ function createGraphTool(handler) {
|
|
|
461
704
|
exportGraphSnapshot
|
|
462
705
|
});
|
|
463
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
|
+
}
|
|
464
917
|
|
|
465
918
|
// src/engine.ts
|
|
466
919
|
function serializeKey(key) {
|
|
@@ -698,7 +1151,7 @@ function subscriberCountServerSnapshot() {
|
|
|
698
1151
|
return 0;
|
|
699
1152
|
}
|
|
700
1153
|
function useGraphDevTools() {
|
|
701
|
-
const subscriberCount =
|
|
1154
|
+
const subscriberCount = React6.useSyncExternalStore(
|
|
702
1155
|
subscribeSubscriberStats,
|
|
703
1156
|
getActiveSubscriberCount,
|
|
704
1157
|
subscriberCountServerSnapshot
|
|
@@ -707,7 +1160,7 @@ function useGraphDevTools() {
|
|
|
707
1160
|
const patches = zustand.useStore(useGraphStore, (state) => state.patches);
|
|
708
1161
|
const entityStates = zustand.useStore(useGraphStore, (state) => state.entityStates);
|
|
709
1162
|
const listsState = zustand.useStore(useGraphStore, (state) => state.lists);
|
|
710
|
-
const graphPart =
|
|
1163
|
+
const graphPart = React6.useMemo(
|
|
711
1164
|
() => collectGraphDevStats(entities, patches, entityStates, listsState),
|
|
712
1165
|
[entities, patches, entityStates, listsState]
|
|
713
1166
|
);
|
|
@@ -723,23 +1176,23 @@ function ensureListeners() {
|
|
|
723
1176
|
function useEntity(opts) {
|
|
724
1177
|
const { type, id, staleTime = getEngineOptions().defaultStaleTime, enabled = true } = opts;
|
|
725
1178
|
ensureListeners();
|
|
726
|
-
const fetchRef =
|
|
1179
|
+
const fetchRef = React6.useRef(opts.fetch);
|
|
727
1180
|
fetchRef.current = opts.fetch;
|
|
728
|
-
const normalizeRef =
|
|
1181
|
+
const normalizeRef = React6.useRef(opts.normalize);
|
|
729
1182
|
normalizeRef.current = opts.normalize;
|
|
730
1183
|
const data = zustand.useStore(useGraphStore, shallow.useShallow((state) => {
|
|
731
1184
|
if (!id) return null;
|
|
732
1185
|
return state.readEntitySnapshot(type, id);
|
|
733
1186
|
}));
|
|
734
|
-
const entityState = zustand.useStore(useGraphStore,
|
|
1187
|
+
const entityState = zustand.useStore(useGraphStore, React6.useCallback(
|
|
735
1188
|
(state) => state.entityStates[`${type}:${id}`] ?? EMPTY_ENTITY_STATE,
|
|
736
1189
|
[type, id]
|
|
737
1190
|
));
|
|
738
|
-
const doFetch =
|
|
1191
|
+
const doFetch = React6.useCallback(() => {
|
|
739
1192
|
if (!id || !enabled) return;
|
|
740
1193
|
fetchEntity({ type, id, fetch: fetchRef.current, normalize: normalizeRef.current }, getEngineOptions());
|
|
741
1194
|
}, [id, enabled, type]);
|
|
742
|
-
|
|
1195
|
+
React6.useEffect(() => {
|
|
743
1196
|
if (!id || !enabled) return;
|
|
744
1197
|
const token = registerSubscriber(`${type}:${id}`);
|
|
745
1198
|
const state = useGraphStore.getState();
|
|
@@ -749,7 +1202,7 @@ function useEntity(opts) {
|
|
|
749
1202
|
if (!hasData || isStale) doFetch();
|
|
750
1203
|
return () => unregisterSubscriber(`${type}:${id}`, token);
|
|
751
1204
|
}, [id, type, enabled, staleTime, doFetch]);
|
|
752
|
-
|
|
1205
|
+
React6.useEffect(() => {
|
|
753
1206
|
if (entityState.stale && id && enabled && !entityState.isFetching) doFetch();
|
|
754
1207
|
}, [entityState.stale, id, enabled, entityState.isFetching, doFetch]);
|
|
755
1208
|
return { data, isLoading: !data && entityState.isFetching, isFetching: entityState.isFetching, error: entityState.error, isStale: entityState.stale, refetch: doFetch };
|
|
@@ -757,12 +1210,12 @@ function useEntity(opts) {
|
|
|
757
1210
|
function useEntityList(opts) {
|
|
758
1211
|
const { type, queryKey, staleTime = getEngineOptions().defaultStaleTime, enabled = true, mode = "replace" } = opts;
|
|
759
1212
|
ensureListeners();
|
|
760
|
-
const key =
|
|
761
|
-
const fetchRef =
|
|
1213
|
+
const key = React6.useMemo(() => serializeKey(queryKey), [queryKey]);
|
|
1214
|
+
const fetchRef = React6.useRef(opts.fetch);
|
|
762
1215
|
fetchRef.current = opts.fetch;
|
|
763
|
-
const normalizeRef =
|
|
1216
|
+
const normalizeRef = React6.useRef(opts.normalize);
|
|
764
1217
|
normalizeRef.current = opts.normalize;
|
|
765
|
-
const listState = zustand.useStore(useGraphStore,
|
|
1218
|
+
const listState = zustand.useStore(useGraphStore, React6.useCallback((state) => state.lists[key] ?? EMPTY_LIST_STATE, [key]));
|
|
766
1219
|
const items = zustand.useStore(
|
|
767
1220
|
useGraphStore,
|
|
768
1221
|
shallow.useShallow((state) => {
|
|
@@ -770,31 +1223,31 @@ function useEntityList(opts) {
|
|
|
770
1223
|
return ids.map((id) => state.readEntitySnapshot(type, id)).filter((x) => x !== null);
|
|
771
1224
|
})
|
|
772
1225
|
);
|
|
773
|
-
const doFetch =
|
|
1226
|
+
const doFetch = React6.useCallback((params = {}) => {
|
|
774
1227
|
if (!enabled) return;
|
|
775
1228
|
fetchList({ type, queryKey, mode, fetch: fetchRef.current, normalize: normalizeRef.current }, params, getEngineOptions(), false);
|
|
776
1229
|
}, [enabled, type, queryKey, mode]);
|
|
777
|
-
const fetchNextPage =
|
|
1230
|
+
const fetchNextPage = React6.useCallback(() => {
|
|
778
1231
|
if (!listState.hasNextPage || listState.isFetchingMore || !enabled) return;
|
|
779
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);
|
|
780
1233
|
}, [listState.hasNextPage, listState.isFetchingMore, listState.nextCursor, listState.currentPage, listState.pageSize, enabled, type, queryKey, mode]);
|
|
781
|
-
|
|
1234
|
+
React6.useEffect(() => {
|
|
782
1235
|
if (!enabled) return;
|
|
783
1236
|
const state = useGraphStore.getState();
|
|
784
1237
|
const existing = state.lists[key];
|
|
785
1238
|
const isStale = !existing?.lastFetched || existing.stale || Date.now() - (existing.lastFetched ?? 0) > staleTime;
|
|
786
1239
|
if (!existing || isStale) doFetch({ page: 1, pageSize: listState.pageSize ?? void 0 });
|
|
787
1240
|
}, [key, enabled, staleTime, doFetch, listState.pageSize]);
|
|
788
|
-
|
|
1241
|
+
React6.useEffect(() => {
|
|
789
1242
|
if (listState.stale && enabled && !listState.isFetching) doFetch();
|
|
790
1243
|
}, [listState.stale, enabled, listState.isFetching, doFetch]);
|
|
791
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 };
|
|
792
1245
|
}
|
|
793
1246
|
function useEntityMutation(opts) {
|
|
794
|
-
const [state, setState] =
|
|
795
|
-
const optsRef =
|
|
1247
|
+
const [state, setState] = React6.useState({ isPending: false, isSuccess: false, isError: false, error: null });
|
|
1248
|
+
const optsRef = React6.useRef(opts);
|
|
796
1249
|
optsRef.current = opts;
|
|
797
|
-
const mutate =
|
|
1250
|
+
const mutate = React6.useCallback(async (input) => {
|
|
798
1251
|
const { type, mutate: apiFn, normalize, optimistic, invalidateLists, invalidateEntities, onSuccess, onError } = optsRef.current;
|
|
799
1252
|
setState({ isPending: true, isSuccess: false, isError: false, error: null });
|
|
800
1253
|
let rollback = null;
|
|
@@ -841,23 +1294,23 @@ function useEntityMutation(opts) {
|
|
|
841
1294
|
return null;
|
|
842
1295
|
}
|
|
843
1296
|
}, []);
|
|
844
|
-
const trigger =
|
|
1297
|
+
const trigger = React6.useCallback((input) => {
|
|
845
1298
|
void mutate(input);
|
|
846
1299
|
}, [mutate]);
|
|
847
|
-
const reset =
|
|
1300
|
+
const reset = React6.useCallback(() => setState({ isPending: false, isSuccess: false, isError: false, error: null }), []);
|
|
848
1301
|
return { mutate, trigger, reset, state };
|
|
849
1302
|
}
|
|
850
1303
|
function useEntityAugment(type, id) {
|
|
851
|
-
const patch = zustand.useStore(useGraphStore,
|
|
852
|
-
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) => {
|
|
853
1306
|
if (!id) return;
|
|
854
1307
|
useGraphStore.getState().patchEntity(type, id, fields);
|
|
855
1308
|
}, [type, id]);
|
|
856
|
-
const unaugment =
|
|
1309
|
+
const unaugment = React6.useCallback((keys) => {
|
|
857
1310
|
if (!id) return;
|
|
858
1311
|
useGraphStore.getState().unpatchEntity(type, id, keys);
|
|
859
1312
|
}, [type, id]);
|
|
860
|
-
const clear =
|
|
1313
|
+
const clear = React6.useCallback(() => {
|
|
861
1314
|
if (!id) return;
|
|
862
1315
|
useGraphStore.getState().clearPatch(type, id);
|
|
863
1316
|
}, [type, id]);
|
|
@@ -950,7 +1403,7 @@ function useSuspenseEntity(opts) {
|
|
|
950
1403
|
};
|
|
951
1404
|
}
|
|
952
1405
|
function useSuspenseEntityList(opts) {
|
|
953
|
-
const key =
|
|
1406
|
+
const key = React6.useMemo(() => serializeKey(opts.queryKey), [opts.queryKey]);
|
|
954
1407
|
const result = useEntityList(opts);
|
|
955
1408
|
if (result.isLoading) throw getListSuspensePromise(key);
|
|
956
1409
|
if (result.error != null && result.items.length === 0) {
|
|
@@ -1288,17 +1741,17 @@ function hasCustomPredicates(filter) {
|
|
|
1288
1741
|
var EMPTY_ENTITY_BUCKET = {};
|
|
1289
1742
|
function useEntityView(opts) {
|
|
1290
1743
|
const { type, baseQueryKey, mode: forcedMode, remoteFetch, remoteDebounce = 300, staleTime = getEngineOptions().defaultStaleTime, enabled = true, initialIds, initialTotal } = opts;
|
|
1291
|
-
const optsRef =
|
|
1744
|
+
const optsRef = React6.useRef(opts);
|
|
1292
1745
|
optsRef.current = opts;
|
|
1293
|
-
const [liveView, setLiveView] =
|
|
1294
|
-
const liveViewRef =
|
|
1746
|
+
const [liveView, setLiveView] = React6.useState(opts.view);
|
|
1747
|
+
const liveViewRef = React6.useRef(liveView);
|
|
1295
1748
|
liveViewRef.current = liveView;
|
|
1296
|
-
const [isRemoteFetching, setIsRemoteFetching] =
|
|
1297
|
-
const [remoteError, setRemoteError] =
|
|
1298
|
-
const [remoteResultKey, setRemoteResultKey] =
|
|
1299
|
-
const debounceTimer =
|
|
1300
|
-
const baseKey =
|
|
1301
|
-
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);
|
|
1302
1755
|
if (!seededRef.current && initialIds && initialIds.length > 0) {
|
|
1303
1756
|
seededRef.current = true;
|
|
1304
1757
|
const store = useGraphStore.getState();
|
|
@@ -1308,14 +1761,14 @@ function useEntityView(opts) {
|
|
|
1308
1761
|
}
|
|
1309
1762
|
const listState = zustand.useStore(
|
|
1310
1763
|
useGraphStore,
|
|
1311
|
-
|
|
1764
|
+
React6.useCallback((state) => state.lists[baseKey] ?? null, [baseKey])
|
|
1312
1765
|
);
|
|
1313
|
-
const remoteListState = zustand.useStore(useGraphStore,
|
|
1314
|
-
const { isComplete } =
|
|
1766
|
+
const remoteListState = zustand.useStore(useGraphStore, React6.useCallback((state) => remoteResultKey ? state.lists[remoteResultKey] ?? null : null, [remoteResultKey]));
|
|
1767
|
+
const { isComplete } = React6.useMemo(() => {
|
|
1315
1768
|
if (!listState) return { isComplete: false };
|
|
1316
1769
|
return checkCompleteness(listState.ids.length, listState.total, listState.hasNextPage);
|
|
1317
1770
|
}, [listState]);
|
|
1318
|
-
const completenessMode =
|
|
1771
|
+
const completenessMode = React6.useMemo(() => {
|
|
1319
1772
|
if (forcedMode) return forcedMode;
|
|
1320
1773
|
if (liveView.filter && hasCustomPredicates(liveView.filter)) return "local";
|
|
1321
1774
|
if (isComplete) return "local";
|
|
@@ -1343,7 +1796,7 @@ function useEntityView(opts) {
|
|
|
1343
1796
|
(state) => localViewIds.map((id) => state.readEntitySnapshot(type, id)).filter((item) => item !== null)
|
|
1344
1797
|
)
|
|
1345
1798
|
);
|
|
1346
|
-
const fireRemoteFetch =
|
|
1799
|
+
const fireRemoteFetch = React6.useCallback(async (view, cursor) => {
|
|
1347
1800
|
const { remoteFetch: rf, normalize: norm, baseQueryKey: bqk } = optsRef.current;
|
|
1348
1801
|
if (!rf) return;
|
|
1349
1802
|
const params = { rest: toRestParams(view), graphql: toGraphQLVariables(view), sql: toSQLClauses(view), view };
|
|
@@ -1367,7 +1820,7 @@ function useEntityView(opts) {
|
|
|
1367
1820
|
setIsRemoteFetching(false);
|
|
1368
1821
|
}
|
|
1369
1822
|
}, [type]);
|
|
1370
|
-
|
|
1823
|
+
React6.useEffect(() => {
|
|
1371
1824
|
if (!enabled || completenessMode === "local" || !remoteFetch) return;
|
|
1372
1825
|
const searchQuery = liveView.search?.query ?? "";
|
|
1373
1826
|
const minChars = liveView.search?.minChars ?? 2;
|
|
@@ -1378,14 +1831,14 @@ function useEntityView(opts) {
|
|
|
1378
1831
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
1379
1832
|
};
|
|
1380
1833
|
}, [liveView, completenessMode, enabled, remoteFetch, remoteDebounce, fireRemoteFetch]);
|
|
1381
|
-
|
|
1834
|
+
React6.useEffect(() => {
|
|
1382
1835
|
if (!enabled) return;
|
|
1383
1836
|
const state = useGraphStore.getState();
|
|
1384
1837
|
const existing = state.lists[baseKey];
|
|
1385
1838
|
const isStale = !existing?.lastFetched || existing.stale || Date.now() - (existing.lastFetched ?? 0) > staleTime;
|
|
1386
1839
|
if (!existing || isStale) fireRemoteFetch(liveViewRef.current);
|
|
1387
1840
|
}, [baseKey, enabled, staleTime, fireRemoteFetch]);
|
|
1388
|
-
|
|
1841
|
+
React6.useEffect(() => {
|
|
1389
1842
|
const unsub = useGraphStore.subscribe((state) => state.entities[type] ?? EMPTY_ENTITY_BUCKET, (newEntities, prevEntities) => {
|
|
1390
1843
|
const view = liveViewRef.current;
|
|
1391
1844
|
const store = useGraphStore.getState();
|
|
@@ -1407,16 +1860,16 @@ function useEntityView(opts) {
|
|
|
1407
1860
|
});
|
|
1408
1861
|
return unsub;
|
|
1409
1862
|
}, [type, baseKey]);
|
|
1410
|
-
const setView =
|
|
1411
|
-
const setFilter =
|
|
1412
|
-
const setSort =
|
|
1413
|
-
const setSearch =
|
|
1414
|
-
const clearView =
|
|
1415
|
-
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(() => {
|
|
1416
1869
|
if (completenessMode === "local" || isRemoteFetching) return;
|
|
1417
1870
|
fireRemoteFetch(liveViewRef.current, remoteListState?.nextCursor ?? void 0);
|
|
1418
1871
|
}, [completenessMode, isRemoteFetching, remoteListState?.nextCursor, fireRemoteFetch]);
|
|
1419
|
-
const refetch =
|
|
1872
|
+
const refetch = React6.useCallback(() => fireRemoteFetch(liveViewRef.current), [fireRemoteFetch]);
|
|
1420
1873
|
const viewTotal = remoteListState?.total ?? (isComplete ? localViewIds.length : listState?.total ?? null);
|
|
1421
1874
|
return {
|
|
1422
1875
|
items,
|
|
@@ -1442,15 +1895,15 @@ function useEntityView(opts) {
|
|
|
1442
1895
|
}
|
|
1443
1896
|
|
|
1444
1897
|
// src/crud/relations.ts
|
|
1445
|
-
var
|
|
1898
|
+
var schemaRegistry2 = /* @__PURE__ */ new Map();
|
|
1446
1899
|
function registerSchema(schema) {
|
|
1447
|
-
|
|
1900
|
+
schemaRegistry2.set(schema.type, schema);
|
|
1448
1901
|
}
|
|
1449
1902
|
function getSchema(type) {
|
|
1450
|
-
return
|
|
1903
|
+
return schemaRegistry2.get(type) ?? null;
|
|
1451
1904
|
}
|
|
1452
1905
|
function cascadeInvalidation(ctx) {
|
|
1453
|
-
const schema =
|
|
1906
|
+
const schema = schemaRegistry2.get(ctx.type);
|
|
1454
1907
|
if (!schema) return;
|
|
1455
1908
|
const store = useGraphStore.getState();
|
|
1456
1909
|
if (schema.globalListKeys) for (const key of schema.globalListKeys) store.invalidateLists(key);
|
|
@@ -1477,7 +1930,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1477
1930
|
}
|
|
1478
1931
|
}
|
|
1479
1932
|
}
|
|
1480
|
-
for (const [, otherSchema] of
|
|
1933
|
+
for (const [, otherSchema] of schemaRegistry2) {
|
|
1481
1934
|
if (!otherSchema.relations) continue;
|
|
1482
1935
|
for (const [, rel] of Object.entries(otherSchema.relations)) {
|
|
1483
1936
|
if (rel.targetType !== ctx.type) continue;
|
|
@@ -1486,7 +1939,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1486
1939
|
}
|
|
1487
1940
|
}
|
|
1488
1941
|
function readRelations(type, entity) {
|
|
1489
|
-
const schema =
|
|
1942
|
+
const schema = schemaRegistry2.get(type);
|
|
1490
1943
|
if (!schema?.relations) return {};
|
|
1491
1944
|
const store = useGraphStore.getState();
|
|
1492
1945
|
const result = {};
|
|
@@ -1516,15 +1969,15 @@ function readRelations(type, entity) {
|
|
|
1516
1969
|
// src/crud/use-entity-crud.ts
|
|
1517
1970
|
function useEntityCRUD(opts) {
|
|
1518
1971
|
const { type, listQueryKey, listFetch, normalize, detailFetch, onCreate, onUpdate, onDelete, createDefaults = {}, initialView = {}, selectAfterCreate = true, clearSelectionAfterDelete = true } = opts;
|
|
1519
|
-
const optsRef =
|
|
1972
|
+
const optsRef = React6.useRef(opts);
|
|
1520
1973
|
optsRef.current = opts;
|
|
1521
|
-
const [mode, setMode] =
|
|
1522
|
-
const [selectedId, setSelectedId] =
|
|
1523
|
-
const select =
|
|
1974
|
+
const [mode, setMode] = React6.useState("list");
|
|
1975
|
+
const [selectedId, setSelectedId] = React6.useState(null);
|
|
1976
|
+
const select = React6.useCallback((id) => {
|
|
1524
1977
|
setSelectedId(id);
|
|
1525
1978
|
setMode(id ? "detail" : "list");
|
|
1526
1979
|
}, []);
|
|
1527
|
-
const openDetail =
|
|
1980
|
+
const openDetail = React6.useCallback((id) => {
|
|
1528
1981
|
setSelectedId(id);
|
|
1529
1982
|
setMode("detail");
|
|
1530
1983
|
}, []);
|
|
@@ -1540,28 +1993,25 @@ function useEntityCRUD(opts) {
|
|
|
1540
1993
|
normalize: (raw) => raw,
|
|
1541
1994
|
enabled: !!selectedId
|
|
1542
1995
|
});
|
|
1543
|
-
const relations =
|
|
1544
|
-
const [editBuffer, setEditBuffer] =
|
|
1545
|
-
const [isSaving, setIsSaving] =
|
|
1546
|
-
const [saveError, setSaveError] =
|
|
1547
|
-
|
|
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(() => {
|
|
1548
2001
|
if (detail) setEditBuffer({ ...detail });
|
|
1549
2002
|
}, [selectedId]);
|
|
1550
|
-
const setField =
|
|
1551
|
-
const setFields =
|
|
1552
|
-
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(() => {
|
|
1553
2006
|
const current = selectedId ? useGraphStore.getState().readEntity(type, selectedId) : null;
|
|
1554
2007
|
setEditBuffer(current ? { ...current } : {});
|
|
1555
2008
|
}, [type, selectedId]);
|
|
1556
|
-
const dirty =
|
|
2009
|
+
const dirty = React6.useMemo(() => {
|
|
1557
2010
|
if (!detail) return { changed: /* @__PURE__ */ new Set(), isDirty: false };
|
|
1558
|
-
const changed =
|
|
1559
|
-
for (const key of Object.keys(editBuffer)) {
|
|
1560
|
-
if (JSON.stringify(editBuffer[key]) !== JSON.stringify(detail[key])) changed.add(key);
|
|
1561
|
-
}
|
|
2011
|
+
const changed = collectDirtyPaths(editBuffer, detail);
|
|
1562
2012
|
return { changed, isDirty: changed.size > 0 };
|
|
1563
2013
|
}, [editBuffer, detail]);
|
|
1564
|
-
const startEdit =
|
|
2014
|
+
const startEdit = React6.useCallback((id) => {
|
|
1565
2015
|
const targetId = id ?? selectedId;
|
|
1566
2016
|
if (targetId) {
|
|
1567
2017
|
setSelectedId(targetId);
|
|
@@ -1570,18 +2020,18 @@ function useEntityCRUD(opts) {
|
|
|
1570
2020
|
}
|
|
1571
2021
|
setMode("edit");
|
|
1572
2022
|
}, [selectedId, type]);
|
|
1573
|
-
const cancelEdit =
|
|
2023
|
+
const cancelEdit = React6.useCallback(() => {
|
|
1574
2024
|
resetBuffer();
|
|
1575
2025
|
setMode(selectedId ? "detail" : "list");
|
|
1576
2026
|
setSaveError(null);
|
|
1577
2027
|
}, [resetBuffer, selectedId]);
|
|
1578
|
-
const applyOptimistic =
|
|
2028
|
+
const applyOptimistic = React6.useCallback(() => {
|
|
1579
2029
|
if (!selectedId) return;
|
|
1580
2030
|
const store = useGraphStore.getState();
|
|
1581
2031
|
store.patchEntity(type, selectedId, editBuffer);
|
|
1582
2032
|
store.setEntitySyncMetadata(type, selectedId, { synced: false, origin: "optimistic", updatedAt: Date.now() });
|
|
1583
2033
|
}, [type, selectedId, editBuffer]);
|
|
1584
|
-
const save =
|
|
2034
|
+
const save = React6.useCallback(async () => {
|
|
1585
2035
|
if (!selectedId || !onUpdate) return null;
|
|
1586
2036
|
setIsSaving(true);
|
|
1587
2037
|
setSaveError(null);
|
|
@@ -1612,23 +2062,23 @@ function useEntityCRUD(opts) {
|
|
|
1612
2062
|
setIsSaving(false);
|
|
1613
2063
|
}
|
|
1614
2064
|
}, [selectedId, type, editBuffer, normalize]);
|
|
1615
|
-
const [createBuffer, setCreateBuffer] =
|
|
1616
|
-
const [isCreating, setIsCreating] =
|
|
1617
|
-
const [createError, setCreateError] =
|
|
1618
|
-
const setCreateField =
|
|
1619
|
-
const setCreateFields =
|
|
1620
|
-
const resetCreateBuffer =
|
|
1621
|
-
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(() => {
|
|
1622
2072
|
resetCreateBuffer();
|
|
1623
2073
|
setCreateError(null);
|
|
1624
2074
|
setMode("create");
|
|
1625
2075
|
}, [resetCreateBuffer]);
|
|
1626
|
-
const cancelCreate =
|
|
2076
|
+
const cancelCreate = React6.useCallback(() => {
|
|
1627
2077
|
resetCreateBuffer();
|
|
1628
2078
|
setMode("list");
|
|
1629
2079
|
setCreateError(null);
|
|
1630
2080
|
}, [resetCreateBuffer]);
|
|
1631
|
-
const
|
|
2081
|
+
const create3 = React6.useCallback(async () => {
|
|
1632
2082
|
if (!onCreate) return null;
|
|
1633
2083
|
setIsCreating(true);
|
|
1634
2084
|
setCreateError(null);
|
|
@@ -1672,9 +2122,9 @@ function useEntityCRUD(opts) {
|
|
|
1672
2122
|
setIsCreating(false);
|
|
1673
2123
|
}
|
|
1674
2124
|
}, [type, createBuffer, normalize, listQueryKey, selectAfterCreate, resetCreateBuffer]);
|
|
1675
|
-
const [isDeleting, setIsDeleting] =
|
|
1676
|
-
const [deleteError, setDeleteError] =
|
|
1677
|
-
const deleteEntity =
|
|
2125
|
+
const [isDeleting, setIsDeleting] = React6.useState(false);
|
|
2126
|
+
const [deleteError, setDeleteError] = React6.useState(null);
|
|
2127
|
+
const deleteEntity = React6.useCallback(async (id) => {
|
|
1678
2128
|
const targetId = id ?? selectedId;
|
|
1679
2129
|
if (!targetId || !onDelete) return;
|
|
1680
2130
|
setIsDeleting(true);
|
|
@@ -1702,7 +2152,7 @@ function useEntityCRUD(opts) {
|
|
|
1702
2152
|
setIsDeleting(false);
|
|
1703
2153
|
}
|
|
1704
2154
|
}, [type, selectedId, listQueryKey, clearSelectionAfterDelete]);
|
|
1705
|
-
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" };
|
|
1706
2156
|
}
|
|
1707
2157
|
|
|
1708
2158
|
// src/adapters/realtime-manager.ts
|
|
@@ -2333,8 +2783,8 @@ function createElectricAdapter(opts) {
|
|
|
2333
2783
|
};
|
|
2334
2784
|
}
|
|
2335
2785
|
function useLocalFirst(adapter) {
|
|
2336
|
-
const [isSynced, setIsSynced] =
|
|
2337
|
-
|
|
2786
|
+
const [isSynced, setIsSynced] = React6.useState(adapter.isSynced());
|
|
2787
|
+
React6.useEffect(() => {
|
|
2338
2788
|
const u1 = adapter.onSyncComplete(() => setIsSynced(true));
|
|
2339
2789
|
const u2 = getRealtimeManager().register(adapter, []);
|
|
2340
2790
|
return () => {
|
|
@@ -2342,15 +2792,15 @@ function useLocalFirst(adapter) {
|
|
|
2342
2792
|
u2();
|
|
2343
2793
|
};
|
|
2344
2794
|
}, [adapter]);
|
|
2345
|
-
const query =
|
|
2346
|
-
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]);
|
|
2347
2797
|
return { isSynced, query, execute };
|
|
2348
2798
|
}
|
|
2349
2799
|
function usePGliteQuery(opts) {
|
|
2350
2800
|
const { adapter, type, sql, params, idColumn = "id", normalize, deps = [] } = opts;
|
|
2351
|
-
const [isLoading, setIsLoading] =
|
|
2352
|
-
const [error, setError] =
|
|
2353
|
-
|
|
2801
|
+
const [isLoading, setIsLoading] = React6.useState(true);
|
|
2802
|
+
const [error, setError] = React6.useState(null);
|
|
2803
|
+
React6.useEffect(() => {
|
|
2354
2804
|
let cancelled = false;
|
|
2355
2805
|
setIsLoading(true);
|
|
2356
2806
|
adapter.query(sql, params).then((r) => {
|
|
@@ -2463,17 +2913,17 @@ function createGQLClient(cfg) {
|
|
|
2463
2913
|
}
|
|
2464
2914
|
function useGQLEntity(opts) {
|
|
2465
2915
|
const { type, id, staleTime = getEngineOptions().defaultStaleTime, enabled = true } = opts;
|
|
2466
|
-
const optsRef =
|
|
2916
|
+
const optsRef = React6.useRef(opts);
|
|
2467
2917
|
optsRef.current = opts;
|
|
2468
2918
|
const data = zustand.useStore(useGraphStore, shallow.useShallow((s) => {
|
|
2469
2919
|
if (!id) return null;
|
|
2470
2920
|
return s.readEntitySnapshot(type, id);
|
|
2471
2921
|
}));
|
|
2472
|
-
const entityState = zustand.useStore(useGraphStore,
|
|
2922
|
+
const entityState = zustand.useStore(useGraphStore, React6.useCallback(
|
|
2473
2923
|
(s) => s.entityStates[`${type}:${id}`] ?? EMPTY_ENTITY_STATE,
|
|
2474
2924
|
[type, id]
|
|
2475
2925
|
));
|
|
2476
|
-
const doFetch =
|
|
2926
|
+
const doFetch = React6.useCallback(() => {
|
|
2477
2927
|
if (!id || !enabled) return;
|
|
2478
2928
|
const { client, document: document2, variables, descriptor, sideDescriptors, onSuccess, onError } = optsRef.current;
|
|
2479
2929
|
useGraphStore.getState().setEntityFetching(type, id, true);
|
|
@@ -2490,7 +2940,7 @@ function useGQLEntity(opts) {
|
|
|
2490
2940
|
onError?.(e);
|
|
2491
2941
|
});
|
|
2492
2942
|
}, [id, type, enabled]);
|
|
2493
|
-
|
|
2943
|
+
React6.useEffect(() => {
|
|
2494
2944
|
if (!id || !enabled) return;
|
|
2495
2945
|
const token = registerSubscriber(`${type}:${id}`);
|
|
2496
2946
|
const s = useGraphStore.getState();
|
|
@@ -2498,17 +2948,17 @@ function useGQLEntity(opts) {
|
|
|
2498
2948
|
if (!s.entities[type]?.[id] || !ex?.lastFetched || ex.stale || Date.now() - (ex.lastFetched ?? 0) > staleTime) doFetch();
|
|
2499
2949
|
return () => unregisterSubscriber(`${type}:${id}`, token);
|
|
2500
2950
|
}, [id, type, enabled, staleTime, doFetch]);
|
|
2501
|
-
|
|
2951
|
+
React6.useEffect(() => {
|
|
2502
2952
|
if (entityState.stale && id && enabled && !entityState.isFetching) doFetch();
|
|
2503
2953
|
}, [entityState.stale, id, enabled, entityState.isFetching, doFetch]);
|
|
2504
2954
|
return { data, isLoading: !data && entityState.isFetching, isFetching: entityState.isFetching, error: entityState.error, isStale: entityState.stale, refetch: doFetch };
|
|
2505
2955
|
}
|
|
2506
2956
|
function useGQLList(opts) {
|
|
2507
2957
|
const { type, queryKey, staleTime = getEngineOptions().defaultStaleTime, enabled = true, mode = "replace" } = opts;
|
|
2508
|
-
const optsRef =
|
|
2958
|
+
const optsRef = React6.useRef(opts);
|
|
2509
2959
|
optsRef.current = opts;
|
|
2510
|
-
const key =
|
|
2511
|
-
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]));
|
|
2512
2962
|
const items = zustand.useStore(
|
|
2513
2963
|
useGraphStore,
|
|
2514
2964
|
shallow.useShallow((s) => {
|
|
@@ -2516,7 +2966,7 @@ function useGQLList(opts) {
|
|
|
2516
2966
|
return ids.map((id) => s.readEntitySnapshot(type, id)).filter((x) => x !== null);
|
|
2517
2967
|
})
|
|
2518
2968
|
);
|
|
2519
|
-
const doFetch =
|
|
2969
|
+
const doFetch = React6.useCallback((cursor, append = false) => {
|
|
2520
2970
|
if (!enabled) return;
|
|
2521
2971
|
const { client, document: document2, variables, descriptor, sideDescriptors, getItems, getPagination } = optsRef.current;
|
|
2522
2972
|
const store = useGraphStore.getState();
|
|
@@ -2539,25 +2989,25 @@ function useGQLList(opts) {
|
|
|
2539
2989
|
else useGraphStore.getState().setListResult(key, ids, meta);
|
|
2540
2990
|
}).catch((e) => useGraphStore.getState().setListError(key, e.message));
|
|
2541
2991
|
}, [key, enabled, mode]);
|
|
2542
|
-
|
|
2992
|
+
React6.useEffect(() => {
|
|
2543
2993
|
if (!enabled) return;
|
|
2544
2994
|
const ex = useGraphStore.getState().lists[key];
|
|
2545
2995
|
if (!ex || ex.stale || !ex.lastFetched || Date.now() - ex.lastFetched > staleTime) doFetch();
|
|
2546
2996
|
}, [key, enabled, staleTime, doFetch]);
|
|
2547
|
-
|
|
2997
|
+
React6.useEffect(() => {
|
|
2548
2998
|
if (listState.stale && enabled && !listState.isFetching) doFetch();
|
|
2549
2999
|
}, [listState.stale, enabled, listState.isFetching, doFetch]);
|
|
2550
|
-
const fetchNextPage =
|
|
3000
|
+
const fetchNextPage = React6.useCallback(() => {
|
|
2551
3001
|
if (!listState.hasNextPage || listState.isFetchingMore) return;
|
|
2552
3002
|
doFetch(listState.nextCursor ?? void 0, true);
|
|
2553
3003
|
}, [listState.hasNextPage, listState.isFetchingMore, listState.nextCursor, doFetch]);
|
|
2554
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() };
|
|
2555
3005
|
}
|
|
2556
3006
|
function useGQLMutation(opts) {
|
|
2557
|
-
const optsRef =
|
|
3007
|
+
const optsRef = React6.useRef(opts);
|
|
2558
3008
|
optsRef.current = opts;
|
|
2559
|
-
const [state, setState] =
|
|
2560
|
-
const mutate =
|
|
3009
|
+
const [state, setState] = React6.useState({ isPending: false, isSuccess: false, isError: false, error: null });
|
|
3010
|
+
const mutate = React6.useCallback(async (variables) => {
|
|
2561
3011
|
const { client, document: document2, descriptors, optimistic, invalidateLists, onSuccess, onError } = optsRef.current;
|
|
2562
3012
|
setState({ isPending: true, isSuccess: false, isError: false, error: null });
|
|
2563
3013
|
try {
|
|
@@ -2573,17 +3023,17 @@ function useGQLMutation(opts) {
|
|
|
2573
3023
|
return null;
|
|
2574
3024
|
}
|
|
2575
3025
|
}, []);
|
|
2576
|
-
const trigger =
|
|
3026
|
+
const trigger = React6.useCallback((v) => {
|
|
2577
3027
|
void mutate(v);
|
|
2578
3028
|
}, [mutate]);
|
|
2579
3029
|
return { mutate, trigger, state };
|
|
2580
3030
|
}
|
|
2581
3031
|
function useGQLSubscription(opts) {
|
|
2582
3032
|
const { document: document2, variables, enabled = true } = opts;
|
|
2583
|
-
const [status, setStatus] =
|
|
2584
|
-
const optsRef =
|
|
3033
|
+
const [status, setStatus] = React6.useState({ connected: false, error: null });
|
|
3034
|
+
const optsRef = React6.useRef(opts);
|
|
2585
3035
|
optsRef.current = opts;
|
|
2586
|
-
|
|
3036
|
+
React6.useEffect(() => {
|
|
2587
3037
|
const { client, wsClient, descriptors, onData, onError } = optsRef.current;
|
|
2588
3038
|
if (!enabled) return;
|
|
2589
3039
|
const unsub = client.subscribe({ document: document2, variables, descriptors, wsClient, onData: (d) => {
|
|
@@ -2602,7 +3052,7 @@ function cn(...inputs) {
|
|
|
2602
3052
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
2603
3053
|
}
|
|
2604
3054
|
function InlineCellEditor({ initialValue, onCommit, onCancel, className }) {
|
|
2605
|
-
const [value, setValue] =
|
|
3055
|
+
const [value, setValue] = React6.useState(initialValue);
|
|
2606
3056
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2607
3057
|
"input",
|
|
2608
3058
|
{
|
|
@@ -2632,22 +3082,22 @@ function InlineCellEditor({ initialValue, onCommit, onCancel, className }) {
|
|
|
2632
3082
|
}
|
|
2633
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 }) {
|
|
2634
3084
|
const { items, isLoading, isFetching, isRemoteFetching, isShowingLocalPending, hasNextPage, fetchNextPage, isFetchingMore, viewTotal, setSort, setSearch, refetch } = viewResult;
|
|
2635
|
-
const [sorting, setSorting] =
|
|
2636
|
-
const [rowSelection, setRowSelection] =
|
|
2637
|
-
const [colVis, setColVis] =
|
|
2638
|
-
const [search, setSearchLocal] =
|
|
2639
|
-
const [editingCell, setEditingCell] =
|
|
2640
|
-
const [page, setPage] =
|
|
2641
|
-
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) => {
|
|
2642
3092
|
const next = typeof updater === "function" ? updater(sorting) : updater;
|
|
2643
3093
|
setSorting(next);
|
|
2644
3094
|
setSort(next.length ? next.map((s) => ({ field: s.id, direction: s.desc ? "desc" : "asc" })) : null);
|
|
2645
3095
|
}, [sorting, setSort]);
|
|
2646
|
-
const handleSearch =
|
|
3096
|
+
const handleSearch = React6.useCallback((v) => {
|
|
2647
3097
|
setSearchLocal(v);
|
|
2648
3098
|
setSearch(v);
|
|
2649
3099
|
}, [setSearch]);
|
|
2650
|
-
const pagedItems =
|
|
3100
|
+
const pagedItems = React6.useMemo(() => paginationMode === "pages" ? items.slice((page - 1) * pageSize, page * pageSize) : items, [items, paginationMode, page, pageSize]);
|
|
2651
3101
|
const totalPages = Math.ceil(items.length / pageSize);
|
|
2652
3102
|
const table = reactTable.useReactTable({
|
|
2653
3103
|
data: pagedItems,
|
|
@@ -2750,7 +3200,7 @@ function EntityTable({ viewResult, columns, getRowId = (r) => String(r.id), sele
|
|
|
2750
3200
|
] });
|
|
2751
3201
|
}
|
|
2752
3202
|
function Sheet({ open, onClose, title, subtitle, children, footer, width = "w-[480px]" }) {
|
|
2753
|
-
|
|
3203
|
+
React6__default.default.useEffect(() => {
|
|
2754
3204
|
const h = (e) => {
|
|
2755
3205
|
if (e.key === "Escape") onClose();
|
|
2756
3206
|
};
|
|
@@ -2786,6 +3236,8 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2786
3236
|
return /* @__PURE__ */ jsxRuntime.jsx("input", { type: "number", value: String(value ?? ""), onChange: (e) => onChange(e.target.valueAsNumber), placeholder: descriptor.placeholder, className: base });
|
|
2787
3237
|
case "textarea":
|
|
2788
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 });
|
|
2789
3241
|
case "date":
|
|
2790
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 });
|
|
2791
3243
|
case "boolean":
|
|
@@ -2805,12 +3257,35 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2805
3257
|
!value && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select\u2026" }),
|
|
2806
3258
|
(descriptor.options ?? []).map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
2807
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
|
+
);
|
|
2808
3277
|
default:
|
|
2809
3278
|
return /* @__PURE__ */ jsxRuntime.jsx("input", { value: String(value ?? ""), onChange: (e) => onChange(e.target.value), className: base });
|
|
2810
3279
|
}
|
|
2811
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
|
+
}
|
|
2812
3287
|
function EntityDetailSheet({ crud, fields, title = "Details", description, children, showEditButton = true, showDeleteButton = true, deleteConfirmMessage = "This action cannot be undone." }) {
|
|
2813
|
-
const [confirmDelete, setConfirmDelete] =
|
|
3288
|
+
const [confirmDelete, setConfirmDelete] = React6__default.default.useState(false);
|
|
2814
3289
|
const open = crud.mode === "detail" && !!crud.selectedId;
|
|
2815
3290
|
const entity = crud.detail;
|
|
2816
3291
|
const resolvedTitle = entity && typeof title === "function" ? title(entity) : String(title);
|
|
@@ -2834,8 +3309,7 @@ function EntityDetailSheet({ crud, fields, title = "Details", description, child
|
|
|
2834
3309
|
entity && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2835
3310
|
fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2836
3311
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wide mb-1", children: f.label }),
|
|
2837
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2838
|
-
}, entity, readonly: true })
|
|
3312
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldReadonlyValue, { descriptor: f, value: getValueAtPath(entity, f.field), entity })
|
|
2839
3313
|
] }, f.field)),
|
|
2840
3314
|
children && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2841
3315
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t my-1" }),
|
|
@@ -2905,13 +3379,14 @@ function EntityFormSheet({ crud, fields, createTitle = "Create", editTitle = "Ed
|
|
|
2905
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 }),
|
|
2906
3380
|
visibleFields.map((f) => {
|
|
2907
3381
|
const isDirty = !isCreate && crud.dirty.changed.has(f.field);
|
|
3382
|
+
const currentValue = getValueAtPath(buf, f.field);
|
|
2908
3383
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
2909
3384
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: cn("text-xs font-medium", isDirty ? "text-primary" : "text-muted-foreground"), children: [
|
|
2910
3385
|
f.label,
|
|
2911
3386
|
f.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive ml-0.5", children: "*" }),
|
|
2912
3387
|
isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1.5 text-[10px] font-normal opacity-70", children: "modified" })
|
|
2913
3388
|
] }),
|
|
2914
|
-
/* @__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 }),
|
|
2915
3390
|
f.hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: f.hint })
|
|
2916
3391
|
] }, f.field);
|
|
2917
3392
|
})
|
|
@@ -3569,43 +4044,43 @@ function buildHeaderGroups(columns, table) {
|
|
|
3569
4044
|
function useTable(options) {
|
|
3570
4045
|
const { data, columns: columnDefs } = options;
|
|
3571
4046
|
const ini = options.initialState;
|
|
3572
|
-
const [sorting, _setSorting] =
|
|
4047
|
+
const [sorting, _setSorting] = React6.useState(
|
|
3573
4048
|
options.state?.sorting ?? ini?.sorting ?? []
|
|
3574
4049
|
);
|
|
3575
|
-
const [columnFilters, _setColumnFilters] =
|
|
4050
|
+
const [columnFilters, _setColumnFilters] = React6.useState(
|
|
3576
4051
|
options.state?.columnFilters ?? ini?.columnFilters ?? []
|
|
3577
4052
|
);
|
|
3578
|
-
const [globalFilter, _setGlobalFilter] =
|
|
4053
|
+
const [globalFilter, _setGlobalFilter] = React6.useState(
|
|
3579
4054
|
options.state?.globalFilter ?? ini?.globalFilter ?? ""
|
|
3580
4055
|
);
|
|
3581
|
-
const [rowSelection, _setRowSelection] =
|
|
4056
|
+
const [rowSelection, _setRowSelection] = React6.useState(
|
|
3582
4057
|
options.state?.rowSelection ?? ini?.rowSelection ?? {}
|
|
3583
4058
|
);
|
|
3584
|
-
const [columnVisibility, _setColumnVisibility] =
|
|
4059
|
+
const [columnVisibility, _setColumnVisibility] = React6.useState(
|
|
3585
4060
|
options.state?.columnVisibility ?? ini?.columnVisibility ?? {}
|
|
3586
4061
|
);
|
|
3587
|
-
const [columnOrder, _setColumnOrder] =
|
|
4062
|
+
const [columnOrder, _setColumnOrder] = React6.useState(
|
|
3588
4063
|
options.state?.columnOrder ?? ini?.columnOrder ?? []
|
|
3589
4064
|
);
|
|
3590
|
-
const [columnPinning, _setColumnPinning] =
|
|
4065
|
+
const [columnPinning, _setColumnPinning] = React6.useState(
|
|
3591
4066
|
options.state?.columnPinning ?? ini?.columnPinning ?? { left: [], right: [] }
|
|
3592
4067
|
);
|
|
3593
|
-
const [columnSizing, _setColumnSizing] =
|
|
4068
|
+
const [columnSizing, _setColumnSizing] = React6.useState(
|
|
3594
4069
|
options.state?.columnSizing ?? ini?.columnSizing ?? {}
|
|
3595
4070
|
);
|
|
3596
|
-
const [columnSizingInfo, _setColumnSizingInfo] =
|
|
4071
|
+
const [columnSizingInfo, _setColumnSizingInfo] = React6.useState(
|
|
3597
4072
|
options.state?.columnSizingInfo ?? ini?.columnSizingInfo ?? defaultState.columnSizingInfo
|
|
3598
4073
|
);
|
|
3599
|
-
const [expanded, _setExpanded] =
|
|
4074
|
+
const [expanded, _setExpanded] = React6.useState(
|
|
3600
4075
|
options.state?.expanded ?? ini?.expanded ?? {}
|
|
3601
4076
|
);
|
|
3602
|
-
const [grouping, _setGrouping] =
|
|
4077
|
+
const [grouping, _setGrouping] = React6.useState(
|
|
3603
4078
|
options.state?.grouping ?? ini?.grouping ?? []
|
|
3604
4079
|
);
|
|
3605
|
-
const [pagination, _setPagination] =
|
|
4080
|
+
const [pagination, _setPagination] = React6.useState(
|
|
3606
4081
|
options.state?.pagination ?? ini?.pagination ?? { pageIndex: 0, pageSize: 10 }
|
|
3607
4082
|
);
|
|
3608
|
-
const state =
|
|
4083
|
+
const state = React6.useMemo(
|
|
3609
4084
|
() => ({
|
|
3610
4085
|
sorting: options.state?.sorting ?? sorting,
|
|
3611
4086
|
columnFilters: options.state?.columnFilters ?? columnFilters,
|
|
@@ -3636,63 +4111,63 @@ function useTable(options) {
|
|
|
3636
4111
|
pagination
|
|
3637
4112
|
]
|
|
3638
4113
|
);
|
|
3639
|
-
const stateRef =
|
|
4114
|
+
const stateRef = React6.useRef(state);
|
|
3640
4115
|
stateRef.current = state;
|
|
3641
|
-
const setSorting =
|
|
4116
|
+
const setSorting = React6.useCallback((updater) => {
|
|
3642
4117
|
options.onSortingChange?.(updater);
|
|
3643
4118
|
if (!options.state?.sorting) _setSorting((prev) => resolveUpdater(updater, prev));
|
|
3644
4119
|
}, [options.onSortingChange, options.state?.sorting]);
|
|
3645
|
-
const setColumnFilters =
|
|
4120
|
+
const setColumnFilters = React6.useCallback((updater) => {
|
|
3646
4121
|
options.onColumnFiltersChange?.(updater);
|
|
3647
4122
|
if (!options.state?.columnFilters) _setColumnFilters((prev) => resolveUpdater(updater, prev));
|
|
3648
4123
|
if (options.autoResetPageIndex !== false) {
|
|
3649
4124
|
_setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
3650
4125
|
}
|
|
3651
4126
|
}, [options.onColumnFiltersChange, options.state?.columnFilters, options.autoResetPageIndex]);
|
|
3652
|
-
const setGlobalFilter =
|
|
4127
|
+
const setGlobalFilter = React6.useCallback((value) => {
|
|
3653
4128
|
options.onGlobalFilterChange?.(value);
|
|
3654
4129
|
if (!options.state?.globalFilter) _setGlobalFilter(value);
|
|
3655
4130
|
if (options.autoResetPageIndex !== false) {
|
|
3656
4131
|
_setPagination((prev) => ({ ...prev, pageIndex: 0 }));
|
|
3657
4132
|
}
|
|
3658
4133
|
}, [options.onGlobalFilterChange, options.state?.globalFilter, options.autoResetPageIndex]);
|
|
3659
|
-
const setRowSelection =
|
|
4134
|
+
const setRowSelection = React6.useCallback((updater) => {
|
|
3660
4135
|
options.onRowSelectionChange?.(updater);
|
|
3661
4136
|
if (!options.state?.rowSelection) _setRowSelection((prev) => resolveUpdater(updater, prev));
|
|
3662
4137
|
}, [options.onRowSelectionChange, options.state?.rowSelection]);
|
|
3663
|
-
const setColumnVisibility =
|
|
4138
|
+
const setColumnVisibility = React6.useCallback((updater) => {
|
|
3664
4139
|
options.onColumnVisibilityChange?.(updater);
|
|
3665
4140
|
if (!options.state?.columnVisibility) _setColumnVisibility((prev) => resolveUpdater(updater, prev));
|
|
3666
4141
|
}, [options.onColumnVisibilityChange, options.state?.columnVisibility]);
|
|
3667
|
-
const setColumnOrder =
|
|
4142
|
+
const setColumnOrder = React6.useCallback((updater) => {
|
|
3668
4143
|
options.onColumnOrderChange?.(updater);
|
|
3669
4144
|
if (!options.state?.columnOrder) _setColumnOrder((prev) => resolveUpdater(updater, prev));
|
|
3670
4145
|
}, [options.onColumnOrderChange, options.state?.columnOrder]);
|
|
3671
|
-
const setColumnPinning =
|
|
4146
|
+
const setColumnPinning = React6.useCallback((updater) => {
|
|
3672
4147
|
options.onColumnPinningChange?.(updater);
|
|
3673
4148
|
if (!options.state?.columnPinning) _setColumnPinning((prev) => resolveUpdater(updater, prev));
|
|
3674
4149
|
}, [options.onColumnPinningChange, options.state?.columnPinning]);
|
|
3675
|
-
const setColumnSizing =
|
|
4150
|
+
const setColumnSizing = React6.useCallback((updater) => {
|
|
3676
4151
|
options.onColumnSizingChange?.(updater);
|
|
3677
4152
|
if (!options.state?.columnSizing) _setColumnSizing((prev) => resolveUpdater(updater, prev));
|
|
3678
4153
|
}, [options.onColumnSizingChange, options.state?.columnSizing]);
|
|
3679
|
-
const setColumnSizingInfo =
|
|
4154
|
+
const setColumnSizingInfo = React6.useCallback((updater) => {
|
|
3680
4155
|
options.onColumnSizingInfoChange?.(updater);
|
|
3681
4156
|
if (!options.state?.columnSizingInfo) _setColumnSizingInfo((prev) => resolveUpdater(updater, prev));
|
|
3682
4157
|
}, [options.onColumnSizingInfoChange, options.state?.columnSizingInfo]);
|
|
3683
|
-
const setExpanded =
|
|
4158
|
+
const setExpanded = React6.useCallback((updater) => {
|
|
3684
4159
|
options.onExpandedChange?.(updater);
|
|
3685
4160
|
if (!options.state?.expanded) _setExpanded((prev) => resolveUpdater(updater, prev));
|
|
3686
4161
|
}, [options.onExpandedChange, options.state?.expanded]);
|
|
3687
|
-
const setGrouping =
|
|
4162
|
+
const setGrouping = React6.useCallback((updater) => {
|
|
3688
4163
|
options.onGroupingChange?.(updater);
|
|
3689
4164
|
if (!options.state?.grouping) _setGrouping((prev) => resolveUpdater(updater, prev));
|
|
3690
4165
|
}, [options.onGroupingChange, options.state?.grouping]);
|
|
3691
|
-
const setPagination =
|
|
4166
|
+
const setPagination = React6.useCallback((updater) => {
|
|
3692
4167
|
options.onPaginationChange?.(updater);
|
|
3693
4168
|
if (!options.state?.pagination) _setPagination((prev) => resolveUpdater(updater, prev));
|
|
3694
4169
|
}, [options.onPaginationChange, options.state?.pagination]);
|
|
3695
|
-
const stateSetters =
|
|
4170
|
+
const stateSetters = React6.useMemo(() => ({
|
|
3696
4171
|
setSorting,
|
|
3697
4172
|
setColumnFilters,
|
|
3698
4173
|
setGlobalFilter,
|
|
@@ -3719,13 +4194,13 @@ function useTable(options) {
|
|
|
3719
4194
|
setGrouping,
|
|
3720
4195
|
setPagination
|
|
3721
4196
|
]);
|
|
3722
|
-
const getState =
|
|
3723
|
-
const coreRowModelRef =
|
|
3724
|
-
const emptyCoreRowModel =
|
|
4197
|
+
const getState = React6.useCallback(() => state, [state]);
|
|
4198
|
+
const coreRowModelRef = React6.useRef(null);
|
|
4199
|
+
const emptyCoreRowModel = React6.useMemo(
|
|
3725
4200
|
() => ({ rows: [], flatRows: [], rowsById: {} }),
|
|
3726
4201
|
[]
|
|
3727
4202
|
);
|
|
3728
|
-
const rowModelTable =
|
|
4203
|
+
const rowModelTable = React6.useMemo(
|
|
3729
4204
|
() => ({
|
|
3730
4205
|
options,
|
|
3731
4206
|
getState: () => stateRef.current,
|
|
@@ -3735,11 +4210,11 @@ function useTable(options) {
|
|
|
3735
4210
|
}),
|
|
3736
4211
|
[options, setRowSelection, setExpanded, emptyCoreRowModel]
|
|
3737
4212
|
);
|
|
3738
|
-
const columns =
|
|
4213
|
+
const columns = React6.useMemo(
|
|
3739
4214
|
() => buildColumns(columnDefs, { getState, ...stateSetters }, stateSetters),
|
|
3740
4215
|
[columnDefs, getState, stateSetters]
|
|
3741
4216
|
);
|
|
3742
|
-
const orderedColumns =
|
|
4217
|
+
const orderedColumns = React6.useMemo(() => {
|
|
3743
4218
|
if (state.columnOrder.length === 0) return columns;
|
|
3744
4219
|
const ordered = [];
|
|
3745
4220
|
const remaining = [...columns];
|
|
@@ -3753,28 +4228,28 @@ function useTable(options) {
|
|
|
3753
4228
|
ordered.push(...remaining);
|
|
3754
4229
|
return ordered;
|
|
3755
4230
|
}, [columns, state.columnOrder]);
|
|
3756
|
-
const visibleColumns =
|
|
4231
|
+
const visibleColumns = React6.useMemo(
|
|
3757
4232
|
() => orderedColumns.filter((c) => c.getIsVisible()),
|
|
3758
4233
|
[orderedColumns]
|
|
3759
4234
|
);
|
|
3760
|
-
const leftPinnedColumns =
|
|
4235
|
+
const leftPinnedColumns = React6.useMemo(
|
|
3761
4236
|
() => visibleColumns.filter((c) => c.getIsPinned() === "left"),
|
|
3762
4237
|
[visibleColumns]
|
|
3763
4238
|
);
|
|
3764
|
-
const rightPinnedColumns =
|
|
4239
|
+
const rightPinnedColumns = React6.useMemo(
|
|
3765
4240
|
() => visibleColumns.filter((c) => c.getIsPinned() === "right"),
|
|
3766
4241
|
[visibleColumns]
|
|
3767
4242
|
);
|
|
3768
|
-
const centerColumns =
|
|
4243
|
+
const centerColumns = React6.useMemo(
|
|
3769
4244
|
() => visibleColumns.filter((c) => c.getIsPinned() === false),
|
|
3770
4245
|
[visibleColumns]
|
|
3771
4246
|
);
|
|
3772
|
-
const coreRowModel =
|
|
4247
|
+
const coreRowModel = React6.useMemo(() => {
|
|
3773
4248
|
const cm = getCoreRowModel2(data, columns, rowModelTable);
|
|
3774
4249
|
coreRowModelRef.current = cm;
|
|
3775
4250
|
return cm;
|
|
3776
4251
|
}, [data, columns, rowModelTable]);
|
|
3777
|
-
const filteredRowModel =
|
|
4252
|
+
const filteredRowModel = React6.useMemo(() => {
|
|
3778
4253
|
if (options.manualFiltering) return coreRowModel;
|
|
3779
4254
|
return getFilteredRowModel(
|
|
3780
4255
|
coreRowModel,
|
|
@@ -3784,32 +4259,32 @@ function useTable(options) {
|
|
|
3784
4259
|
options.globalFilterFn
|
|
3785
4260
|
);
|
|
3786
4261
|
}, [coreRowModel, state.columnFilters, state.globalFilter, columns, options.manualFiltering, options.globalFilterFn]);
|
|
3787
|
-
const sortedRowModel =
|
|
4262
|
+
const sortedRowModel = React6.useMemo(() => {
|
|
3788
4263
|
if (options.manualSorting) return filteredRowModel;
|
|
3789
4264
|
return getSortedRowModel2(filteredRowModel, state.sorting, columns);
|
|
3790
4265
|
}, [filteredRowModel, state.sorting, columns, options.manualSorting]);
|
|
3791
|
-
const groupedRowModel =
|
|
4266
|
+
const groupedRowModel = React6.useMemo(() => {
|
|
3792
4267
|
if (options.manualGrouping || state.grouping.length === 0) return sortedRowModel;
|
|
3793
4268
|
return getGroupedRowModel(sortedRowModel, state.grouping, columns, rowModelTable);
|
|
3794
4269
|
}, [sortedRowModel, state.grouping, columns, options.manualGrouping, rowModelTable]);
|
|
3795
|
-
const expandedRowModel =
|
|
4270
|
+
const expandedRowModel = React6.useMemo(
|
|
3796
4271
|
() => getExpandedRowModel(groupedRowModel, state.expanded),
|
|
3797
4272
|
[groupedRowModel, state.expanded]
|
|
3798
4273
|
);
|
|
3799
4274
|
const prePaginationRowModel = expandedRowModel;
|
|
3800
|
-
const paginatedRowModel =
|
|
4275
|
+
const paginatedRowModel = React6.useMemo(() => {
|
|
3801
4276
|
if (options.manualPagination) return prePaginationRowModel;
|
|
3802
4277
|
return getPaginatedRowModel(prePaginationRowModel, state.pagination);
|
|
3803
4278
|
}, [prePaginationRowModel, state.pagination, options.manualPagination]);
|
|
3804
|
-
const selectedRowModel =
|
|
4279
|
+
const selectedRowModel = React6.useMemo(
|
|
3805
4280
|
() => getSelectedRowModel(coreRowModel, state.rowSelection),
|
|
3806
4281
|
[coreRowModel, state.rowSelection]
|
|
3807
4282
|
);
|
|
3808
|
-
const pageCount =
|
|
4283
|
+
const pageCount = React6.useMemo(() => {
|
|
3809
4284
|
if (options.pageCount != null) return options.pageCount;
|
|
3810
4285
|
return Math.ceil(prePaginationRowModel.rows.length / state.pagination.pageSize);
|
|
3811
4286
|
}, [options.pageCount, prePaginationRowModel, state.pagination.pageSize]);
|
|
3812
|
-
const table =
|
|
4287
|
+
const table = React6.useMemo(() => {
|
|
3813
4288
|
const inst = {
|
|
3814
4289
|
options,
|
|
3815
4290
|
getState: () => state,
|
|
@@ -4112,9 +4587,9 @@ function createSelectionStore() {
|
|
|
4112
4587
|
function useSelectionStore(store, selector) {
|
|
4113
4588
|
return zustand.useStore(store, selector);
|
|
4114
4589
|
}
|
|
4115
|
-
var SelectionContext =
|
|
4590
|
+
var SelectionContext = React6__default.default.createContext(null);
|
|
4116
4591
|
function useSelectionContext() {
|
|
4117
|
-
const store =
|
|
4592
|
+
const store = React6__default.default.useContext(SelectionContext);
|
|
4118
4593
|
if (!store) throw new Error("useSelectionContext must be used within a SelectionContext.Provider");
|
|
4119
4594
|
return store;
|
|
4120
4595
|
}
|
|
@@ -4840,18 +5315,18 @@ function generateId() {
|
|
|
4840
5315
|
function useTablePresets(tableId, options = {}) {
|
|
4841
5316
|
const { adapter, realtimeMode = "auto-apply", enabled = true } = options;
|
|
4842
5317
|
const resolvedAdapter = adapter ?? new MemoryAdapter();
|
|
4843
|
-
const adapterRef =
|
|
5318
|
+
const adapterRef = React6.useRef(resolvedAdapter);
|
|
4844
5319
|
adapterRef.current = resolvedAdapter;
|
|
4845
|
-
const storeRef =
|
|
5320
|
+
const storeRef = React6.useRef(createPresetStore(realtimeMode));
|
|
4846
5321
|
const store = storeRef.current;
|
|
4847
|
-
const [isLoading, setIsLoading] =
|
|
4848
|
-
const [isSubscribed, setIsSubscribed] =
|
|
4849
|
-
|
|
5322
|
+
const [isLoading, setIsLoading] = React6.useState(false);
|
|
5323
|
+
const [isSubscribed, setIsSubscribed] = React6.useState(false);
|
|
5324
|
+
React6.useEffect(() => {
|
|
4850
5325
|
if (!enabled) return;
|
|
4851
5326
|
setIsLoading(true);
|
|
4852
5327
|
store.getState().loadPresets(tableId, adapterRef.current).finally(() => setIsLoading(false));
|
|
4853
5328
|
}, [tableId, enabled, store]);
|
|
4854
|
-
|
|
5329
|
+
React6.useEffect(() => {
|
|
4855
5330
|
if (!enabled) return;
|
|
4856
5331
|
const currentAdapter = adapterRef.current;
|
|
4857
5332
|
if (!currentAdapter.subscribe) {
|
|
@@ -4866,19 +5341,19 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4866
5341
|
}, [tableId, enabled, store]);
|
|
4867
5342
|
const slice = zustand.useStore(store, (s) => s.presets[tableId] ?? s.getTablePresets(tableId));
|
|
4868
5343
|
const allPendingChanges = zustand.useStore(store, (s) => s.pendingChanges);
|
|
4869
|
-
const pendingChanges =
|
|
5344
|
+
const pendingChanges = React6.useMemo(
|
|
4870
5345
|
() => allPendingChanges.filter((e) => e.tableId === tableId),
|
|
4871
5346
|
[allPendingChanges, tableId]
|
|
4872
5347
|
);
|
|
4873
|
-
const activeFilterPreset =
|
|
5348
|
+
const activeFilterPreset = React6.useMemo(
|
|
4874
5349
|
() => slice.filters.find((p) => p.id === slice.activeFilterId) ?? null,
|
|
4875
5350
|
[slice.filters, slice.activeFilterId]
|
|
4876
5351
|
);
|
|
4877
|
-
const activeColumnPreset =
|
|
5352
|
+
const activeColumnPreset = React6.useMemo(
|
|
4878
5353
|
() => slice.columns.find((p) => p.id === slice.activeColumnId) ?? null,
|
|
4879
5354
|
[slice.columns, slice.activeColumnId]
|
|
4880
5355
|
);
|
|
4881
|
-
const applyFilterPreset =
|
|
5356
|
+
const applyFilterPreset = React6.useCallback(
|
|
4882
5357
|
(id) => {
|
|
4883
5358
|
store.getState().applyFilterPreset(tableId, id);
|
|
4884
5359
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4889,7 +5364,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4889
5364
|
},
|
|
4890
5365
|
[tableId, slice.activeColumnId, slice.activeViewMode, store]
|
|
4891
5366
|
);
|
|
4892
|
-
const applyColumnPreset =
|
|
5367
|
+
const applyColumnPreset = React6.useCallback(
|
|
4893
5368
|
(id) => {
|
|
4894
5369
|
store.getState().applyColumnPreset(tableId, id);
|
|
4895
5370
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4900,7 +5375,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4900
5375
|
},
|
|
4901
5376
|
[tableId, slice.activeFilterId, slice.activeViewMode, store]
|
|
4902
5377
|
);
|
|
4903
|
-
const setViewMode =
|
|
5378
|
+
const setViewMode = React6.useCallback(
|
|
4904
5379
|
(mode) => {
|
|
4905
5380
|
store.getState().setViewMode(tableId, mode);
|
|
4906
5381
|
adapterRef.current.saveActivePresets(tableId, {
|
|
@@ -4911,7 +5386,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4911
5386
|
},
|
|
4912
5387
|
[tableId, slice.activeFilterId, slice.activeColumnId, store]
|
|
4913
5388
|
);
|
|
4914
|
-
const saveFilterPreset =
|
|
5389
|
+
const saveFilterPreset = React6.useCallback(
|
|
4915
5390
|
async (preset) => {
|
|
4916
5391
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4917
5392
|
const full = {
|
|
@@ -4924,7 +5399,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4924
5399
|
},
|
|
4925
5400
|
[tableId, store]
|
|
4926
5401
|
);
|
|
4927
|
-
const updateFilterPreset =
|
|
5402
|
+
const updateFilterPreset = React6.useCallback(
|
|
4928
5403
|
async (id, patch) => {
|
|
4929
5404
|
const existing = slice.filters.find((p) => p.id === id);
|
|
4930
5405
|
if (!existing) return;
|
|
@@ -4938,7 +5413,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4938
5413
|
},
|
|
4939
5414
|
[tableId, slice.filters, store]
|
|
4940
5415
|
);
|
|
4941
|
-
const saveColumnPreset =
|
|
5416
|
+
const saveColumnPreset = React6.useCallback(
|
|
4942
5417
|
async (preset) => {
|
|
4943
5418
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4944
5419
|
const full = {
|
|
@@ -4951,7 +5426,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4951
5426
|
},
|
|
4952
5427
|
[tableId, store]
|
|
4953
5428
|
);
|
|
4954
|
-
const updateColumnPreset =
|
|
5429
|
+
const updateColumnPreset = React6.useCallback(
|
|
4955
5430
|
async (id, patch) => {
|
|
4956
5431
|
const existing = slice.columns.find((p) => p.id === id);
|
|
4957
5432
|
if (!existing) return;
|
|
@@ -4965,25 +5440,25 @@ function useTablePresets(tableId, options = {}) {
|
|
|
4965
5440
|
},
|
|
4966
5441
|
[tableId, slice.columns, store]
|
|
4967
5442
|
);
|
|
4968
|
-
const deleteFilterPreset =
|
|
5443
|
+
const deleteFilterPreset = React6.useCallback(
|
|
4969
5444
|
async (id) => {
|
|
4970
5445
|
await store.getState().deleteFilterPreset(tableId, id, adapterRef.current);
|
|
4971
5446
|
},
|
|
4972
5447
|
[tableId, store]
|
|
4973
5448
|
);
|
|
4974
|
-
const deleteColumnPreset =
|
|
5449
|
+
const deleteColumnPreset = React6.useCallback(
|
|
4975
5450
|
async (id) => {
|
|
4976
5451
|
await store.getState().deleteColumnPreset(tableId, id, adapterRef.current);
|
|
4977
5452
|
},
|
|
4978
5453
|
[tableId, store]
|
|
4979
5454
|
);
|
|
4980
|
-
const acknowledgePendingChange =
|
|
5455
|
+
const acknowledgePendingChange = React6.useCallback(
|
|
4981
5456
|
(index) => {
|
|
4982
5457
|
store.getState().acknowledgePendingChange(index);
|
|
4983
5458
|
},
|
|
4984
5459
|
[store]
|
|
4985
5460
|
);
|
|
4986
|
-
const dismissPendingChanges =
|
|
5461
|
+
const dismissPendingChanges = React6.useCallback(() => {
|
|
4987
5462
|
store.getState().dismissPendingChanges(tableId);
|
|
4988
5463
|
}, [tableId, store]);
|
|
4989
5464
|
return {
|
|
@@ -5008,7 +5483,7 @@ function useTablePresets(tableId, options = {}) {
|
|
|
5008
5483
|
isSubscribed
|
|
5009
5484
|
};
|
|
5010
5485
|
}
|
|
5011
|
-
var TableStorageContext =
|
|
5486
|
+
var TableStorageContext = React6.createContext({
|
|
5012
5487
|
adapter: new MemoryAdapter(),
|
|
5013
5488
|
realtimeMode: "auto-apply"
|
|
5014
5489
|
});
|
|
@@ -5017,19 +5492,19 @@ function TableStorageProvider({
|
|
|
5017
5492
|
realtimeMode = "auto-apply",
|
|
5018
5493
|
children
|
|
5019
5494
|
}) {
|
|
5020
|
-
const value =
|
|
5495
|
+
const value = React6.useMemo(
|
|
5021
5496
|
() => ({ adapter, realtimeMode }),
|
|
5022
5497
|
[adapter, realtimeMode]
|
|
5023
5498
|
);
|
|
5024
5499
|
return /* @__PURE__ */ jsxRuntime.jsx(TableStorageContext.Provider, { value, children });
|
|
5025
5500
|
}
|
|
5026
5501
|
function useTableStorageAdapter() {
|
|
5027
|
-
return
|
|
5502
|
+
return React6.useContext(TableStorageContext).adapter;
|
|
5028
5503
|
}
|
|
5029
5504
|
function useTableRealtimeMode() {
|
|
5030
|
-
return
|
|
5505
|
+
return React6.useContext(TableStorageContext).realtimeMode;
|
|
5031
5506
|
}
|
|
5032
|
-
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(
|
|
5033
5508
|
"table",
|
|
5034
5509
|
{
|
|
5035
5510
|
ref,
|
|
@@ -5038,11 +5513,11 @@ var Table = React5__default.default.forwardRef(({ className, ...props }, ref) =>
|
|
|
5038
5513
|
}
|
|
5039
5514
|
) }));
|
|
5040
5515
|
Table.displayName = "Table";
|
|
5041
|
-
var TableHeader =
|
|
5516
|
+
var TableHeader = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("bg-muted/60", className), ...props }));
|
|
5042
5517
|
TableHeader.displayName = "TableHeader";
|
|
5043
|
-
var TableBody =
|
|
5518
|
+
var TableBody = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("bg-background", className), ...props }));
|
|
5044
5519
|
TableBody.displayName = "TableBody";
|
|
5045
|
-
var TableFooter =
|
|
5520
|
+
var TableFooter = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5046
5521
|
"tfoot",
|
|
5047
5522
|
{
|
|
5048
5523
|
ref,
|
|
@@ -5051,7 +5526,7 @@ var TableFooter = React5__default.default.forwardRef(({ className, ...props }, r
|
|
|
5051
5526
|
}
|
|
5052
5527
|
));
|
|
5053
5528
|
TableFooter.displayName = "TableFooter";
|
|
5054
|
-
var TableRow =
|
|
5529
|
+
var TableRow = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5055
5530
|
"tr",
|
|
5056
5531
|
{
|
|
5057
5532
|
ref,
|
|
@@ -5063,7 +5538,7 @@ var TableRow = React5__default.default.forwardRef(({ className, ...props }, ref)
|
|
|
5063
5538
|
}
|
|
5064
5539
|
));
|
|
5065
5540
|
TableRow.displayName = "TableRow";
|
|
5066
|
-
var TableHead =
|
|
5541
|
+
var TableHead = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5067
5542
|
"th",
|
|
5068
5543
|
{
|
|
5069
5544
|
ref,
|
|
@@ -5075,7 +5550,7 @@ var TableHead = React5__default.default.forwardRef(({ className, ...props }, ref
|
|
|
5075
5550
|
}
|
|
5076
5551
|
));
|
|
5077
5552
|
TableHead.displayName = "TableHead";
|
|
5078
|
-
var TableCell =
|
|
5553
|
+
var TableCell = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5079
5554
|
"td",
|
|
5080
5555
|
{
|
|
5081
5556
|
ref,
|
|
@@ -5087,7 +5562,7 @@ var TableCell = React5__default.default.forwardRef(({ className, ...props }, ref
|
|
|
5087
5562
|
}
|
|
5088
5563
|
));
|
|
5089
5564
|
TableCell.displayName = "TableCell";
|
|
5090
|
-
var TableCaption =
|
|
5565
|
+
var TableCaption = React6__default.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5091
5566
|
"caption",
|
|
5092
5567
|
{
|
|
5093
5568
|
ref,
|
|
@@ -5150,11 +5625,11 @@ function InlineCellEditor2({
|
|
|
5150
5625
|
inputId,
|
|
5151
5626
|
ariaLabel
|
|
5152
5627
|
}) {
|
|
5153
|
-
const [value, setValue] =
|
|
5154
|
-
const inputRef =
|
|
5155
|
-
const selectRef =
|
|
5628
|
+
const [value, setValue] = React6.useState(initialValue);
|
|
5629
|
+
const inputRef = React6.useRef(null);
|
|
5630
|
+
const selectRef = React6.useRef(null);
|
|
5156
5631
|
const filterType = columnDef.meta?.entityMeta?.filterType ?? "text";
|
|
5157
|
-
|
|
5632
|
+
React6.useEffect(() => {
|
|
5158
5633
|
if (filterType === "enum") {
|
|
5159
5634
|
selectRef.current?.focus();
|
|
5160
5635
|
return;
|
|
@@ -5163,7 +5638,7 @@ function InlineCellEditor2({
|
|
|
5163
5638
|
inputRef.current?.focus();
|
|
5164
5639
|
inputRef.current?.select();
|
|
5165
5640
|
}, [filterType]);
|
|
5166
|
-
const handleKeyDown =
|
|
5641
|
+
const handleKeyDown = React6.useCallback(
|
|
5167
5642
|
(e) => {
|
|
5168
5643
|
if (e.key === "Enter") {
|
|
5169
5644
|
e.preventDefault();
|
|
@@ -5175,7 +5650,7 @@ function InlineCellEditor2({
|
|
|
5175
5650
|
},
|
|
5176
5651
|
[value, onSave, onCancel]
|
|
5177
5652
|
);
|
|
5178
|
-
const handleBlur =
|
|
5653
|
+
const handleBlur = React6.useCallback(() => {
|
|
5179
5654
|
onSave(value);
|
|
5180
5655
|
}, [value, onSave]);
|
|
5181
5656
|
if (filterType === "boolean") {
|
|
@@ -5283,8 +5758,8 @@ function InlineItemEditor({
|
|
|
5283
5758
|
onCancel,
|
|
5284
5759
|
className
|
|
5285
5760
|
}) {
|
|
5286
|
-
const baseId =
|
|
5287
|
-
const [editValues, setEditValues] =
|
|
5761
|
+
const baseId = React6.useId();
|
|
5762
|
+
const [editValues, setEditValues] = React6.useState({});
|
|
5288
5763
|
const editableFields = columns.filter(
|
|
5289
5764
|
(c) => c.meta?.entityMeta?.editable && c.accessorKey
|
|
5290
5765
|
);
|
|
@@ -5385,11 +5860,11 @@ function ActionDropdown({
|
|
|
5385
5860
|
actions,
|
|
5386
5861
|
className
|
|
5387
5862
|
}) {
|
|
5388
|
-
const [isOpen, setIsOpen] =
|
|
5389
|
-
const [confirmAction, setConfirmAction] =
|
|
5390
|
-
const menuRef =
|
|
5863
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
5864
|
+
const [confirmAction, setConfirmAction] = React6.useState(null);
|
|
5865
|
+
const menuRef = React6.useRef(null);
|
|
5391
5866
|
const visibleActions = actions.filter((a) => !a.hidden?.(item));
|
|
5392
|
-
|
|
5867
|
+
React6.useEffect(() => {
|
|
5393
5868
|
function handleClick(e) {
|
|
5394
5869
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
5395
5870
|
setIsOpen(false);
|
|
@@ -5461,7 +5936,7 @@ function ActionButtonRow({
|
|
|
5461
5936
|
const visibleActions = actions.filter((a) => !a.hidden?.(item));
|
|
5462
5937
|
const inline = visibleActions.slice(0, maxVisible);
|
|
5463
5938
|
const overflow = visibleActions.slice(maxVisible);
|
|
5464
|
-
const [confirmAction, setConfirmAction] =
|
|
5939
|
+
const [confirmAction, setConfirmAction] = React6.useState(null);
|
|
5465
5940
|
function executeAction(action) {
|
|
5466
5941
|
if (action.confirm) {
|
|
5467
5942
|
setConfirmAction(action);
|
|
@@ -5629,10 +6104,10 @@ function DataTable({
|
|
|
5629
6104
|
getRowId,
|
|
5630
6105
|
className
|
|
5631
6106
|
}) {
|
|
5632
|
-
const [editingCell, setEditingCell] =
|
|
6107
|
+
const [editingCell, setEditingCell] = React6.useState(null);
|
|
5633
6108
|
const headerGroups = table.getHeaderGroups();
|
|
5634
6109
|
const rowModel = table.getRowModel();
|
|
5635
|
-
const handleCellDoubleClick =
|
|
6110
|
+
const handleCellDoubleClick = React6.useCallback(
|
|
5636
6111
|
(rowId, columnId, columnDef) => {
|
|
5637
6112
|
if (!enableInlineEdit) return;
|
|
5638
6113
|
if (!columnDef.meta?.entityMeta?.editable) return;
|
|
@@ -5640,7 +6115,7 @@ function DataTable({
|
|
|
5640
6115
|
},
|
|
5641
6116
|
[enableInlineEdit]
|
|
5642
6117
|
);
|
|
5643
|
-
const handleInlineSave =
|
|
6118
|
+
const handleInlineSave = React6.useCallback(
|
|
5644
6119
|
async (row, columnId, value) => {
|
|
5645
6120
|
const field = columnId;
|
|
5646
6121
|
await onInlineSave?.(row.original, field, value);
|
|
@@ -5817,7 +6292,7 @@ function GalleryView({
|
|
|
5817
6292
|
galleryColumns,
|
|
5818
6293
|
className
|
|
5819
6294
|
}) {
|
|
5820
|
-
const [editingId, setEditingId] =
|
|
6295
|
+
const [editingId, setEditingId] = React6.useState(null);
|
|
5821
6296
|
const breakpointClasses = galleryColumns ? buildBreakpointClasses(galleryColumns) : "";
|
|
5822
6297
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5823
6298
|
"div",
|
|
@@ -5881,7 +6356,7 @@ function GalleryCard({
|
|
|
5881
6356
|
(s) => selectionStore ? s.isMultiSelectMode : false
|
|
5882
6357
|
);
|
|
5883
6358
|
const storeToggle = useSelectionStore(selStore, (s) => s.toggle);
|
|
5884
|
-
const toggle =
|
|
6359
|
+
const toggle = React6.useCallback(
|
|
5885
6360
|
(id) => {
|
|
5886
6361
|
if (selectionStore) storeToggle(id);
|
|
5887
6362
|
},
|
|
@@ -6042,7 +6517,7 @@ function ListView({
|
|
|
6042
6517
|
getRowId,
|
|
6043
6518
|
className
|
|
6044
6519
|
}) {
|
|
6045
|
-
const [editingId, setEditingId] =
|
|
6520
|
+
const [editingId, setEditingId] = React6.useState(null);
|
|
6046
6521
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("divide-y rounded-md border", className), children: rows.map((row) => {
|
|
6047
6522
|
const id = getRowId?.(row.original) ?? row.id;
|
|
6048
6523
|
const isEditing = editingId === id;
|
|
@@ -6095,7 +6570,7 @@ function ListItem({
|
|
|
6095
6570
|
(s) => selectionStore ? s.isMultiSelectMode : false
|
|
6096
6571
|
);
|
|
6097
6572
|
const storeToggle = useSelectionStore(selStore, (s) => s.toggle);
|
|
6098
|
-
const toggle =
|
|
6573
|
+
const toggle = React6.useCallback(
|
|
6099
6574
|
(id) => {
|
|
6100
6575
|
if (selectionStore) storeToggle(id);
|
|
6101
6576
|
},
|
|
@@ -6289,7 +6764,7 @@ function DataTableToolbar({
|
|
|
6289
6764
|
className,
|
|
6290
6765
|
children
|
|
6291
6766
|
}) {
|
|
6292
|
-
const [colVisOpen, setColVisOpen] =
|
|
6767
|
+
const [colVisOpen, setColVisOpen] = React6.useState(false);
|
|
6293
6768
|
const globalFilter = table.getState().globalFilter;
|
|
6294
6769
|
const columnFilters = table.getState().columnFilters;
|
|
6295
6770
|
const hasFilters = columnFilters.length > 0;
|
|
@@ -6457,7 +6932,7 @@ function DataTablePagination({
|
|
|
6457
6932
|
totalCount,
|
|
6458
6933
|
className
|
|
6459
6934
|
}) {
|
|
6460
|
-
const pageSizeId =
|
|
6935
|
+
const pageSizeId = React6.useId();
|
|
6461
6936
|
if (mode === "none") return null;
|
|
6462
6937
|
const state = table.getState();
|
|
6463
6938
|
const count = totalCount ?? table.getPrePaginationRowModel().rows.length;
|
|
@@ -6606,7 +7081,7 @@ function ChevronsRightIcon({ className }) {
|
|
|
6606
7081
|
] });
|
|
6607
7082
|
}
|
|
6608
7083
|
function EmptyState({ config, isFiltered = false, className }) {
|
|
6609
|
-
if (
|
|
7084
|
+
if (React6__default.default.isValidElement(config)) {
|
|
6610
7085
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: config });
|
|
6611
7086
|
}
|
|
6612
7087
|
const cfg = config ?? {};
|
|
@@ -6656,7 +7131,7 @@ function MultiSelectBar({
|
|
|
6656
7131
|
}) {
|
|
6657
7132
|
const selectedIdsSet = useSelectionStore(store, (s) => s.selectedIds);
|
|
6658
7133
|
const selectedCount = selectedIdsSet.size;
|
|
6659
|
-
const selectedIds =
|
|
7134
|
+
const selectedIds = React6.useMemo(() => Array.from(selectedIdsSet), [selectedIdsSet]);
|
|
6660
7135
|
const deselectAll = useSelectionStore(store, (s) => s.deselectAll);
|
|
6661
7136
|
useSelectionStore(store, (s) => s.selectAll);
|
|
6662
7137
|
if (selectedCount === 0) return null;
|
|
@@ -6734,11 +7209,11 @@ function PresetPicker({
|
|
|
6734
7209
|
pendingChangesCount = 0,
|
|
6735
7210
|
className
|
|
6736
7211
|
}) {
|
|
6737
|
-
const [isOpen, setIsOpen] =
|
|
6738
|
-
const [activeTab, setActiveTab] =
|
|
6739
|
-
const popoverRef =
|
|
6740
|
-
const triggerRef =
|
|
6741
|
-
|
|
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(() => {
|
|
6742
7217
|
function handleClick(e) {
|
|
6743
7218
|
if (popoverRef.current && !popoverRef.current.contains(e.target) && !triggerRef.current?.contains(e.target)) {
|
|
6744
7219
|
setIsOpen(false);
|
|
@@ -6909,7 +7384,7 @@ function PresetItem({
|
|
|
6909
7384
|
onEdit,
|
|
6910
7385
|
onDelete
|
|
6911
7386
|
}) {
|
|
6912
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
7387
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = React6.useState(false);
|
|
6913
7388
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6914
7389
|
"div",
|
|
6915
7390
|
{
|
|
@@ -7021,13 +7496,13 @@ function FilterPresetDialog({
|
|
|
7021
7496
|
preset,
|
|
7022
7497
|
onSave
|
|
7023
7498
|
}) {
|
|
7024
|
-
const nameId =
|
|
7025
|
-
const descriptionId =
|
|
7026
|
-
const [name, setName] =
|
|
7027
|
-
const [description, setDescription] =
|
|
7028
|
-
const [isDefault, setIsDefault] =
|
|
7029
|
-
const [logic, setLogic] =
|
|
7030
|
-
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(() => {
|
|
7031
7506
|
if (!preset?.filter) return [];
|
|
7032
7507
|
const filterSpec = preset.filter;
|
|
7033
7508
|
const rawClauses = Array.isArray(filterSpec) ? filterSpec : filterSpec.clauses ?? [];
|
|
@@ -7270,10 +7745,10 @@ function ColumnPresetDialog({
|
|
|
7270
7745
|
preset,
|
|
7271
7746
|
onSave
|
|
7272
7747
|
}) {
|
|
7273
|
-
const [name, setName] =
|
|
7274
|
-
const [description, setDescription] =
|
|
7275
|
-
const [isDefault, setIsDefault] =
|
|
7276
|
-
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(() => {
|
|
7277
7752
|
if (preset?.columns) return [...preset.columns];
|
|
7278
7753
|
return columns.map((col, idx) => ({
|
|
7279
7754
|
id: col.accessorKey ?? col.id ?? `col_${idx}`,
|
|
@@ -7283,7 +7758,7 @@ function ColumnPresetDialog({
|
|
|
7283
7758
|
pinned: false
|
|
7284
7759
|
}));
|
|
7285
7760
|
});
|
|
7286
|
-
const [dragIdx, setDragIdx] =
|
|
7761
|
+
const [dragIdx, setDragIdx] = React6.useState(null);
|
|
7287
7762
|
function updateEntry(id, updates) {
|
|
7288
7763
|
setEntries(
|
|
7289
7764
|
(prev) => prev.map((e) => e.id === id ? { ...e, ...updates } : e)
|
|
@@ -7556,15 +8031,15 @@ function EntityListView(props) {
|
|
|
7556
8031
|
onRefresh,
|
|
7557
8032
|
className
|
|
7558
8033
|
} = props;
|
|
7559
|
-
const data =
|
|
8034
|
+
const data = React6.useMemo(
|
|
7560
8035
|
() => viewResult?.items ?? dataProp ?? [],
|
|
7561
8036
|
[viewResult?.items, dataProp]
|
|
7562
8037
|
);
|
|
7563
|
-
const selectionStoreRef =
|
|
8038
|
+
const selectionStoreRef = React6.useRef(null);
|
|
7564
8039
|
if (!selectionStoreRef.current) {
|
|
7565
8040
|
selectionStoreRef.current = createSelectionStore();
|
|
7566
8041
|
}
|
|
7567
|
-
const [viewMode, setViewMode] =
|
|
8042
|
+
const [viewMode, setViewMode] = React6.useState(defaultViewMode);
|
|
7568
8043
|
const adapter = useTableStorageAdapter();
|
|
7569
8044
|
const realtimeMode = useTableRealtimeMode();
|
|
7570
8045
|
const presets = useTablePresets(tableId ?? "__no_table_id__", {
|
|
@@ -7572,10 +8047,10 @@ function EntityListView(props) {
|
|
|
7572
8047
|
realtimeMode,
|
|
7573
8048
|
enabled: enablePresets && !!tableId
|
|
7574
8049
|
});
|
|
7575
|
-
const [filterDialogOpen, setFilterDialogOpen] =
|
|
7576
|
-
const [columnDialogOpen, setColumnDialogOpen] =
|
|
7577
|
-
const [editingFilterPreset, setEditingFilterPreset] =
|
|
7578
|
-
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);
|
|
7579
8054
|
const table = useTable({
|
|
7580
8055
|
data,
|
|
7581
8056
|
columns,
|
|
@@ -7596,7 +8071,7 @@ function EntityListView(props) {
|
|
|
7596
8071
|
const prePagRows = table.getPrePaginationRowModel();
|
|
7597
8072
|
const isEmpty = data.length === 0;
|
|
7598
8073
|
const isFilteredEmpty = !isEmpty && prePagRows.rows.length === 0;
|
|
7599
|
-
const handleViewModeChange =
|
|
8074
|
+
const handleViewModeChange = React6.useCallback(
|
|
7600
8075
|
(mode) => {
|
|
7601
8076
|
setViewMode(mode);
|
|
7602
8077
|
if (enablePresets && tableId) {
|
|
@@ -7605,19 +8080,19 @@ function EntityListView(props) {
|
|
|
7605
8080
|
},
|
|
7606
8081
|
[enablePresets, tableId, presets]
|
|
7607
8082
|
);
|
|
7608
|
-
const handleInlineSaveTable =
|
|
8083
|
+
const handleInlineSaveTable = React6.useCallback(
|
|
7609
8084
|
(item, field, value) => {
|
|
7610
8085
|
onInlineEdit?.(item, field, value);
|
|
7611
8086
|
},
|
|
7612
8087
|
[onInlineEdit]
|
|
7613
8088
|
);
|
|
7614
|
-
const handleInlineSaveItem =
|
|
8089
|
+
const handleInlineSaveItem = React6.useCallback(
|
|
7615
8090
|
(item, changes) => {
|
|
7616
8091
|
onInlineSave?.(item, changes);
|
|
7617
8092
|
},
|
|
7618
8093
|
[onInlineSave]
|
|
7619
8094
|
);
|
|
7620
|
-
const handleBatchAction =
|
|
8095
|
+
const handleBatchAction = React6.useCallback(
|
|
7621
8096
|
(actionId, selectedIds) => {
|
|
7622
8097
|
if (!onBatchAction) return;
|
|
7623
8098
|
const selectedItems = data.filter((item) => {
|
|
@@ -7766,12 +8241,12 @@ function DataTableFilter({
|
|
|
7766
8241
|
column,
|
|
7767
8242
|
className
|
|
7768
8243
|
}) {
|
|
7769
|
-
const [isOpen, setIsOpen] =
|
|
7770
|
-
const popoverRef =
|
|
7771
|
-
const triggerRef =
|
|
8244
|
+
const [isOpen, setIsOpen] = React6.useState(false);
|
|
8245
|
+
const popoverRef = React6.useRef(null);
|
|
8246
|
+
const triggerRef = React6.useRef(null);
|
|
7772
8247
|
const filterType = column.columnDef.meta?.entityMeta?.filterType ?? "text";
|
|
7773
8248
|
const isFiltered = column.getIsFiltered();
|
|
7774
|
-
|
|
8249
|
+
React6.useEffect(() => {
|
|
7775
8250
|
function handleClick(e) {
|
|
7776
8251
|
if (popoverRef.current && !popoverRef.current.contains(e.target) && !triggerRef.current?.contains(e.target)) {
|
|
7777
8252
|
setIsOpen(false);
|
|
@@ -7829,7 +8304,7 @@ function FilterControl({
|
|
|
7829
8304
|
}
|
|
7830
8305
|
}
|
|
7831
8306
|
function TextFilter({ column }) {
|
|
7832
|
-
const id =
|
|
8307
|
+
const id = React6.useId();
|
|
7833
8308
|
const value = column.getFilterValue() ?? "";
|
|
7834
8309
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7835
8310
|
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "text-xs font-medium", children: "Contains" }),
|
|
@@ -7856,8 +8331,8 @@ function TextFilter({ column }) {
|
|
|
7856
8331
|
] });
|
|
7857
8332
|
}
|
|
7858
8333
|
function NumberFilter({ column }) {
|
|
7859
|
-
const minId =
|
|
7860
|
-
const maxId =
|
|
8334
|
+
const minId = React6.useId();
|
|
8335
|
+
const maxId = React6.useId();
|
|
7861
8336
|
const value = column.getFilterValue() ?? [void 0, void 0];
|
|
7862
8337
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7863
8338
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: "Range" }),
|
|
@@ -7961,8 +8436,8 @@ function EnumFilter({ column }) {
|
|
|
7961
8436
|
] });
|
|
7962
8437
|
}
|
|
7963
8438
|
function DateFilter({ column }) {
|
|
7964
|
-
const startId =
|
|
7965
|
-
const endId =
|
|
8439
|
+
const startId = React6.useId();
|
|
8440
|
+
const endId = React6.useId();
|
|
7966
8441
|
const value = column.getFilterValue() ?? [void 0, void 0];
|
|
7967
8442
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
7968
8443
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium", children: "Date range" }),
|
|
@@ -8006,13 +8481,13 @@ function selectionColumn2() {
|
|
|
8006
8481
|
enableFiltering: false,
|
|
8007
8482
|
enableHiding: false,
|
|
8008
8483
|
enableResizing: false,
|
|
8009
|
-
header: ({ table }) =>
|
|
8484
|
+
header: ({ table }) => React6__default.default.createElement("input", {
|
|
8010
8485
|
type: "checkbox",
|
|
8011
8486
|
checked: table.getIsAllPageRowsSelected(),
|
|
8012
8487
|
onChange: table.getToggleAllPageRowsSelectedHandler(),
|
|
8013
8488
|
className: "h-4 w-4 rounded border-primary text-primary focus:ring-ring"
|
|
8014
8489
|
}),
|
|
8015
|
-
cell: ({ row }) =>
|
|
8490
|
+
cell: ({ row }) => React6__default.default.createElement("input", {
|
|
8016
8491
|
type: "checkbox",
|
|
8017
8492
|
checked: row.getIsSelected(),
|
|
8018
8493
|
onChange: row.getToggleSelectedHandler(),
|
|
@@ -8148,7 +8623,7 @@ function enumColumn2(options) {
|
|
|
8148
8623
|
const opt = options.options.find((o) => o.value === val);
|
|
8149
8624
|
if (!opt) return val;
|
|
8150
8625
|
if (opt.badgeClassName) {
|
|
8151
|
-
return
|
|
8626
|
+
return React6__default.default.createElement(
|
|
8152
8627
|
"span",
|
|
8153
8628
|
{
|
|
8154
8629
|
className: `inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium capitalize ${opt.badgeClassName}`
|
|
@@ -8156,7 +8631,7 @@ function enumColumn2(options) {
|
|
|
8156
8631
|
opt.label
|
|
8157
8632
|
);
|
|
8158
8633
|
}
|
|
8159
|
-
return
|
|
8634
|
+
return React6__default.default.createElement(
|
|
8160
8635
|
"span",
|
|
8161
8636
|
{
|
|
8162
8637
|
className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
@@ -8213,6 +8688,8 @@ exports.GalleryView = GalleryView;
|
|
|
8213
8688
|
exports.InlineCellEditor = InlineCellEditor;
|
|
8214
8689
|
exports.InlineItemEditor = InlineItemEditor;
|
|
8215
8690
|
exports.ListView = ListView;
|
|
8691
|
+
exports.MarkdownFieldEditor = MarkdownFieldEditor;
|
|
8692
|
+
exports.MarkdownFieldRenderer = MarkdownFieldRenderer;
|
|
8216
8693
|
exports.MemoryAdapter = MemoryAdapter;
|
|
8217
8694
|
exports.MultiSelectBar = MultiSelectBar;
|
|
8218
8695
|
exports.PresetPicker = PresetPicker;
|
|
@@ -8237,6 +8714,7 @@ exports.ZustandPersistAdapter = ZustandPersistAdapter;
|
|
|
8237
8714
|
exports.actionsColumn = actionsColumn;
|
|
8238
8715
|
exports.applyView = applyView;
|
|
8239
8716
|
exports.booleanColumn = booleanColumn;
|
|
8717
|
+
exports.buildEntityFieldsFromSchema = buildEntityFieldsFromSchema;
|
|
8240
8718
|
exports.cascadeInvalidation = cascadeInvalidation;
|
|
8241
8719
|
exports.checkCompleteness = checkCompleteness;
|
|
8242
8720
|
exports.compareEntities = compareEntities;
|
|
@@ -8252,6 +8730,7 @@ exports.createGraphTransaction = createGraphTransaction;
|
|
|
8252
8730
|
exports.createPresetStore = createPresetStore;
|
|
8253
8731
|
exports.createPrismaEntityConfig = createPrismaEntityConfig;
|
|
8254
8732
|
exports.createRow = createRow;
|
|
8733
|
+
exports.createSchemaGraphTool = createSchemaGraphTool;
|
|
8255
8734
|
exports.createSelectionStore = createSelectionStore;
|
|
8256
8735
|
exports.createSupabaseRealtimeAdapter = createSupabaseRealtimeAdapter;
|
|
8257
8736
|
exports.createWebSocketAdapter = createWebSocketAdapter;
|
|
@@ -8262,10 +8741,12 @@ exports.editAction = editAction;
|
|
|
8262
8741
|
exports.enumColumn = enumColumn;
|
|
8263
8742
|
exports.executeGQL = executeGQL;
|
|
8264
8743
|
exports.exportGraphSnapshot = exportGraphSnapshot;
|
|
8744
|
+
exports.exportGraphSnapshotWithSchemas = exportGraphSnapshotWithSchemas;
|
|
8265
8745
|
exports.fetchEntity = fetchEntity;
|
|
8266
8746
|
exports.fetchList = fetchList;
|
|
8267
8747
|
exports.flattenClauses = flattenClauses;
|
|
8268
8748
|
exports.getCoreRowModel = getCoreRowModel2;
|
|
8749
|
+
exports.getEntityJsonSchema = getEntityJsonSchema;
|
|
8269
8750
|
exports.getExpandedRowModel = getExpandedRowModel;
|
|
8270
8751
|
exports.getFacetedMinMaxValues = getFacetedMinMaxValues;
|
|
8271
8752
|
exports.getFacetedRowModel = getFacetedRowModel;
|
|
@@ -8278,10 +8759,12 @@ exports.getSchema = getSchema;
|
|
|
8278
8759
|
exports.getSelectedRowModel = getSelectedRowModel;
|
|
8279
8760
|
exports.getSortedRowModel = getSortedRowModel2;
|
|
8280
8761
|
exports.hasCustomPredicates = hasCustomPredicates;
|
|
8762
|
+
exports.hydrateGraphFromStorage = hydrateGraphFromStorage;
|
|
8281
8763
|
exports.matchesFilter = matchesFilter;
|
|
8282
8764
|
exports.matchesSearch = matchesSearch;
|
|
8283
8765
|
exports.normalizeGQLResponse = normalizeGQLResponse;
|
|
8284
8766
|
exports.numberColumn = numberColumn;
|
|
8767
|
+
exports.persistGraphToStorage = persistGraphToStorage;
|
|
8285
8768
|
exports.prismaRelationsToSchema = prismaRelationsToSchema;
|
|
8286
8769
|
exports.pureActionsColumn = actionsColumn2;
|
|
8287
8770
|
exports.pureBooleanColumn = booleanColumn2;
|
|
@@ -8292,12 +8775,16 @@ exports.pureSelectionColumn = selectionColumn2;
|
|
|
8292
8775
|
exports.pureTextColumn = textColumn2;
|
|
8293
8776
|
exports.queryOnce = queryOnce;
|
|
8294
8777
|
exports.readRelations = readRelations;
|
|
8778
|
+
exports.registerEntityJsonSchema = registerEntityJsonSchema;
|
|
8779
|
+
exports.registerRuntimeSchema = registerRuntimeSchema;
|
|
8295
8780
|
exports.registerSchema = registerSchema;
|
|
8781
|
+
exports.renderMarkdownToHtml = renderMarkdownToHtml;
|
|
8296
8782
|
exports.resetRealtimeManager = resetRealtimeManager;
|
|
8297
8783
|
exports.selectGraph = selectGraph;
|
|
8298
8784
|
exports.selectionColumn = selectionColumn;
|
|
8299
8785
|
exports.serializeKey = serializeKey;
|
|
8300
8786
|
exports.startGarbageCollector = startGarbageCollector;
|
|
8787
|
+
exports.startLocalFirstGraph = startLocalFirstGraph;
|
|
8301
8788
|
exports.stopGarbageCollector = stopGarbageCollector;
|
|
8302
8789
|
exports.textColumn = textColumn;
|
|
8303
8790
|
exports.toGraphQLVariables = toGraphQLVariables;
|
|
@@ -8318,8 +8805,10 @@ exports.useGQLMutation = useGQLMutation;
|
|
|
8318
8805
|
exports.useGQLSubscription = useGQLSubscription;
|
|
8319
8806
|
exports.useGraphDevTools = useGraphDevTools;
|
|
8320
8807
|
exports.useGraphStore = useGraphStore;
|
|
8808
|
+
exports.useGraphSyncStatus = useGraphSyncStatus;
|
|
8321
8809
|
exports.useLocalFirst = useLocalFirst;
|
|
8322
8810
|
exports.usePGliteQuery = usePGliteQuery;
|
|
8811
|
+
exports.useSchemaEntityFields = useSchemaEntityFields;
|
|
8323
8812
|
exports.useSelectionContext = useSelectionContext;
|
|
8324
8813
|
exports.useSelectionStore = useSelectionStore;
|
|
8325
8814
|
exports.useSuspenseEntity = useSuspenseEntity;
|