@ai-matrx/records-ui 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -463,9 +463,14 @@ interface TableSettingsProps {
463
463
  proposals?: FieldProposalRow[] | undefined;
464
464
  onAcceptProposal?: ((proposal: FieldProposalRow) => void) | undefined;
465
465
  onRejectProposal?: ((proposal: FieldProposalRow) => void) | undefined;
466
+ /**
467
+ * SCR-3's fourth verb. Called after the store has accepted the delete, so the
468
+ * host can leave a page that is now about a table nobody can open.
469
+ */
470
+ onDeleted?: (() => void) | undefined;
466
471
  className?: string | undefined;
467
472
  }
468
- declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, className, }: TableSettingsProps): react.JSX.Element;
473
+ declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, onDeleted, className, }: TableSettingsProps): react.JSX.Element;
469
474
 
470
475
  interface PeekProps {
471
476
  tableId: Uuid;
@@ -579,6 +584,31 @@ interface UseSystemTableState {
579
584
  }
580
585
  /** The hook every package-owned component opens with. */
581
586
  declare function useSystemTable(spec: SystemTableSpec): UseSystemTableState;
587
+ /**
588
+ * THE VERSION OF THE ONE RECORD BEING EDITED.
589
+ *
590
+ * The read door (`custom.read_records`) answers documents, never versions —
591
+ * deliberately, because a version is a fact about the row and not about what
592
+ * this reader may see. A screen that saves optimistically still needs the
593
+ * version it LOADED, so it reads it here, for the one record it is editing and
594
+ * never for a list, through `custom.io_revisions`.
595
+ *
596
+ * `null` is an honest answer: the save then carries no expected version and is
597
+ * the store's ordinary last-writer-wins write. It is never a guess.
598
+ */
599
+ /** What `useRecordVersion` hands a screen that writes the record more than once. */
600
+ interface TrackedVersion {
601
+ /** The version this screen is writing against, or `null` when none was read. */
602
+ version: number | null;
603
+ /**
604
+ * TELL IT THE STORE MOVED. Every successful write answers the record's NEW
605
+ * version; a screen that does not hand it back here will write against the
606
+ * old one next time and the store will — correctly — refuse it as a conflict
607
+ * with somebody who turns out to be the same person. Measured 2026-09-19:
608
+ * switching a saved view's layout twice in a row did exactly that.
609
+ */
610
+ note: (version: number) => void;
611
+ }
582
612
 
583
613
  /** The four ways one saved view can be looked at (SCR-6). */
584
614
  declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
@@ -1369,6 +1399,18 @@ type DeclareResult = {
1369
1399
  /** `My Sales Pipeline` → `my_sales_pipeline`. A token, never a sentence. */
1370
1400
  declare function tokenFor(name: string): string;
1371
1401
  /** The one Field a Table cannot be declared without: something to call a record. */
1402
+ /**
1403
+ * WHY THE FIRST FIELD IS NOT REQUIRED.
1404
+ *
1405
+ * It was, and the cost showed up the moment the grid could add a row: "New
1406
+ * record" writes an empty record and puts you in the first cell, and the store
1407
+ * correctly refused every one of them — `REC-51: Title is required` — so the
1408
+ * one gesture that makes a grid feel like a grid never worked on a table a
1409
+ * person had just made. A title is what makes a record a CHIP (REC-2), which is
1410
+ * a fact about how it is shown, not a promise it can never be written without;
1411
+ * an organization that wants it demanded says so in the field editor, and the
1412
+ * store then enforces it for everyone.
1413
+ */
1372
1414
  declare const DEFAULT_FIELDS: NewFieldSpec[];
1373
1415
  declare function declareTable(client: RecordsClient, spec: NewTableSpec): Promise<DeclareResult>;
1374
1416
  /** Write Field records for an existing Table. Used by the create path and by import. */
@@ -1380,4 +1422,4 @@ declare function addFields(client: RecordsClient, tableId: Uuid$1, fields: NewFi
1380
1422
  error: RecordsError;
1381
1423
  }>;
1382
1424
 
1383
- export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
1425
+ export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type TrackedVersion, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
package/dist/index.d.ts CHANGED
@@ -463,9 +463,14 @@ interface TableSettingsProps {
463
463
  proposals?: FieldProposalRow[] | undefined;
464
464
  onAcceptProposal?: ((proposal: FieldProposalRow) => void) | undefined;
465
465
  onRejectProposal?: ((proposal: FieldProposalRow) => void) | undefined;
466
+ /**
467
+ * SCR-3's fourth verb. Called after the store has accepted the delete, so the
468
+ * host can leave a page that is now about a table nobody can open.
469
+ */
470
+ onDeleted?: (() => void) | undefined;
466
471
  className?: string | undefined;
467
472
  }
468
- declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, className, }: TableSettingsProps): react.JSX.Element;
473
+ declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, onDeleted, className, }: TableSettingsProps): react.JSX.Element;
469
474
 
470
475
  interface PeekProps {
471
476
  tableId: Uuid;
@@ -579,6 +584,31 @@ interface UseSystemTableState {
579
584
  }
580
585
  /** The hook every package-owned component opens with. */
581
586
  declare function useSystemTable(spec: SystemTableSpec): UseSystemTableState;
587
+ /**
588
+ * THE VERSION OF THE ONE RECORD BEING EDITED.
589
+ *
590
+ * The read door (`custom.read_records`) answers documents, never versions —
591
+ * deliberately, because a version is a fact about the row and not about what
592
+ * this reader may see. A screen that saves optimistically still needs the
593
+ * version it LOADED, so it reads it here, for the one record it is editing and
594
+ * never for a list, through `custom.io_revisions`.
595
+ *
596
+ * `null` is an honest answer: the save then carries no expected version and is
597
+ * the store's ordinary last-writer-wins write. It is never a guess.
598
+ */
599
+ /** What `useRecordVersion` hands a screen that writes the record more than once. */
600
+ interface TrackedVersion {
601
+ /** The version this screen is writing against, or `null` when none was read. */
602
+ version: number | null;
603
+ /**
604
+ * TELL IT THE STORE MOVED. Every successful write answers the record's NEW
605
+ * version; a screen that does not hand it back here will write against the
606
+ * old one next time and the store will — correctly — refuse it as a conflict
607
+ * with somebody who turns out to be the same person. Measured 2026-09-19:
608
+ * switching a saved view's layout twice in a row did exactly that.
609
+ */
610
+ note: (version: number) => void;
611
+ }
582
612
 
583
613
  /** The four ways one saved view can be looked at (SCR-6). */
584
614
  declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
@@ -1369,6 +1399,18 @@ type DeclareResult = {
1369
1399
  /** `My Sales Pipeline` → `my_sales_pipeline`. A token, never a sentence. */
1370
1400
  declare function tokenFor(name: string): string;
1371
1401
  /** The one Field a Table cannot be declared without: something to call a record. */
1402
+ /**
1403
+ * WHY THE FIRST FIELD IS NOT REQUIRED.
1404
+ *
1405
+ * It was, and the cost showed up the moment the grid could add a row: "New
1406
+ * record" writes an empty record and puts you in the first cell, and the store
1407
+ * correctly refused every one of them — `REC-51: Title is required` — so the
1408
+ * one gesture that makes a grid feel like a grid never worked on a table a
1409
+ * person had just made. A title is what makes a record a CHIP (REC-2), which is
1410
+ * a fact about how it is shown, not a promise it can never be written without;
1411
+ * an organization that wants it demanded says so in the field editor, and the
1412
+ * store then enforces it for everyone.
1413
+ */
1372
1414
  declare const DEFAULT_FIELDS: NewFieldSpec[];
1373
1415
  declare function declareTable(client: RecordsClient, spec: NewTableSpec): Promise<DeclareResult>;
1374
1416
  /** Write Field records for an existing Table. Used by the create path and by import. */
@@ -1380,4 +1422,4 @@ declare function addFields(client: RecordsClient, tableId: Uuid$1, fields: NewFi
1380
1422
  error: RecordsError;
1381
1423
  }>;
1382
1424
 
1383
- export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
1425
+ export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type TrackedVersion, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
package/dist/index.js CHANGED
@@ -812,6 +812,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite }) {
812
812
  const [rowError, setRowError] = useState4(null);
813
813
  const [busy, setBusy] = useState4(false);
814
814
  const versions = useRef(/* @__PURE__ */ new Map());
815
+ const queues = useRef(/* @__PURE__ */ new Map());
815
816
  const editable = useMemo4(() => fields.filter(fieldIsEditable), [fields]);
816
817
  const order = useMemo4(() => editable.map((f) => f.key), [editable]);
817
818
  const rowIds = useMemo4(() => rows.map((r) => r.id), [rows]);
@@ -845,7 +846,7 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite }) {
845
846
  [canWrite, client]
846
847
  );
847
848
  const cancel = useCallback2(() => setEditing(null), []);
848
- const writeCell = useCallback2(
849
+ const writeCellNow = useCallback2(
849
850
  async (rowId, key, value2) => {
850
851
  const id = cellKey(rowId, key);
851
852
  setOptimistic((held) => ({ ...held, [id]: value2 }));
@@ -889,6 +890,22 @@ function useGridEditing({ tableId, fields, rows, reload, canWrite }) {
889
890
  },
890
891
  [client, reload]
891
892
  );
893
+ const writeCell = useCallback2(
894
+ (rowId, key, value2) => {
895
+ const behind = queues.current.get(rowId) ?? Promise.resolve();
896
+ const next = behind.then(() => writeCellNow(rowId, key, value2));
897
+ queues.current.set(
898
+ rowId,
899
+ next.then(
900
+ () => void 0,
901
+ () => void 0
902
+ )
903
+ );
904
+ return next;
905
+ },
906
+ // eslint-disable-next-line react-hooks/exhaustive-deps
907
+ [client, reload]
908
+ );
892
909
  const commit = useCallback2(
893
910
  (value2, move = null) => {
894
911
  const open = editing;
@@ -1097,10 +1114,16 @@ function OpenCell({
1097
1114
  const [draft, setDraft] = useState4(value2);
1098
1115
  const multiline = editorKindFor(field) === "long_text";
1099
1116
  const blurCommits = closesOnBlur(field);
1117
+ const done = useRef(false);
1118
+ const once = (run) => {
1119
+ if (done.current) return;
1120
+ done.current = true;
1121
+ run();
1122
+ };
1100
1123
  const blur = blurCommits ? {
1101
1124
  onBlur: (event) => {
1102
1125
  if (event.currentTarget.contains(event.relatedTarget)) return;
1103
- onCommit(draft, null);
1126
+ once(() => onCommit(draft, null));
1104
1127
  }
1105
1128
  } : {};
1106
1129
  return /* @__PURE__ */ jsxs5(
@@ -1117,27 +1140,27 @@ function OpenCell({
1117
1140
  if (event.key === "Escape") {
1118
1141
  event.preventDefault();
1119
1142
  event.stopPropagation();
1120
- onCancel();
1143
+ once(onCancel);
1121
1144
  return;
1122
1145
  }
1123
1146
  if (event.key === "Tab") {
1124
1147
  event.preventDefault();
1125
1148
  event.stopPropagation();
1126
- onCommit(draft, event.shiftKey ? "previous" : "next");
1149
+ once(() => onCommit(draft, event.shiftKey ? "previous" : "next"));
1127
1150
  return;
1128
1151
  }
1129
1152
  if (event.key === "Enter" && (!multiline || event.metaKey || event.ctrlKey)) {
1130
1153
  event.preventDefault();
1131
1154
  event.stopPropagation();
1132
- onCommit(draft, null);
1155
+ once(() => onCommit(draft, null));
1133
1156
  }
1134
1157
  },
1135
1158
  ...blur,
1136
1159
  children: [
1137
1160
  /* @__PURE__ */ jsx7(FieldControl, { field, value: draft, onChange: setDraft, id: `cell-${field.id}` }),
1138
1161
  blurCommits ? /* @__PURE__ */ jsx7("span", { className: "text-[10px] text-muted-foreground", children: multiline ? "\u2318\u23CE saves \xB7 Esc cancels \xB7 Tab next" : "\u23CE saves \xB7 Esc cancels \xB7 Tab next" }) : /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-1", children: [
1139
- /* @__PURE__ */ jsx7(Button4, { size: "sm", onClick: () => onCommit(draft, null), children: "Save" }),
1140
- /* @__PURE__ */ jsx7(Button4, { size: "sm", variant: "ghost", onClick: onCancel, children: "Cancel" })
1162
+ /* @__PURE__ */ jsx7(Button4, { size: "sm", onClick: () => once(() => onCommit(draft, null)), children: "Save" }),
1163
+ /* @__PURE__ */ jsx7(Button4, { size: "sm", variant: "ghost", onClick: () => once(onCancel), children: "Cancel" })
1141
1164
  ] })
1142
1165
  ]
1143
1166
  }
@@ -1755,7 +1778,7 @@ function useRecordVersion(recordId) {
1755
1778
  cancelled = true;
1756
1779
  };
1757
1780
  }, [client, recordId]);
1758
- return version;
1781
+ return { version, note: setVersion };
1759
1782
  }
1760
1783
 
1761
1784
  // src/RecordForm.tsx
@@ -1774,7 +1797,8 @@ function RecordForm({
1774
1797
  const mutation = useRecordMutation2();
1775
1798
  const [draft, setDraft] = useState9({});
1776
1799
  const [touched, setTouched] = useState9(false);
1777
- const loadedVersion = useRecordVersion(recordId ?? null);
1800
+ const loaded = useRecordVersion(recordId ?? null);
1801
+ const loadedVersion = loaded.version;
1778
1802
  useEffect5(() => {
1779
1803
  const document3 = existing.data?.document;
1780
1804
  if (document3) setDraft({ ...document3 });
@@ -1803,6 +1827,7 @@ function RecordForm({
1803
1827
  ...version === null ? {} : { expectedVersion: version }
1804
1828
  });
1805
1829
  if (moved !== null) {
1830
+ loaded.note(moved);
1806
1831
  host.notify?.success("Saved");
1807
1832
  existing.reload();
1808
1833
  onSaved?.(recordId);
@@ -2169,12 +2194,13 @@ var FIELD_KERNEL = KERNEL_TABLES2.find((t) => t.name === "Field").id;
2169
2194
  import { useState as useState12 } from "react";
2170
2195
  import { useFields as useFields6, useRecordMutation as useRecordMutation4, useTable as useTable5 } from "@ai-matrx/records/react";
2171
2196
  import { Badge as Badge4, Button as Button11, Separator as Separator5, cn as cn13 } from "@ai-matrx/design-system";
2172
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2197
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2173
2198
  function TableSettings({
2174
2199
  tableId,
2175
2200
  proposals,
2176
2201
  onAcceptProposal,
2177
2202
  onRejectProposal,
2203
+ onDeleted,
2178
2204
  className
2179
2205
  }) {
2180
2206
  const table = useTable5(tableId);
@@ -2182,6 +2208,7 @@ function TableSettings({
2182
2208
  const rights = useTableRights(table.data);
2183
2209
  const mutation = useRecordMutation4();
2184
2210
  const [editing, setEditing] = useState12(null);
2211
+ const [askingToDelete, setAskingToDelete] = useState12(false);
2185
2212
  if (table.error) return /* @__PURE__ */ jsx14(RefusalNotice, { error: table.error, className });
2186
2213
  if (fields.error) return /* @__PURE__ */ jsx14(RefusalNotice, { error: fields.error, className });
2187
2214
  if (!rights.admin) return /* @__PURE__ */ jsx14("p", { className: cn13("text-xs text-muted-foreground", className), children: rights.reason });
@@ -2198,6 +2225,11 @@ function TableSettings({
2198
2225
  await mutation.remove({ record_id: field.id });
2199
2226
  fields.reload();
2200
2227
  };
2228
+ const deleteTable = async () => {
2229
+ const gone = await mutation.remove({ record_id: tableId });
2230
+ setAskingToDelete(false);
2231
+ if (gone !== null) onDeleted?.();
2232
+ };
2201
2233
  if (editing) {
2202
2234
  return /* @__PURE__ */ jsx14(
2203
2235
  FieldEditor,
@@ -2273,7 +2305,28 @@ function TableSettings({
2273
2305
  /* @__PURE__ */ jsx14(Badge4, { variant: "secondary", className: "text-[10px] font-normal", children: proposal.proposed_by }),
2274
2306
  /* @__PURE__ */ jsx14(Button11, { size: "sm", variant: "outline", onClick: () => onAcceptProposal?.(proposal), children: "Accept" }),
2275
2307
  /* @__PURE__ */ jsx14(Button11, { size: "sm", variant: "ghost", onClick: () => onRejectProposal?.(proposal), children: "Reject" })
2276
- ] }, proposal.id)) })
2308
+ ] }, proposal.id)) }),
2309
+ /* @__PURE__ */ jsx14(Separator5, {}),
2310
+ /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-1", children: [
2311
+ /* @__PURE__ */ jsx14("span", { className: "font-medium", children: "This table" }),
2312
+ askingToDelete ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
2313
+ /* @__PURE__ */ jsxs12("p", { className: "text-muted-foreground", children: [
2314
+ "Deleting ",
2315
+ table.data ? tableName(table.data) : "this table",
2316
+ " takes it out of everyone's list, with its ",
2317
+ rows.length,
2318
+ " field",
2319
+ rows.length === 1 ? "" : "s",
2320
+ " and every record in it.",
2321
+ table.data?.retention_days ? ` The store keeps them for ${table.data.retention_days} days, so it can still be restored.` : " The store keeps them, so it can still be restored."
2322
+ ] }),
2323
+ /* @__PURE__ */ jsxs12("div", { className: "flex gap-1", children: [
2324
+ /* @__PURE__ */ jsx14(Button11, { size: "sm", variant: "destructive", disabled: mutation.saving, onClick: () => void deleteTable(), children: mutation.saving ? "Deleting\u2026" : "Delete this table" }),
2325
+ /* @__PURE__ */ jsx14(Button11, { size: "sm", variant: "ghost", onClick: () => setAskingToDelete(false), children: "Keep it" })
2326
+ ] })
2327
+ ] }) : /* @__PURE__ */ jsx14("div", { children: /* @__PURE__ */ jsx14(Button11, { size: "sm", variant: "outline", onClick: () => setAskingToDelete(true), children: "Delete this table" }) }),
2328
+ mutation.error ? /* @__PURE__ */ jsx14(RefusalNotice, { error: mutation.error }) : null
2329
+ ] })
2277
2330
  ] });
2278
2331
  }
2279
2332
 
@@ -2282,7 +2335,7 @@ import { useState as useState13 } from "react";
2282
2335
  import { useFields as useFields7, useRecord as useRecord3, useTable as useTable6 } from "@ai-matrx/records/react";
2283
2336
  import { AlchemyMenu as AlchemyMenu2 } from "@ai-matrx/alchemy/react";
2284
2337
  import { Button as Button12, Separator as Separator6, Skeleton as Skeleton2, cn as cn14 } from "@ai-matrx/design-system";
2285
- import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2338
+ import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2286
2339
  function Peek({ tableId, recordId, onClose, className }) {
2287
2340
  const table = useTable6(tableId);
2288
2341
  const fields = useFields7(tableId);
@@ -2331,7 +2384,7 @@ function Peek({ tableId, recordId, onClose, className }) {
2331
2384
  ] }),
2332
2385
  /* @__PURE__ */ jsx15("dd", { className: "min-w-0", children: renderValue(field, document2?.[field.key], document2) })
2333
2386
  ] }, field.id)) }),
2334
- record.data?.computed?.length ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
2387
+ record.data?.computed?.length ? /* @__PURE__ */ jsxs13(Fragment4, { children: [
2335
2388
  /* @__PURE__ */ jsx15(Separator6, {}),
2336
2389
  /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1", children: [
2337
2390
  /* @__PURE__ */ jsx15("span", { className: "font-medium", children: "Worked out by the system" }),
@@ -3553,7 +3606,7 @@ import { useCallback as useCallback8, useEffect as useEffect11, useMemo as useMe
3553
3606
  import { useFields as useFields10, useRecordsClient as useRecordsClient12 } from "@ai-matrx/records/react";
3554
3607
  import { doorExists, DOORS } from "@ai-matrx/records/core";
3555
3608
  import { Button as Button19, Progress, Skeleton as Skeleton8, cn as cn21 } from "@ai-matrx/design-system";
3556
- import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3609
+ import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3557
3610
  function FormRunner({ form, preview = false, onSubmitted, className }) {
3558
3611
  const client = useRecordsClient12();
3559
3612
  const host = useRecordsUi();
@@ -3741,7 +3794,7 @@ function Question({
3741
3794
  return /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1.5", children: [
3742
3795
  /* @__PURE__ */ jsx22(FieldLabel, { field: { ...field, label: question.ask, required: question.required }, htmlFor: id }),
3743
3796
  question.help ? /* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground", children: question.help }) : null,
3744
- isAttachment && !upload ? /* @__PURE__ */ jsx22("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : isAttachment ? /* @__PURE__ */ jsxs20(Fragment4, { children: [
3797
+ isAttachment && !upload ? /* @__PURE__ */ jsx22("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : isAttachment ? /* @__PURE__ */ jsxs20(Fragment5, { children: [
3745
3798
  /* @__PURE__ */ jsx22(
3746
3799
  "input",
3747
3800
  {
@@ -3766,7 +3819,7 @@ function Question({
3766
3819
  }
3767
3820
 
3768
3821
  // src/FormBuilder.tsx
3769
- import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
3822
+ import { Fragment as Fragment6, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
3770
3823
  var CONDITION_OPS = [
3771
3824
  { op: "eq", label: "is" },
3772
3825
  { op: "ne", label: "is not" },
@@ -3787,7 +3840,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
3787
3840
  const [draft, setDraft] = useState21(null);
3788
3841
  const [saving, setSaving] = useState21(false);
3789
3842
  const [saved, setSaved] = useState21(null);
3790
- const loadedVersion = useRecordVersion(activeId);
3843
+ const loaded = useRecordVersion(activeId);
3791
3844
  const formTableId = home.tableId;
3792
3845
  const load = useCallback9(async () => {
3793
3846
  if (!formTableId) return;
@@ -3851,13 +3904,14 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
3851
3904
  record_id: draft.id,
3852
3905
  patch: document2,
3853
3906
  // The form record's own version: two people editing one form are TOLD.
3854
- ...loadedVersion === null ? {} : { expectedVersion: loadedVersion }
3907
+ ...loaded.version === null ? {} : { expectedVersion: loaded.version }
3855
3908
  });
3856
3909
  setSaving(false);
3857
3910
  if (!written.ok) {
3858
3911
  setError(written.error);
3859
3912
  return;
3860
3913
  }
3914
+ loaded.note(written.data);
3861
3915
  setSaved("Saved.");
3862
3916
  await load();
3863
3917
  }
@@ -3913,7 +3967,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
3913
3967
  /* @__PURE__ */ jsx23(Button20, { size: "sm", disabled: saving || !draft, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" })
3914
3968
  ] })
3915
3969
  ] }),
3916
- !draft ? /* @__PURE__ */ jsx23("p", { className: "text-xs text-muted-foreground", children: 'No form collects into this table yet. "New form" makes one, or an agent writes a whole one with a single record.' }) : /* @__PURE__ */ jsxs21(Fragment5, { children: [
3970
+ !draft ? /* @__PURE__ */ jsx23("p", { className: "text-xs text-muted-foreground", children: 'No form collects into this table yet. "New form" makes one, or an agent writes a whole one with a single record.' }) : /* @__PURE__ */ jsxs21(Fragment6, { children: [
3917
3971
  /* @__PURE__ */ jsxs21("div", { className: "grid grid-cols-2 gap-2", children: [
3918
3972
  /* @__PURE__ */ jsxs21("label", { className: "flex flex-col gap-1", children: [
3919
3973
  /* @__PURE__ */ jsx23(Label3, { className: "text-xs font-medium", children: "Name" }),
@@ -4076,7 +4130,7 @@ function Condition({
4076
4130
  ]
4077
4131
  }
4078
4132
  ),
4079
- onField ? /* @__PURE__ */ jsxs21(Fragment5, { children: [
4133
+ onField ? /* @__PURE__ */ jsxs21(Fragment6, { children: [
4080
4134
  /* @__PURE__ */ jsx23(
4081
4135
  "select",
4082
4136
  {
@@ -4960,7 +5014,7 @@ function DashboardCanvas({ tableId, seed, activeDashboardId, className }) {
4960
5014
  const [boards, setBoards] = useState27(null);
4961
5015
  const [error, setError] = useState27(null);
4962
5016
  const [activeId, setActiveId] = useState27(activeDashboardId ?? null);
4963
- const loadedVersion = useRecordVersion(activeId);
5017
+ const loaded = useRecordVersion(activeId);
4964
5018
  const boardTableId = home.tableId;
4965
5019
  const load = useCallback14(async () => {
4966
5020
  if (!boardTableId) return;
@@ -5006,12 +5060,13 @@ function DashboardCanvas({ tableId, seed, activeDashboardId, className }) {
5006
5060
  record_id: board2.id,
5007
5061
  patch: dashboardDocument({ ...board2, blocks }),
5008
5062
  // The dashboard record's own version: two tabs editing one board are TOLD.
5009
- ...loadedVersion === null ? {} : { expectedVersion: loadedVersion }
5063
+ ...loaded.version === null ? {} : { expectedVersion: loaded.version }
5010
5064
  });
5011
5065
  if (!updated.ok) {
5012
5066
  setError(updated.error);
5013
5067
  return;
5014
5068
  }
5069
+ loaded.note(updated.data);
5015
5070
  await load();
5016
5071
  }
5017
5072
  async function create() {
@@ -5876,7 +5931,7 @@ function whenText(at) {
5876
5931
  import { useCallback as useCallback18, useEffect as useEffect23, useRef as useRef5, useState as useState32 } from "react";
5877
5932
  import { useFields as useFields17, useRecordsClient as useRecordsClient24, useTable as useTable19 } from "@ai-matrx/records/react";
5878
5933
  import { Button as Button29, Input as Input2, Skeleton as Skeleton20, Textarea as Textarea2, cn as cn33 } from "@ai-matrx/design-system";
5879
- import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
5934
+ import { Fragment as Fragment7, jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
5880
5935
  var CAPTURE_MODES = ["reading", "photo", "voice"];
5881
5936
  var IN_MEMORY_QUEUE_REASON = "No capture queue is bound, so anything that cannot be sent right now is held in this page's memory and is lost if the page closes. Bind `captureQueue` on <RecordsUiProvider> with your host's own durable store (IndexedDB in a browser) and a queued capture survives the tab, the reload and the flight. It is said here rather than discovered later.";
5882
5937
  function mintClientKey() {
@@ -6033,7 +6088,7 @@ function CaptureSheet({
6033
6088
  " ",
6034
6089
  /* @__PURE__ */ jsx34("code", { children: "attachmentField" }),
6035
6090
  "."
6036
- ] }) : /* @__PURE__ */ jsxs32(Fragment6, { children: [
6091
+ ] }) : /* @__PURE__ */ jsxs32(Fragment7, { children: [
6037
6092
  /* @__PURE__ */ jsx34(
6038
6093
  "input",
6039
6094
  {
@@ -6287,7 +6342,7 @@ import { useCallback as useCallback21, useEffect as useEffect26, useState as use
6287
6342
  import { useRecordsClient as useRecordsClient27 } from "@ai-matrx/records/react";
6288
6343
  import { Button as Button31, Input as Input3, Skeleton as Skeleton23, Textarea as Textarea3, cn as cn36 } from "@ai-matrx/design-system";
6289
6344
  import { useTable as useTable20 } from "@ai-matrx/records/react";
6290
- import { Fragment as Fragment7, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
6345
+ import { Fragment as Fragment8, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
6291
6346
  function EmbedFrame({
6292
6347
  tableId,
6293
6348
  formId,
@@ -6371,7 +6426,7 @@ function EmbedFrame({
6371
6426
  " will not pass."
6372
6427
  ] })
6373
6428
  ] }),
6374
- !secret ? /* @__PURE__ */ jsx37(Button31, { size: "sm", className: "self-start", disabled: busy || parsed.length === 0, onClick: () => void issue(), children: busy ? "Issuing\u2026" : "Issue embed" }) : /* @__PURE__ */ jsxs35(Fragment7, { children: [
6429
+ !secret ? /* @__PURE__ */ jsx37(Button31, { size: "sm", className: "self-start", disabled: busy || parsed.length === 0, onClick: () => void issue(), children: busy ? "Issuing\u2026" : "Issue embed" }) : /* @__PURE__ */ jsxs35(Fragment8, { children: [
6375
6430
  /* @__PURE__ */ jsx37("p", { className: "rounded border px-2 py-1 text-xs text-muted-foreground", children: "Copy this now. Only its digest is stored, so nobody \u2014 including us \u2014 can show it to you again; if it is lost, issue a new one and replace the old." }),
6376
6431
  /* @__PURE__ */ jsx37(Textarea3, { "aria-label": "Embed snippet", readOnly: true, rows: 3, className: "font-mono text-[11px]", value: snippet ?? "" }),
6377
6432
  /* @__PURE__ */ jsxs35("div", { className: "flex gap-2", children: [
@@ -6466,7 +6521,7 @@ function tokenFor(name) {
6466
6521
  return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48) || "table";
6467
6522
  }
6468
6523
  var DEFAULT_FIELDS = [
6469
- { key: "title", label: "Title", type: "text", sort: 10, required: true }
6524
+ { key: "title", label: "Title", type: "text", sort: 10, required: false }
6470
6525
  ];
6471
6526
  async function declareTable(client, spec) {
6472
6527
  const fields = spec.fields && spec.fields.length > 0 ? spec.fields : DEFAULT_FIELDS;
@@ -6536,7 +6591,7 @@ async function addFields(client, tableId, fields) {
6536
6591
  }
6537
6592
 
6538
6593
  // src/TablesHome.tsx
6539
- import { Fragment as Fragment8, jsx as jsx39, jsxs as jsxs36 } from "react/jsx-runtime";
6594
+ import { Fragment as Fragment9, jsx as jsx39, jsxs as jsxs36 } from "react/jsx-runtime";
6540
6595
  var TABLE_LANES = ["mine", "organization", "system", "community", "app"];
6541
6596
  var LANE_TITLE = {
6542
6597
  mine: "Mine",
@@ -6589,7 +6644,7 @@ function TablesHome({ onOpenTable, className }) {
6589
6644
  [client, name, onOpenTable, tables]
6590
6645
  );
6591
6646
  return /* @__PURE__ */ jsxs36("div", { className: cn37("flex min-h-0 flex-col gap-4", className), children: [
6592
- /* @__PURE__ */ jsx39("div", { className: "flex items-center gap-2", children: creating ? /* @__PURE__ */ jsxs36(Fragment8, { children: [
6647
+ /* @__PURE__ */ jsx39("div", { className: "flex items-center gap-2", children: creating ? /* @__PURE__ */ jsxs36(Fragment9, { children: [
6593
6648
  /* @__PURE__ */ jsx39(
6594
6649
  BasicInput8,
6595
6650
  {
@@ -6663,7 +6718,7 @@ function TablesHome({ onOpenTable, className }) {
6663
6718
  import { useCallback as useCallback23, useState as useState37 } from "react";
6664
6719
  import { useRecordsClient as useRecordsClient29, useTable as useTable21 } from "@ai-matrx/records/react";
6665
6720
  import { Button as Button33, Separator as Separator7, Skeleton as Skeleton25, cn as cn38 } from "@ai-matrx/design-system";
6666
- import { Fragment as Fragment9, jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
6721
+ import { Fragment as Fragment10, jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
6667
6722
  var TABLE_NOT_REACHABLE = "This table is not in the organization you are working in, so there is nothing here to show. Switch to the organization that owns it and open it again \u2014 or it may have been deleted.";
6668
6723
  var DEFAULT_VIEW_NAME = "All records";
6669
6724
  function defaultView(tableId) {
@@ -6692,11 +6747,12 @@ function TablePage({
6692
6747
  setView({ ...current, ...patch });
6693
6748
  const document2 = viewPatchDocument(patch);
6694
6749
  if (Object.keys(document2).length === 0) return;
6695
- await client.recordUpdate({
6750
+ const written = await client.recordUpdate({
6696
6751
  record_id: current.id,
6697
6752
  patch: document2,
6698
- ...viewVersion === null ? {} : { expectedVersion: viewVersion }
6753
+ ...viewVersion.version === null ? {} : { expectedVersion: viewVersion.version }
6699
6754
  });
6755
+ if (written.ok) viewVersion.note(written.data);
6700
6756
  },
6701
6757
  [client, view, viewVersion]
6702
6758
  );
@@ -6722,7 +6778,7 @@ function TablePage({
6722
6778
  }
6723
6779
  ),
6724
6780
  rights.write && view && view.layout !== "grid" ? /* @__PURE__ */ jsx40(Button33, { size: "sm", onClick: () => show("new-record"), children: "New record" }) : null,
6725
- rights.admin ? /* @__PURE__ */ jsxs37(Fragment9, { children: [
6781
+ rights.admin ? /* @__PURE__ */ jsxs37(Fragment10, { children: [
6726
6782
  /* @__PURE__ */ jsx40(Button33, { size: "sm", variant: "outline", onClick: () => show("field"), children: "Add field" }),
6727
6783
  /* @__PURE__ */ jsx40(Button33, { size: "sm", variant: "ghost", onClick: () => show("settings"), children: "Settings" }),
6728
6784
  /* @__PURE__ */ jsx40(Button33, { size: "sm", variant: "ghost", onClick: () => show("import"), children: "Import" })
@@ -6749,7 +6805,13 @@ function TablePage({
6749
6805
  ] })
6750
6806
  ] }),
6751
6807
  rail === "none" ? null : /* @__PURE__ */ jsxs37("aside", { className: "w-[26rem] shrink-0 overflow-y-auto rounded-md border p-3", children: [
6752
- rail === "settings" ? /* @__PURE__ */ jsx40(TableSettings, { tableId }) : null,
6808
+ rail === "settings" ? /* @__PURE__ */ jsx40(
6809
+ TableSettings,
6810
+ {
6811
+ tableId,
6812
+ ...onLeave ? { onDeleted: onLeave } : {}
6813
+ }
6814
+ ) : null,
6753
6815
  rail === "inbox" ? /* @__PURE__ */ jsx40(
6754
6816
  ActionInbox,
6755
6817
  {