@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.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { create, createStore, useStore } from 'zustand';
|
|
2
2
|
import { subscribeWithSelector, persist } from 'zustand/middleware';
|
|
3
3
|
import { immer } from 'zustand/middleware/immer';
|
|
4
|
-
import
|
|
4
|
+
import React6, { createContext, useMemo, useSyncExternalStore, useRef, useCallback, useEffect, useState, useContext, useId } from 'react';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
6
|
import { useShallow } from 'zustand/react/shallow';
|
|
6
7
|
import { useReactTable, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
7
8
|
import { Search, X, Loader2, RefreshCw, ChevronLeft, ChevronRight, Pencil, Trash2 } from 'lucide-react';
|
|
8
9
|
import { clsx } from 'clsx';
|
|
9
10
|
import { twMerge } from 'tailwind-merge';
|
|
10
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
11
|
|
|
12
12
|
// src/graph.ts
|
|
13
13
|
var EMPTY_IDS = [];
|
|
@@ -288,6 +288,8 @@ function applySelection(row, select) {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// src/graph-actions.ts
|
|
291
|
+
var graphActionListeners = /* @__PURE__ */ new Set();
|
|
292
|
+
var graphActionReplayers = /* @__PURE__ */ new Map();
|
|
291
293
|
function createGraphTransaction() {
|
|
292
294
|
const baseline = cloneGraphData();
|
|
293
295
|
let closed = false;
|
|
@@ -355,22 +357,53 @@ function createGraphTransaction() {
|
|
|
355
357
|
return tx;
|
|
356
358
|
}
|
|
357
359
|
function createGraphAction(opts) {
|
|
360
|
+
if (opts.key) {
|
|
361
|
+
graphActionReplayers.set(opts.key, async (record) => {
|
|
362
|
+
const tx = createGraphTransaction();
|
|
363
|
+
try {
|
|
364
|
+
const result = await opts.run(tx, record.input);
|
|
365
|
+
tx.commit();
|
|
366
|
+
return result;
|
|
367
|
+
} catch (error) {
|
|
368
|
+
tx.rollback();
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
358
373
|
return async (input) => {
|
|
359
374
|
const tx = createGraphTransaction();
|
|
375
|
+
const record = opts.key ? {
|
|
376
|
+
id: `${opts.key}:${Date.now()}`,
|
|
377
|
+
key: opts.key,
|
|
378
|
+
input: structuredClone(input),
|
|
379
|
+
enqueuedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
380
|
+
} : null;
|
|
360
381
|
try {
|
|
382
|
+
if (record) emitGraphActionEvent({ type: "enqueued", record });
|
|
361
383
|
opts.optimistic?.(tx, input);
|
|
362
384
|
const result = await opts.run(tx, input);
|
|
363
385
|
opts.onSuccess?.(result, input, tx);
|
|
364
386
|
tx.commit();
|
|
387
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
365
388
|
return result;
|
|
366
389
|
} catch (error) {
|
|
367
390
|
tx.rollback();
|
|
368
391
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
392
|
+
if (record) emitGraphActionEvent({ type: "settled", record });
|
|
369
393
|
opts.onError?.(normalized, input);
|
|
370
394
|
throw normalized;
|
|
371
395
|
}
|
|
372
396
|
};
|
|
373
397
|
}
|
|
398
|
+
function subscribeGraphActionEvents(listener) {
|
|
399
|
+
graphActionListeners.add(listener);
|
|
400
|
+
return () => graphActionListeners.delete(listener);
|
|
401
|
+
}
|
|
402
|
+
async function replayRegisteredGraphAction(record) {
|
|
403
|
+
const replayer = graphActionReplayers.get(record.key);
|
|
404
|
+
if (!replayer) throw new Error(`No graph action registered for key "${record.key}"`);
|
|
405
|
+
return replayer(record);
|
|
406
|
+
}
|
|
374
407
|
function cloneGraphData(source = useGraphStore.getState()) {
|
|
375
408
|
return {
|
|
376
409
|
entities: structuredClone(source.entities),
|
|
@@ -380,6 +413,9 @@ function cloneGraphData(source = useGraphStore.getState()) {
|
|
|
380
413
|
lists: structuredClone(source.lists)
|
|
381
414
|
};
|
|
382
415
|
}
|
|
416
|
+
function emitGraphActionEvent(event) {
|
|
417
|
+
for (const listener of graphActionListeners) listener(event);
|
|
418
|
+
}
|
|
383
419
|
|
|
384
420
|
// src/graph-effects.ts
|
|
385
421
|
function createGraphEffect(opts) {
|
|
@@ -439,6 +475,213 @@ function defaultIsEqual(previousValue, nextValue) {
|
|
|
439
475
|
return JSON.stringify(previousValue) === JSON.stringify(nextValue);
|
|
440
476
|
}
|
|
441
477
|
|
|
478
|
+
// src/object-path.ts
|
|
479
|
+
function isObject(value) {
|
|
480
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
481
|
+
}
|
|
482
|
+
function getValueAtPath(source, path) {
|
|
483
|
+
if (!path) return source;
|
|
484
|
+
const segments = path.split(".").filter(Boolean);
|
|
485
|
+
let current = source;
|
|
486
|
+
for (const segment of segments) {
|
|
487
|
+
if (!isObject(current) && !Array.isArray(current)) return void 0;
|
|
488
|
+
current = current[segment];
|
|
489
|
+
}
|
|
490
|
+
return current;
|
|
491
|
+
}
|
|
492
|
+
function setValueAtPath(source, path, value) {
|
|
493
|
+
const segments = path.split(".").filter(Boolean);
|
|
494
|
+
if (segments.length === 0) return source;
|
|
495
|
+
const clone = structuredClone(source);
|
|
496
|
+
let current = clone;
|
|
497
|
+
for (let index = 0; index < segments.length - 1; index += 1) {
|
|
498
|
+
const segment = segments[index];
|
|
499
|
+
const next = current[segment];
|
|
500
|
+
if (!isObject(next)) current[segment] = {};
|
|
501
|
+
current = current[segment];
|
|
502
|
+
}
|
|
503
|
+
current[segments[segments.length - 1]] = value;
|
|
504
|
+
return clone;
|
|
505
|
+
}
|
|
506
|
+
function collectDirtyPaths(current, original, prefix = "", acc = /* @__PURE__ */ new Set()) {
|
|
507
|
+
if (isObject(current) && isObject(original)) {
|
|
508
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(current), ...Object.keys(original)]);
|
|
509
|
+
for (const key of keys) {
|
|
510
|
+
const nextPrefix = prefix ? `${prefix}.${key}` : key;
|
|
511
|
+
collectDirtyPaths(current[key], original[key], nextPrefix, acc);
|
|
512
|
+
}
|
|
513
|
+
return acc;
|
|
514
|
+
}
|
|
515
|
+
if (JSON.stringify(current) !== JSON.stringify(original) && prefix) acc.add(prefix);
|
|
516
|
+
return acc;
|
|
517
|
+
}
|
|
518
|
+
var schemaRegistry = /* @__PURE__ */ new Map();
|
|
519
|
+
function registerEntityJsonSchema(config) {
|
|
520
|
+
const key = registryKey(config.entityType, config.field, config.schemaId);
|
|
521
|
+
schemaRegistry.set(key, config);
|
|
522
|
+
}
|
|
523
|
+
function registerRuntimeSchema(config) {
|
|
524
|
+
registerEntityJsonSchema(config);
|
|
525
|
+
}
|
|
526
|
+
function getEntityJsonSchema(opts) {
|
|
527
|
+
const exact = schemaRegistry.get(registryKey(opts.entityType, opts.field, opts.schemaId));
|
|
528
|
+
if (exact) return exact;
|
|
529
|
+
if (opts.field) {
|
|
530
|
+
const byField = schemaRegistry.get(registryKey(opts.entityType, opts.field));
|
|
531
|
+
if (byField) return byField;
|
|
532
|
+
}
|
|
533
|
+
if (opts.schemaId) {
|
|
534
|
+
const byId = schemaRegistry.get(registryKey(opts.entityType, void 0, opts.schemaId));
|
|
535
|
+
if (byId) return byId;
|
|
536
|
+
}
|
|
537
|
+
for (const schema of schemaRegistry.values()) {
|
|
538
|
+
if (schema.entityType !== opts.entityType) continue;
|
|
539
|
+
if (opts.field && schema.field !== opts.field) continue;
|
|
540
|
+
return schema;
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
function useSchemaEntityFields(opts) {
|
|
545
|
+
return useMemo(() => {
|
|
546
|
+
const schema = opts.schema ?? getEntityJsonSchema(opts)?.schema;
|
|
547
|
+
if (!schema) return [];
|
|
548
|
+
return buildEntityFieldsFromSchema({ schema, rootField: opts.rootField ?? opts.field });
|
|
549
|
+
}, [opts.entityType, opts.field, opts.rootField, opts.schemaId, opts.schema]);
|
|
550
|
+
}
|
|
551
|
+
function buildEntityFieldsFromSchema(opts) {
|
|
552
|
+
return buildSchemaFields(opts.schema, opts.rootField ?? "", "");
|
|
553
|
+
}
|
|
554
|
+
function exportGraphSnapshotWithSchemas(opts) {
|
|
555
|
+
return JSON.stringify(
|
|
556
|
+
{
|
|
557
|
+
scope: opts.scope,
|
|
558
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
559
|
+
data: opts.data,
|
|
560
|
+
schemas: opts.schemas.filter(Boolean)
|
|
561
|
+
},
|
|
562
|
+
null,
|
|
563
|
+
opts.pretty === false ? 0 : 2
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
function escapeHtml(input) {
|
|
567
|
+
return input.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
568
|
+
}
|
|
569
|
+
function renderMarkdownToHtml(value) {
|
|
570
|
+
const escaped = escapeHtml(value);
|
|
571
|
+
const blocks = escaped.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
|
|
572
|
+
return blocks.map((block) => renderMarkdownBlock(block)).join("");
|
|
573
|
+
}
|
|
574
|
+
function MarkdownFieldRenderer({ value, className }) {
|
|
575
|
+
return /* @__PURE__ */ jsx(
|
|
576
|
+
"div",
|
|
577
|
+
{
|
|
578
|
+
className,
|
|
579
|
+
dangerouslySetInnerHTML: { __html: renderMarkdownToHtml(value ?? "") }
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
function MarkdownFieldEditor({
|
|
584
|
+
value,
|
|
585
|
+
onChange,
|
|
586
|
+
placeholder
|
|
587
|
+
}) {
|
|
588
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
589
|
+
/* @__PURE__ */ jsx(
|
|
590
|
+
"textarea",
|
|
591
|
+
{
|
|
592
|
+
value,
|
|
593
|
+
onChange: (event) => onChange(event.target.value),
|
|
594
|
+
placeholder,
|
|
595
|
+
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"
|
|
596
|
+
}
|
|
597
|
+
),
|
|
598
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-md border bg-background px-3 py-2", children: /* @__PURE__ */ jsx(MarkdownFieldRenderer, { value, className: "prose prose-sm max-w-none" }) })
|
|
599
|
+
] });
|
|
600
|
+
}
|
|
601
|
+
function createMarkdownDetailRenderer(field) {
|
|
602
|
+
return (value, entity) => /* @__PURE__ */ jsx(MarkdownFieldRenderer, { value: String(value ?? getValueAtPath(entity, field) ?? ""), className: "prose prose-sm max-w-none" });
|
|
603
|
+
}
|
|
604
|
+
function buildSchemaFields(schema, pathPrefix, schemaPathPrefix) {
|
|
605
|
+
if (schema.type === "object" && schema.properties) {
|
|
606
|
+
const entries = Object.entries(schema.properties).sort(([, left], [, right]) => {
|
|
607
|
+
const l = left["x-display-order"] ?? Number.MAX_SAFE_INTEGER;
|
|
608
|
+
const r = right["x-display-order"] ?? Number.MAX_SAFE_INTEGER;
|
|
609
|
+
return l - r;
|
|
610
|
+
});
|
|
611
|
+
return entries.flatMap(([key, childSchema]) => {
|
|
612
|
+
if (childSchema["x-hidden"]) return [];
|
|
613
|
+
const field = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
614
|
+
const schemaPath = schemaPathPrefix ? `${schemaPathPrefix}.${key}` : key;
|
|
615
|
+
if (childSchema.type === "object" && childSchema.properties) {
|
|
616
|
+
return buildSchemaFields(childSchema, field, schemaPath);
|
|
617
|
+
}
|
|
618
|
+
return [schemaField(field, schemaPath, childSchema, schema.required?.includes(key) ?? false)];
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
return [];
|
|
622
|
+
}
|
|
623
|
+
function schemaField(field, schemaPath, schema, required) {
|
|
624
|
+
const type = inferFieldType(schema);
|
|
625
|
+
const descriptor = {
|
|
626
|
+
field,
|
|
627
|
+
label: schema.title ?? humanize(field.split(".").pop() ?? field),
|
|
628
|
+
type,
|
|
629
|
+
required,
|
|
630
|
+
hint: schema.description,
|
|
631
|
+
schemaPath,
|
|
632
|
+
schema,
|
|
633
|
+
componentHint: schema["x-a2ui-component"]
|
|
634
|
+
};
|
|
635
|
+
if (schema.enum) {
|
|
636
|
+
descriptor.options = schema.enum.map((value) => ({
|
|
637
|
+
value: String(value),
|
|
638
|
+
label: String(value)
|
|
639
|
+
}));
|
|
640
|
+
}
|
|
641
|
+
if (type === "markdown") {
|
|
642
|
+
descriptor.render = createMarkdownDetailRenderer(field);
|
|
643
|
+
}
|
|
644
|
+
return descriptor;
|
|
645
|
+
}
|
|
646
|
+
function inferFieldType(schema) {
|
|
647
|
+
const forced = schema["x-field-type"];
|
|
648
|
+
if (forced === "markdown") return "markdown";
|
|
649
|
+
if (schema.format === "markdown") return "markdown";
|
|
650
|
+
if (schema.enum) return "enum";
|
|
651
|
+
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
|
|
652
|
+
switch (type) {
|
|
653
|
+
case "boolean":
|
|
654
|
+
return "boolean";
|
|
655
|
+
case "integer":
|
|
656
|
+
case "number":
|
|
657
|
+
return "number";
|
|
658
|
+
case "string":
|
|
659
|
+
if (schema.format === "email") return "email";
|
|
660
|
+
if (schema.format === "uri" || schema.format === "url") return "url";
|
|
661
|
+
if (schema.format === "date" || schema.format === "date-time") return "date";
|
|
662
|
+
return "text";
|
|
663
|
+
case "array":
|
|
664
|
+
case "object":
|
|
665
|
+
return "json";
|
|
666
|
+
default:
|
|
667
|
+
return "text";
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function registryKey(entityType, field, schemaId) {
|
|
671
|
+
return `${entityType}::${field ?? "*"}::${schemaId ?? "*"}`;
|
|
672
|
+
}
|
|
673
|
+
function humanize(value) {
|
|
674
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
675
|
+
}
|
|
676
|
+
function renderMarkdownBlock(block) {
|
|
677
|
+
if (block.startsWith("# ")) return `<h1>${renderInlineMarkdown(block.slice(2))}</h1>`;
|
|
678
|
+
if (block.startsWith("## ")) return `<h2>${renderInlineMarkdown(block.slice(3))}</h2>`;
|
|
679
|
+
return `<p>${renderInlineMarkdown(block).replaceAll("\n", "<br/>")}</p>`;
|
|
680
|
+
}
|
|
681
|
+
function renderInlineMarkdown(block) {
|
|
682
|
+
return block.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
683
|
+
}
|
|
684
|
+
|
|
442
685
|
// src/ai-interop.ts
|
|
443
686
|
function exportGraphSnapshot(opts) {
|
|
444
687
|
const payload = {
|
|
@@ -455,6 +698,216 @@ function createGraphTool(handler) {
|
|
|
455
698
|
exportGraphSnapshot
|
|
456
699
|
});
|
|
457
700
|
}
|
|
701
|
+
function createSchemaGraphTool(handler) {
|
|
702
|
+
return (input) => handler(input, {
|
|
703
|
+
store: useGraphStore.getState(),
|
|
704
|
+
queryOnce,
|
|
705
|
+
exportGraphSnapshot,
|
|
706
|
+
getEntityJsonSchema,
|
|
707
|
+
exportGraphSnapshotWithSchemas
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
var DEFAULT_STORAGE_KEY = "prometheus:graph";
|
|
711
|
+
var useGraphSyncStatusStore = create((set) => ({
|
|
712
|
+
status: {
|
|
713
|
+
phase: "idle",
|
|
714
|
+
isOnline: true,
|
|
715
|
+
isSynced: true,
|
|
716
|
+
pendingActions: 0,
|
|
717
|
+
lastHydratedAt: null,
|
|
718
|
+
lastPersistedAt: null,
|
|
719
|
+
storageKey: null,
|
|
720
|
+
error: null
|
|
721
|
+
},
|
|
722
|
+
setStatus: (status) => set((state) => ({
|
|
723
|
+
status: {
|
|
724
|
+
...state.status,
|
|
725
|
+
...status
|
|
726
|
+
}
|
|
727
|
+
}))
|
|
728
|
+
}));
|
|
729
|
+
var pendingActions = /* @__PURE__ */ new Map();
|
|
730
|
+
function useGraphSyncStatus() {
|
|
731
|
+
return useGraphSyncStatusStore((state) => state.status);
|
|
732
|
+
}
|
|
733
|
+
async function persistGraphToStorage(opts) {
|
|
734
|
+
const payload = {
|
|
735
|
+
version: 1,
|
|
736
|
+
snapshot: cloneGraphSnapshot(),
|
|
737
|
+
pendingActions: opts.pendingActions ?? Array.from(pendingActions.values())
|
|
738
|
+
};
|
|
739
|
+
const json = JSON.stringify(payload);
|
|
740
|
+
await opts.storage.set(opts.key, json);
|
|
741
|
+
const persistedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
742
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
743
|
+
lastPersistedAt: persistedAt,
|
|
744
|
+
storageKey: opts.key,
|
|
745
|
+
pendingActions: payload.pendingActions.length
|
|
746
|
+
});
|
|
747
|
+
return {
|
|
748
|
+
ok: true,
|
|
749
|
+
key: opts.key,
|
|
750
|
+
bytes: json.length,
|
|
751
|
+
persistedAt
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
async function hydrateGraphFromStorage(opts) {
|
|
755
|
+
const raw = await opts.storage.get(opts.key);
|
|
756
|
+
if (!raw) {
|
|
757
|
+
return {
|
|
758
|
+
ok: false,
|
|
759
|
+
key: opts.key,
|
|
760
|
+
hydratedAt: null,
|
|
761
|
+
entityCounts: {},
|
|
762
|
+
error: "No persisted graph snapshot found"
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
try {
|
|
766
|
+
const parsed = JSON.parse(raw);
|
|
767
|
+
useGraphStore.setState(parsed.snapshot);
|
|
768
|
+
pendingActions.clear();
|
|
769
|
+
for (const action of parsed.pendingActions ?? []) pendingActions.set(action.id, action);
|
|
770
|
+
const hydratedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
771
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
772
|
+
lastHydratedAt: hydratedAt,
|
|
773
|
+
storageKey: opts.key,
|
|
774
|
+
pendingActions: pendingActions.size,
|
|
775
|
+
error: null
|
|
776
|
+
});
|
|
777
|
+
return {
|
|
778
|
+
ok: true,
|
|
779
|
+
key: opts.key,
|
|
780
|
+
hydratedAt,
|
|
781
|
+
entityCounts: Object.fromEntries(
|
|
782
|
+
Object.entries(parsed.snapshot.entities).map(([type, entities]) => [type, Object.keys(entities).length])
|
|
783
|
+
),
|
|
784
|
+
pendingActions: Array.from(pendingActions.values())
|
|
785
|
+
};
|
|
786
|
+
} catch (error) {
|
|
787
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
788
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
789
|
+
phase: "error",
|
|
790
|
+
error: message,
|
|
791
|
+
storageKey: opts.key
|
|
792
|
+
});
|
|
793
|
+
return {
|
|
794
|
+
ok: false,
|
|
795
|
+
key: opts.key,
|
|
796
|
+
hydratedAt: null,
|
|
797
|
+
entityCounts: {},
|
|
798
|
+
error: message
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
function startLocalFirstGraph(opts) {
|
|
803
|
+
const key = opts.key ?? DEFAULT_STORAGE_KEY;
|
|
804
|
+
const persistDebounceMs = opts.persistDebounceMs ?? 50;
|
|
805
|
+
const statusStore = useGraphSyncStatusStore.getState();
|
|
806
|
+
statusStore.setStatus({
|
|
807
|
+
phase: "hydrating",
|
|
808
|
+
storageKey: key,
|
|
809
|
+
isOnline: opts.onlineSource?.getIsOnline() ?? getDefaultOnlineSource().getIsOnline(),
|
|
810
|
+
isSynced: pendingActions.size === 0,
|
|
811
|
+
error: null
|
|
812
|
+
});
|
|
813
|
+
let persistTimer = null;
|
|
814
|
+
const schedulePersist = () => {
|
|
815
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
816
|
+
persistTimer = setTimeout(() => {
|
|
817
|
+
void persistGraphToStorage({ storage: opts.storage, key });
|
|
818
|
+
}, persistDebounceMs);
|
|
819
|
+
};
|
|
820
|
+
const graphUnsub = useGraphStore.subscribe(() => {
|
|
821
|
+
schedulePersist();
|
|
822
|
+
});
|
|
823
|
+
const actionUnsub = subscribeGraphActionEvents((event) => {
|
|
824
|
+
if (event.type === "enqueued") pendingActions.set(event.record.id, event.record);
|
|
825
|
+
if (event.type === "settled") pendingActions.delete(event.record.id);
|
|
826
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
827
|
+
pendingActions: pendingActions.size,
|
|
828
|
+
isSynced: pendingActions.size === 0
|
|
829
|
+
});
|
|
830
|
+
schedulePersist();
|
|
831
|
+
});
|
|
832
|
+
const onlineSource = opts.onlineSource ?? getDefaultOnlineSource();
|
|
833
|
+
const onlineUnsub = onlineSource.subscribe((online) => {
|
|
834
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
835
|
+
isOnline: online,
|
|
836
|
+
phase: online ? "ready" : "offline"
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
const ready = (async () => {
|
|
840
|
+
const hydrated = await hydrateGraphFromStorage({ storage: opts.storage, key });
|
|
841
|
+
if (opts.replayPendingActions && hydrated.ok && pendingActions.size > 0) {
|
|
842
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
843
|
+
phase: "syncing",
|
|
844
|
+
isSynced: false
|
|
845
|
+
});
|
|
846
|
+
for (const action of Array.from(pendingActions.values())) {
|
|
847
|
+
await replayRegisteredGraphAction(action);
|
|
848
|
+
pendingActions.delete(action.id);
|
|
849
|
+
}
|
|
850
|
+
await persistGraphToStorage({ storage: opts.storage, key });
|
|
851
|
+
}
|
|
852
|
+
const online = onlineSource.getIsOnline();
|
|
853
|
+
useGraphSyncStatusStore.getState().setStatus({
|
|
854
|
+
phase: online ? "ready" : "offline",
|
|
855
|
+
isOnline: online,
|
|
856
|
+
isSynced: pendingActions.size === 0,
|
|
857
|
+
pendingActions: pendingActions.size
|
|
858
|
+
});
|
|
859
|
+
})();
|
|
860
|
+
return {
|
|
861
|
+
ready,
|
|
862
|
+
dispose() {
|
|
863
|
+
graphUnsub();
|
|
864
|
+
actionUnsub();
|
|
865
|
+
onlineUnsub();
|
|
866
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
867
|
+
},
|
|
868
|
+
async persistNow() {
|
|
869
|
+
await persistGraphToStorage({ storage: opts.storage, key });
|
|
870
|
+
},
|
|
871
|
+
hydrate() {
|
|
872
|
+
return hydrateGraphFromStorage({ storage: opts.storage, key });
|
|
873
|
+
},
|
|
874
|
+
getStatus() {
|
|
875
|
+
return useGraphSyncStatusStore.getState().status;
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
function cloneGraphSnapshot() {
|
|
880
|
+
const state = useGraphStore.getState();
|
|
881
|
+
return {
|
|
882
|
+
entities: structuredClone(state.entities),
|
|
883
|
+
patches: structuredClone(state.patches),
|
|
884
|
+
entityStates: structuredClone(state.entityStates),
|
|
885
|
+
syncMetadata: structuredClone(state.syncMetadata),
|
|
886
|
+
lists: structuredClone(state.lists)
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function getDefaultOnlineSource() {
|
|
890
|
+
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
891
|
+
return {
|
|
892
|
+
getIsOnline: () => window.navigator.onLine,
|
|
893
|
+
subscribe: (listener) => {
|
|
894
|
+
const onlineHandler = () => listener(true);
|
|
895
|
+
const offlineHandler = () => listener(false);
|
|
896
|
+
window.addEventListener("online", onlineHandler);
|
|
897
|
+
window.addEventListener("offline", offlineHandler);
|
|
898
|
+
return () => {
|
|
899
|
+
window.removeEventListener("online", onlineHandler);
|
|
900
|
+
window.removeEventListener("offline", offlineHandler);
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
return {
|
|
906
|
+
getIsOnline: () => true,
|
|
907
|
+
subscribe: () => () => {
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
458
911
|
|
|
459
912
|
// src/engine.ts
|
|
460
913
|
function serializeKey(key) {
|
|
@@ -721,10 +1174,11 @@ function useEntity(opts) {
|
|
|
721
1174
|
fetchRef.current = opts.fetch;
|
|
722
1175
|
const normalizeRef = useRef(opts.normalize);
|
|
723
1176
|
normalizeRef.current = opts.normalize;
|
|
724
|
-
const
|
|
1177
|
+
const dataSelector = useCallback((state) => {
|
|
725
1178
|
if (!id) return null;
|
|
726
1179
|
return state.readEntitySnapshot(type, id);
|
|
727
|
-
})
|
|
1180
|
+
}, [id, type]);
|
|
1181
|
+
const data = useStore(useGraphStore, useShallow(dataSelector));
|
|
728
1182
|
const entityState = useStore(useGraphStore, useCallback(
|
|
729
1183
|
(state) => state.entityStates[`${type}:${id}`] ?? EMPTY_ENTITY_STATE,
|
|
730
1184
|
[type, id]
|
|
@@ -757,13 +1211,11 @@ function useEntityList(opts) {
|
|
|
757
1211
|
const normalizeRef = useRef(opts.normalize);
|
|
758
1212
|
normalizeRef.current = opts.normalize;
|
|
759
1213
|
const listState = useStore(useGraphStore, useCallback((state) => state.lists[key] ?? EMPTY_LIST_STATE, [key]));
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
})
|
|
766
|
-
);
|
|
1214
|
+
const itemsSelector = useCallback((state) => {
|
|
1215
|
+
const ids = state.lists[key]?.ids ?? EMPTY_IDS;
|
|
1216
|
+
return ids.map((id) => state.readEntitySnapshot(type, id)).filter((x) => x !== null);
|
|
1217
|
+
}, [key, type]);
|
|
1218
|
+
const items = useStore(useGraphStore, useShallow(itemsSelector));
|
|
767
1219
|
const doFetch = useCallback((params = {}) => {
|
|
768
1220
|
if (!enabled) return;
|
|
769
1221
|
fetchList({ type, queryKey, mode, fetch: fetchRef.current, normalize: normalizeRef.current }, params, getEngineOptions(), false);
|
|
@@ -1436,15 +1888,15 @@ function useEntityView(opts) {
|
|
|
1436
1888
|
}
|
|
1437
1889
|
|
|
1438
1890
|
// src/crud/relations.ts
|
|
1439
|
-
var
|
|
1891
|
+
var schemaRegistry2 = /* @__PURE__ */ new Map();
|
|
1440
1892
|
function registerSchema(schema) {
|
|
1441
|
-
|
|
1893
|
+
schemaRegistry2.set(schema.type, schema);
|
|
1442
1894
|
}
|
|
1443
1895
|
function getSchema(type) {
|
|
1444
|
-
return
|
|
1896
|
+
return schemaRegistry2.get(type) ?? null;
|
|
1445
1897
|
}
|
|
1446
1898
|
function cascadeInvalidation(ctx) {
|
|
1447
|
-
const schema =
|
|
1899
|
+
const schema = schemaRegistry2.get(ctx.type);
|
|
1448
1900
|
if (!schema) return;
|
|
1449
1901
|
const store = useGraphStore.getState();
|
|
1450
1902
|
if (schema.globalListKeys) for (const key of schema.globalListKeys) store.invalidateLists(key);
|
|
@@ -1471,7 +1923,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1471
1923
|
}
|
|
1472
1924
|
}
|
|
1473
1925
|
}
|
|
1474
|
-
for (const [, otherSchema] of
|
|
1926
|
+
for (const [, otherSchema] of schemaRegistry2) {
|
|
1475
1927
|
if (!otherSchema.relations) continue;
|
|
1476
1928
|
for (const [, rel] of Object.entries(otherSchema.relations)) {
|
|
1477
1929
|
if (rel.targetType !== ctx.type) continue;
|
|
@@ -1480,7 +1932,7 @@ function cascadeInvalidation(ctx) {
|
|
|
1480
1932
|
}
|
|
1481
1933
|
}
|
|
1482
1934
|
function readRelations(type, entity) {
|
|
1483
|
-
const schema =
|
|
1935
|
+
const schema = schemaRegistry2.get(type);
|
|
1484
1936
|
if (!schema?.relations) return {};
|
|
1485
1937
|
const store = useGraphStore.getState();
|
|
1486
1938
|
const result = {};
|
|
@@ -1541,7 +1993,7 @@ function useEntityCRUD(opts) {
|
|
|
1541
1993
|
useEffect(() => {
|
|
1542
1994
|
if (detail) setEditBuffer({ ...detail });
|
|
1543
1995
|
}, [selectedId]);
|
|
1544
|
-
const setField = useCallback((field, value) => setEditBuffer((prev) => (
|
|
1996
|
+
const setField = useCallback((field, value) => setEditBuffer((prev) => setValueAtPath(prev, String(field), value)), []);
|
|
1545
1997
|
const setFields = useCallback((fields) => setEditBuffer((prev) => ({ ...prev, ...fields })), []);
|
|
1546
1998
|
const resetBuffer = useCallback(() => {
|
|
1547
1999
|
const current = selectedId ? useGraphStore.getState().readEntity(type, selectedId) : null;
|
|
@@ -1549,10 +2001,7 @@ function useEntityCRUD(opts) {
|
|
|
1549
2001
|
}, [type, selectedId]);
|
|
1550
2002
|
const dirty = useMemo(() => {
|
|
1551
2003
|
if (!detail) return { changed: /* @__PURE__ */ new Set(), isDirty: false };
|
|
1552
|
-
const changed =
|
|
1553
|
-
for (const key of Object.keys(editBuffer)) {
|
|
1554
|
-
if (JSON.stringify(editBuffer[key]) !== JSON.stringify(detail[key])) changed.add(key);
|
|
1555
|
-
}
|
|
2004
|
+
const changed = collectDirtyPaths(editBuffer, detail);
|
|
1556
2005
|
return { changed, isDirty: changed.size > 0 };
|
|
1557
2006
|
}, [editBuffer, detail]);
|
|
1558
2007
|
const startEdit = useCallback((id) => {
|
|
@@ -1609,7 +2058,7 @@ function useEntityCRUD(opts) {
|
|
|
1609
2058
|
const [createBuffer, setCreateBuffer] = useState({ ...createDefaults });
|
|
1610
2059
|
const [isCreating, setIsCreating] = useState(false);
|
|
1611
2060
|
const [createError, setCreateError] = useState(null);
|
|
1612
|
-
const setCreateField = useCallback((field, value) => setCreateBuffer((prev) => (
|
|
2061
|
+
const setCreateField = useCallback((field, value) => setCreateBuffer((prev) => setValueAtPath(prev, String(field), value)), []);
|
|
1613
2062
|
const setCreateFields = useCallback((fields) => setCreateBuffer((prev) => ({ ...prev, ...fields })), []);
|
|
1614
2063
|
const resetCreateBuffer = useCallback(() => setCreateBuffer({ ...optsRef.current.createDefaults ?? {} }), []);
|
|
1615
2064
|
const startCreate = useCallback(() => {
|
|
@@ -1622,7 +2071,7 @@ function useEntityCRUD(opts) {
|
|
|
1622
2071
|
setMode("list");
|
|
1623
2072
|
setCreateError(null);
|
|
1624
2073
|
}, [resetCreateBuffer]);
|
|
1625
|
-
const
|
|
2074
|
+
const create3 = useCallback(async () => {
|
|
1626
2075
|
if (!onCreate) return null;
|
|
1627
2076
|
setIsCreating(true);
|
|
1628
2077
|
setCreateError(null);
|
|
@@ -1696,7 +2145,7 @@ function useEntityCRUD(opts) {
|
|
|
1696
2145
|
setIsDeleting(false);
|
|
1697
2146
|
}
|
|
1698
2147
|
}, [type, selectedId, listQueryKey, clearSelectionAfterDelete]);
|
|
1699
|
-
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:
|
|
2148
|
+
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" };
|
|
1700
2149
|
}
|
|
1701
2150
|
|
|
1702
2151
|
// src/adapters/realtime-manager.ts
|
|
@@ -2744,7 +3193,7 @@ function EntityTable({ viewResult, columns, getRowId = (r) => String(r.id), sele
|
|
|
2744
3193
|
] });
|
|
2745
3194
|
}
|
|
2746
3195
|
function Sheet({ open, onClose, title, subtitle, children, footer, width = "w-[480px]" }) {
|
|
2747
|
-
|
|
3196
|
+
React6.useEffect(() => {
|
|
2748
3197
|
const h = (e) => {
|
|
2749
3198
|
if (e.key === "Escape") onClose();
|
|
2750
3199
|
};
|
|
@@ -2780,6 +3229,8 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2780
3229
|
return /* @__PURE__ */ jsx("input", { type: "number", value: String(value ?? ""), onChange: (e) => onChange(e.target.valueAsNumber), placeholder: descriptor.placeholder, className: base });
|
|
2781
3230
|
case "textarea":
|
|
2782
3231
|
return /* @__PURE__ */ 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" });
|
|
3232
|
+
case "markdown":
|
|
3233
|
+
return /* @__PURE__ */ jsx(MarkdownFieldEditor, { value: String(value ?? ""), onChange: (nextValue) => onChange(nextValue), placeholder: descriptor.placeholder });
|
|
2783
3234
|
case "date":
|
|
2784
3235
|
return /* @__PURE__ */ 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 });
|
|
2785
3236
|
case "boolean":
|
|
@@ -2799,12 +3250,35 @@ function FieldControl({ descriptor, value, onChange, entity, readonly }) {
|
|
|
2799
3250
|
!value && /* @__PURE__ */ jsx("option", { value: "", children: "Select\u2026" }),
|
|
2800
3251
|
(descriptor.options ?? []).map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
2801
3252
|
] });
|
|
3253
|
+
case "json":
|
|
3254
|
+
return /* @__PURE__ */ jsx(
|
|
3255
|
+
"textarea",
|
|
3256
|
+
{
|
|
3257
|
+
value: value != null ? JSON.stringify(value, null, 2) : "",
|
|
3258
|
+
onChange: (event) => {
|
|
3259
|
+
const nextValue = event.target.value;
|
|
3260
|
+
try {
|
|
3261
|
+
onChange(nextValue ? JSON.parse(nextValue) : null);
|
|
3262
|
+
} catch {
|
|
3263
|
+
onChange(nextValue);
|
|
3264
|
+
}
|
|
3265
|
+
},
|
|
3266
|
+
placeholder: descriptor.placeholder,
|
|
3267
|
+
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"
|
|
3268
|
+
}
|
|
3269
|
+
);
|
|
2802
3270
|
default:
|
|
2803
3271
|
return /* @__PURE__ */ jsx("input", { value: String(value ?? ""), onChange: (e) => onChange(e.target.value), className: base });
|
|
2804
3272
|
}
|
|
2805
3273
|
}
|
|
3274
|
+
function FieldReadonlyValue({ descriptor, value, entity }) {
|
|
3275
|
+
if (descriptor.render) return /* @__PURE__ */ jsx(Fragment, { children: descriptor.render(value, entity) });
|
|
3276
|
+
if (descriptor.type === "markdown") return /* @__PURE__ */ jsx(MarkdownFieldRenderer, { value: String(value ?? ""), className: "prose prose-sm max-w-none py-1" });
|
|
3277
|
+
if (descriptor.type === "json") return /* @__PURE__ */ jsx("pre", { className: "text-xs py-1 whitespace-pre-wrap break-words", children: JSON.stringify(value ?? null, null, 2) });
|
|
3278
|
+
return /* @__PURE__ */ jsx("p", { className: "text-sm py-1", children: value != null && value !== "" ? String(value) : "\u2014" });
|
|
3279
|
+
}
|
|
2806
3280
|
function EntityDetailSheet({ crud, fields, title = "Details", description, children, showEditButton = true, showDeleteButton = true, deleteConfirmMessage = "This action cannot be undone." }) {
|
|
2807
|
-
const [confirmDelete, setConfirmDelete] =
|
|
3281
|
+
const [confirmDelete, setConfirmDelete] = React6.useState(false);
|
|
2808
3282
|
const open = crud.mode === "detail" && !!crud.selectedId;
|
|
2809
3283
|
const entity = crud.detail;
|
|
2810
3284
|
const resolvedTitle = entity && typeof title === "function" ? title(entity) : String(title);
|
|
@@ -2828,8 +3302,7 @@ function EntityDetailSheet({ crud, fields, title = "Details", description, child
|
|
|
2828
3302
|
entity && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2829
3303
|
fields.map((f) => /* @__PURE__ */ jsxs("div", { children: [
|
|
2830
3304
|
/* @__PURE__ */ jsx("p", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wide mb-1", children: f.label }),
|
|
2831
|
-
/* @__PURE__ */ jsx(
|
|
2832
|
-
}, entity, readonly: true })
|
|
3305
|
+
/* @__PURE__ */ jsx(FieldReadonlyValue, { descriptor: f, value: getValueAtPath(entity, f.field), entity })
|
|
2833
3306
|
] }, f.field)),
|
|
2834
3307
|
children && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2835
3308
|
/* @__PURE__ */ jsx("div", { className: "border-t my-1" }),
|
|
@@ -2899,13 +3372,14 @@ function EntityFormSheet({ crud, fields, createTitle = "Create", editTitle = "Ed
|
|
|
2899
3372
|
error && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 rounded-md bg-destructive/10 border border-destructive/20 text-xs text-destructive", children: error }),
|
|
2900
3373
|
visibleFields.map((f) => {
|
|
2901
3374
|
const isDirty = !isCreate && crud.dirty.changed.has(f.field);
|
|
3375
|
+
const currentValue = getValueAtPath(buf, f.field);
|
|
2902
3376
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
2903
3377
|
/* @__PURE__ */ jsxs("label", { className: cn("text-xs font-medium", isDirty ? "text-primary" : "text-muted-foreground"), children: [
|
|
2904
3378
|
f.label,
|
|
2905
3379
|
f.required && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-0.5", children: "*" }),
|
|
2906
3380
|
isDirty && /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-[10px] font-normal opacity-70", children: "modified" })
|
|
2907
3381
|
] }),
|
|
2908
|
-
/* @__PURE__ */ jsx(FieldControl, { descriptor: f, value:
|
|
3382
|
+
/* @__PURE__ */ jsx(FieldControl, { descriptor: f, value: currentValue, onChange: (v) => setField(f.field, v), entity: buf, readonly: f.readonlyOnEdit && isEdit }),
|
|
2909
3383
|
f.hint && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: f.hint })
|
|
2910
3384
|
] }, f.field);
|
|
2911
3385
|
})
|
|
@@ -4106,9 +4580,9 @@ function createSelectionStore() {
|
|
|
4106
4580
|
function useSelectionStore(store, selector) {
|
|
4107
4581
|
return useStore(store, selector);
|
|
4108
4582
|
}
|
|
4109
|
-
var SelectionContext =
|
|
4583
|
+
var SelectionContext = React6.createContext(null);
|
|
4110
4584
|
function useSelectionContext() {
|
|
4111
|
-
const store =
|
|
4585
|
+
const store = React6.useContext(SelectionContext);
|
|
4112
4586
|
if (!store) throw new Error("useSelectionContext must be used within a SelectionContext.Provider");
|
|
4113
4587
|
return store;
|
|
4114
4588
|
}
|
|
@@ -5023,7 +5497,7 @@ function useTableStorageAdapter() {
|
|
|
5023
5497
|
function useTableRealtimeMode() {
|
|
5024
5498
|
return useContext(TableStorageContext).realtimeMode;
|
|
5025
5499
|
}
|
|
5026
|
-
var Table =
|
|
5500
|
+
var Table = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
|
|
5027
5501
|
"table",
|
|
5028
5502
|
{
|
|
5029
5503
|
ref,
|
|
@@ -5032,11 +5506,11 @@ var Table = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
5032
5506
|
}
|
|
5033
5507
|
) }));
|
|
5034
5508
|
Table.displayName = "Table";
|
|
5035
|
-
var TableHeader =
|
|
5509
|
+
var TableHeader = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("bg-muted/60", className), ...props }));
|
|
5036
5510
|
TableHeader.displayName = "TableHeader";
|
|
5037
|
-
var TableBody =
|
|
5511
|
+
var TableBody = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("bg-background", className), ...props }));
|
|
5038
5512
|
TableBody.displayName = "TableBody";
|
|
5039
|
-
var TableFooter =
|
|
5513
|
+
var TableFooter = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5040
5514
|
"tfoot",
|
|
5041
5515
|
{
|
|
5042
5516
|
ref,
|
|
@@ -5045,7 +5519,7 @@ var TableFooter = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
5045
5519
|
}
|
|
5046
5520
|
));
|
|
5047
5521
|
TableFooter.displayName = "TableFooter";
|
|
5048
|
-
var TableRow =
|
|
5522
|
+
var TableRow = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5049
5523
|
"tr",
|
|
5050
5524
|
{
|
|
5051
5525
|
ref,
|
|
@@ -5057,7 +5531,7 @@ var TableRow = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
5057
5531
|
}
|
|
5058
5532
|
));
|
|
5059
5533
|
TableRow.displayName = "TableRow";
|
|
5060
|
-
var TableHead =
|
|
5534
|
+
var TableHead = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5061
5535
|
"th",
|
|
5062
5536
|
{
|
|
5063
5537
|
ref,
|
|
@@ -5069,7 +5543,7 @@ var TableHead = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
5069
5543
|
}
|
|
5070
5544
|
));
|
|
5071
5545
|
TableHead.displayName = "TableHead";
|
|
5072
|
-
var TableCell =
|
|
5546
|
+
var TableCell = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5073
5547
|
"td",
|
|
5074
5548
|
{
|
|
5075
5549
|
ref,
|
|
@@ -5081,7 +5555,7 @@ var TableCell = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
5081
5555
|
}
|
|
5082
5556
|
));
|
|
5083
5557
|
TableCell.displayName = "TableCell";
|
|
5084
|
-
var TableCaption =
|
|
5558
|
+
var TableCaption = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5085
5559
|
"caption",
|
|
5086
5560
|
{
|
|
5087
5561
|
ref,
|
|
@@ -6600,7 +7074,7 @@ function ChevronsRightIcon({ className }) {
|
|
|
6600
7074
|
] });
|
|
6601
7075
|
}
|
|
6602
7076
|
function EmptyState({ config, isFiltered = false, className }) {
|
|
6603
|
-
if (
|
|
7077
|
+
if (React6.isValidElement(config)) {
|
|
6604
7078
|
return /* @__PURE__ */ jsx(Fragment, { children: config });
|
|
6605
7079
|
}
|
|
6606
7080
|
const cfg = config ?? {};
|
|
@@ -8000,13 +8474,13 @@ function selectionColumn2() {
|
|
|
8000
8474
|
enableFiltering: false,
|
|
8001
8475
|
enableHiding: false,
|
|
8002
8476
|
enableResizing: false,
|
|
8003
|
-
header: ({ table }) =>
|
|
8477
|
+
header: ({ table }) => React6.createElement("input", {
|
|
8004
8478
|
type: "checkbox",
|
|
8005
8479
|
checked: table.getIsAllPageRowsSelected(),
|
|
8006
8480
|
onChange: table.getToggleAllPageRowsSelectedHandler(),
|
|
8007
8481
|
className: "h-4 w-4 rounded border-primary text-primary focus:ring-ring"
|
|
8008
8482
|
}),
|
|
8009
|
-
cell: ({ row }) =>
|
|
8483
|
+
cell: ({ row }) => React6.createElement("input", {
|
|
8010
8484
|
type: "checkbox",
|
|
8011
8485
|
checked: row.getIsSelected(),
|
|
8012
8486
|
onChange: row.getToggleSelectedHandler(),
|
|
@@ -8142,7 +8616,7 @@ function enumColumn2(options) {
|
|
|
8142
8616
|
const opt = options.options.find((o) => o.value === val);
|
|
8143
8617
|
if (!opt) return val;
|
|
8144
8618
|
if (opt.badgeClassName) {
|
|
8145
|
-
return
|
|
8619
|
+
return React6.createElement(
|
|
8146
8620
|
"span",
|
|
8147
8621
|
{
|
|
8148
8622
|
className: `inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium capitalize ${opt.badgeClassName}`
|
|
@@ -8150,7 +8624,7 @@ function enumColumn2(options) {
|
|
|
8150
8624
|
opt.label
|
|
8151
8625
|
);
|
|
8152
8626
|
}
|
|
8153
|
-
return
|
|
8627
|
+
return React6.createElement(
|
|
8154
8628
|
"span",
|
|
8155
8629
|
{
|
|
8156
8630
|
className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
@@ -8187,6 +8661,6 @@ function actionsColumn2() {
|
|
|
8187
8661
|
};
|
|
8188
8662
|
}
|
|
8189
8663
|
|
|
8190
|
-
export { ActionButtonRow, ActionDropdown, ColumnPresetDialog, DataTable, DataTableColumnHeader, DataTableFilter, DataTablePagination, DataTableToolbar, ElectricSQLAdapter as ElectricSQLPresetAdapter, EmptyState, EntityDetailSheet, EntityFormSheet, EntityListView, EntityTable, FilterPresetDialog, GQLClient, GalleryView, InlineCellEditor, InlineItemEditor, ListView, MemoryAdapter, MultiSelectBar, PresetPicker, InlineCellEditor2 as PureInlineCellEditor, RealtimeManager, RestApiAdapter, SelectionContext, Sheet, SortHeader, SupabaseRealtimeAdapter as SupabasePresetAdapter, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableStorageProvider, ViewModeSwitcher, ZustandPersistAdapter, actionsColumn, applyView, booleanColumn, cascadeInvalidation, checkCompleteness, compareEntities, configureEngine, createConvexAdapter, createElectricAdapter, createGQLClient, createGraphAction, createGraphEffect, createGraphQLSubscriptionAdapter, createGraphTool, createGraphTransaction, createPresetStore, createPrismaEntityConfig, createRow, createSelectionStore, createSupabaseRealtimeAdapter, createWebSocketAdapter, dateColumn, dedupe, deleteAction, editAction, enumColumn, executeGQL, exportGraphSnapshot, fetchEntity, fetchList, flattenClauses, getCoreRowModel2 as getCoreRowModel, getExpandedRowModel, getFacetedMinMaxValues, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getGroupedRowModel, getPaginatedRowModel, getRealtimeManager, getSchema, getSelectedRowModel, getSortedRowModel2 as getSortedRowModel, hasCustomPredicates, matchesFilter, matchesSearch, normalizeGQLResponse, numberColumn, prismaRelationsToSchema, actionsColumn2 as pureActionsColumn, booleanColumn2 as pureBooleanColumn, dateColumn2 as pureDateColumn, enumColumn2 as pureEnumColumn, numberColumn2 as pureNumberColumn, selectionColumn2 as pureSelectionColumn, textColumn2 as pureTextColumn, queryOnce, readRelations, registerSchema, resetRealtimeManager, selectGraph, selectionColumn, serializeKey, startGarbageCollector, stopGarbageCollector, textColumn, toGraphQLVariables, toPrismaInclude, toPrismaOrderBy, toPrismaWhere, toRestParams, toSQLClauses, useEntity, useEntityAugment, useEntityCRUD, useEntityList, useEntityMutation, useEntityView, useGQLEntity, useGQLList, useGQLMutation, useGQLSubscription, useGraphDevTools, useGraphStore, useLocalFirst, usePGliteQuery, useSelectionContext, useSelectionStore, useSuspenseEntity, useSuspenseEntityList, useTable, useTablePresets, useTableRealtimeMode, useTableStorageAdapter, viewAction };
|
|
8664
|
+
export { ActionButtonRow, ActionDropdown, ColumnPresetDialog, DataTable, DataTableColumnHeader, DataTableFilter, DataTablePagination, DataTableToolbar, ElectricSQLAdapter as ElectricSQLPresetAdapter, EmptyState, EntityDetailSheet, EntityFormSheet, EntityListView, EntityTable, FilterPresetDialog, GQLClient, GalleryView, InlineCellEditor, InlineItemEditor, ListView, MarkdownFieldEditor, MarkdownFieldRenderer, MemoryAdapter, MultiSelectBar, PresetPicker, InlineCellEditor2 as PureInlineCellEditor, RealtimeManager, RestApiAdapter, SelectionContext, Sheet, SortHeader, SupabaseRealtimeAdapter as SupabasePresetAdapter, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableStorageProvider, ViewModeSwitcher, ZustandPersistAdapter, actionsColumn, applyView, booleanColumn, buildEntityFieldsFromSchema, cascadeInvalidation, checkCompleteness, compareEntities, configureEngine, createConvexAdapter, createElectricAdapter, createGQLClient, createGraphAction, createGraphEffect, createGraphQLSubscriptionAdapter, createGraphTool, createGraphTransaction, createPresetStore, createPrismaEntityConfig, createRow, createSchemaGraphTool, createSelectionStore, createSupabaseRealtimeAdapter, createWebSocketAdapter, dateColumn, dedupe, deleteAction, editAction, enumColumn, executeGQL, exportGraphSnapshot, exportGraphSnapshotWithSchemas, fetchEntity, fetchList, flattenClauses, getCoreRowModel2 as getCoreRowModel, getEntityJsonSchema, getExpandedRowModel, getFacetedMinMaxValues, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getGroupedRowModel, getPaginatedRowModel, getRealtimeManager, getSchema, getSelectedRowModel, getSortedRowModel2 as getSortedRowModel, hasCustomPredicates, hydrateGraphFromStorage, matchesFilter, matchesSearch, normalizeGQLResponse, numberColumn, persistGraphToStorage, prismaRelationsToSchema, actionsColumn2 as pureActionsColumn, booleanColumn2 as pureBooleanColumn, dateColumn2 as pureDateColumn, enumColumn2 as pureEnumColumn, numberColumn2 as pureNumberColumn, selectionColumn2 as pureSelectionColumn, textColumn2 as pureTextColumn, queryOnce, readRelations, registerEntityJsonSchema, registerRuntimeSchema, registerSchema, renderMarkdownToHtml, resetRealtimeManager, selectGraph, selectionColumn, serializeKey, startGarbageCollector, startLocalFirstGraph, stopGarbageCollector, textColumn, toGraphQLVariables, toPrismaInclude, toPrismaOrderBy, toPrismaWhere, toRestParams, toSQLClauses, useEntity, useEntityAugment, useEntityCRUD, useEntityList, useEntityMutation, useEntityView, useGQLEntity, useGQLList, useGQLMutation, useGQLSubscription, useGraphDevTools, useGraphStore, useGraphSyncStatus, useLocalFirst, usePGliteQuery, useSchemaEntityFields, useSelectionContext, useSelectionStore, useSuspenseEntity, useSuspenseEntityList, useTable, useTablePresets, useTableRealtimeMode, useTableStorageAdapter, viewAction };
|
|
8191
8665
|
//# sourceMappingURL=index.mjs.map
|
|
8192
8666
|
//# sourceMappingURL=index.mjs.map
|