@ai-matrx/records-ui 0.107.5 → 0.109.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/first-page.cjs +435 -0
- package/dist/first-page.cjs.map +1 -0
- package/dist/first-page.d.cts +320 -0
- package/dist/first-page.d.ts +320 -0
- package/dist/first-page.js +429 -0
- package/dist/first-page.js.map +1 -0
- package/dist/index.cjs +842 -797
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +629 -586
- package/dist/index.js.map +1 -1
- package/dist/pickers.cjs +1 -0
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.js +2 -3
- package/dist/pickers.js.map +1 -1
- package/package.json +30 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.109.1
|
|
4
|
+
|
|
5
|
+
Release of 0.109.0's SSR-ROWS work (its publish gate stopped at the new test's untyped `jsdom` import; the test now types the one constructor it uses). No source change.
|
|
6
|
+
|
|
7
|
+
**Consumer action:** none.
|
|
8
|
+
|
|
9
|
+
## 0.109.0
|
|
10
|
+
### Archive record from the row menu works
|
|
11
|
+
|
|
12
|
+
- The grid's row menu "Archive record" opens its confirm once the menu has closed (`afterMenuLayerCloses`, exported from `gridControls`); opened inside the menu's select callback, the closing menu dismissed it at once (always inside a contenteditable host such as a Space), so the press did nothing. A row the page no longer holds says so. No consumer action.
|
|
13
|
+
|
|
14
|
+
### SSR-ROWS: the table page arrives with its rows
|
|
15
|
+
|
|
16
|
+
- NEW in `@ai-matrx/records-ui/first-page`: `askTablePageSeed({ dataSource, organizationId, tableId, actor, recordId?, rows?, embedded?, pageSize? })` — a host's server asks, AS THE PERSON, the table's bundle, the grid's exact first page (`firstGridPageRequest`) and on a record page the record's bundle, and gets a `RecordsSeed`. Mount `<RecordsSeedProvider seed>` (`@ai-matrx/records/react`) above `TablePage` and the page is drawn — rows included — in the server's HTML, then hydrates with no mismatch and no page read. `embedded: true` asks the embedded table's page size (`EMBEDDED_PAGE_SIZE`, now declared here).
|
|
17
|
+
- `first-page` is built WITHOUT the package's "use client" banner (its own tsup entry), so a server component can call it; `presentation.ts` reads `parseTableStyle` from `@ai-matrx/design-system/data-table/table-style` (client-free) for the same reason.
|
|
18
|
+
- `TablePage` starts from the seed's saved views and looks (`useSeededAnswer`), so it knows its face in the first pass instead of drawing its skeleton until two effects land; `ViewBar` takes `initialViews` and skips its mount read. Without a seed both read exactly as before.
|
|
19
|
+
|
|
20
|
+
**Consumer action:** none (additive). Spaces: ask `askTablePageSeed({ …, embedded: true })` in the route and wrap the inline table in `<RecordsSeedProvider>`.
|
|
21
|
+
|
|
22
|
+
## 0.108.0
|
|
23
|
+
### PAGE-BUNDLE-2: the grid's first page, asked before the grid exists
|
|
24
|
+
|
|
25
|
+
NEW ENTRY `@ai-matrx/records-ui/first-page` (server-safe, no React): `firstGridPageRequest(client, tableId)` and the pure `firstGridPageArgs({ tableId, table, fields, shown })` build the EXACT `custom.read_records_page` arguments the table page's grid sends on open (the bar's default view with the person's look over it, the view's sort else the table's `default_sort`, page size 100). Null for a grouped, drilled, filtered, hand-ordered, Rule or non-grid view. A test renders the grid and holds the two byte-equal.
|
|
26
|
+
|
|
27
|
+
**Consumer action:** none (additive). A server-rendered host seeds the first page by door name + these arguments.
|
|
28
|
+
|
|
3
29
|
## 0.107.5
|
|
4
30
|
|
|
5
31
|
TYPEFORM-2: no keystroke is lost while the store works out a branching form's route. Keys typed after Enter are held and land in the next question (appended to a text answer, replayed as keys on a choice so a letter picks). Walk: type straight on after Enter.
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@ai-matrx/records/core');
|
|
4
|
+
var records = require('@ai-matrx/records');
|
|
5
|
+
require('@ai-matrx/kit/text-case');
|
|
6
|
+
require('@ai-matrx/design-system/data-table');
|
|
7
|
+
var tableStyle = require('@ai-matrx/design-system/data-table/table-style');
|
|
8
|
+
require('@ai-matrx/design-system/field-formats');
|
|
9
|
+
|
|
10
|
+
// src/firstPage.ts
|
|
11
|
+
var kernelId = (name) => records.KERNEL_TABLES.find((t) => t.name === name)?.id ?? "";
|
|
12
|
+
var KERNEL_FILE_TABLE = kernelId("File");
|
|
13
|
+
var KERNEL_PERSON_TABLE = kernelId("Person");
|
|
14
|
+
Object.fromEntries(
|
|
15
|
+
records.PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
|
|
16
|
+
);
|
|
17
|
+
var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
|
|
18
|
+
function editorKindFor(field) {
|
|
19
|
+
return records.fieldKindFor(field, KERNEL);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/gridLook.ts
|
|
23
|
+
function defaultSortOf(table, fields) {
|
|
24
|
+
const raw = table?.default_sort ?? null;
|
|
25
|
+
const first = Array.isArray(raw) ? raw[0] : raw;
|
|
26
|
+
let name = null;
|
|
27
|
+
let direction = "asc";
|
|
28
|
+
if (typeof first === "string") {
|
|
29
|
+
const trimmed = first.trim();
|
|
30
|
+
if (trimmed === "") return null;
|
|
31
|
+
if (trimmed.startsWith("-")) {
|
|
32
|
+
name = trimmed.slice(1).trim();
|
|
33
|
+
direction = "desc";
|
|
34
|
+
} else {
|
|
35
|
+
const [head, tail] = trimmed.split(/\s+/);
|
|
36
|
+
name = head ?? null;
|
|
37
|
+
if (tail && tail.toLowerCase() === "desc") direction = "desc";
|
|
38
|
+
}
|
|
39
|
+
} else if (first && typeof first === "object") {
|
|
40
|
+
const entry = first;
|
|
41
|
+
const named = entry["field"] ?? entry["key"] ?? entry["id"];
|
|
42
|
+
name = typeof named === "string" ? named : null;
|
|
43
|
+
if (String(entry["direction"] ?? "").toLowerCase() === "desc") direction = "desc";
|
|
44
|
+
}
|
|
45
|
+
if (!name) return null;
|
|
46
|
+
const field = fields.find((f) => f.key === name) ?? fields.find((f) => f.id === name);
|
|
47
|
+
return field ? { id: field.key, direction } : null;
|
|
48
|
+
}
|
|
49
|
+
function holdsNumbers(field) {
|
|
50
|
+
const kind = String(editorKindFor(field));
|
|
51
|
+
if (kind === "number" || kind === "currency" || kind === "percent") return true;
|
|
52
|
+
return String((field.config ?? {})["system"] ?? "") === "autonumber";
|
|
53
|
+
}
|
|
54
|
+
function sortAsFor(field) {
|
|
55
|
+
const kind = String(editorKindFor(field));
|
|
56
|
+
if (holdsNumbers(field)) return "number";
|
|
57
|
+
if (kind === "datetime") return "date";
|
|
58
|
+
return "text";
|
|
59
|
+
}
|
|
60
|
+
function pageSortFor(fields, sort) {
|
|
61
|
+
if (!sort) return [];
|
|
62
|
+
const field = fields.find((f) => f.key === sort.id);
|
|
63
|
+
if (!field) return [];
|
|
64
|
+
return [{ field: field.key, direction: sort.direction === "desc" ? "desc" : "asc", as: sortAsFor(field) }];
|
|
65
|
+
}
|
|
66
|
+
var MIN_ROW_HEIGHT = 24;
|
|
67
|
+
var MAX_ROW_HEIGHT = 96;
|
|
68
|
+
var AGGREGATE_KINDS = [
|
|
69
|
+
"count",
|
|
70
|
+
"sum",
|
|
71
|
+
"average",
|
|
72
|
+
"min",
|
|
73
|
+
"max",
|
|
74
|
+
"empty",
|
|
75
|
+
"filled",
|
|
76
|
+
"unique",
|
|
77
|
+
"checked",
|
|
78
|
+
"unchecked",
|
|
79
|
+
"percentFilled"
|
|
80
|
+
];
|
|
81
|
+
var GROUP_ORDERS = [
|
|
82
|
+
"value-asc",
|
|
83
|
+
"value-desc",
|
|
84
|
+
"count-desc",
|
|
85
|
+
"first-seen"
|
|
86
|
+
];
|
|
87
|
+
function isRecord(v) {
|
|
88
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
89
|
+
}
|
|
90
|
+
function parseGridPresentation(raw) {
|
|
91
|
+
let value = raw;
|
|
92
|
+
if (typeof value === "string") {
|
|
93
|
+
const trimmed = value.trim();
|
|
94
|
+
if (trimmed === "") return {};
|
|
95
|
+
try {
|
|
96
|
+
value = JSON.parse(trimmed);
|
|
97
|
+
} catch {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!isRecord(value)) return {};
|
|
102
|
+
const out = {};
|
|
103
|
+
const style = tableStyle.parseTableStyle(value["style"]);
|
|
104
|
+
if (!tableStyle.tableStyleIsEmpty(style)) out.style = style;
|
|
105
|
+
if (isRecord(value["formats"])) {
|
|
106
|
+
const formats = {};
|
|
107
|
+
for (const [key, cfg] of Object.entries(value["formats"])) {
|
|
108
|
+
if (!isRecord(cfg)) continue;
|
|
109
|
+
const id = cfg["id"];
|
|
110
|
+
if (typeof id !== "string") continue;
|
|
111
|
+
const options = cfg["options"];
|
|
112
|
+
formats[key] = isRecord(options) ? {
|
|
113
|
+
id,
|
|
114
|
+
options
|
|
115
|
+
} : { id };
|
|
116
|
+
}
|
|
117
|
+
if (Object.keys(formats).length > 0) out.formats = formats;
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(value["frozen"])) {
|
|
120
|
+
const frozen = value["frozen"].filter((k) => typeof k === "string");
|
|
121
|
+
if (frozen.length > 0) out.frozen = frozen;
|
|
122
|
+
}
|
|
123
|
+
const grouping = parseGrouping(value["grouping"]);
|
|
124
|
+
if (grouping) out.grouping = grouping;
|
|
125
|
+
if (isRecord(value["widths"])) {
|
|
126
|
+
const widths = {};
|
|
127
|
+
for (const [key, raw2] of Object.entries(value["widths"])) {
|
|
128
|
+
if (typeof raw2 !== "number" || !Number.isFinite(raw2) || raw2 <= 0) continue;
|
|
129
|
+
widths[key] = Math.round(raw2);
|
|
130
|
+
}
|
|
131
|
+
if (Object.keys(widths).length > 0) out.widths = widths;
|
|
132
|
+
}
|
|
133
|
+
const rowHeight = value["rowHeight"];
|
|
134
|
+
if (typeof rowHeight === "number" && Number.isFinite(rowHeight) && rowHeight >= MIN_ROW_HEIGHT && rowHeight <= MAX_ROW_HEIGHT) {
|
|
135
|
+
out.rowHeight = Math.round(rowHeight);
|
|
136
|
+
}
|
|
137
|
+
if (Array.isArray(value["hiddenFields"])) {
|
|
138
|
+
const hiddenFields = value["hiddenFields"].filter((k) => typeof k === "string");
|
|
139
|
+
if (hiddenFields.length > 0) out.hiddenFields = hiddenFields;
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value["cardHidden"])) {
|
|
142
|
+
out.cardHidden = value["cardHidden"].filter((k) => typeof k === "string");
|
|
143
|
+
}
|
|
144
|
+
if (Array.isArray(value["columnOrder"])) {
|
|
145
|
+
const columnOrder = value["columnOrder"].filter((k) => typeof k === "string");
|
|
146
|
+
if (columnOrder.length > 0) out.columnOrder = columnOrder;
|
|
147
|
+
}
|
|
148
|
+
const gallerySize = value["gallerySize"];
|
|
149
|
+
if (gallerySize === "small" || gallerySize === "medium" || gallerySize === "large") {
|
|
150
|
+
out.gallerySize = gallerySize;
|
|
151
|
+
}
|
|
152
|
+
if (typeof value["wrap"] === "boolean") out.wrap = value["wrap"];
|
|
153
|
+
if (Array.isArray(value["wrapColumns"])) {
|
|
154
|
+
const wrapColumns = value["wrapColumns"].filter((k) => typeof k === "string");
|
|
155
|
+
if (wrapColumns.length > 0) out.wrapColumns = wrapColumns;
|
|
156
|
+
}
|
|
157
|
+
const fit = value["fit"];
|
|
158
|
+
if (fit === "auto" || fit === "fit" || fit === "scroll") out.fit = fit;
|
|
159
|
+
if (typeof value["freezeFirst"] === "boolean") out.freezeFirst = value["freezeFirst"];
|
|
160
|
+
const footer = value["footer"];
|
|
161
|
+
if (footer === "sticky" || footer === "inline") out.footer = footer;
|
|
162
|
+
if (isRecord(value["summaries"])) {
|
|
163
|
+
const summaries = {};
|
|
164
|
+
for (const [key, op] of Object.entries(value["summaries"])) {
|
|
165
|
+
if (typeof op === "string" && op.trim() !== "") summaries[key] = op;
|
|
166
|
+
}
|
|
167
|
+
if (Object.keys(summaries).length > 0) out.summaries = summaries;
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
function parseGrouping(raw) {
|
|
172
|
+
if (!isRecord(raw)) return void 0;
|
|
173
|
+
const field = raw["field"];
|
|
174
|
+
if (typeof field !== "string" || field.trim() === "") return void 0;
|
|
175
|
+
const out = { field };
|
|
176
|
+
if (isRecord(raw["aggregates"])) {
|
|
177
|
+
const aggregates = {};
|
|
178
|
+
for (const [key, spec] of Object.entries(raw["aggregates"])) {
|
|
179
|
+
if (!isRecord(spec)) continue;
|
|
180
|
+
const kind = spec["kind"];
|
|
181
|
+
if (typeof kind !== "string") continue;
|
|
182
|
+
if (!AGGREGATE_KINDS.includes(kind)) continue;
|
|
183
|
+
const label = spec["label"];
|
|
184
|
+
aggregates[key] = typeof label === "string" ? { kind, label } : { kind };
|
|
185
|
+
}
|
|
186
|
+
if (Object.keys(aggregates).length > 0) out.aggregates = aggregates;
|
|
187
|
+
}
|
|
188
|
+
const order = raw["order"];
|
|
189
|
+
if (typeof order === "string" && GROUP_ORDERS.includes(order)) {
|
|
190
|
+
out.order = order;
|
|
191
|
+
}
|
|
192
|
+
if (Array.isArray(raw["collapsed"])) {
|
|
193
|
+
const collapsed = raw["collapsed"].filter((k) => typeof k === "string");
|
|
194
|
+
if (collapsed.length > 0) out.collapsed = collapsed;
|
|
195
|
+
}
|
|
196
|
+
if (raw["showColumn"] === true) out.showColumn = true;
|
|
197
|
+
if (Array.isArray(raw["then"])) {
|
|
198
|
+
const then = [];
|
|
199
|
+
for (const level of raw["then"]) {
|
|
200
|
+
if (!isRecord(level)) continue;
|
|
201
|
+
const sub = level["field"];
|
|
202
|
+
if (typeof sub !== "string" || sub.trim() === "") continue;
|
|
203
|
+
const subOrder = level["order"];
|
|
204
|
+
const subGrain = level["grain"];
|
|
205
|
+
then.push({
|
|
206
|
+
field: sub,
|
|
207
|
+
...typeof subOrder === "string" && GROUP_ORDERS.includes(subOrder) ? { order: subOrder } : {},
|
|
208
|
+
...typeof subGrain === "string" && subGrain !== "" ? { grain: subGrain } : {}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (then.length > 0) out.then = then.slice(0, 2);
|
|
212
|
+
}
|
|
213
|
+
const grain = raw["grain"];
|
|
214
|
+
if (typeof grain === "string" && grain !== "") out.grain = grain;
|
|
215
|
+
const across = raw["across"];
|
|
216
|
+
if (typeof across === "string" && across.trim() !== "") out.across = across;
|
|
217
|
+
if (Array.isArray(raw["show"])) {
|
|
218
|
+
const show = raw["show"].filter((k) => typeof k === "string" && k !== "");
|
|
219
|
+
if (show.length > 0) out.show = show;
|
|
220
|
+
}
|
|
221
|
+
if (Array.isArray(raw["trail"])) {
|
|
222
|
+
const trail = [];
|
|
223
|
+
for (const step of raw["trail"]) {
|
|
224
|
+
if (!isRecord(step) || typeof step["dim"] !== "string" || step["dim"] === "") continue;
|
|
225
|
+
const value = step["value"];
|
|
226
|
+
if (value !== null && typeof value !== "string") continue;
|
|
227
|
+
trail.push({ dim: step["dim"], value });
|
|
228
|
+
}
|
|
229
|
+
if (trail.length > 0) out.trail = trail;
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
var STORE_KEPT_LAYOUTS = ["grid", "kanban", "calendar", "gallery", ...["timeline"] , "list"];
|
|
234
|
+
var KINDS = STORE_KEPT_LAYOUTS;
|
|
235
|
+
function viewSettings(definition, rowFilters) {
|
|
236
|
+
const data = definition ?? {};
|
|
237
|
+
const text = (key) => {
|
|
238
|
+
const v = data[key];
|
|
239
|
+
return typeof v === "string" && v !== "" ? v : null;
|
|
240
|
+
};
|
|
241
|
+
const layout = String(data["layout"] ?? "grid");
|
|
242
|
+
const flat = rowFilters ?? (isObject(data["filters"]) ? data["filters"] : null);
|
|
243
|
+
const moved = data["moved_from"];
|
|
244
|
+
return {
|
|
245
|
+
layout: KINDS.includes(layout) ? layout : "grid",
|
|
246
|
+
filters: flat && Object.keys(flat).length > 0 ? flat : null,
|
|
247
|
+
where: isRule(data["where"]) ? data["where"] : null,
|
|
248
|
+
groupField: text("group_field"),
|
|
249
|
+
swimlaneField: text("swimlane_field"),
|
|
250
|
+
collapsedColumns: Array.isArray(data["collapsed_columns"]) ? data["collapsed_columns"].filter((v) => ["string", "number", "boolean"].includes(typeof v)).map(String) : [],
|
|
251
|
+
measure: text("measure"),
|
|
252
|
+
dateField: text("date_field"),
|
|
253
|
+
startField: text("start_field"),
|
|
254
|
+
endField: text("end_field"),
|
|
255
|
+
imageField: text("image_field"),
|
|
256
|
+
sorts: parseSorts(data["sorts"]),
|
|
257
|
+
ruleId: text("rule_id"),
|
|
258
|
+
isDefault: data["is_default"] === true || data["is_default"] === "true",
|
|
259
|
+
presentation: parseGridPresentation(data["presentation"]),
|
|
260
|
+
movedFrom: isObject(moved) ? moved : null
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function isObject(raw) {
|
|
264
|
+
return Boolean(raw) && typeof raw === "object" && !Array.isArray(raw);
|
|
265
|
+
}
|
|
266
|
+
function isRule(raw) {
|
|
267
|
+
if (!isObject(raw)) return false;
|
|
268
|
+
const node = raw;
|
|
269
|
+
return typeof node.op === "string" && Array.isArray(node.args);
|
|
270
|
+
}
|
|
271
|
+
function parseSorts(raw) {
|
|
272
|
+
let list = raw;
|
|
273
|
+
if (typeof raw === "string") {
|
|
274
|
+
try {
|
|
275
|
+
list = raw.trim() === "" ? [] : JSON.parse(raw);
|
|
276
|
+
} catch {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (!Array.isArray(list)) return [];
|
|
281
|
+
return list.filter((s) => isObject(s) && typeof s.field === "string").map((s) => ({ field: s.field, direction: s.direction === "desc" ? "desc" : "asc" }));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/views.ts
|
|
285
|
+
var VIEW_LAYOUTS = ["grid", "kanban", "calendar", "gallery", "timeline", "list"];
|
|
286
|
+
function viewOrderOf(definition) {
|
|
287
|
+
const raw = definition?.["order"];
|
|
288
|
+
return raw === "manual" ? "manual" : raw === "sorted" ? "sorted" : null;
|
|
289
|
+
}
|
|
290
|
+
function defaultViewOf(views) {
|
|
291
|
+
return views.find((v) => v.isDefault);
|
|
292
|
+
}
|
|
293
|
+
function viewFromRow(row) {
|
|
294
|
+
const data = row.definition ?? {};
|
|
295
|
+
const k = viewSettings(data, row.filters && Object.keys(row.filters).length > 0 ? row.filters : null);
|
|
296
|
+
const tableFromDefinition = typeof data["table_id"] === "string" && data["table_id"] !== "" ? data["table_id"] : null;
|
|
297
|
+
return {
|
|
298
|
+
id: row.view_id,
|
|
299
|
+
name: row.name || "Untitled view",
|
|
300
|
+
subject: row.table_id ?? tableFromDefinition ?? "",
|
|
301
|
+
layout: k.layout,
|
|
302
|
+
groupField: k.groupField,
|
|
303
|
+
swimlaneField: k.swimlaneField,
|
|
304
|
+
collapsedColumns: k.collapsedColumns,
|
|
305
|
+
measure: k.measure,
|
|
306
|
+
dateField: k.dateField,
|
|
307
|
+
startField: k.startField,
|
|
308
|
+
endField: k.endField,
|
|
309
|
+
imageField: k.imageField,
|
|
310
|
+
sorts: k.sorts,
|
|
311
|
+
order: viewOrderOf(data),
|
|
312
|
+
ruleId: k.ruleId,
|
|
313
|
+
...k.filters ? { filters: k.filters } : {},
|
|
314
|
+
where: k.where,
|
|
315
|
+
// The older table's own default view, carried in by the mover, IS this table's default —
|
|
316
|
+
// the mover wrote the row's column, which `custom.views` does not return. Read as anything
|
|
317
|
+
// else, the page would seed a second "All records" beside it and open on that.
|
|
318
|
+
isDefault: k.isDefault || k.movedFrom?.["kind"] === "default_view",
|
|
319
|
+
presentation: k.presentation,
|
|
320
|
+
movedFrom: k.movedFrom
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/viewLook.ts
|
|
325
|
+
function lookFromDocument(doc) {
|
|
326
|
+
const data = doc ?? {};
|
|
327
|
+
const read = viewSettings(data);
|
|
328
|
+
const out = {};
|
|
329
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(data, key);
|
|
330
|
+
if (has("layout") && VIEW_LAYOUTS.includes(String(data["layout"]))) {
|
|
331
|
+
out.layout = data["layout"];
|
|
332
|
+
}
|
|
333
|
+
if (has("group_field")) out.groupField = read.groupField;
|
|
334
|
+
if (has("swimlane_field")) out.swimlaneField = read.swimlaneField;
|
|
335
|
+
if (has("collapsed_columns")) out.collapsedColumns = read.collapsedColumns;
|
|
336
|
+
if (has("measure")) out.measure = read.measure;
|
|
337
|
+
if (has("date_field")) out.dateField = read.dateField;
|
|
338
|
+
if (has("start_field")) out.startField = read.startField;
|
|
339
|
+
if (has("end_field")) out.endField = read.endField;
|
|
340
|
+
if (has("image_field")) out.imageField = read.imageField;
|
|
341
|
+
if (has("sorts")) out.sorts = read.sorts;
|
|
342
|
+
if (has("where")) out.where = read.where;
|
|
343
|
+
if (has("presentation")) out.presentation = parseGridPresentation(data["presentation"]);
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
function applyLook(view, look) {
|
|
347
|
+
if (!look) return view;
|
|
348
|
+
return { ...view, ...look };
|
|
349
|
+
}
|
|
350
|
+
async function readLooks(client, tableId) {
|
|
351
|
+
const answered = await client.viewLookRead({ table_id: tableId });
|
|
352
|
+
if (!answered.ok) return answered;
|
|
353
|
+
const out = {};
|
|
354
|
+
for (const [viewId, row] of Object.entries(answered.data ?? {})) {
|
|
355
|
+
out[viewId] = lookFromDocument(row?.look ?? null);
|
|
356
|
+
}
|
|
357
|
+
return { ok: true, data: out };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/firstPage.ts
|
|
361
|
+
var TABLE_PAGE_SIZE = 100;
|
|
362
|
+
var EMBEDDED_PAGE_SIZE = 50;
|
|
363
|
+
function firstGridPageArgs(input) {
|
|
364
|
+
const { shown, fields } = input;
|
|
365
|
+
if (!shown) return null;
|
|
366
|
+
if ((shown.layout ?? "grid") !== "grid") return null;
|
|
367
|
+
if (shown.ruleId) return null;
|
|
368
|
+
if (shown.order === "manual") return null;
|
|
369
|
+
if (shown.filters && Object.keys(shown.filters).length > 0) return null;
|
|
370
|
+
if (shown.presentation?.grouping) return null;
|
|
371
|
+
const first = (shown.sorts ?? [])[0];
|
|
372
|
+
const viewSort = first && fields.some((f) => f.key === first.field) ? { id: first.field, direction: first.direction } : null;
|
|
373
|
+
const opening = viewSort ?? defaultSortOf(input.table, fields);
|
|
374
|
+
return {
|
|
375
|
+
p_table_id: input.tableId,
|
|
376
|
+
p_filter: {},
|
|
377
|
+
p_search: null,
|
|
378
|
+
p_sort: pageSortFor(fields, opening),
|
|
379
|
+
p_view_id: null,
|
|
380
|
+
p_limit: input.pageSize ?? TABLE_PAGE_SIZE,
|
|
381
|
+
p_offset: 0
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
async function firstGridPageRequest(client, tableId, options = {}) {
|
|
385
|
+
const [table, fields, views, looks] = await Promise.all([
|
|
386
|
+
client.tableRead({ table_id: tableId }),
|
|
387
|
+
client.fields({ table_id: tableId }),
|
|
388
|
+
client.views({ table_id: tableId }),
|
|
389
|
+
readLooks(client, tableId)
|
|
390
|
+
]);
|
|
391
|
+
if (!table.ok || !fields.ok || !views.ok || !looks.ok) return null;
|
|
392
|
+
const mine = views.data.map(viewFromRow).filter((v) => v.subject === tableId);
|
|
393
|
+
const view = defaultViewOf(mine) ?? mine[0] ?? null;
|
|
394
|
+
const shown = view ? applyLook(view, looks.data[view.id]) : null;
|
|
395
|
+
return firstGridPageArgs({ tableId, table: table.data, fields: fields.data, shown, ...options.pageSize ? { pageSize: options.pageSize } : {} });
|
|
396
|
+
}
|
|
397
|
+
async function askTablePageSeed(input) {
|
|
398
|
+
const recording = core.recordingDataSource(core.asRecordsDataSource(input.dataSource));
|
|
399
|
+
const client = core.createRecordsClient({
|
|
400
|
+
dataSource: recording.source,
|
|
401
|
+
organizationId: input.organizationId,
|
|
402
|
+
actor: input.actor,
|
|
403
|
+
onError: () => {
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
const record = input.recordId ? Promise.resolve(
|
|
407
|
+
recording.source.rpc("record_page_bundle", { p_organization_id: input.organizationId, p_record_id: input.recordId }, { schema: "custom" })
|
|
408
|
+
).catch(() => null) : null;
|
|
409
|
+
try {
|
|
410
|
+
const pageSize = input.pageSize ?? (input.embedded ? EMBEDDED_PAGE_SIZE : TABLE_PAGE_SIZE);
|
|
411
|
+
const args = await firstGridPageRequest(client, input.tableId, { pageSize });
|
|
412
|
+
if (args && input.rows !== false) {
|
|
413
|
+
await client.listPage({
|
|
414
|
+
table_id: args.p_table_id,
|
|
415
|
+
filter: args.p_filter,
|
|
416
|
+
search: args.p_search,
|
|
417
|
+
sort: args.p_sort,
|
|
418
|
+
view_id: args.p_view_id,
|
|
419
|
+
limit: args.p_limit,
|
|
420
|
+
offset: args.p_offset
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
} catch {
|
|
424
|
+
}
|
|
425
|
+
if (record) await record;
|
|
426
|
+
return recording.seed();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
exports.EMBEDDED_PAGE_SIZE = EMBEDDED_PAGE_SIZE;
|
|
430
|
+
exports.TABLE_PAGE_SIZE = TABLE_PAGE_SIZE;
|
|
431
|
+
exports.askTablePageSeed = askTablePageSeed;
|
|
432
|
+
exports.firstGridPageArgs = firstGridPageArgs;
|
|
433
|
+
exports.firstGridPageRequest = firstGridPageRequest;
|
|
434
|
+
//# sourceMappingURL=first-page.cjs.map
|
|
435
|
+
//# sourceMappingURL=first-page.cjs.map
|