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