grist-widget-sdk 0.2.15 → 0.3.3
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 +23 -0
- package/README.md +2 -2
- package/dist/advanced.js +3 -2
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-ER6UWHZA.js → chunk-7GXVEZ2J.js} +2 -2
- package/dist/{chunk-KOVYBNPJ.js → chunk-D5GBS2NT.js} +8 -31
- package/dist/chunk-D5GBS2NT.js.map +1 -0
- package/dist/chunk-N3X46JW2.js +37 -0
- package/dist/chunk-N3X46JW2.js.map +1 -0
- package/dist/emulator/devtools.cjs +37 -0
- package/dist/emulator/devtools.cjs.map +1 -1
- package/dist/emulator/devtools.js +28 -0
- package/dist/emulator/devtools.js.map +1 -1
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.js +2 -1
- package/dist/emulator/testing.js.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-KOVYBNPJ.js.map +0 -1
- /package/dist/{chunk-ER6UWHZA.js.map → chunk-7GXVEZ2J.js.map} +0 -0
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
materializeGristRowsFromColumnar,
|
|
6
6
|
safeParseRowsToDisplayRows
|
|
7
7
|
} from "../chunk-JASMM2YC.js";
|
|
8
|
+
import {
|
|
9
|
+
gristAccessLevelLabel
|
|
10
|
+
} from "../chunk-N3X46JW2.js";
|
|
8
11
|
import {
|
|
9
12
|
rowsToColumnar
|
|
10
13
|
} from "../chunk-ELGVOHFD.js";
|
|
@@ -60,6 +63,7 @@ function eventTag(event) {
|
|
|
60
63
|
|
|
61
64
|
// src/emulator/devtools/inspector.tsx
|
|
62
65
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
66
|
+
var ACCESS_LEVELS = ["none", "read table", "full"];
|
|
63
67
|
function EmulatorInspector({ emulator, className, showTimeline = true }) {
|
|
64
68
|
const { state, history } = useEmulatorSnapshot(emulator);
|
|
65
69
|
const tableIds = [...state.tables.keys()];
|
|
@@ -80,6 +84,10 @@ function EmulatorInspector({ emulator, className, showTimeline = true }) {
|
|
|
80
84
|
const onEditCell = (rowId, colId, value) => {
|
|
81
85
|
emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })]);
|
|
82
86
|
};
|
|
87
|
+
const grantedAccessLevel = state.widgetInteraction.access_level ?? "read table";
|
|
88
|
+
const onSetAccessLevel = (level) => {
|
|
89
|
+
emulator.setInteraction({ ...state.widgetInteraction, access_level: level });
|
|
90
|
+
};
|
|
83
91
|
return /* @__PURE__ */ jsxs("div", { className, style: baseStyle, children: [
|
|
84
92
|
/* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
|
|
85
93
|
/* @__PURE__ */ jsx("span", { style: badgeStyle, children: "EMULATOR" }),
|
|
@@ -167,6 +175,26 @@ function EmulatorInspector({ emulator, className, showTimeline = true }) {
|
|
|
167
175
|
/* @__PURE__ */ jsx(KV, { k: "mappings", v: JSON.stringify(resolveMappings(state)) }),
|
|
168
176
|
/* @__PURE__ */ jsx(KV, { k: "configuration", v: JSON.stringify(state.configuration) })
|
|
169
177
|
] }) }),
|
|
178
|
+
/* @__PURE__ */ jsxs(Section, { title: "Access level", children: [
|
|
179
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 6, marginBottom: 6, flexWrap: "wrap" }, children: ACCESS_LEVELS.map((level) => /* @__PURE__ */ jsx(
|
|
180
|
+
"button",
|
|
181
|
+
{
|
|
182
|
+
type: "button",
|
|
183
|
+
onClick: () => onSetAccessLevel(level),
|
|
184
|
+
style: level === grantedAccessLevel ? tabActiveStyle : tabStyle,
|
|
185
|
+
title: gristAccessLevelLabel(level),
|
|
186
|
+
children: level
|
|
187
|
+
},
|
|
188
|
+
level
|
|
189
|
+
)) }),
|
|
190
|
+
/* @__PURE__ */ jsxs("p", { style: mutedStyle, children: [
|
|
191
|
+
"Granted to the widget via ",
|
|
192
|
+
/* @__PURE__ */ jsx("code", { children: "access_level" }),
|
|
193
|
+
" \u2014 ",
|
|
194
|
+
gristAccessLevelLabel(grantedAccessLevel),
|
|
195
|
+
"."
|
|
196
|
+
] })
|
|
197
|
+
] }),
|
|
170
198
|
/* @__PURE__ */ jsxs(Section, { title: "Widget options", children: [
|
|
171
199
|
/* @__PURE__ */ jsx("pre", { style: preStyle, children: JSON.stringify(state.widgetOptions, null, 2) }),
|
|
172
200
|
/* @__PURE__ */ jsx(KV, { k: "interaction", v: JSON.stringify(state.widgetInteraction) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/emulator/devtools/inspector.tsx","../../src/emulator/devtools/use-emulator-state.ts","../../src/emulator/devtools/use-rows.ts","../../src/emulator/devtools/use-columns.ts"],"sourcesContent":["/**\n * `<EmulatorInspector />` — drop-in DevTools for the playground / IDE.\n *\n * Capabilities:\n * - Multi-table picker with row count + label\n * - Inline row editor (Add / Update / Delete) routed through the emulator's\n * action engine — every edit produces real Grist user actions on the bus.\n * - Cursor selector that drives `onRecord` for the widget under test.\n * - Widget options & mappings panel.\n * - Live event timeline (last 50 events) with pretty formatting.\n *\n * The component owns no state of its own beyond UI accordion toggles —\n * everything is read off the emulator and re-renders via {@link\n * useEmulatorSnapshot}.\n */\n\nimport type { CSSProperties, ReactNode } from \"react\"\nimport { useState } from \"react\"\n\nimport { gristAddRecordAction, gristRemoveRecordAction, gristUpdateRecordAction } from \"../../sdk/helpers/grist-user-actions\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { resolveMappings } from \"../core/mappings\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type EmulatorInspectorProps = {\n emulator: GristEmulator\n /** Override visual style. */\n className?: string\n /** Default `true`. Set to `false` to render only the toolbar. */\n showTimeline?: boolean\n}\n\nexport function EmulatorInspector({ emulator, className, showTimeline = true }: EmulatorInspectorProps) {\n const { state, history } = useEmulatorSnapshot(emulator)\n const tableIds = [...state.tables.keys()]\n const selectedTableId = state.selection.tableId\n const table = state.tables.get(selectedTableId)\n const columnIds = table ? Object.keys(table.columns) : []\n\n const onSelectTable = (tableId: string) => emulator.selectTable(tableId)\n const onSelectRow = (rowId: number | \"new\" | null) => emulator.selectRow(rowId)\n const onAddRow = () => {\n if (!table) return\n const fields: Record<string, unknown> = {}\n for (const col of columnIds) fields[col] = \"\"\n emulator.apply([gristAddRecordAction(selectedTableId, fields)])\n }\n const onDeleteRow = (rowId: number) => {\n emulator.apply([gristRemoveRecordAction(selectedTableId, rowId)])\n }\n const onEditCell = (rowId: number, colId: string, value: string) => {\n emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })])\n }\n\n return (\n <div className={className} style={baseStyle}>\n <div style={headerStyle}>\n <span style={badgeStyle}>EMULATOR</span>\n <strong>{state.docName}</strong>\n <span style={mutedStyle}>· {tableIds.length} table{tableIds.length === 1 ? \"\" : \"s\"}</span>\n </div>\n\n <div style={{ display: \"flex\", gap: 6, padding: \"8px 12px\", flexWrap: \"wrap\" }}>\n {tableIds.map((id) => {\n const t = state.tables.get(id)!\n const active = id === selectedTableId\n return (\n <button\n key={id}\n type=\"button\"\n onClick={() => onSelectTable(id)}\n style={active ? tabActiveStyle : tabStyle}\n >\n {t.label ?? id}\n <span style={mutedStyle}> · {t.rows.length}</span>\n </button>\n )\n })}\n </div>\n\n <Section title=\"Rows\">\n {!table ? (\n <p style={mutedStyle}>No table selected.</p>\n ) : (\n <div>\n <div style={{ display: \"flex\", gap: 6, marginBottom: 6 }}>\n <button type=\"button\" onClick={onAddRow} style={primaryBtnStyle}>+ Row</button>\n <button type=\"button\" onClick={() => onSelectRow(\"new\")} style={ghostBtnStyle}>Cursor → new</button>\n <button type=\"button\" onClick={() => onSelectRow(null)} style={ghostBtnStyle}>Cursor → none</button>\n </div>\n <div style={{ overflowX: \"auto\" }}>\n <table style={tableStyle}>\n <thead>\n <tr style={{ borderBottom: \"1px solid #2a2f37\" }}>\n <th style={thStyle}>id</th>\n {columnIds.map((col) => (\n <th key={col} style={thStyle}>\n {table.columns[col]?.label ?? col}\n </th>\n ))}\n <th style={thStyle}></th>\n </tr>\n </thead>\n <tbody>\n {table.rows.map((row) => {\n const rowId = row.id\n const active = state.selection.rowId === rowId\n return (\n <tr\n key={rowId}\n style={active ? trActiveStyle : trStyle}\n onClick={() => onSelectRow(rowId)}\n >\n <td style={tdStyle}>{rowId}</td>\n {columnIds.map((col) => (\n <td key={col} style={tdStyle}>\n <input\n value={formatCell(row[col])}\n style={inputStyle}\n onClick={(event) => event.stopPropagation()}\n onChange={(event) => onEditCell(rowId, col, event.target.value)}\n />\n </td>\n ))}\n <td style={tdStyle}>\n <button\n type=\"button\"\n style={dangerBtnStyle}\n onClick={(event) => {\n event.stopPropagation()\n onDeleteRow(rowId)\n }}\n >\n Delete\n </button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </Section>\n\n <Section title=\"Selection / mappings\">\n <div style={kvStyle}>\n <KV k=\"tableId\" v={state.selection.tableId} />\n <KV k=\"rowId\" v={String(state.selection.rowId)} />\n <KV k=\"mappings\" v={JSON.stringify(resolveMappings(state))} />\n <KV k=\"configuration\" v={JSON.stringify(state.configuration)} />\n </div>\n </Section>\n\n <Section title=\"Widget options\">\n <pre style={preStyle}>{JSON.stringify(state.widgetOptions, null, 2)}</pre>\n <KV k=\"interaction\" v={JSON.stringify(state.widgetInteraction)} />\n </Section>\n\n {showTimeline && (\n <Section title={`Event timeline (${history.length})`}>\n <div style={{ maxHeight: 200, overflow: \"auto\", fontFamily: \"monospace\", fontSize: 11 }}>\n {history.slice(-50).reverse().map((event, idx) => (\n <div key={idx} style={timelineRowStyle}>\n <span style={typeBadgeStyle(event.type)}>{event.type}</span>\n <span style={mutedStyle}>{summariseEvent(event)}</span>\n </div>\n ))}\n {history.length === 0 && <p style={mutedStyle}>No events yet.</p>}\n </div>\n </Section>\n )}\n </div>\n )\n}\n\nfunction Section({ title, children }: { title: string; children: ReactNode }) {\n const [open, setOpen] = useState(true)\n return (\n <div style={{ borderTop: \"1px solid #2a2f37\" }}>\n <button type=\"button\" style={sectionHeaderStyle} onClick={() => setOpen((v) => !v)}>\n <span>{open ? \"▾\" : \"▸\"}</span>\n <strong>{title}</strong>\n </button>\n {open && <div style={{ padding: \"0 12px 12px\" }}>{children}</div>}\n </div>\n )\n}\n\nfunction KV({ k, v }: { k: string; v: ReactNode }) {\n return (\n <div style={kvRowStyle}>\n <span style={mutedStyle}>{k}</span>\n <code style={{ fontFamily: \"monospace\", fontSize: 11 }}>{v}</code>\n </div>\n )\n}\n\nfunction summariseEvent(event: { type: string } & Record<string, unknown>): string {\n switch (event.type) {\n case \"user-action\":\n return JSON.stringify(event.action)\n case \"data-change\":\n return `tableId=${String(event.tableId)}`\n case \"cursor-change\":\n return `tableId=${String(event.tableId)} rowId=${String(event.rowId)}`\n case \"options-change\":\n return JSON.stringify(event.options)\n case \"ready\":\n return JSON.stringify(event.configuration)\n case \"theme-change\":\n return JSON.stringify(event.message)\n case \"mappings-change\":\n return JSON.stringify(event.mappings)\n default:\n return \"\"\n }\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\"\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n return JSON.stringify(value)\n}\n\n// --- styles -----------------------------------------------------------------\n\nconst baseStyle: CSSProperties = {\n background: \"#15171c\",\n color: \"#e6e6e6\",\n fontFamily: \"system-ui, sans-serif\",\n fontSize: 13,\n border: \"1px solid #2a2f37\",\n borderRadius: 8,\n overflow: \"hidden\",\n}\nconst headerStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"10px 12px\",\n background: \"#0f1115\",\n borderBottom: \"1px solid #2a2f37\",\n}\nconst badgeStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n letterSpacing: 0.5,\n}\nconst mutedStyle: CSSProperties = { color: \"#9ba1ad\" }\nconst sectionHeaderStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n background: \"transparent\",\n color: \"inherit\",\n border: \"none\",\n padding: \"10px 12px\",\n textAlign: \"left\" as const,\n cursor: \"pointer\",\n}\nconst tabStyle: CSSProperties = {\n background: \"#1c1f26\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst tabActiveStyle: CSSProperties = { ...tabStyle, background: \"#27313f\", borderColor: \"#3a4f6e\", color: \"#fff\" }\nconst primaryBtnStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst ghostBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst dangerBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#e58f8f\",\n border: \"1px solid #4a2226\",\n borderRadius: 6,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n}\nconst tableStyle: CSSProperties = { width: \"100%\", borderCollapse: \"collapse\" as const, fontSize: 12 }\nconst thStyle: CSSProperties = { textAlign: \"left\" as const, padding: \"4px 6px\", color: \"#9ba1ad\", fontWeight: 500 }\nconst trStyle: CSSProperties = { borderBottom: \"1px solid #1f232b\" }\nconst trActiveStyle: CSSProperties = { ...trStyle, background: \"#1d2733\" }\nconst tdStyle: CSSProperties = { padding: \"4px 6px\" }\nconst inputStyle: CSSProperties = {\n width: \"100%\",\n background: \"#0f1115\",\n color: \"#e6e6e6\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: \"2px 4px\",\n fontSize: 12,\n fontFamily: \"monospace\",\n}\nconst preStyle: CSSProperties = {\n background: \"#0f1115\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: 8,\n fontSize: 11,\n fontFamily: \"monospace\",\n margin: 0,\n whiteSpace: \"pre-wrap\",\n}\nconst kvStyle: CSSProperties = { display: \"flex\", flexDirection: \"column\" as const, gap: 4 }\nconst kvRowStyle: CSSProperties = { display: \"flex\", gap: 8 }\nconst timelineRowStyle: CSSProperties = {\n display: \"flex\",\n gap: 8,\n padding: \"2px 0\",\n borderBottom: \"1px solid #1f232b\",\n}\nfunction typeBadgeStyle(type: string): CSSProperties {\n const colour = ({\n \"user-action\": \"#a06bff\",\n \"data-change\": \"#3a8e57\",\n \"cursor-change\": \"#3a87b8\",\n \"options-change\": \"#b8893a\",\n ready: \"#888\",\n \"theme-change\": \"#888\",\n \"mappings-change\": \"#888\",\n } as Record<string, string>)[type] ?? \"#888\"\n return {\n background: colour,\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n flexShrink: 0,\n }\n}\n","import { useSyncExternalStore } from \"react\"\n\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\n\n/**\n * React-friendly snapshot of the emulator state. Re-renders whenever the\n * event bus fires (so the inspector stays in lock-step with widget actions).\n */\nexport function useEmulatorSnapshot(emulator: GristEmulator) {\n const subscribe = (notify: () => void) => {\n return emulator.bus.on(() => notify())\n }\n const getSnapshot = () => snapshotKey(emulator)\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n return {\n state: emulator.state,\n history: emulator.bus.history(),\n }\n}\n\n/**\n * A monotonic-ish key that changes on every event. We tag each event with\n * its index in the history so React detects changes cheaply.\n */\nfunction snapshotKey(emulator: GristEmulator): string {\n const history = emulator.bus.history()\n const last = history[history.length - 1]\n return `${history.length}:${eventTag(last)}`\n}\n\nfunction eventTag(event: EmulatorEvent | undefined): string {\n if (!event) return \"empty\"\n switch (event.type) {\n case \"data-change\":\n return `data:${event.tableId}`\n case \"cursor-change\":\n return `cursor:${event.tableId}:${String(event.rowId)}`\n case \"options-change\":\n return `options:${Object.keys(event.options).length}`\n case \"ready\":\n return \"ready\"\n case \"user-action\":\n return `action:${(event.action[0] as string | undefined) ?? \"?\"}`\n case \"mappings-change\":\n return \"mappings\"\n case \"theme-change\":\n return \"theme\"\n }\n}\n","import { useEffect, useState } from \"react\"\n\nimport {\n materializeGristRowsFromColumnar,\n safeParseRowsToDisplayRows,\n} from \"../../sdk/helpers/grist-table-data\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type UseEmulatorRowsResult<T extends Record<string, unknown> = Record<string, unknown>> = {\n rows: GristRowRecord<T>[]\n invalidCellKeys: Set<string>\n}\n\n/**\n * Build display-ready rows from emulator in-memory state (same parse pipeline as\n * {@link fetchGristTableRows}, without `docApi.fetchTable`).\n */\nexport function fetchEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string\n): UseEmulatorRowsResult<T> {\n const table = emulator.state.tables.get(tableId)\n if (!table) {\n return { rows: [], invalidCellKeys: new Set() }\n }\n\n let cellMetaByKey: Record<string, { issues: Array<{ code: string }> }> = {}\n const data = rowsToColumnar(table, table.rows)\n const parsedRows = materializeGristRowsFromColumnar<T>(data, {\n columns: table.columns,\n order: \"grist\",\n safeParse: {\n refMode: \"detailed\",\n },\n onSafeParseCellMetaByKey: (metaByKey) => {\n cellMetaByKey = metaByKey as Record<string, { issues: Array<{ code: string }> }>\n },\n })\n const rows = safeParseRowsToDisplayRows(parsedRows) as GristRowRecord<T>[]\n const invalidCellKeys = new Set<string>()\n for (const [cellKey, meta] of Object.entries(cellMetaByKey)) {\n const hasIssue = meta.issues.some(\n (issue) => issue.code === \"type_mismatch\" || issue.code === \"invalid_format\"\n )\n if (hasIssue) invalidCellKeys.add(cellKey)\n }\n return { rows, invalidCellKeys }\n}\n\nexport function useEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string | undefined | null\n): UseEmulatorRowsResult<T> {\n const { history } = useEmulatorSnapshot(emulator)\n const [result, setResult] = useState<UseEmulatorRowsResult<T>>({\n rows: [],\n invalidCellKeys: new Set(),\n })\n\n useEffect(() => {\n let cancelled = false\n if (!tableId) {\n queueMicrotask(() => {\n if (!cancelled) setResult({ rows: [], invalidCellKeys: new Set() })\n })\n return () => {\n cancelled = true\n }\n }\n\n try {\n const next = fetchEmulatorRows<T>(emulator, tableId)\n if (!cancelled) setResult(next)\n } catch {\n const table = emulator.state.tables.get(tableId)\n if (!cancelled) {\n setResult({\n rows: (table?.rows ?? []) as GristRowRecord<T>[],\n invalidCellKeys: new Set(),\n })\n }\n }\n\n return () => {\n cancelled = true\n }\n }, [emulator, tableId, history.length])\n\n return result\n}\n","import { useMemo } from \"react\"\n\nimport type { GristReplicaColumn, GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport { isGristNoiseColumn } from \"../../sdk/helpers/grist-columns-filters\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type EmulatorColumnsTableView = GristReplicaTable & { tableId: string }\n\nexport type UseEmulatorColumnsResult = {\n document: GristReplicaDocument\n table: EmulatorColumnsTableView | null\n isNoiseColumnId: (colId: string, col?: GristReplicaColumn) => boolean\n sortColumnIds: (colIds: string[], columns: Record<string, GristReplicaColumn>) => string[]\n}\n\nexport function useEmulatorColumns(emulator: GristEmulator): UseEmulatorColumnsResult {\n const { state } = useEmulatorSnapshot(emulator)\n const requestedTableId = state.selection.tableId\n\n const document = useMemo<GristReplicaDocument>(() => {\n const tables: Record<string, GristReplicaTable> = {}\n for (const [tableId, table] of state.tables.entries()) {\n const filteredColumns = Object.fromEntries(\n Object.entries(table.columns).filter(([colId, col]) => {\n return !isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n })\n })\n )\n tables[tableId] = {\n label: table.label,\n columns: filteredColumns,\n rows: table.rows.map((row) => ({ ...row })),\n rowCount: table.rows.length,\n }\n }\n return {\n generatedAt: new Date().toISOString(),\n docName: state.docName,\n mode: \"schema+data\",\n source: \"emulator-devtools\",\n tables,\n }\n }, [state])\n\n const table = useMemo<EmulatorColumnsTableView | null>(() => {\n if (!requestedTableId) return null\n const slice = document.tables[requestedTableId]\n if (!slice) return null\n return { tableId: requestedTableId, ...slice }\n }, [document, requestedTableId])\n\n const isNoiseColumnId = useMemo(\n () =>\n (colId: string, col?: GristReplicaColumn): boolean =>\n isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n }),\n []\n )\n\n const sortColumnIds = useMemo(\n () => (colIds: string[], columns: Record<string, GristReplicaColumn>): string[] => {\n return [...colIds].sort((a, b) => {\n const la = (columns[a]?.label || a).toLowerCase()\n const lb = (columns[b]?.label || b).toLowerCase()\n if (la !== lb) return la.localeCompare(lb)\n return a.localeCompare(b)\n })\n },\n []\n )\n\n return { document, table, isNoiseColumnId, sortColumnIds }\n}\n"],"mappings":"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","names":["useState","useState","table"]}
|
|
1
|
+
{"version":3,"sources":["../../src/emulator/devtools/inspector.tsx","../../src/emulator/devtools/use-emulator-state.ts","../../src/emulator/devtools/use-rows.ts","../../src/emulator/devtools/use-columns.ts"],"sourcesContent":["/**\n * `<EmulatorInspector />` — drop-in DevTools for the playground / IDE.\n *\n * Capabilities:\n * - Multi-table picker with row count + label\n * - Inline row editor (Add / Update / Delete) routed through the emulator's\n * action engine — every edit produces real Grist user actions on the bus.\n * - Cursor selector that drives `onRecord` for the widget under test.\n * - Widget options & mappings panel.\n * - Live event timeline (last 50 events) with pretty formatting.\n *\n * The component owns no state of its own beyond UI accordion toggles —\n * everything is read off the emulator and re-renders via {@link\n * useEmulatorSnapshot}.\n */\n\nimport type { CSSProperties, ReactNode } from \"react\"\nimport { useState } from \"react\"\n\nimport { gristAddRecordAction, gristRemoveRecordAction, gristUpdateRecordAction } from \"../../sdk/helpers/grist-user-actions\"\nimport { gristAccessLevelLabel } from \"../../sdk/internal/handshake/access\"\nimport type { GristRequiredAccess } from \"../../sdk/types\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { resolveMappings } from \"../core/mappings\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nconst ACCESS_LEVELS: readonly GristRequiredAccess[] = [\"none\", \"read table\", \"full\"]\n\nexport type EmulatorInspectorProps = {\n emulator: GristEmulator\n /** Override visual style. */\n className?: string\n /** Default `true`. Set to `false` to render only the toolbar. */\n showTimeline?: boolean\n}\n\nexport function EmulatorInspector({ emulator, className, showTimeline = true }: EmulatorInspectorProps) {\n const { state, history } = useEmulatorSnapshot(emulator)\n const tableIds = [...state.tables.keys()]\n const selectedTableId = state.selection.tableId\n const table = state.tables.get(selectedTableId)\n const columnIds = table ? Object.keys(table.columns) : []\n\n const onSelectTable = (tableId: string) => emulator.selectTable(tableId)\n const onSelectRow = (rowId: number | \"new\" | null) => emulator.selectRow(rowId)\n const onAddRow = () => {\n if (!table) return\n const fields: Record<string, unknown> = {}\n for (const col of columnIds) fields[col] = \"\"\n emulator.apply([gristAddRecordAction(selectedTableId, fields)])\n }\n const onDeleteRow = (rowId: number) => {\n emulator.apply([gristRemoveRecordAction(selectedTableId, rowId)])\n }\n const onEditCell = (rowId: number, colId: string, value: string) => {\n emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })])\n }\n\n const grantedAccessLevel = (state.widgetInteraction.access_level as GristRequiredAccess | undefined) ?? \"read table\"\n const onSetAccessLevel = (level: GristRequiredAccess) => {\n emulator.setInteraction({ ...state.widgetInteraction, access_level: level })\n }\n\n return (\n <div className={className} style={baseStyle}>\n <div style={headerStyle}>\n <span style={badgeStyle}>EMULATOR</span>\n <strong>{state.docName}</strong>\n <span style={mutedStyle}>· {tableIds.length} table{tableIds.length === 1 ? \"\" : \"s\"}</span>\n </div>\n\n <div style={{ display: \"flex\", gap: 6, padding: \"8px 12px\", flexWrap: \"wrap\" }}>\n {tableIds.map((id) => {\n const t = state.tables.get(id)!\n const active = id === selectedTableId\n return (\n <button\n key={id}\n type=\"button\"\n onClick={() => onSelectTable(id)}\n style={active ? tabActiveStyle : tabStyle}\n >\n {t.label ?? id}\n <span style={mutedStyle}> · {t.rows.length}</span>\n </button>\n )\n })}\n </div>\n\n <Section title=\"Rows\">\n {!table ? (\n <p style={mutedStyle}>No table selected.</p>\n ) : (\n <div>\n <div style={{ display: \"flex\", gap: 6, marginBottom: 6 }}>\n <button type=\"button\" onClick={onAddRow} style={primaryBtnStyle}>+ Row</button>\n <button type=\"button\" onClick={() => onSelectRow(\"new\")} style={ghostBtnStyle}>Cursor → new</button>\n <button type=\"button\" onClick={() => onSelectRow(null)} style={ghostBtnStyle}>Cursor → none</button>\n </div>\n <div style={{ overflowX: \"auto\" }}>\n <table style={tableStyle}>\n <thead>\n <tr style={{ borderBottom: \"1px solid #2a2f37\" }}>\n <th style={thStyle}>id</th>\n {columnIds.map((col) => (\n <th key={col} style={thStyle}>\n {table.columns[col]?.label ?? col}\n </th>\n ))}\n <th style={thStyle}></th>\n </tr>\n </thead>\n <tbody>\n {table.rows.map((row) => {\n const rowId = row.id\n const active = state.selection.rowId === rowId\n return (\n <tr\n key={rowId}\n style={active ? trActiveStyle : trStyle}\n onClick={() => onSelectRow(rowId)}\n >\n <td style={tdStyle}>{rowId}</td>\n {columnIds.map((col) => (\n <td key={col} style={tdStyle}>\n <input\n value={formatCell(row[col])}\n style={inputStyle}\n onClick={(event) => event.stopPropagation()}\n onChange={(event) => onEditCell(rowId, col, event.target.value)}\n />\n </td>\n ))}\n <td style={tdStyle}>\n <button\n type=\"button\"\n style={dangerBtnStyle}\n onClick={(event) => {\n event.stopPropagation()\n onDeleteRow(rowId)\n }}\n >\n Delete\n </button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n </div>\n )}\n </Section>\n\n <Section title=\"Selection / mappings\">\n <div style={kvStyle}>\n <KV k=\"tableId\" v={state.selection.tableId} />\n <KV k=\"rowId\" v={String(state.selection.rowId)} />\n <KV k=\"mappings\" v={JSON.stringify(resolveMappings(state))} />\n <KV k=\"configuration\" v={JSON.stringify(state.configuration)} />\n </div>\n </Section>\n\n <Section title=\"Access level\">\n <div style={{ display: \"flex\", gap: 6, marginBottom: 6, flexWrap: \"wrap\" }}>\n {ACCESS_LEVELS.map((level) => (\n <button\n key={level}\n type=\"button\"\n onClick={() => onSetAccessLevel(level)}\n style={level === grantedAccessLevel ? tabActiveStyle : tabStyle}\n title={gristAccessLevelLabel(level)}\n >\n {level}\n </button>\n ))}\n </div>\n <p style={mutedStyle}>\n Granted to the widget via <code>access_level</code> — {gristAccessLevelLabel(grantedAccessLevel)}.\n </p>\n </Section>\n\n <Section title=\"Widget options\">\n <pre style={preStyle}>{JSON.stringify(state.widgetOptions, null, 2)}</pre>\n <KV k=\"interaction\" v={JSON.stringify(state.widgetInteraction)} />\n </Section>\n\n {showTimeline && (\n <Section title={`Event timeline (${history.length})`}>\n <div style={{ maxHeight: 200, overflow: \"auto\", fontFamily: \"monospace\", fontSize: 11 }}>\n {history.slice(-50).reverse().map((event, idx) => (\n <div key={idx} style={timelineRowStyle}>\n <span style={typeBadgeStyle(event.type)}>{event.type}</span>\n <span style={mutedStyle}>{summariseEvent(event)}</span>\n </div>\n ))}\n {history.length === 0 && <p style={mutedStyle}>No events yet.</p>}\n </div>\n </Section>\n )}\n </div>\n )\n}\n\nfunction Section({ title, children }: { title: string; children: ReactNode }) {\n const [open, setOpen] = useState(true)\n return (\n <div style={{ borderTop: \"1px solid #2a2f37\" }}>\n <button type=\"button\" style={sectionHeaderStyle} onClick={() => setOpen((v) => !v)}>\n <span>{open ? \"▾\" : \"▸\"}</span>\n <strong>{title}</strong>\n </button>\n {open && <div style={{ padding: \"0 12px 12px\" }}>{children}</div>}\n </div>\n )\n}\n\nfunction KV({ k, v }: { k: string; v: ReactNode }) {\n return (\n <div style={kvRowStyle}>\n <span style={mutedStyle}>{k}</span>\n <code style={{ fontFamily: \"monospace\", fontSize: 11 }}>{v}</code>\n </div>\n )\n}\n\nfunction summariseEvent(event: { type: string } & Record<string, unknown>): string {\n switch (event.type) {\n case \"user-action\":\n return JSON.stringify(event.action)\n case \"data-change\":\n return `tableId=${String(event.tableId)}`\n case \"cursor-change\":\n return `tableId=${String(event.tableId)} rowId=${String(event.rowId)}`\n case \"options-change\":\n return JSON.stringify(event.options)\n case \"ready\":\n return JSON.stringify(event.configuration)\n case \"theme-change\":\n return JSON.stringify(event.message)\n case \"mappings-change\":\n return JSON.stringify(event.mappings)\n default:\n return \"\"\n }\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return \"\"\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") return String(value)\n return JSON.stringify(value)\n}\n\n// --- styles -----------------------------------------------------------------\n\nconst baseStyle: CSSProperties = {\n background: \"#15171c\",\n color: \"#e6e6e6\",\n fontFamily: \"system-ui, sans-serif\",\n fontSize: 13,\n border: \"1px solid #2a2f37\",\n borderRadius: 8,\n overflow: \"hidden\",\n}\nconst headerStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"10px 12px\",\n background: \"#0f1115\",\n borderBottom: \"1px solid #2a2f37\",\n}\nconst badgeStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n letterSpacing: 0.5,\n}\nconst mutedStyle: CSSProperties = { color: \"#9ba1ad\" }\nconst sectionHeaderStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n background: \"transparent\",\n color: \"inherit\",\n border: \"none\",\n padding: \"10px 12px\",\n textAlign: \"left\" as const,\n cursor: \"pointer\",\n}\nconst tabStyle: CSSProperties = {\n background: \"#1c1f26\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst tabActiveStyle: CSSProperties = { ...tabStyle, background: \"#27313f\", borderColor: \"#3a4f6e\", color: \"#fff\" }\nconst primaryBtnStyle: CSSProperties = {\n background: \"#3a8e57\",\n color: \"#fff\",\n border: \"none\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst ghostBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#cfd2d8\",\n border: \"1px solid #2a2f37\",\n borderRadius: 6,\n padding: \"4px 10px\",\n cursor: \"pointer\",\n}\nconst dangerBtnStyle: CSSProperties = {\n background: \"transparent\",\n color: \"#e58f8f\",\n border: \"1px solid #4a2226\",\n borderRadius: 6,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n}\nconst tableStyle: CSSProperties = { width: \"100%\", borderCollapse: \"collapse\" as const, fontSize: 12 }\nconst thStyle: CSSProperties = { textAlign: \"left\" as const, padding: \"4px 6px\", color: \"#9ba1ad\", fontWeight: 500 }\nconst trStyle: CSSProperties = { borderBottom: \"1px solid #1f232b\" }\nconst trActiveStyle: CSSProperties = { ...trStyle, background: \"#1d2733\" }\nconst tdStyle: CSSProperties = { padding: \"4px 6px\" }\nconst inputStyle: CSSProperties = {\n width: \"100%\",\n background: \"#0f1115\",\n color: \"#e6e6e6\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: \"2px 4px\",\n fontSize: 12,\n fontFamily: \"monospace\",\n}\nconst preStyle: CSSProperties = {\n background: \"#0f1115\",\n border: \"1px solid #2a2f37\",\n borderRadius: 4,\n padding: 8,\n fontSize: 11,\n fontFamily: \"monospace\",\n margin: 0,\n whiteSpace: \"pre-wrap\",\n}\nconst kvStyle: CSSProperties = { display: \"flex\", flexDirection: \"column\" as const, gap: 4 }\nconst kvRowStyle: CSSProperties = { display: \"flex\", gap: 8 }\nconst timelineRowStyle: CSSProperties = {\n display: \"flex\",\n gap: 8,\n padding: \"2px 0\",\n borderBottom: \"1px solid #1f232b\",\n}\nfunction typeBadgeStyle(type: string): CSSProperties {\n const colour = ({\n \"user-action\": \"#a06bff\",\n \"data-change\": \"#3a8e57\",\n \"cursor-change\": \"#3a87b8\",\n \"options-change\": \"#b8893a\",\n ready: \"#888\",\n \"theme-change\": \"#888\",\n \"mappings-change\": \"#888\",\n } as Record<string, string>)[type] ?? \"#888\"\n return {\n background: colour,\n color: \"#fff\",\n padding: \"1px 6px\",\n borderRadius: 4,\n fontSize: 10,\n flexShrink: 0,\n }\n}\n","import { useSyncExternalStore } from \"react\"\n\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport type { EmulatorEvent } from \"../core/event-bus\"\n\n/**\n * React-friendly snapshot of the emulator state. Re-renders whenever the\n * event bus fires (so the inspector stays in lock-step with widget actions).\n */\nexport function useEmulatorSnapshot(emulator: GristEmulator) {\n const subscribe = (notify: () => void) => {\n return emulator.bus.on(() => notify())\n }\n const getSnapshot = () => snapshotKey(emulator)\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n return {\n state: emulator.state,\n history: emulator.bus.history(),\n }\n}\n\n/**\n * A monotonic-ish key that changes on every event. We tag each event with\n * its index in the history so React detects changes cheaply.\n */\nfunction snapshotKey(emulator: GristEmulator): string {\n const history = emulator.bus.history()\n const last = history[history.length - 1]\n return `${history.length}:${eventTag(last)}`\n}\n\nfunction eventTag(event: EmulatorEvent | undefined): string {\n if (!event) return \"empty\"\n switch (event.type) {\n case \"data-change\":\n return `data:${event.tableId}`\n case \"cursor-change\":\n return `cursor:${event.tableId}:${String(event.rowId)}`\n case \"options-change\":\n return `options:${Object.keys(event.options).length}`\n case \"ready\":\n return \"ready\"\n case \"user-action\":\n return `action:${(event.action[0] as string | undefined) ?? \"?\"}`\n case \"mappings-change\":\n return \"mappings\"\n case \"theme-change\":\n return \"theme\"\n }\n}\n","import { useEffect, useState } from \"react\"\n\nimport {\n materializeGristRowsFromColumnar,\n safeParseRowsToDisplayRows,\n} from \"../../sdk/helpers/grist-table-data\"\nimport type { GristRowRecord } from \"../../sdk/types\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { rowsToColumnar } from \"../core/columnar\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type UseEmulatorRowsResult<T extends Record<string, unknown> = Record<string, unknown>> = {\n rows: GristRowRecord<T>[]\n invalidCellKeys: Set<string>\n}\n\n/**\n * Build display-ready rows from emulator in-memory state (same parse pipeline as\n * {@link fetchGristTableRows}, without `docApi.fetchTable`).\n */\nexport function fetchEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string\n): UseEmulatorRowsResult<T> {\n const table = emulator.state.tables.get(tableId)\n if (!table) {\n return { rows: [], invalidCellKeys: new Set() }\n }\n\n let cellMetaByKey: Record<string, { issues: Array<{ code: string }> }> = {}\n const data = rowsToColumnar(table, table.rows)\n const parsedRows = materializeGristRowsFromColumnar<T>(data, {\n columns: table.columns,\n order: \"grist\",\n safeParse: {\n refMode: \"detailed\",\n },\n onSafeParseCellMetaByKey: (metaByKey) => {\n cellMetaByKey = metaByKey as Record<string, { issues: Array<{ code: string }> }>\n },\n })\n const rows = safeParseRowsToDisplayRows(parsedRows) as GristRowRecord<T>[]\n const invalidCellKeys = new Set<string>()\n for (const [cellKey, meta] of Object.entries(cellMetaByKey)) {\n const hasIssue = meta.issues.some(\n (issue) => issue.code === \"type_mismatch\" || issue.code === \"invalid_format\"\n )\n if (hasIssue) invalidCellKeys.add(cellKey)\n }\n return { rows, invalidCellKeys }\n}\n\nexport function useEmulatorRows<T extends Record<string, unknown> = Record<string, unknown>>(\n emulator: GristEmulator,\n tableId: string | undefined | null\n): UseEmulatorRowsResult<T> {\n const { history } = useEmulatorSnapshot(emulator)\n const [result, setResult] = useState<UseEmulatorRowsResult<T>>({\n rows: [],\n invalidCellKeys: new Set(),\n })\n\n useEffect(() => {\n let cancelled = false\n if (!tableId) {\n queueMicrotask(() => {\n if (!cancelled) setResult({ rows: [], invalidCellKeys: new Set() })\n })\n return () => {\n cancelled = true\n }\n }\n\n try {\n const next = fetchEmulatorRows<T>(emulator, tableId)\n if (!cancelled) setResult(next)\n } catch {\n const table = emulator.state.tables.get(tableId)\n if (!cancelled) {\n setResult({\n rows: (table?.rows ?? []) as GristRowRecord<T>[],\n invalidCellKeys: new Set(),\n })\n }\n }\n\n return () => {\n cancelled = true\n }\n }, [emulator, tableId, history.length])\n\n return result\n}\n","import { useMemo } from \"react\"\n\nimport type { GristReplicaColumn, GristReplicaDocument, GristReplicaTable } from \"../../sdk/replica-document\"\nimport { isGristNoiseColumn } from \"../../sdk/helpers/grist-columns-filters\"\nimport type { GristEmulator } from \"../create-grist-emulator\"\nimport { useEmulatorSnapshot } from \"./use-emulator-state\"\n\nexport type EmulatorColumnsTableView = GristReplicaTable & { tableId: string }\n\nexport type UseEmulatorColumnsResult = {\n document: GristReplicaDocument\n table: EmulatorColumnsTableView | null\n isNoiseColumnId: (colId: string, col?: GristReplicaColumn) => boolean\n sortColumnIds: (colIds: string[], columns: Record<string, GristReplicaColumn>) => string[]\n}\n\nexport function useEmulatorColumns(emulator: GristEmulator): UseEmulatorColumnsResult {\n const { state } = useEmulatorSnapshot(emulator)\n const requestedTableId = state.selection.tableId\n\n const document = useMemo<GristReplicaDocument>(() => {\n const tables: Record<string, GristReplicaTable> = {}\n for (const [tableId, table] of state.tables.entries()) {\n const filteredColumns = Object.fromEntries(\n Object.entries(table.columns).filter(([colId, col]) => {\n return !isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n })\n })\n )\n tables[tableId] = {\n label: table.label,\n columns: filteredColumns,\n rows: table.rows.map((row) => ({ ...row })),\n rowCount: table.rows.length,\n }\n }\n return {\n generatedAt: new Date().toISOString(),\n docName: state.docName,\n mode: \"schema+data\",\n source: \"emulator-devtools\",\n tables,\n }\n }, [state])\n\n const table = useMemo<EmulatorColumnsTableView | null>(() => {\n if (!requestedTableId) return null\n const slice = document.tables[requestedTableId]\n if (!slice) return null\n return { tableId: requestedTableId, ...slice }\n }, [document, requestedTableId])\n\n const isNoiseColumnId = useMemo(\n () =>\n (colId: string, col?: GristReplicaColumn): boolean =>\n isGristNoiseColumn(colId, col, {\n excludeId: true,\n excludeGristHelpers: true,\n excludeLoggingColumns: true,\n excludeManualSort: true,\n }),\n []\n )\n\n const sortColumnIds = useMemo(\n () => (colIds: string[], columns: Record<string, GristReplicaColumn>): string[] => {\n return [...colIds].sort((a, b) => {\n const la = (columns[a]?.label || a).toLowerCase()\n const lb = (columns[b]?.label || b).toLowerCase()\n if (la !== lb) return la.localeCompare(lb)\n return a.localeCompare(b)\n })\n },\n []\n )\n\n return { document, table, isNoiseColumnId, sortColumnIds }\n}\n"],"mappings":"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","names":["useState","useState","table"]}
|