grist-widget-sdk 0.3.26 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +1 -1
- package/dist/app.cjs +1139 -4336
- package/dist/app.cjs.map +1 -1
- package/dist/app.d.cts +1 -3
- package/dist/app.d.ts +1 -3
- package/dist/app.js +9 -517
- package/dist/app.js.map +1 -1
- package/dist/chunk-4ZGVKGDF.js +204 -0
- package/dist/chunk-4ZGVKGDF.js.map +1 -0
- package/dist/{chunk-YQNMIL33.js → chunk-B5ZZNLVS.js} +528 -181
- package/dist/chunk-B5ZZNLVS.js.map +1 -0
- package/dist/chunk-O7NY46QY.js +1830 -0
- package/dist/chunk-O7NY46QY.js.map +1 -0
- package/dist/chunk-P6VTEKWO.js +618 -0
- package/dist/chunk-P6VTEKWO.js.map +1 -0
- package/dist/emulator/testing.cjs +2084 -391
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.d.cts +55 -7
- package/dist/emulator/testing.d.ts +55 -7
- package/dist/emulator/testing.js +144 -19
- package/dist/emulator/testing.js.map +1 -1
- package/dist/emulator.cjs +59 -249
- package/dist/emulator.cjs.map +1 -1
- package/dist/emulator.d.cts +3 -5
- package/dist/emulator.d.ts +3 -5
- package/dist/emulator.js +5 -11
- package/dist/index.cjs +1373 -4859
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -260
- package/dist/index.d.ts +81 -260
- package/dist/index.js +8 -161
- package/dist/{inline-C7DkvuET.d.cts → templates-CGmRIQBV.d.cts} +89 -35
- package/dist/{inline-DpcT8tV9.d.ts → templates-Cq94qOcf.d.ts} +89 -35
- package/dist/{types-D3JxUCfL.d.cts → types-DBStn0Dk.d.cts} +2 -26
- package/dist/{types-D3JxUCfL.d.ts → types-DBStn0Dk.d.ts} +2 -26
- package/dist/use-grist-BK0eke9K.d.cts +358 -0
- package/dist/use-grist-C5DMZ3wU.d.ts +358 -0
- package/package.json +8 -37
- package/dist/advanced.cjs +0 -2799
- package/dist/advanced.cjs.map +0 -1
- package/dist/advanced.d.cts +0 -822
- package/dist/advanced.d.ts +0 -822
- package/dist/advanced.js +0 -875
- package/dist/advanced.js.map +0 -1
- package/dist/chunk-22U7WAY3.js +0 -463
- package/dist/chunk-22U7WAY3.js.map +0 -1
- package/dist/chunk-64SVRWW7.js +0 -758
- package/dist/chunk-64SVRWW7.js.map +0 -1
- package/dist/chunk-ELGVOHFD.js +0 -32
- package/dist/chunk-ELGVOHFD.js.map +0 -1
- package/dist/chunk-EPEBKXVN.js +0 -470
- package/dist/chunk-EPEBKXVN.js.map +0 -1
- package/dist/chunk-GTTD5HPO.js +0 -36
- package/dist/chunk-GTTD5HPO.js.map +0 -1
- package/dist/chunk-JASMM2YC.js +0 -243
- package/dist/chunk-JASMM2YC.js.map +0 -1
- package/dist/chunk-N3X46JW2.js +0 -37
- package/dist/chunk-N3X46JW2.js.map +0 -1
- package/dist/chunk-PDGEZ24B.js +0 -2366
- package/dist/chunk-PDGEZ24B.js.map +0 -1
- package/dist/chunk-PM3B4WYV.js +0 -12
- package/dist/chunk-PM3B4WYV.js.map +0 -1
- package/dist/chunk-REV5AUXD.js +0 -25
- package/dist/chunk-REV5AUXD.js.map +0 -1
- package/dist/chunk-TZB3OZA6.js +0 -1630
- package/dist/chunk-TZB3OZA6.js.map +0 -1
- package/dist/chunk-YQNMIL33.js.map +0 -1
- package/dist/create-grist-emulator-BCqp1BF9.d.ts +0 -81
- package/dist/create-grist-emulator-DBM8OSIR.d.cts +0 -81
- package/dist/emulator/devtools.cjs +0 -1404
- package/dist/emulator/devtools.cjs.map +0 -1
- package/dist/emulator/devtools.d.cts +0 -48
- package/dist/emulator/devtools.d.ts +0 -48
- package/dist/emulator/devtools.js +0 -508
- package/dist/emulator/devtools.js.map +0 -1
- package/dist/emulator/transports.cjs +0 -1132
- package/dist/emulator/transports.cjs.map +0 -1
- package/dist/emulator/transports.d.cts +0 -38
- package/dist/emulator/transports.d.ts +0 -38
- package/dist/emulator/transports.js +0 -12
- package/dist/emulator/transports.js.map +0 -1
- package/dist/templates-8k2LKoO-.d.cts +0 -24
- package/dist/templates-DIwi_mvI.d.ts +0 -24
- package/dist/use-grist-reads-DUMvJgV7.d.ts +0 -480
- package/dist/use-grist-reads-DpjVuI0H.d.cts +0 -480
- package/dist/use-grist-types-DdOLEJXN.d.cts +0 -499
- package/dist/use-grist-types-kwxoFeub.d.ts +0 -499
- package/dist/use-grist-widget-options-from-context-CGOlQ5Vc.d.cts +0 -43
- package/dist/use-grist-widget-options-from-context-CGOlQ5Vc.d.ts +0 -43
|
@@ -1,1404 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/emulator/devtools/index.ts
|
|
21
|
-
var devtools_exports = {};
|
|
22
|
-
__export(devtools_exports, {
|
|
23
|
-
EmulatorInspector: () => EmulatorInspector,
|
|
24
|
-
fetchEmulatorRows: () => fetchEmulatorRows,
|
|
25
|
-
useEmulatorColumns: () => useEmulatorColumns,
|
|
26
|
-
useEmulatorRows: () => useEmulatorRows,
|
|
27
|
-
useEmulatorSnapshot: () => useEmulatorSnapshot
|
|
28
|
-
});
|
|
29
|
-
module.exports = __toCommonJS(devtools_exports);
|
|
30
|
-
|
|
31
|
-
// src/emulator/devtools/inspector.tsx
|
|
32
|
-
var import_react2 = require("react");
|
|
33
|
-
|
|
34
|
-
// src/sdk/helpers/grist-user-actions.ts
|
|
35
|
-
function gristUpdateRecordAction(tableId, rowId, patch) {
|
|
36
|
-
return ["UpdateRecord", tableId, rowId, patch];
|
|
37
|
-
}
|
|
38
|
-
function gristAddRecordAction(tableId, values) {
|
|
39
|
-
return ["AddRecord", tableId, null, values];
|
|
40
|
-
}
|
|
41
|
-
function gristRemoveRecordAction(tableId, rowId) {
|
|
42
|
-
return ["RemoveRecord", tableId, rowId];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// src/sdk/internal/handshake/access.ts
|
|
46
|
-
function gristAccessLevelLabel(level) {
|
|
47
|
-
switch (level) {
|
|
48
|
-
case "none":
|
|
49
|
-
return "No document access";
|
|
50
|
-
case "read table":
|
|
51
|
-
return "Read selected table";
|
|
52
|
-
case "full":
|
|
53
|
-
return "Full document access";
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// src/emulator/core/mappings.ts
|
|
58
|
-
function resolveMappings(state) {
|
|
59
|
-
if (state.selection.mappings !== void 0 && state.selection.mappings !== null) {
|
|
60
|
-
return state.selection.mappings;
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// src/emulator/devtools/use-emulator-state.ts
|
|
66
|
-
var import_react = require("react");
|
|
67
|
-
function useEmulatorSnapshot(emulator) {
|
|
68
|
-
const subscribe = (notify) => {
|
|
69
|
-
return emulator.bus.on(() => notify());
|
|
70
|
-
};
|
|
71
|
-
const getSnapshot = () => snapshotKey(emulator);
|
|
72
|
-
(0, import_react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
73
|
-
return {
|
|
74
|
-
state: emulator.state,
|
|
75
|
-
history: emulator.bus.history()
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function snapshotKey(emulator) {
|
|
79
|
-
const history = emulator.bus.history();
|
|
80
|
-
const last = history[history.length - 1];
|
|
81
|
-
return `${history.length}:${eventTag(last)}`;
|
|
82
|
-
}
|
|
83
|
-
function eventTag(event) {
|
|
84
|
-
if (!event) return "empty";
|
|
85
|
-
switch (event.type) {
|
|
86
|
-
case "data-change":
|
|
87
|
-
return `data:${event.tableId}`;
|
|
88
|
-
case "cursor-change":
|
|
89
|
-
return `cursor:${event.tableId}:${String(event.rowId)}`;
|
|
90
|
-
case "options-change":
|
|
91
|
-
return `options:${Object.keys(event.options).length}`;
|
|
92
|
-
case "ready":
|
|
93
|
-
return "ready";
|
|
94
|
-
case "user-action":
|
|
95
|
-
return `action:${event.action[0] ?? "?"}`;
|
|
96
|
-
case "mappings-change":
|
|
97
|
-
return "mappings";
|
|
98
|
-
case "theme-change":
|
|
99
|
-
return "theme";
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// src/emulator/devtools/inspector.tsx
|
|
104
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
105
|
-
var ACCESS_LEVELS = ["none", "read table", "full"];
|
|
106
|
-
function EmulatorInspector({ emulator, className, showTimeline = true }) {
|
|
107
|
-
const { state, history } = useEmulatorSnapshot(emulator);
|
|
108
|
-
const tableIds = [...state.tables.keys()];
|
|
109
|
-
const selectedTableId = state.selection.tableId;
|
|
110
|
-
const table = state.tables.get(selectedTableId);
|
|
111
|
-
const columnIds = table ? Object.keys(table.columns) : [];
|
|
112
|
-
const onSelectTable = (tableId) => emulator.selectTable(tableId);
|
|
113
|
-
const onSelectRow = (rowId) => emulator.selectRow(rowId);
|
|
114
|
-
const onAddRow = () => {
|
|
115
|
-
if (!table) return;
|
|
116
|
-
const fields = {};
|
|
117
|
-
for (const col of columnIds) fields[col] = "";
|
|
118
|
-
emulator.apply([gristAddRecordAction(selectedTableId, fields)]);
|
|
119
|
-
};
|
|
120
|
-
const onDeleteRow = (rowId) => {
|
|
121
|
-
emulator.apply([gristRemoveRecordAction(selectedTableId, rowId)]);
|
|
122
|
-
};
|
|
123
|
-
const onEditCell = (rowId, colId, value) => {
|
|
124
|
-
emulator.apply([gristUpdateRecordAction(selectedTableId, rowId, { [colId]: value })]);
|
|
125
|
-
};
|
|
126
|
-
const grantedAccessLevel = state.widgetInteraction.access_level ?? "read table";
|
|
127
|
-
const onSetAccessLevel = (level) => {
|
|
128
|
-
emulator.setInteraction({ ...state.widgetInteraction, access_level: level });
|
|
129
|
-
};
|
|
130
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: baseStyle, children: [
|
|
131
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: headerStyle, children: [
|
|
132
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: badgeStyle, children: "EMULATOR" }),
|
|
133
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: state.docName }),
|
|
134
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: mutedStyle, children: [
|
|
135
|
-
"\xB7 ",
|
|
136
|
-
tableIds.length,
|
|
137
|
-
" table",
|
|
138
|
-
tableIds.length === 1 ? "" : "s"
|
|
139
|
-
] })
|
|
140
|
-
] }),
|
|
141
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 6, padding: "8px 12px", flexWrap: "wrap" }, children: tableIds.map((id) => {
|
|
142
|
-
const t = state.tables.get(id);
|
|
143
|
-
const active = id === selectedTableId;
|
|
144
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
145
|
-
"button",
|
|
146
|
-
{
|
|
147
|
-
type: "button",
|
|
148
|
-
onClick: () => onSelectTable(id),
|
|
149
|
-
style: active ? tabActiveStyle : tabStyle,
|
|
150
|
-
children: [
|
|
151
|
-
t.label ?? id,
|
|
152
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: mutedStyle, children: [
|
|
153
|
-
" \xB7 ",
|
|
154
|
-
t.rows.length
|
|
155
|
-
] })
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
id
|
|
159
|
-
);
|
|
160
|
-
}) }),
|
|
161
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, { title: "Rows", children: !table ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: mutedStyle, children: "No table selected." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
162
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 6, marginBottom: 6 }, children: [
|
|
163
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: onAddRow, style: primaryBtnStyle, children: "+ Row" }),
|
|
164
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => onSelectRow("new"), style: ghostBtnStyle, children: "Cursor \u2192 new" }),
|
|
165
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: () => onSelectRow(null), style: ghostBtnStyle, children: "Cursor \u2192 none" })
|
|
166
|
-
] }),
|
|
167
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: tableStyle, children: [
|
|
168
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: { borderBottom: "1px solid #2a2f37" }, children: [
|
|
169
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: thStyle, children: "id" }),
|
|
170
|
-
columnIds.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: thStyle, children: table.columns[col]?.label ?? col }, col)),
|
|
171
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: thStyle })
|
|
172
|
-
] }) }),
|
|
173
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: table.rows.map((row) => {
|
|
174
|
-
const rowId = row.id;
|
|
175
|
-
const active = state.selection.rowId === rowId;
|
|
176
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
177
|
-
"tr",
|
|
178
|
-
{
|
|
179
|
-
style: active ? trActiveStyle : trStyle,
|
|
180
|
-
onClick: () => onSelectRow(rowId),
|
|
181
|
-
children: [
|
|
182
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: tdStyle, children: rowId }),
|
|
183
|
-
columnIds.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: tdStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
184
|
-
"input",
|
|
185
|
-
{
|
|
186
|
-
value: formatCell(row[col]),
|
|
187
|
-
style: inputStyle,
|
|
188
|
-
onClick: (event) => event.stopPropagation(),
|
|
189
|
-
onChange: (event) => onEditCell(rowId, col, event.target.value)
|
|
190
|
-
}
|
|
191
|
-
) }, col)),
|
|
192
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: tdStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
193
|
-
"button",
|
|
194
|
-
{
|
|
195
|
-
type: "button",
|
|
196
|
-
style: dangerBtnStyle,
|
|
197
|
-
onClick: (event) => {
|
|
198
|
-
event.stopPropagation();
|
|
199
|
-
onDeleteRow(rowId);
|
|
200
|
-
},
|
|
201
|
-
children: "Delete"
|
|
202
|
-
}
|
|
203
|
-
) })
|
|
204
|
-
]
|
|
205
|
-
},
|
|
206
|
-
rowId
|
|
207
|
-
);
|
|
208
|
-
}) })
|
|
209
|
-
] }) })
|
|
210
|
-
] }) }),
|
|
211
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, { title: "Selection / mappings", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: kvStyle, children: [
|
|
212
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(KV, { k: "tableId", v: state.selection.tableId }),
|
|
213
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(KV, { k: "rowId", v: String(state.selection.rowId) }),
|
|
214
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(KV, { k: "mappings", v: JSON.stringify(resolveMappings(state)) }),
|
|
215
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(KV, { k: "configuration", v: JSON.stringify(state.configuration) })
|
|
216
|
-
] }) }),
|
|
217
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { title: "Access level", children: [
|
|
218
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 6, marginBottom: 6, flexWrap: "wrap" }, children: ACCESS_LEVELS.map((level) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
219
|
-
"button",
|
|
220
|
-
{
|
|
221
|
-
type: "button",
|
|
222
|
-
onClick: () => onSetAccessLevel(level),
|
|
223
|
-
style: level === grantedAccessLevel ? tabActiveStyle : tabStyle,
|
|
224
|
-
title: gristAccessLevelLabel(level),
|
|
225
|
-
children: level
|
|
226
|
-
},
|
|
227
|
-
level
|
|
228
|
-
)) }),
|
|
229
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: mutedStyle, children: [
|
|
230
|
-
"Granted to the widget via ",
|
|
231
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "access_level" }),
|
|
232
|
-
" \u2014 ",
|
|
233
|
-
gristAccessLevelLabel(grantedAccessLevel),
|
|
234
|
-
"."
|
|
235
|
-
] })
|
|
236
|
-
] }),
|
|
237
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { title: "Widget options", children: [
|
|
238
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: preStyle, children: JSON.stringify(state.widgetOptions, null, 2) }),
|
|
239
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(KV, { k: "interaction", v: JSON.stringify(state.widgetInteraction) })
|
|
240
|
-
] }),
|
|
241
|
-
showTimeline && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, { title: `Event timeline (${history.length})`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { maxHeight: 200, overflow: "auto", fontFamily: "monospace", fontSize: 11 }, children: [
|
|
242
|
-
history.slice(-50).reverse().map((event, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: timelineRowStyle, children: [
|
|
243
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: typeBadgeStyle(event.type), children: event.type }),
|
|
244
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: mutedStyle, children: summariseEvent(event) })
|
|
245
|
-
] }, idx)),
|
|
246
|
-
history.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: mutedStyle, children: "No events yet." })
|
|
247
|
-
] }) })
|
|
248
|
-
] });
|
|
249
|
-
}
|
|
250
|
-
function Section({ title, children }) {
|
|
251
|
-
const [open, setOpen] = (0, import_react2.useState)(true);
|
|
252
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderTop: "1px solid #2a2f37" }, children: [
|
|
253
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", style: sectionHeaderStyle, onClick: () => setOpen((v) => !v), children: [
|
|
254
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: open ? "\u25BE" : "\u25B8" }),
|
|
255
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: title })
|
|
256
|
-
] }),
|
|
257
|
-
open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "0 12px 12px" }, children })
|
|
258
|
-
] });
|
|
259
|
-
}
|
|
260
|
-
function KV({ k, v }) {
|
|
261
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: kvRowStyle, children: [
|
|
262
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: mutedStyle, children: k }),
|
|
263
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontFamily: "monospace", fontSize: 11 }, children: v })
|
|
264
|
-
] });
|
|
265
|
-
}
|
|
266
|
-
function summariseEvent(event) {
|
|
267
|
-
switch (event.type) {
|
|
268
|
-
case "user-action":
|
|
269
|
-
return JSON.stringify(event.action);
|
|
270
|
-
case "data-change":
|
|
271
|
-
return `tableId=${String(event.tableId)}`;
|
|
272
|
-
case "cursor-change":
|
|
273
|
-
return `tableId=${String(event.tableId)} rowId=${String(event.rowId)}`;
|
|
274
|
-
case "options-change":
|
|
275
|
-
return JSON.stringify(event.options);
|
|
276
|
-
case "ready":
|
|
277
|
-
return JSON.stringify(event.configuration);
|
|
278
|
-
case "theme-change":
|
|
279
|
-
return JSON.stringify(event.message);
|
|
280
|
-
case "mappings-change":
|
|
281
|
-
return JSON.stringify(event.mappings);
|
|
282
|
-
default:
|
|
283
|
-
return "";
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
function formatCell(value) {
|
|
287
|
-
if (value === null || value === void 0) return "";
|
|
288
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
289
|
-
return JSON.stringify(value);
|
|
290
|
-
}
|
|
291
|
-
var baseStyle = {
|
|
292
|
-
background: "#15171c",
|
|
293
|
-
color: "#e6e6e6",
|
|
294
|
-
fontFamily: "system-ui, sans-serif",
|
|
295
|
-
fontSize: 13,
|
|
296
|
-
border: "1px solid #2a2f37",
|
|
297
|
-
borderRadius: 8,
|
|
298
|
-
overflow: "hidden"
|
|
299
|
-
};
|
|
300
|
-
var headerStyle = {
|
|
301
|
-
display: "flex",
|
|
302
|
-
alignItems: "center",
|
|
303
|
-
gap: 8,
|
|
304
|
-
padding: "10px 12px",
|
|
305
|
-
background: "#0f1115",
|
|
306
|
-
borderBottom: "1px solid #2a2f37"
|
|
307
|
-
};
|
|
308
|
-
var badgeStyle = {
|
|
309
|
-
background: "#3a8e57",
|
|
310
|
-
color: "#fff",
|
|
311
|
-
padding: "1px 6px",
|
|
312
|
-
borderRadius: 4,
|
|
313
|
-
fontSize: 10,
|
|
314
|
-
letterSpacing: 0.5
|
|
315
|
-
};
|
|
316
|
-
var mutedStyle = { color: "#9ba1ad" };
|
|
317
|
-
var sectionHeaderStyle = {
|
|
318
|
-
display: "flex",
|
|
319
|
-
alignItems: "center",
|
|
320
|
-
gap: 6,
|
|
321
|
-
width: "100%",
|
|
322
|
-
background: "transparent",
|
|
323
|
-
color: "inherit",
|
|
324
|
-
border: "none",
|
|
325
|
-
padding: "10px 12px",
|
|
326
|
-
textAlign: "left",
|
|
327
|
-
cursor: "pointer"
|
|
328
|
-
};
|
|
329
|
-
var tabStyle = {
|
|
330
|
-
background: "#1c1f26",
|
|
331
|
-
color: "#cfd2d8",
|
|
332
|
-
border: "1px solid #2a2f37",
|
|
333
|
-
borderRadius: 6,
|
|
334
|
-
padding: "4px 10px",
|
|
335
|
-
cursor: "pointer"
|
|
336
|
-
};
|
|
337
|
-
var tabActiveStyle = { ...tabStyle, background: "#27313f", borderColor: "#3a4f6e", color: "#fff" };
|
|
338
|
-
var primaryBtnStyle = {
|
|
339
|
-
background: "#3a8e57",
|
|
340
|
-
color: "#fff",
|
|
341
|
-
border: "none",
|
|
342
|
-
borderRadius: 6,
|
|
343
|
-
padding: "4px 10px",
|
|
344
|
-
cursor: "pointer"
|
|
345
|
-
};
|
|
346
|
-
var ghostBtnStyle = {
|
|
347
|
-
background: "transparent",
|
|
348
|
-
color: "#cfd2d8",
|
|
349
|
-
border: "1px solid #2a2f37",
|
|
350
|
-
borderRadius: 6,
|
|
351
|
-
padding: "4px 10px",
|
|
352
|
-
cursor: "pointer"
|
|
353
|
-
};
|
|
354
|
-
var dangerBtnStyle = {
|
|
355
|
-
background: "transparent",
|
|
356
|
-
color: "#e58f8f",
|
|
357
|
-
border: "1px solid #4a2226",
|
|
358
|
-
borderRadius: 6,
|
|
359
|
-
padding: "2px 8px",
|
|
360
|
-
cursor: "pointer"
|
|
361
|
-
};
|
|
362
|
-
var tableStyle = { width: "100%", borderCollapse: "collapse", fontSize: 12 };
|
|
363
|
-
var thStyle = { textAlign: "left", padding: "4px 6px", color: "#9ba1ad", fontWeight: 500 };
|
|
364
|
-
var trStyle = { borderBottom: "1px solid #1f232b" };
|
|
365
|
-
var trActiveStyle = { ...trStyle, background: "#1d2733" };
|
|
366
|
-
var tdStyle = { padding: "4px 6px" };
|
|
367
|
-
var inputStyle = {
|
|
368
|
-
width: "100%",
|
|
369
|
-
background: "#0f1115",
|
|
370
|
-
color: "#e6e6e6",
|
|
371
|
-
border: "1px solid #2a2f37",
|
|
372
|
-
borderRadius: 4,
|
|
373
|
-
padding: "2px 4px",
|
|
374
|
-
fontSize: 12,
|
|
375
|
-
fontFamily: "monospace"
|
|
376
|
-
};
|
|
377
|
-
var preStyle = {
|
|
378
|
-
background: "#0f1115",
|
|
379
|
-
border: "1px solid #2a2f37",
|
|
380
|
-
borderRadius: 4,
|
|
381
|
-
padding: 8,
|
|
382
|
-
fontSize: 11,
|
|
383
|
-
fontFamily: "monospace",
|
|
384
|
-
margin: 0,
|
|
385
|
-
whiteSpace: "pre-wrap"
|
|
386
|
-
};
|
|
387
|
-
var kvStyle = { display: "flex", flexDirection: "column", gap: 4 };
|
|
388
|
-
var kvRowStyle = { display: "flex", gap: 8 };
|
|
389
|
-
var timelineRowStyle = {
|
|
390
|
-
display: "flex",
|
|
391
|
-
gap: 8,
|
|
392
|
-
padding: "2px 0",
|
|
393
|
-
borderBottom: "1px solid #1f232b"
|
|
394
|
-
};
|
|
395
|
-
function typeBadgeStyle(type) {
|
|
396
|
-
const colour = {
|
|
397
|
-
"user-action": "#a06bff",
|
|
398
|
-
"data-change": "#3a8e57",
|
|
399
|
-
"cursor-change": "#3a87b8",
|
|
400
|
-
"options-change": "#b8893a",
|
|
401
|
-
ready: "#888",
|
|
402
|
-
"theme-change": "#888",
|
|
403
|
-
"mappings-change": "#888"
|
|
404
|
-
}[type] ?? "#888";
|
|
405
|
-
return {
|
|
406
|
-
background: colour,
|
|
407
|
-
color: "#fff",
|
|
408
|
-
padding: "1px 6px",
|
|
409
|
-
borderRadius: 4,
|
|
410
|
-
fontSize: 10,
|
|
411
|
-
flexShrink: 0
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// src/emulator/devtools/use-rows.ts
|
|
416
|
-
var import_react3 = require("react");
|
|
417
|
-
|
|
418
|
-
// src/sdk/helpers/grist-value-codec.ts
|
|
419
|
-
var MARSHALLED_TAGS = /* @__PURE__ */ new Set(["E", "L", "D", "d", "R", "r", "P"]);
|
|
420
|
-
function isMarshalledTuple(value) {
|
|
421
|
-
return Array.isArray(value) && typeof value[0] === "string" && value[0].length <= 2 && MARSHALLED_TAGS.has(value[0]);
|
|
422
|
-
}
|
|
423
|
-
function looksLikeAttachmentColumn(column) {
|
|
424
|
-
return column?.type === "Attachments";
|
|
425
|
-
}
|
|
426
|
-
function looksLikeChoiceListColumn(column) {
|
|
427
|
-
return column?.type === "ChoiceList";
|
|
428
|
-
}
|
|
429
|
-
function looksLikeRefListColumn(column) {
|
|
430
|
-
return typeof column?.type === "string" && column.type.startsWith("RefList:");
|
|
431
|
-
}
|
|
432
|
-
function looksLikeRefColumn(column) {
|
|
433
|
-
return typeof column?.type === "string" && column.type.startsWith("Ref:");
|
|
434
|
-
}
|
|
435
|
-
function looksLikeDateColumn(column) {
|
|
436
|
-
return column?.type === "Date";
|
|
437
|
-
}
|
|
438
|
-
function looksLikeDateTimeColumn(column) {
|
|
439
|
-
return typeof column?.type === "string" && column.type.startsWith("DateTime");
|
|
440
|
-
}
|
|
441
|
-
function decodeGristValue(value, column) {
|
|
442
|
-
if (value === null || value === void 0) return null;
|
|
443
|
-
if (isMarshalledTuple(value)) {
|
|
444
|
-
const tag = value[0];
|
|
445
|
-
switch (tag) {
|
|
446
|
-
case "E":
|
|
447
|
-
return {
|
|
448
|
-
__error: true,
|
|
449
|
-
type: typeof value[1] === "string" ? value[1] : "Error",
|
|
450
|
-
message: typeof value[2] === "string" ? value[2] : void 0,
|
|
451
|
-
traceback: typeof value[3] === "string" ? value[3] : void 0
|
|
452
|
-
};
|
|
453
|
-
case "L":
|
|
454
|
-
return value.slice(1).map((v) => decodeGristValue(v, void 0));
|
|
455
|
-
case "D":
|
|
456
|
-
if (typeof value[1] === "number") return new Date(value[1] * 1e3);
|
|
457
|
-
return null;
|
|
458
|
-
case "d":
|
|
459
|
-
if (typeof value[1] === "number") return new Date(value[1] * 1e3);
|
|
460
|
-
return null;
|
|
461
|
-
case "R":
|
|
462
|
-
return {
|
|
463
|
-
__ref: true,
|
|
464
|
-
tableId: typeof value[1] === "string" ? value[1] : void 0,
|
|
465
|
-
rowId: typeof value[2] === "number" ? value[2] : 0
|
|
466
|
-
};
|
|
467
|
-
case "r":
|
|
468
|
-
return { __ref: true, rowId: typeof value[1] === "number" ? value[1] : 0 };
|
|
469
|
-
case "P":
|
|
470
|
-
return null;
|
|
471
|
-
default:
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
if (looksLikeDateColumn(column) || looksLikeDateTimeColumn(column)) {
|
|
476
|
-
if (typeof value === "number" && Number.isFinite(value)) return new Date(value * 1e3);
|
|
477
|
-
}
|
|
478
|
-
if (looksLikeRefColumn(column) && typeof value === "number") {
|
|
479
|
-
return { __ref: true, rowId: value };
|
|
480
|
-
}
|
|
481
|
-
if ((looksLikeRefListColumn(column) || looksLikeChoiceListColumn(column) || looksLikeAttachmentColumn(column)) && Array.isArray(value)) {
|
|
482
|
-
return value.map((v) => decodeGristValue(v, void 0));
|
|
483
|
-
}
|
|
484
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
|
485
|
-
if (Array.isArray(value)) return value.map((v) => decodeGristValue(v, void 0));
|
|
486
|
-
return null;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// src/sdk/helpers/grist-safe-parse.ts
|
|
490
|
-
var import_zod = require("zod");
|
|
491
|
-
|
|
492
|
-
// src/sdk/helpers/grist-widget-options.ts
|
|
493
|
-
function readStyleColor(style, key) {
|
|
494
|
-
const v = style[key];
|
|
495
|
-
return typeof v === "string" ? v : void 0;
|
|
496
|
-
}
|
|
497
|
-
function normalizeGristChoiceListEntries(widgetOptions) {
|
|
498
|
-
if (!widgetOptions) return [];
|
|
499
|
-
const rawChoices = widgetOptions.choices;
|
|
500
|
-
if (!Array.isArray(rawChoices)) return [];
|
|
501
|
-
const choiceOptionsRaw = widgetOptions.choiceOptions;
|
|
502
|
-
const choiceOptions = choiceOptionsRaw && typeof choiceOptionsRaw === "object" && !Array.isArray(choiceOptionsRaw) ? choiceOptionsRaw : {};
|
|
503
|
-
const out = [];
|
|
504
|
-
for (const c of rawChoices) {
|
|
505
|
-
const value = typeof c === "string" ? c : c != null ? String(c) : "";
|
|
506
|
-
if (!value) continue;
|
|
507
|
-
const style = choiceOptions[value] ?? {};
|
|
508
|
-
out.push({
|
|
509
|
-
value,
|
|
510
|
-
label: value,
|
|
511
|
-
fillColor: readStyleColor(style, "fillColor"),
|
|
512
|
-
textColor: readStyleColor(style, "textColor")
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
return out;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// src/sdk/helpers/grist-safe-parse.ts
|
|
519
|
-
var gristSafeRefValueSchema = import_zod.z.object({
|
|
520
|
-
rowId: import_zod.z.number(),
|
|
521
|
-
display: import_zod.z.string().nullable().optional()
|
|
522
|
-
});
|
|
523
|
-
var gristSafeRefListValueSchema = import_zod.z.object({
|
|
524
|
-
rowIds: import_zod.z.array(import_zod.z.number()),
|
|
525
|
-
displays: import_zod.z.array(import_zod.z.string()).optional()
|
|
526
|
-
});
|
|
527
|
-
var gristCellValueSchema = import_zod.z.union([
|
|
528
|
-
import_zod.z.null(),
|
|
529
|
-
import_zod.z.string(),
|
|
530
|
-
import_zod.z.number(),
|
|
531
|
-
import_zod.z.boolean(),
|
|
532
|
-
import_zod.z.date(),
|
|
533
|
-
import_zod.z.array(import_zod.z.unknown()),
|
|
534
|
-
gristSafeRefValueSchema,
|
|
535
|
-
gristSafeRefListValueSchema
|
|
536
|
-
]);
|
|
537
|
-
function inferDisplayHelpersByRef(columns) {
|
|
538
|
-
const out = {};
|
|
539
|
-
const helperColumns = Object.entries(columns).filter(
|
|
540
|
-
([colId]) => colId.startsWith("gristHelper_")
|
|
541
|
-
);
|
|
542
|
-
const usedHelpers = /* @__PURE__ */ new Set();
|
|
543
|
-
const colRefToColId = /* @__PURE__ */ new Map();
|
|
544
|
-
for (const [colId, col] of Object.entries(columns)) {
|
|
545
|
-
if (typeof col?.colRef === "number" && Number.isFinite(col.colRef)) {
|
|
546
|
-
colRefToColId.set(col.colRef, colId);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
for (const [colId, col] of Object.entries(columns)) {
|
|
550
|
-
const type = col?.type;
|
|
551
|
-
if (typeof type !== "string" || !type.startsWith("Ref:") && !type.startsWith("RefList:")) {
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
if (typeof col.displayColRef === "number" && Number.isFinite(col.displayColRef)) {
|
|
555
|
-
const helperColId = colRefToColId.get(col.displayColRef);
|
|
556
|
-
if (helperColId) {
|
|
557
|
-
out[colId] = helperColId;
|
|
558
|
-
usedHelpers.add(helperColId);
|
|
559
|
-
continue;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
const match = helperColumns.find(([, helper]) => {
|
|
563
|
-
const formula = helper?.formula;
|
|
564
|
-
return typeof formula === "string" && (formula.includes(`$${colId}.`) || formula.includes(`$${colId}`));
|
|
565
|
-
});
|
|
566
|
-
if (match) {
|
|
567
|
-
out[colId] = match[0];
|
|
568
|
-
usedHelpers.add(match[0]);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
const unresolvedRefs = Object.entries(columns).filter(([colId, col]) => {
|
|
572
|
-
const type = col?.type;
|
|
573
|
-
return !out[colId] && typeof type === "string" && (type.startsWith("Ref:") || type.startsWith("RefList:"));
|
|
574
|
-
}).sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER));
|
|
575
|
-
const helperByPos = helperColumns.filter(([helperId]) => !usedHelpers.has(helperId)).sort((a, b) => (a[1]?.parentPos ?? Number.MAX_SAFE_INTEGER) - (b[1]?.parentPos ?? Number.MAX_SAFE_INTEGER));
|
|
576
|
-
for (const [refId, refCol] of unresolvedRefs) {
|
|
577
|
-
const refPos = refCol?.parentPos ?? Number.MAX_SAFE_INTEGER;
|
|
578
|
-
const candidate = helperByPos.find(([, helperCol]) => {
|
|
579
|
-
const helperPos = helperCol?.parentPos ?? Number.MAX_SAFE_INTEGER;
|
|
580
|
-
return helperPos > refPos;
|
|
581
|
-
});
|
|
582
|
-
if (!candidate) continue;
|
|
583
|
-
out[refId] = candidate[0];
|
|
584
|
-
usedHelpers.add(candidate[0]);
|
|
585
|
-
}
|
|
586
|
-
for (const [refId] of unresolvedRefs) {
|
|
587
|
-
if (out[refId]) continue;
|
|
588
|
-
const candidate = helperByPos.find(([helperId]) => !usedHelpers.has(helperId));
|
|
589
|
-
if (!candidate) continue;
|
|
590
|
-
out[refId] = candidate[0];
|
|
591
|
-
usedHelpers.add(candidate[0]);
|
|
592
|
-
}
|
|
593
|
-
return out;
|
|
594
|
-
}
|
|
595
|
-
function computeRowCount(data) {
|
|
596
|
-
const idCol = data.id;
|
|
597
|
-
if (Array.isArray(idCol)) return idCol.length;
|
|
598
|
-
for (const key of Object.keys(data)) {
|
|
599
|
-
const col = data[key];
|
|
600
|
-
if (Array.isArray(col)) return col.length;
|
|
601
|
-
}
|
|
602
|
-
return 0;
|
|
603
|
-
}
|
|
604
|
-
function manualSortKey(row) {
|
|
605
|
-
const v = row.manualSort;
|
|
606
|
-
if (typeof v === "number" && !Number.isNaN(v)) return v;
|
|
607
|
-
if (typeof v === "string" && v.trim() !== "") {
|
|
608
|
-
const n = Number(v);
|
|
609
|
-
if (!Number.isNaN(n)) return n;
|
|
610
|
-
}
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
function sortRowsByGristOrder(rows) {
|
|
614
|
-
const hasManual = rows.some((r) => manualSortKey(r) !== null);
|
|
615
|
-
if (!hasManual) {
|
|
616
|
-
return [...rows].sort((a, b) => {
|
|
617
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
618
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
619
|
-
return ida - idb;
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
return [...rows].sort((a, b) => {
|
|
623
|
-
const ma = manualSortKey(a);
|
|
624
|
-
const mb = manualSortKey(b);
|
|
625
|
-
if (ma !== null && mb !== null && ma !== mb) return ma - mb;
|
|
626
|
-
if (ma !== null && mb === null) return -1;
|
|
627
|
-
if (ma === null && mb !== null) return 1;
|
|
628
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
629
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
630
|
-
return ida - idb;
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
function columnKind(column) {
|
|
634
|
-
const type = column?.type;
|
|
635
|
-
if (!type) return "unknown";
|
|
636
|
-
if (type === "Text") return "text";
|
|
637
|
-
if (type === "Numeric") return "numeric";
|
|
638
|
-
if (type === "Int") return "int";
|
|
639
|
-
if (type === "Bool") return "bool";
|
|
640
|
-
if (type === "Date") return "date";
|
|
641
|
-
if (type === "DateTime" || type.startsWith("DateTime:")) return "datetime";
|
|
642
|
-
if (type === "Choice") return "choice";
|
|
643
|
-
if (type === "ChoiceList") return "choiceList";
|
|
644
|
-
if (type.startsWith("Ref:")) return "ref";
|
|
645
|
-
if (type.startsWith("RefList:")) return "refList";
|
|
646
|
-
if (type === "Attachments") return "attachments";
|
|
647
|
-
if (type === "Any") return "any";
|
|
648
|
-
return "unknown";
|
|
649
|
-
}
|
|
650
|
-
function primitiveToString(value) {
|
|
651
|
-
if (value === null || value === void 0) return null;
|
|
652
|
-
if (typeof value === "string") return value;
|
|
653
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
654
|
-
return String(value);
|
|
655
|
-
}
|
|
656
|
-
return null;
|
|
657
|
-
}
|
|
658
|
-
function normalizeRefDisplay(value) {
|
|
659
|
-
if (value === null || value === void 0) return { value: null };
|
|
660
|
-
if (typeof value === "string") return { value };
|
|
661
|
-
if (typeof value === "number" || typeof value === "boolean") return { value: String(value) };
|
|
662
|
-
return {
|
|
663
|
-
issue: {
|
|
664
|
-
code: "helper_mismatch",
|
|
665
|
-
message: "Ref display helper value should be a scalar value."
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
function normalizeRefListDisplays(value) {
|
|
670
|
-
if (value === null || value === void 0) return { values: [] };
|
|
671
|
-
if (typeof value === "string") {
|
|
672
|
-
const s = value.trim();
|
|
673
|
-
if (s === "") return { values: [] };
|
|
674
|
-
if (s.startsWith("[")) {
|
|
675
|
-
try {
|
|
676
|
-
const parsed = JSON.parse(s);
|
|
677
|
-
if (Array.isArray(parsed)) {
|
|
678
|
-
return normalizeRefListDisplays(parsed);
|
|
679
|
-
}
|
|
680
|
-
} catch {
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
if (!Array.isArray(value)) {
|
|
685
|
-
return {
|
|
686
|
-
issue: {
|
|
687
|
-
code: "helper_mismatch",
|
|
688
|
-
message: "RefList display helper value should be an array."
|
|
689
|
-
}
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
const items = value.length > 0 && value[0] === "L" ? value.slice(1) : value;
|
|
693
|
-
const out = [];
|
|
694
|
-
for (const item of items) {
|
|
695
|
-
const s = primitiveToString(item);
|
|
696
|
-
if (s === null) {
|
|
697
|
-
return {
|
|
698
|
-
issue: {
|
|
699
|
-
code: "helper_mismatch",
|
|
700
|
-
message: "RefList helper items should be scalar values."
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
out.push(s);
|
|
705
|
-
}
|
|
706
|
-
return { values: out };
|
|
707
|
-
}
|
|
708
|
-
function normalizeRefValue(decoded, helperValue, refMode) {
|
|
709
|
-
const issues = [];
|
|
710
|
-
if (decoded === null) return { value: null, issues };
|
|
711
|
-
const rowId = typeof decoded === "number" && Number.isFinite(decoded) ? decoded : decoded && typeof decoded === "object" && "__ref" in decoded ? decoded.rowId : null;
|
|
712
|
-
if (rowId === 0) return { value: null, issues };
|
|
713
|
-
if (rowId === null || !Number.isFinite(rowId)) {
|
|
714
|
-
issues.push({
|
|
715
|
-
code: "type_mismatch",
|
|
716
|
-
message: "Expected a Ref row id."
|
|
717
|
-
});
|
|
718
|
-
return { value: null, issues };
|
|
719
|
-
}
|
|
720
|
-
if (refMode === "id") return { value: rowId, issues };
|
|
721
|
-
const helper = normalizeRefDisplay(helperValue);
|
|
722
|
-
if (helper.issue) issues.push(helper.issue);
|
|
723
|
-
return {
|
|
724
|
-
value: { rowId, display: helper.value },
|
|
725
|
-
issues
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
function normalizeRefListValue(decoded, helperValue, refMode) {
|
|
729
|
-
const issues = [];
|
|
730
|
-
if (decoded === null) return { value: null, issues };
|
|
731
|
-
if (!Array.isArray(decoded)) {
|
|
732
|
-
issues.push({
|
|
733
|
-
code: "type_mismatch",
|
|
734
|
-
message: "Expected an array for RefList."
|
|
735
|
-
});
|
|
736
|
-
return { value: null, issues };
|
|
737
|
-
}
|
|
738
|
-
const rowIds = [];
|
|
739
|
-
for (const item of decoded) {
|
|
740
|
-
if (typeof item === "number" && Number.isFinite(item) && item !== 0) {
|
|
741
|
-
rowIds.push(item);
|
|
742
|
-
continue;
|
|
743
|
-
}
|
|
744
|
-
if (item && typeof item === "object" && "__ref" in item) {
|
|
745
|
-
const rowId = item.rowId;
|
|
746
|
-
if (typeof rowId === "number" && Number.isFinite(rowId) && rowId !== 0) {
|
|
747
|
-
rowIds.push(rowId);
|
|
748
|
-
continue;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
issues.push({
|
|
752
|
-
code: "type_mismatch",
|
|
753
|
-
message: "RefList items should be row ids."
|
|
754
|
-
});
|
|
755
|
-
return { value: null, issues };
|
|
756
|
-
}
|
|
757
|
-
if (refMode === "id") return { value: rowIds, issues };
|
|
758
|
-
const helper = normalizeRefListDisplays(helperValue);
|
|
759
|
-
if (helper.issue) {
|
|
760
|
-
issues.push(helper.issue);
|
|
761
|
-
} else if (helper.values && helper.values.length > 0 && helper.values.length !== rowIds.length) {
|
|
762
|
-
issues.push({
|
|
763
|
-
code: "helper_mismatch",
|
|
764
|
-
message: "RefList helper labels count does not match row ids count."
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
return {
|
|
768
|
-
value: { rowIds, displays: helper.values },
|
|
769
|
-
issues
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
function normalizeByColumnKind(decoded, kind, helperValue, fallbackUntypedToString, refMode) {
|
|
773
|
-
const issues = [];
|
|
774
|
-
if (decoded && typeof decoded === "object" && "__error" in decoded) {
|
|
775
|
-
issues.push({
|
|
776
|
-
code: "grist_error",
|
|
777
|
-
message: decoded.message ?? "Grist returned a cell error."
|
|
778
|
-
});
|
|
779
|
-
return { value: null, issues };
|
|
780
|
-
}
|
|
781
|
-
switch (kind) {
|
|
782
|
-
case "ref":
|
|
783
|
-
return normalizeRefValue(decoded, helperValue, refMode);
|
|
784
|
-
case "refList":
|
|
785
|
-
return normalizeRefListValue(decoded, helperValue, refMode);
|
|
786
|
-
case "date":
|
|
787
|
-
case "datetime":
|
|
788
|
-
if (decoded === null || decoded instanceof Date) return { value: decoded, issues };
|
|
789
|
-
issues.push({ code: "type_mismatch", message: "Expected a Date value." });
|
|
790
|
-
return { value: null, issues };
|
|
791
|
-
case "bool":
|
|
792
|
-
if (decoded === null || typeof decoded === "boolean") return { value: decoded, issues };
|
|
793
|
-
issues.push({ code: "type_mismatch", message: "Expected a boolean value." });
|
|
794
|
-
return { value: null, issues };
|
|
795
|
-
case "numeric":
|
|
796
|
-
if (decoded === null || typeof decoded === "number" && Number.isFinite(decoded)) {
|
|
797
|
-
return { value: decoded, issues };
|
|
798
|
-
}
|
|
799
|
-
issues.push({ code: "type_mismatch", message: "Expected a numeric value." });
|
|
800
|
-
return {
|
|
801
|
-
value: typeof decoded === "string" || typeof decoded === "number" || typeof decoded === "boolean" ? decoded : null,
|
|
802
|
-
issues
|
|
803
|
-
};
|
|
804
|
-
case "int":
|
|
805
|
-
if (decoded === null || typeof decoded === "number" && Number.isInteger(decoded)) {
|
|
806
|
-
return { value: decoded, issues };
|
|
807
|
-
}
|
|
808
|
-
issues.push({ code: "type_mismatch", message: "Expected an integer value." });
|
|
809
|
-
return {
|
|
810
|
-
value: typeof decoded === "string" || typeof decoded === "number" || typeof decoded === "boolean" ? decoded : null,
|
|
811
|
-
issues
|
|
812
|
-
};
|
|
813
|
-
case "choice":
|
|
814
|
-
case "text":
|
|
815
|
-
if (decoded === null || typeof decoded === "string") return { value: decoded, issues };
|
|
816
|
-
issues.push({ code: "type_mismatch", message: "Expected a string value." });
|
|
817
|
-
return { value: null, issues };
|
|
818
|
-
case "choiceList":
|
|
819
|
-
case "attachments":
|
|
820
|
-
if (decoded === null || Array.isArray(decoded)) return { value: decoded, issues };
|
|
821
|
-
issues.push({ code: "type_mismatch", message: "Expected a list value." });
|
|
822
|
-
return { value: null, issues };
|
|
823
|
-
case "any":
|
|
824
|
-
case "unknown":
|
|
825
|
-
if (helperValue !== void 0) {
|
|
826
|
-
if (typeof decoded === "number" || decoded && typeof decoded === "object" && "__ref" in decoded) {
|
|
827
|
-
return normalizeRefValue(decoded, helperValue, refMode);
|
|
828
|
-
}
|
|
829
|
-
if (Array.isArray(decoded)) {
|
|
830
|
-
return normalizeRefListValue(decoded, helperValue, refMode);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
if (!fallbackUntypedToString) return { value: decoded, issues };
|
|
834
|
-
if (decoded === null) return { value: null, issues };
|
|
835
|
-
if (typeof decoded === "string") return { value: decoded, issues };
|
|
836
|
-
if (typeof decoded === "number" || typeof decoded === "boolean" || decoded instanceof Date) {
|
|
837
|
-
return {
|
|
838
|
-
value: decoded instanceof Date ? decoded.toISOString() : String(decoded),
|
|
839
|
-
issues
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
if (Array.isArray(decoded)) {
|
|
843
|
-
try {
|
|
844
|
-
return { value: JSON.stringify(decoded), issues };
|
|
845
|
-
} catch {
|
|
846
|
-
issues.push({
|
|
847
|
-
code: "invalid_format",
|
|
848
|
-
message: "Unable to stringify list value."
|
|
849
|
-
});
|
|
850
|
-
return { value: null, issues };
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
issues.push({
|
|
854
|
-
code: "type_mismatch",
|
|
855
|
-
message: "Untyped value could not be represented as a string."
|
|
856
|
-
});
|
|
857
|
-
return { value: null, issues };
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
function buildChoiceTokens(col, value) {
|
|
861
|
-
const type = col?.type;
|
|
862
|
-
if (type !== "Choice" && type !== "ChoiceList") return void 0;
|
|
863
|
-
const entries = normalizeGristChoiceListEntries(col?.widgetOptions);
|
|
864
|
-
const byValue = new Map(entries.map((entry) => [entry.value, entry]));
|
|
865
|
-
if (type === "Choice") {
|
|
866
|
-
if (value == null || typeof value !== "string" || value.trim() === "") return [];
|
|
867
|
-
const meta = byValue.get(value);
|
|
868
|
-
if (!meta) return [{ value, label: value, valid: false }];
|
|
869
|
-
return [
|
|
870
|
-
{
|
|
871
|
-
value,
|
|
872
|
-
label: meta.label,
|
|
873
|
-
fillColor: meta.fillColor,
|
|
874
|
-
textColor: meta.textColor,
|
|
875
|
-
valid: true
|
|
876
|
-
}
|
|
877
|
-
];
|
|
878
|
-
}
|
|
879
|
-
if (!Array.isArray(value)) return [];
|
|
880
|
-
const out = [];
|
|
881
|
-
for (const item of value) {
|
|
882
|
-
const v = typeof item === "string" ? item : String(item);
|
|
883
|
-
const meta = byValue.get(v);
|
|
884
|
-
if (!meta) {
|
|
885
|
-
out.push({ value: v, label: v, valid: false });
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
888
|
-
out.push({
|
|
889
|
-
value: v,
|
|
890
|
-
label: meta.label,
|
|
891
|
-
fillColor: meta.fillColor,
|
|
892
|
-
textColor: meta.textColor,
|
|
893
|
-
valid: true
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
return out;
|
|
897
|
-
}
|
|
898
|
-
function safeParseGristValues(options) {
|
|
899
|
-
const fallbackUntypedToString = options.fallbackUntypedToString ?? true;
|
|
900
|
-
const refMode = options.refMode ?? "id";
|
|
901
|
-
const kind = columnKind(options.column);
|
|
902
|
-
return options.values.map((raw, index) => {
|
|
903
|
-
const decoded = decodeGristValue(raw, options.column);
|
|
904
|
-
const helperValue = options.helperValues?.[index];
|
|
905
|
-
const normalized = normalizeByColumnKind(
|
|
906
|
-
decoded,
|
|
907
|
-
kind,
|
|
908
|
-
helperValue,
|
|
909
|
-
fallbackUntypedToString,
|
|
910
|
-
refMode
|
|
911
|
-
);
|
|
912
|
-
const issues = [...normalized.issues];
|
|
913
|
-
if (options.schema) {
|
|
914
|
-
const result = options.schema.safeParse(normalized.value);
|
|
915
|
-
if (!result.success) {
|
|
916
|
-
issues.push({
|
|
917
|
-
code: "zod_error",
|
|
918
|
-
message: result.error.issues.map((issue) => issue.message).join("; ")
|
|
919
|
-
});
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
return {
|
|
923
|
-
ok: issues.length === 0,
|
|
924
|
-
typedValue: normalized.value,
|
|
925
|
-
displayValue: normalized.value,
|
|
926
|
-
raw,
|
|
927
|
-
issues
|
|
928
|
-
};
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
function safeParseGristTableData(data, options) {
|
|
932
|
-
const columns = options?.columns ?? {};
|
|
933
|
-
const inferredDisplayHelpersByRef = inferDisplayHelpersByRef(columns);
|
|
934
|
-
const displayHelpersByRef = {
|
|
935
|
-
...inferredDisplayHelpersByRef,
|
|
936
|
-
...options?.displayHelpersByRef ?? {}
|
|
937
|
-
};
|
|
938
|
-
for (const [colId, col] of Object.entries(columns)) {
|
|
939
|
-
const type = col?.type;
|
|
940
|
-
if (typeof type !== "string" || !type.startsWith("Ref:") && !type.startsWith("RefList:")) {
|
|
941
|
-
continue;
|
|
942
|
-
}
|
|
943
|
-
if (displayHelpersByRef[colId]) continue;
|
|
944
|
-
const byName = `gristHelper_${colId}`;
|
|
945
|
-
if (Array.isArray(data[byName])) {
|
|
946
|
-
displayHelpersByRef[colId] = byName;
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
const fallbackUntypedToString = options?.fallbackUntypedToString ?? true;
|
|
950
|
-
const refMode = options?.refMode ?? "id";
|
|
951
|
-
const colIds = Object.keys(data);
|
|
952
|
-
const parsedByColumn = {};
|
|
953
|
-
for (const colId of colIds) {
|
|
954
|
-
const rawValues = Array.isArray(data[colId]) ? data[colId] : [];
|
|
955
|
-
const helperColId = displayHelpersByRef[colId];
|
|
956
|
-
const helperValues = helperColId && Array.isArray(data[helperColId]) ? data[helperColId] : void 0;
|
|
957
|
-
parsedByColumn[colId] = colId === "id" ? rawValues.map((raw) => ({
|
|
958
|
-
ok: typeof raw === "number" && Number.isFinite(raw),
|
|
959
|
-
typedValue: typeof raw === "number" && Number.isFinite(raw) ? raw : null,
|
|
960
|
-
displayValue: raw,
|
|
961
|
-
raw,
|
|
962
|
-
issues: typeof raw === "number" && Number.isFinite(raw) ? [] : [{ code: "type_mismatch", message: "Row id should be numeric." }]
|
|
963
|
-
})) : safeParseGristValues({
|
|
964
|
-
values: rawValues,
|
|
965
|
-
column: columns[colId],
|
|
966
|
-
helperValues,
|
|
967
|
-
fallbackUntypedToString,
|
|
968
|
-
refMode
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
const rowCount = computeRowCount(data);
|
|
972
|
-
const rows = [];
|
|
973
|
-
const cellIssues = [];
|
|
974
|
-
const cellMeta = [];
|
|
975
|
-
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
976
|
-
const row = {};
|
|
977
|
-
for (const colId of colIds) {
|
|
978
|
-
const parsed = parsedByColumn[colId]?.[rowIndex];
|
|
979
|
-
row[colId] = parsed?.typedValue ?? null;
|
|
980
|
-
const choiceTokens = buildChoiceTokens(columns[colId], parsed?.displayValue);
|
|
981
|
-
if (parsed) {
|
|
982
|
-
if (parsed.issues.length > 0 || choiceTokens && choiceTokens.length > 0) {
|
|
983
|
-
cellMeta.push({
|
|
984
|
-
rowIndex,
|
|
985
|
-
colId,
|
|
986
|
-
ok: parsed.ok,
|
|
987
|
-
issues: parsed.issues,
|
|
988
|
-
choiceTokens
|
|
989
|
-
});
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (!parsed || parsed.issues.length === 0) continue;
|
|
993
|
-
for (const issue of parsed.issues) {
|
|
994
|
-
cellIssues.push({ ...issue, rowIndex, colId });
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
rows.push(row);
|
|
998
|
-
}
|
|
999
|
-
const cellMetaByKey = {};
|
|
1000
|
-
for (const meta of cellMeta) {
|
|
1001
|
-
const rowId = rows[meta.rowIndex]?.id;
|
|
1002
|
-
if (typeof rowId !== "number") continue;
|
|
1003
|
-
cellMetaByKey[`${rowId}:${meta.colId}`] = meta;
|
|
1004
|
-
}
|
|
1005
|
-
const order = options?.order ?? "grist";
|
|
1006
|
-
if (order === "none") {
|
|
1007
|
-
return { rows, cellIssues, cellMeta, cellMetaByKey, cellResultsByColumn: parsedByColumn };
|
|
1008
|
-
}
|
|
1009
|
-
if (order === "id") {
|
|
1010
|
-
return {
|
|
1011
|
-
rows: [...rows].sort((a, b) => {
|
|
1012
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
1013
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
1014
|
-
return ida - idb;
|
|
1015
|
-
}),
|
|
1016
|
-
cellIssues,
|
|
1017
|
-
cellMeta,
|
|
1018
|
-
cellMetaByKey,
|
|
1019
|
-
cellResultsByColumn: parsedByColumn
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
return {
|
|
1023
|
-
rows: sortRowsByGristOrder(rows),
|
|
1024
|
-
cellIssues,
|
|
1025
|
-
cellMeta,
|
|
1026
|
-
cellMetaByKey,
|
|
1027
|
-
cellResultsByColumn: parsedByColumn
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
// src/sdk/helpers/grist-table-data.ts
|
|
1032
|
-
function inferDisplayHelpersByNameFromData(data) {
|
|
1033
|
-
const out = {};
|
|
1034
|
-
for (const colId of Object.keys(data)) {
|
|
1035
|
-
if (!colId.startsWith("gristHelper_")) continue;
|
|
1036
|
-
const baseColId = colId.slice("gristHelper_".length);
|
|
1037
|
-
if (!baseColId) continue;
|
|
1038
|
-
if (!Array.isArray(data[baseColId])) continue;
|
|
1039
|
-
out[baseColId] = colId;
|
|
1040
|
-
}
|
|
1041
|
-
return out;
|
|
1042
|
-
}
|
|
1043
|
-
function enrichSafeParseColumnsFromData(data, columns) {
|
|
1044
|
-
const out = { ...columns ?? {} };
|
|
1045
|
-
const keys = Object.keys(data);
|
|
1046
|
-
const positionByColId = new Map(keys.map((colId, index) => [colId, index + 1]));
|
|
1047
|
-
for (const colId of keys) {
|
|
1048
|
-
if (!colId.startsWith("gristHelper_")) continue;
|
|
1049
|
-
if (out[colId]) continue;
|
|
1050
|
-
out[colId] = {
|
|
1051
|
-
type: "Any",
|
|
1052
|
-
label: colId,
|
|
1053
|
-
parentPos: positionByColId.get(colId)
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
return out;
|
|
1057
|
-
}
|
|
1058
|
-
function rowsFromSafeCellResults(parsedByColumn) {
|
|
1059
|
-
const colIds = Object.keys(parsedByColumn);
|
|
1060
|
-
const rowCount = colIds.reduce((max, colId) => {
|
|
1061
|
-
const len = parsedByColumn[colId]?.length ?? 0;
|
|
1062
|
-
return Math.max(max, len);
|
|
1063
|
-
}, 0);
|
|
1064
|
-
const rows = [];
|
|
1065
|
-
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
1066
|
-
const row = {};
|
|
1067
|
-
for (const colId of colIds) {
|
|
1068
|
-
row[colId] = parsedByColumn[colId]?.[rowIndex] ?? null;
|
|
1069
|
-
}
|
|
1070
|
-
rows.push(row);
|
|
1071
|
-
}
|
|
1072
|
-
return rows;
|
|
1073
|
-
}
|
|
1074
|
-
function safeCellRowId(row) {
|
|
1075
|
-
const idCell = row.id;
|
|
1076
|
-
if (!idCell || typeof idCell !== "object" || !("typedValue" in idCell)) return null;
|
|
1077
|
-
const typed = idCell.typedValue;
|
|
1078
|
-
return typeof typed === "number" && Number.isFinite(typed) ? typed : null;
|
|
1079
|
-
}
|
|
1080
|
-
function orderSafeCellRowsByParsedRows(rows, orderedParsedRows) {
|
|
1081
|
-
const byId = /* @__PURE__ */ new Map();
|
|
1082
|
-
for (const row of rows) {
|
|
1083
|
-
const id = safeCellRowId(row);
|
|
1084
|
-
if (id === null) continue;
|
|
1085
|
-
const bucket = byId.get(id);
|
|
1086
|
-
if (bucket) bucket.push(row);
|
|
1087
|
-
else byId.set(id, [row]);
|
|
1088
|
-
}
|
|
1089
|
-
const out = [];
|
|
1090
|
-
for (const parsedRow of orderedParsedRows) {
|
|
1091
|
-
const id = typeof parsedRow.id === "number" ? parsedRow.id : null;
|
|
1092
|
-
if (id === null) continue;
|
|
1093
|
-
const bucket = byId.get(id);
|
|
1094
|
-
if (!bucket || bucket.length === 0) continue;
|
|
1095
|
-
const next = bucket.shift();
|
|
1096
|
-
if (next) out.push(next);
|
|
1097
|
-
}
|
|
1098
|
-
for (const bucket of byId.values()) {
|
|
1099
|
-
out.push(...bucket);
|
|
1100
|
-
}
|
|
1101
|
-
return out;
|
|
1102
|
-
}
|
|
1103
|
-
function safeParseRowsToDisplayRows(rows) {
|
|
1104
|
-
return rows.map((row) => {
|
|
1105
|
-
const out = {};
|
|
1106
|
-
for (const [colId, cell] of Object.entries(row)) {
|
|
1107
|
-
if (cell && typeof cell === "object" && "displayValue" in cell) {
|
|
1108
|
-
out[colId] = cell.displayValue;
|
|
1109
|
-
} else {
|
|
1110
|
-
out[colId] = cell;
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
return out;
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1116
|
-
function computeRowCount2(data) {
|
|
1117
|
-
const idCol = data.id;
|
|
1118
|
-
if (Array.isArray(idCol)) return idCol.length;
|
|
1119
|
-
for (const key of Object.keys(data)) {
|
|
1120
|
-
const col = data[key];
|
|
1121
|
-
if (Array.isArray(col)) return col.length;
|
|
1122
|
-
}
|
|
1123
|
-
return 0;
|
|
1124
|
-
}
|
|
1125
|
-
function decodeColumnarToReplicaRows(data, columnIds, columns, maxRows) {
|
|
1126
|
-
const nFull = computeRowCount2(data);
|
|
1127
|
-
const n = maxRows !== void 0 ? Math.min(nFull, maxRows) : nFull;
|
|
1128
|
-
const out = [];
|
|
1129
|
-
for (let i = 0; i < n; i++) {
|
|
1130
|
-
const row = {};
|
|
1131
|
-
for (const k of columnIds) {
|
|
1132
|
-
const arr = data[k];
|
|
1133
|
-
const raw = Array.isArray(arr) ? arr[i] : void 0;
|
|
1134
|
-
if (k === "id") {
|
|
1135
|
-
row[k] = raw;
|
|
1136
|
-
} else {
|
|
1137
|
-
row[k] = decodeGristValue(raw, columns[k]);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
out.push(row);
|
|
1141
|
-
}
|
|
1142
|
-
return out;
|
|
1143
|
-
}
|
|
1144
|
-
function tableDataToRows(data) {
|
|
1145
|
-
const idCol = data.id;
|
|
1146
|
-
if (!Array.isArray(idCol) || idCol.length === 0) return [];
|
|
1147
|
-
const keys = Object.keys(data);
|
|
1148
|
-
const n = idCol.length;
|
|
1149
|
-
const rows = [];
|
|
1150
|
-
for (let i = 0; i < n; i++) {
|
|
1151
|
-
const row = {};
|
|
1152
|
-
for (const k of keys) {
|
|
1153
|
-
const col = data[k];
|
|
1154
|
-
row[k] = Array.isArray(col) ? col[i] : void 0;
|
|
1155
|
-
}
|
|
1156
|
-
rows.push(row);
|
|
1157
|
-
}
|
|
1158
|
-
return rows;
|
|
1159
|
-
}
|
|
1160
|
-
function manualSortKey2(row) {
|
|
1161
|
-
const v = row.manualSort;
|
|
1162
|
-
if (typeof v === "number" && !Number.isNaN(v)) return v;
|
|
1163
|
-
if (typeof v === "string" && v.trim() !== "") {
|
|
1164
|
-
const n = Number(v);
|
|
1165
|
-
if (!Number.isNaN(n)) return n;
|
|
1166
|
-
}
|
|
1167
|
-
return null;
|
|
1168
|
-
}
|
|
1169
|
-
function sortRowsByGristOrder2(rows) {
|
|
1170
|
-
const hasManual = rows.some((r) => manualSortKey2(r) !== null);
|
|
1171
|
-
if (!hasManual) {
|
|
1172
|
-
return [...rows].sort((a, b) => {
|
|
1173
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
1174
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
1175
|
-
return ida - idb;
|
|
1176
|
-
});
|
|
1177
|
-
}
|
|
1178
|
-
return [...rows].sort((a, b) => {
|
|
1179
|
-
const ma = manualSortKey2(a);
|
|
1180
|
-
const mb = manualSortKey2(b);
|
|
1181
|
-
if (ma !== null && mb !== null && ma !== mb) return ma - mb;
|
|
1182
|
-
if (ma !== null && mb === null) return -1;
|
|
1183
|
-
if (ma === null && mb !== null) return 1;
|
|
1184
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
1185
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
1186
|
-
return ida - idb;
|
|
1187
|
-
});
|
|
1188
|
-
}
|
|
1189
|
-
function materializeGristRowsFromColumnar(data, options) {
|
|
1190
|
-
const order = options?.order ?? "grist";
|
|
1191
|
-
if (options?.safeParse) {
|
|
1192
|
-
const safeOptions = options.safeParse === true ? {} : options.safeParse;
|
|
1193
|
-
const columnsForSafeParse = enrichSafeParseColumnsFromData(data, options?.columns);
|
|
1194
|
-
const displayHelpersByRef = {
|
|
1195
|
-
...inferDisplayHelpersByNameFromData(data),
|
|
1196
|
-
...safeOptions.displayHelpersByRef ?? {}
|
|
1197
|
-
};
|
|
1198
|
-
const parsed = safeParseGristTableData(data, {
|
|
1199
|
-
...safeOptions,
|
|
1200
|
-
columns: columnsForSafeParse,
|
|
1201
|
-
displayHelpersByRef,
|
|
1202
|
-
order
|
|
1203
|
-
});
|
|
1204
|
-
options.onSafeParseIssues?.(parsed.cellIssues);
|
|
1205
|
-
options.onSafeParseCellMeta?.(parsed.cellMeta);
|
|
1206
|
-
options.onSafeParseCellMetaByKey?.(parsed.cellMetaByKey);
|
|
1207
|
-
const rawSafeRows = rowsFromSafeCellResults(parsed.cellResultsByColumn);
|
|
1208
|
-
const orderedSafeRows = order === "none" ? rawSafeRows : orderSafeCellRowsByParsedRows(rawSafeRows, parsed.rows);
|
|
1209
|
-
return orderedSafeRows;
|
|
1210
|
-
}
|
|
1211
|
-
let rows;
|
|
1212
|
-
if (options?.columns) {
|
|
1213
|
-
const columnIds = Object.keys(data);
|
|
1214
|
-
rows = decodeColumnarToReplicaRows(data, columnIds, options.columns);
|
|
1215
|
-
} else {
|
|
1216
|
-
rows = tableDataToRows(data);
|
|
1217
|
-
}
|
|
1218
|
-
if (order === "none") return rows;
|
|
1219
|
-
if (order === "id") {
|
|
1220
|
-
return [...rows].sort((a, b) => {
|
|
1221
|
-
const ida = typeof a.id === "number" ? a.id : 0;
|
|
1222
|
-
const idb = typeof b.id === "number" ? b.id : 0;
|
|
1223
|
-
return ida - idb;
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
return sortRowsByGristOrder2(rows);
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
// src/emulator/core/columnar.ts
|
|
1230
|
-
function rowsToColumnar(table, rows, options = {}) {
|
|
1231
|
-
const cols = Object.keys(table.columns);
|
|
1232
|
-
const out = { id: rows.map((r) => r.id) };
|
|
1233
|
-
for (const col of cols) {
|
|
1234
|
-
out[col] = rows.map((r) => encodeForWire(r[col], table.columns[col]?.type, options.keepEncoded));
|
|
1235
|
-
}
|
|
1236
|
-
return out;
|
|
1237
|
-
}
|
|
1238
|
-
function encodeForWire(value, type, keepEncoded) {
|
|
1239
|
-
if (value instanceof Date) {
|
|
1240
|
-
const epoch = Math.floor(value.getTime() / 1e3);
|
|
1241
|
-
if (keepEncoded) {
|
|
1242
|
-
return type && type.startsWith("DateTime") ? ["D", epoch, "UTC"] : ["d", epoch];
|
|
1243
|
-
}
|
|
1244
|
-
return epoch;
|
|
1245
|
-
}
|
|
1246
|
-
return value;
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
// src/emulator/devtools/use-rows.ts
|
|
1250
|
-
function fetchEmulatorRows(emulator, tableId) {
|
|
1251
|
-
const table = emulator.state.tables.get(tableId);
|
|
1252
|
-
if (!table) {
|
|
1253
|
-
return { rows: [], invalidCellKeys: /* @__PURE__ */ new Set() };
|
|
1254
|
-
}
|
|
1255
|
-
let cellMetaByKey = {};
|
|
1256
|
-
const data = rowsToColumnar(table, table.rows);
|
|
1257
|
-
const parsedRows = materializeGristRowsFromColumnar(data, {
|
|
1258
|
-
columns: table.columns,
|
|
1259
|
-
order: "grist",
|
|
1260
|
-
safeParse: {
|
|
1261
|
-
refMode: "detailed"
|
|
1262
|
-
},
|
|
1263
|
-
onSafeParseCellMetaByKey: (metaByKey) => {
|
|
1264
|
-
cellMetaByKey = metaByKey;
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1267
|
-
const rows = safeParseRowsToDisplayRows(parsedRows);
|
|
1268
|
-
const invalidCellKeys = /* @__PURE__ */ new Set();
|
|
1269
|
-
for (const [cellKey, meta] of Object.entries(cellMetaByKey)) {
|
|
1270
|
-
const hasIssue = meta.issues.some(
|
|
1271
|
-
(issue) => issue.code === "type_mismatch" || issue.code === "invalid_format"
|
|
1272
|
-
);
|
|
1273
|
-
if (hasIssue) invalidCellKeys.add(cellKey);
|
|
1274
|
-
}
|
|
1275
|
-
return { rows, invalidCellKeys };
|
|
1276
|
-
}
|
|
1277
|
-
function useEmulatorRows(emulator, tableId) {
|
|
1278
|
-
const { history } = useEmulatorSnapshot(emulator);
|
|
1279
|
-
const [result, setResult] = (0, import_react3.useState)({
|
|
1280
|
-
rows: [],
|
|
1281
|
-
invalidCellKeys: /* @__PURE__ */ new Set()
|
|
1282
|
-
});
|
|
1283
|
-
(0, import_react3.useEffect)(() => {
|
|
1284
|
-
let cancelled = false;
|
|
1285
|
-
if (!tableId) {
|
|
1286
|
-
queueMicrotask(() => {
|
|
1287
|
-
if (!cancelled) setResult({ rows: [], invalidCellKeys: /* @__PURE__ */ new Set() });
|
|
1288
|
-
});
|
|
1289
|
-
return () => {
|
|
1290
|
-
cancelled = true;
|
|
1291
|
-
};
|
|
1292
|
-
}
|
|
1293
|
-
try {
|
|
1294
|
-
const next = fetchEmulatorRows(emulator, tableId);
|
|
1295
|
-
if (!cancelled) setResult(next);
|
|
1296
|
-
} catch {
|
|
1297
|
-
const table = emulator.state.tables.get(tableId);
|
|
1298
|
-
if (!cancelled) {
|
|
1299
|
-
setResult({
|
|
1300
|
-
rows: table?.rows ?? [],
|
|
1301
|
-
invalidCellKeys: /* @__PURE__ */ new Set()
|
|
1302
|
-
});
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
return () => {
|
|
1306
|
-
cancelled = true;
|
|
1307
|
-
};
|
|
1308
|
-
}, [emulator, tableId, history.length]);
|
|
1309
|
-
return result;
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
// src/emulator/devtools/use-columns.ts
|
|
1313
|
-
var import_react4 = require("react");
|
|
1314
|
-
|
|
1315
|
-
// src/sdk/helpers/grist-columns-filters.ts
|
|
1316
|
-
var NOISE_COLUMN_FORMULAS = /* @__PURE__ */ new Set(["now()"]);
|
|
1317
|
-
function normalizeFormulaForComparison(formula) {
|
|
1318
|
-
return formula.trim().toLowerCase().replace(/\s+/g, "");
|
|
1319
|
-
}
|
|
1320
|
-
function isGristNoiseColumn(colId, col, options) {
|
|
1321
|
-
const excludeId = options?.excludeId ?? true;
|
|
1322
|
-
const excludeGristHelpers = options?.excludeGristHelpers ?? true;
|
|
1323
|
-
const excludeLoggingColumns = options?.excludeLoggingColumns ?? true;
|
|
1324
|
-
const excludeManualSort = options?.excludeManualSort ?? false;
|
|
1325
|
-
if (excludeId && colId === "id") return true;
|
|
1326
|
-
if (excludeManualSort && colId === "manualSort") return true;
|
|
1327
|
-
if (excludeGristHelpers && colId.startsWith("gristHelper_")) return true;
|
|
1328
|
-
if (excludeLoggingColumns) {
|
|
1329
|
-
const formula = typeof col?.formula === "string" ? normalizeFormulaForComparison(col.formula) : "";
|
|
1330
|
-
if (formula && NOISE_COLUMN_FORMULAS.has(formula)) return true;
|
|
1331
|
-
if (formula.startsWith("user.")) return true;
|
|
1332
|
-
}
|
|
1333
|
-
return false;
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
// src/emulator/devtools/use-columns.ts
|
|
1337
|
-
function useEmulatorColumns(emulator) {
|
|
1338
|
-
const { state } = useEmulatorSnapshot(emulator);
|
|
1339
|
-
const requestedTableId = state.selection.tableId;
|
|
1340
|
-
const document = (0, import_react4.useMemo)(() => {
|
|
1341
|
-
const tables = {};
|
|
1342
|
-
for (const [tableId, table2] of state.tables.entries()) {
|
|
1343
|
-
const filteredColumns = Object.fromEntries(
|
|
1344
|
-
Object.entries(table2.columns).filter(([colId, col]) => {
|
|
1345
|
-
return !isGristNoiseColumn(colId, col, {
|
|
1346
|
-
excludeId: true,
|
|
1347
|
-
excludeGristHelpers: true,
|
|
1348
|
-
excludeLoggingColumns: true,
|
|
1349
|
-
excludeManualSort: true
|
|
1350
|
-
});
|
|
1351
|
-
})
|
|
1352
|
-
);
|
|
1353
|
-
tables[tableId] = {
|
|
1354
|
-
label: table2.label,
|
|
1355
|
-
columns: filteredColumns,
|
|
1356
|
-
rows: table2.rows.map((row) => ({ ...row })),
|
|
1357
|
-
rowCount: table2.rows.length
|
|
1358
|
-
};
|
|
1359
|
-
}
|
|
1360
|
-
return {
|
|
1361
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1362
|
-
docName: state.docName,
|
|
1363
|
-
mode: "schema+data",
|
|
1364
|
-
source: "emulator-devtools",
|
|
1365
|
-
tables
|
|
1366
|
-
};
|
|
1367
|
-
}, [state]);
|
|
1368
|
-
const table = (0, import_react4.useMemo)(() => {
|
|
1369
|
-
if (!requestedTableId) return null;
|
|
1370
|
-
const slice = document.tables[requestedTableId];
|
|
1371
|
-
if (!slice) return null;
|
|
1372
|
-
return { tableId: requestedTableId, ...slice };
|
|
1373
|
-
}, [document, requestedTableId]);
|
|
1374
|
-
const isNoiseColumnId = (0, import_react4.useMemo)(
|
|
1375
|
-
() => (colId, col) => isGristNoiseColumn(colId, col, {
|
|
1376
|
-
excludeId: true,
|
|
1377
|
-
excludeGristHelpers: true,
|
|
1378
|
-
excludeLoggingColumns: true,
|
|
1379
|
-
excludeManualSort: true
|
|
1380
|
-
}),
|
|
1381
|
-
[]
|
|
1382
|
-
);
|
|
1383
|
-
const sortColumnIds = (0, import_react4.useMemo)(
|
|
1384
|
-
() => (colIds, columns) => {
|
|
1385
|
-
return [...colIds].sort((a, b) => {
|
|
1386
|
-
const la = (columns[a]?.label || a).toLowerCase();
|
|
1387
|
-
const lb = (columns[b]?.label || b).toLowerCase();
|
|
1388
|
-
if (la !== lb) return la.localeCompare(lb);
|
|
1389
|
-
return a.localeCompare(b);
|
|
1390
|
-
});
|
|
1391
|
-
},
|
|
1392
|
-
[]
|
|
1393
|
-
);
|
|
1394
|
-
return { document, table, isNoiseColumnId, sortColumnIds };
|
|
1395
|
-
}
|
|
1396
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1397
|
-
0 && (module.exports = {
|
|
1398
|
-
EmulatorInspector,
|
|
1399
|
-
fetchEmulatorRows,
|
|
1400
|
-
useEmulatorColumns,
|
|
1401
|
-
useEmulatorRows,
|
|
1402
|
-
useEmulatorSnapshot
|
|
1403
|
-
});
|
|
1404
|
-
//# sourceMappingURL=devtools.cjs.map
|