@ai-matrx/records-ui 0.93.72 → 0.93.74
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 +20 -0
- package/dist/index.cjs +241 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -3
- package/dist/index.d.ts +61 -3
- package/dist/index.js +244 -144
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.93.74
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records-ui/v0.93.73..npm/records-ui/v0.93.74 -- apps/shared/records-ui`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.93.73
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/records-ui/v0.93.72..npm/records-ui/v0.93.73 -- apps/shared/records-ui`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
3
15
|
## 0.93.72
|
|
4
16
|
### Unreleased
|
|
5
17
|
|
|
18
|
+
- **Rows that are not a file read as rows after the write** (lane SAVE-AS-TABLE-EVERYWHERE, walked 2026-09-29): after rows from a chat answer landed, the wizard said "the rows above has been sent to this table … To import another file, choose it above" under a line still promising "Nothing is written until you press Import". With a `source`, it now says "These rows have been sent to this table" and the pre-write line is gone.
|
|
6
19
|
- **An import no longer calls every row of a choice column refused** (lane SAVE-AS-TABLE-EVERYWHERE, found walking Cedar Ridge 2026-09-29): the pre-write rule check judged a choice column without its options and said "3 of 3 rows would be refused … its options have not been read yet" over words that WERE choices, and held Import behind "Import the rest anyway". `checkImportRules` now takes the options the wizard reads for the enum ask; a choice column is judged only once they are in hand, and a word it does not know is the enum ask's to raise. The wizard's source line for rows with no title reads "From the rows above".
|
|
7
20
|
- **Changing a booking page never sends the store's own columns back** (lane HANDOVER, 2026-09-29): with the page's stored questions loaded, "Change it" also sent the store's hidden `slot`, `status` and `booked_with`, and the save was refused ("A booking page never asks for \"slot\""). Hidden questions and `STORE_ANSWERS_THESE` are left out on load. Proof: `a-booking-page-that-exists-can-be-changed.test.tsx` (the stored list as the store keeps it), red on the old builder.
|
|
8
21
|
|
|
@@ -39,6 +52,13 @@ No source changes intended and no consumer action required.
|
|
|
39
52
|
beside `field`/`then`), so Save keeps the exploration as a Saved view; the drill trail also
|
|
40
53
|
narrows the page the grid reads ("See these records"). Proof:
|
|
41
54
|
`a-grid-drills-through-the-store.test.tsx`, red 4/5 on the HEAD grid.
|
|
55
|
+
- **The drill reads the one read door** (lane DRILL-TABLE-PRIMITIVE, after D1/D2): Dimensions, Measures and
|
|
56
|
+
drill paths come from `platform.drill_describe` (a custom Table's from `custom.table_dimensions`, with its
|
|
57
|
+
overrides) and every grouping from `platform.drill_ask` — nothing is inferred in the browser any more.
|
|
58
|
+
`useDrill({ source })` is the port for ANY source: a custom Table `{kind: "table", id}` or a standard table
|
|
59
|
+
`{kind: "entity", token}`, drawn by the same table; relation groups read by the names the door read as the
|
|
60
|
+
person. A view whose question is nested (a Rule filter, which the contract's flat `where` does not carry
|
|
61
|
+
yet) is answered by the store's aggregate door `drill_ask` itself delegates to, with the same rule.
|
|
42
62
|
|
|
43
63
|
## 0.93.67
|
|
44
64
|
|
package/dist/index.cjs
CHANGED
|
@@ -269,6 +269,10 @@ __export(src_exports, {
|
|
|
269
269
|
declareView: () => declareView,
|
|
270
270
|
defaultViewOf: () => defaultViewOf,
|
|
271
271
|
designatedLayoutOf: () => designatedLayoutOf,
|
|
272
|
+
drillDimensionsOf: () => drillDimensionsOf,
|
|
273
|
+
drillMeasuresOf: () => drillMeasuresOf,
|
|
274
|
+
drillPathsOf: () => drillPathsOf,
|
|
275
|
+
drillWhere: () => drillWhere,
|
|
272
276
|
editorKindFor: () => editorKindFor,
|
|
273
277
|
ensureSystemTable: () => ensureSystemTable,
|
|
274
278
|
entityReferenceSpec: () => entityReferenceSpec,
|
|
@@ -378,6 +382,9 @@ __export(src_exports, {
|
|
|
378
382
|
unknownViewLine: () => unknownViewLine,
|
|
379
383
|
useCanShare: () => useCanShare,
|
|
380
384
|
useChoiceNudge: () => useChoiceNudge,
|
|
385
|
+
useDrill: () => useDrill,
|
|
386
|
+
useDrillAnswers: () => useDrillAnswers,
|
|
387
|
+
useDrillDefinition: () => useDrillDefinition,
|
|
381
388
|
useEmbedHandshake: () => useEmbedHandshake,
|
|
382
389
|
useEnrichCells: () => useEnrichCells,
|
|
383
390
|
useGridEditing: () => useGridEditing,
|
|
@@ -9596,55 +9603,206 @@ var import_react51 = require("react");
|
|
|
9596
9603
|
var import_react52 = require("@ai-matrx/records/react");
|
|
9597
9604
|
var import_records17 = require("@ai-matrx/records");
|
|
9598
9605
|
var import_data_table8 = require("@ai-matrx/design-system/data-table");
|
|
9599
|
-
var
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
checkbox: "boolean",
|
|
9609
|
-
text: "text",
|
|
9610
|
-
datetime: "time"
|
|
9611
|
-
};
|
|
9612
|
-
function drillDimensionsFor(fields, options) {
|
|
9613
|
-
const out = [];
|
|
9614
|
-
for (const field2 of fields) {
|
|
9615
|
-
const kind = DIMENSION_KINDS[String(editorKindFor(field2))];
|
|
9616
|
-
if (!kind) continue;
|
|
9617
|
-
if (field2.multi) continue;
|
|
9618
|
-
const dim = { key: field2.key, label: fieldName(field2), kind };
|
|
9619
|
-
if (kind === "text") dim.cardinality = "high";
|
|
9620
|
-
if (kind === "choice" && isChoiceField(field2)) {
|
|
9606
|
+
var ADDITIVE_OPS = /* @__PURE__ */ new Set(["count", "sum", "filled", "empty"]);
|
|
9607
|
+
function drillDimensionsOf(def, labels) {
|
|
9608
|
+
if (!def) return [];
|
|
9609
|
+
return def.dimensions.map((d) => {
|
|
9610
|
+
const dim = { key: d.key, label: d.label, kind: d.kind };
|
|
9611
|
+
if (d.cardinality) dim.cardinality = d.cardinality;
|
|
9612
|
+
if (d.grains) dim.grains = d.grains.filter((g) => g !== "hour");
|
|
9613
|
+
const choices = new Map((d.choices ?? []).map((c) => [c.value, c.label]));
|
|
9614
|
+
if (d.kind === "choice" || d.kind === "relation") {
|
|
9621
9615
|
dim.labelFor = (value) => {
|
|
9622
9616
|
if (value === null || value === "") return "No value";
|
|
9623
|
-
return
|
|
9617
|
+
return choices.get(value) ?? labels.get(d.key)?.get(value) ?? value;
|
|
9624
9618
|
};
|
|
9625
9619
|
}
|
|
9626
|
-
|
|
9627
|
-
}
|
|
9628
|
-
return out;
|
|
9620
|
+
return dim;
|
|
9621
|
+
});
|
|
9629
9622
|
}
|
|
9630
|
-
function
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9623
|
+
function drillMeasuresOf(def) {
|
|
9624
|
+
if (!def) return [];
|
|
9625
|
+
return def.measures.map((m) => ({ key: m.key, label: m.label, additive: m.additive ?? ADDITIVE_OPS.has(m.op) }));
|
|
9626
|
+
}
|
|
9627
|
+
function drillPathsOf(def) {
|
|
9628
|
+
return (def?.paths ?? []).map((p) => p.levels);
|
|
9629
|
+
}
|
|
9630
|
+
function useDrillDefinition(source) {
|
|
9631
|
+
const client = (0, import_react52.useRecordsClient)();
|
|
9632
|
+
const key = source ? JSON.stringify(source) : null;
|
|
9633
|
+
const [state, setState] = (0, import_react51.useState)({ key: null, def: null, error: null });
|
|
9634
|
+
(0, import_react51.useEffect)(() => {
|
|
9635
|
+
if (!key) return;
|
|
9636
|
+
let cancelled = false;
|
|
9637
|
+
void client.drillDescribe({ source: JSON.parse(key) }).then((got) => {
|
|
9638
|
+
if (cancelled) return;
|
|
9639
|
+
setState(got.ok ? { key, def: got.data ?? null, error: null } : { key, def: null, error: got.error.message || "This table's groupings could not be read." });
|
|
9640
|
+
});
|
|
9641
|
+
return () => {
|
|
9642
|
+
cancelled = true;
|
|
9643
|
+
};
|
|
9644
|
+
}, [client, key]);
|
|
9645
|
+
return state.key === key ? { def: state.def, error: state.error } : { def: null, error: null };
|
|
9646
|
+
}
|
|
9647
|
+
function drillWhere(base, trail, booleans) {
|
|
9648
|
+
const where = { ...base ?? {} };
|
|
9649
|
+
for (const w of trail) {
|
|
9650
|
+
const { key, grain } = (0, import_data_table8.parseDimensionRef)(w.dim);
|
|
9651
|
+
if (grain) where[w.dim] = w.value;
|
|
9652
|
+
else if (booleans.has(key) && (w.value === "true" || w.value === "false")) where[key] = w.value === "true";
|
|
9653
|
+
else where[key] = w.value;
|
|
9638
9654
|
}
|
|
9639
|
-
return
|
|
9655
|
+
return where;
|
|
9640
9656
|
}
|
|
9641
|
-
function
|
|
9657
|
+
function rowOf(row) {
|
|
9658
|
+
const groups = {};
|
|
9659
|
+
for (const [k, v] of Object.entries(row.groups ?? {})) groups[k] = v === null || v === void 0 ? null : String(v);
|
|
9660
|
+
const measures = {};
|
|
9661
|
+
for (const [k, v] of Object.entries(row.measures ?? {})) measures[k] = v === null || v === void 0 ? null : Number(v);
|
|
9662
|
+
return { groups, measures, row_count: Number(row.row_count ?? 0) };
|
|
9663
|
+
}
|
|
9664
|
+
function storeMeasure(key) {
|
|
9642
9665
|
if (key === "count") return { op: "count" };
|
|
9643
9666
|
const at = key.indexOf("_");
|
|
9644
9667
|
if (at <= 0) return null;
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9668
|
+
return { op: key.slice(0, at), key: key.slice(at + 1) };
|
|
9669
|
+
}
|
|
9670
|
+
function useDrillAnswers(args) {
|
|
9671
|
+
const client = (0, import_react52.useRecordsClient)();
|
|
9672
|
+
const { source, question, enabled, version } = args;
|
|
9673
|
+
const [answers, setAnswers] = (0, import_react51.useState)({});
|
|
9674
|
+
const [labels, setLabels] = (0, import_react51.useState)(() => /* @__PURE__ */ new Map());
|
|
9675
|
+
const [error, setError] = (0, import_react51.useState)(null);
|
|
9676
|
+
const [says, setSays] = (0, import_react51.useState)([]);
|
|
9677
|
+
const askKey2 = JSON.stringify({
|
|
9678
|
+
source,
|
|
9679
|
+
by: question.by,
|
|
9680
|
+
across: question.across ?? null,
|
|
9681
|
+
show: question.show,
|
|
9682
|
+
where: args.where,
|
|
9683
|
+
rule: args.rule && (0, import_records17.isRuleFilter)(args.rule) ? args.rule : null
|
|
9684
|
+
});
|
|
9685
|
+
(0, import_react51.useEffect)(() => {
|
|
9686
|
+
if (!enabled || !source || question.by.length === 0) return;
|
|
9687
|
+
const asked2 = JSON.parse(askKey2);
|
|
9688
|
+
let cancelled = false;
|
|
9689
|
+
setAnswers({});
|
|
9690
|
+
setError(null);
|
|
9691
|
+
const requests = (0, import_data_table8.drillRequests)({ by: asked2.by, across: asked2.across, show: asked2.show, where: [] });
|
|
9692
|
+
void Promise.all(
|
|
9693
|
+
requests.map(async (request) => {
|
|
9694
|
+
if (asked2.rule && asked2.source.kind === "table") {
|
|
9695
|
+
const time = request.by.find((ref) => (0, import_data_table8.parseDimensionRef)(ref).grain !== null) ?? null;
|
|
9696
|
+
const t = time ? (0, import_data_table8.parseDimensionRef)(time) : null;
|
|
9697
|
+
const measures = asked2.show.map(storeMeasure).filter((m) => m !== null);
|
|
9698
|
+
const got2 = await client.recordAggregate({
|
|
9699
|
+
table_id: asked2.source.id,
|
|
9700
|
+
groupBy: request.by.filter((ref) => ref !== time),
|
|
9701
|
+
measures,
|
|
9702
|
+
bucket: t && t.grain ? { key: t.key, by: t.grain } : null,
|
|
9703
|
+
filter: asked2.rule,
|
|
9704
|
+
limit: 200
|
|
9705
|
+
});
|
|
9706
|
+
if (!got2.ok) return { request, error: got2.error.message };
|
|
9707
|
+
return {
|
|
9708
|
+
request,
|
|
9709
|
+
rows: (got2.data ?? []).map((row) => {
|
|
9710
|
+
const groups = {};
|
|
9711
|
+
for (const ref of request.by) {
|
|
9712
|
+
const k = ref === time && t ? t.key : ref;
|
|
9713
|
+
groups[ref] = row.groups[k] ?? null;
|
|
9714
|
+
}
|
|
9715
|
+
return { groups, measures: row.measures, row_count: row.row_count };
|
|
9716
|
+
}),
|
|
9717
|
+
labels: {},
|
|
9718
|
+
says: []
|
|
9719
|
+
};
|
|
9720
|
+
}
|
|
9721
|
+
const got = await client.drillAsk({
|
|
9722
|
+
source: asked2.source,
|
|
9723
|
+
question: { by: request.by, show: asked2.show, where: asked2.where }
|
|
9724
|
+
});
|
|
9725
|
+
if (!got.ok) return { request, error: got.error.message || "The groups could not be read." };
|
|
9726
|
+
const answer = got.data;
|
|
9727
|
+
const kind = request.by.length === 0 ? "total" : "group";
|
|
9728
|
+
const rows = answer.rows.filter((r) => r.kind === kind && (kind === "group" || !r.groups || Object.keys(r.groups).length === 0)).map(rowOf);
|
|
9729
|
+
const found = {};
|
|
9730
|
+
for (const r of answer.rows) {
|
|
9731
|
+
for (const [dim, text] of Object.entries(r.labels ?? {})) {
|
|
9732
|
+
const value = r.groups?.[dim];
|
|
9733
|
+
if (value === null || value === void 0) continue;
|
|
9734
|
+
(found[dim] ??= {})[String(value)] = text;
|
|
9735
|
+
}
|
|
9736
|
+
}
|
|
9737
|
+
return { request, rows, labels: found, says: answer.says };
|
|
9738
|
+
})
|
|
9739
|
+
).then((results) => {
|
|
9740
|
+
if (cancelled) return;
|
|
9741
|
+
const failed = results.find((r) => "error" in r);
|
|
9742
|
+
if (failed) {
|
|
9743
|
+
setError(failed.error);
|
|
9744
|
+
return;
|
|
9745
|
+
}
|
|
9746
|
+
const out = {};
|
|
9747
|
+
const nextLabels = /* @__PURE__ */ new Map();
|
|
9748
|
+
const sentences = [];
|
|
9749
|
+
for (const r of results) {
|
|
9750
|
+
if (!("rows" in r)) continue;
|
|
9751
|
+
out[r.request.key] = r.rows;
|
|
9752
|
+
for (const [dim, map] of Object.entries(r.labels ?? {})) {
|
|
9753
|
+
const held = nextLabels.get(dim) ?? /* @__PURE__ */ new Map();
|
|
9754
|
+
for (const [v, t] of Object.entries(map)) held.set(v, t);
|
|
9755
|
+
nextLabels.set(dim, held);
|
|
9756
|
+
}
|
|
9757
|
+
for (const s of r.says ?? []) if (!sentences.includes(s)) sentences.push(s);
|
|
9758
|
+
}
|
|
9759
|
+
setLabels(nextLabels);
|
|
9760
|
+
setSays(sentences);
|
|
9761
|
+
setAnswers(out);
|
|
9762
|
+
});
|
|
9763
|
+
return () => {
|
|
9764
|
+
cancelled = true;
|
|
9765
|
+
};
|
|
9766
|
+
}, [client, askKey2, enabled, version, question.by.length]);
|
|
9767
|
+
return { answers, labels, error, says };
|
|
9768
|
+
}
|
|
9769
|
+
function drillQuestionFor(question, def) {
|
|
9770
|
+
if (!def) return question;
|
|
9771
|
+
const known = (ref) => def.dimensions.some((d) => d.key === (0, import_data_table8.parseDimensionRef)(ref).key);
|
|
9772
|
+
const show = question.show.filter((key) => def.measures.some((m) => m.key === key));
|
|
9773
|
+
return {
|
|
9774
|
+
...question,
|
|
9775
|
+
by: question.by.filter(known),
|
|
9776
|
+
across: question.across && known(question.across) ? question.across : null,
|
|
9777
|
+
show: show.length > 0 ? show : [def.measures[0]?.key ?? "count"],
|
|
9778
|
+
where: question.where.filter((w) => known(w.dim))
|
|
9779
|
+
};
|
|
9780
|
+
}
|
|
9781
|
+
function useDrill(args) {
|
|
9782
|
+
const enabled = args.enabled ?? true;
|
|
9783
|
+
const { def, error: describeError } = useDrillDefinition(enabled ? args.source : null);
|
|
9784
|
+
const question = (0, import_react51.useMemo)(() => drillQuestionFor(args.question, def), [args.question, def]);
|
|
9785
|
+
const booleans = (0, import_react51.useMemo)(() => new Set((def?.dimensions ?? []).filter((d) => d.kind === "boolean").map((d) => d.key)), [def]);
|
|
9786
|
+
const where = (0, import_react51.useMemo)(() => drillWhere(args.filter, question.where, booleans), [args.filter, question.where, booleans]);
|
|
9787
|
+
const { answers, labels, error } = useDrillAnswers({
|
|
9788
|
+
source: args.source,
|
|
9789
|
+
question,
|
|
9790
|
+
where,
|
|
9791
|
+
rule: args.rule,
|
|
9792
|
+
version: args.version,
|
|
9793
|
+
enabled: enabled && def !== null
|
|
9794
|
+
});
|
|
9795
|
+
const dimensions = (0, import_react51.useMemo)(() => drillDimensionsOf(def, labels), [def, labels]);
|
|
9796
|
+
const measures = (0, import_react51.useMemo)(() => drillMeasuresOf(def), [def]);
|
|
9797
|
+
const paths = (0, import_react51.useMemo)(() => drillPathsOf(def), [def]);
|
|
9798
|
+
const { onQuestionChange } = args;
|
|
9799
|
+
const rowNoun = args.rowNoun ?? "record";
|
|
9800
|
+
const rootLabel = args.rootLabel ?? "All records";
|
|
9801
|
+
const config = (0, import_react51.useMemo)(() => {
|
|
9802
|
+
if (!enabled || !def || dimensions.length === 0) return null;
|
|
9803
|
+
return { dimensions, measures, paths, question, answers, error: describeError ?? error, rowNoun, rootLabel, onQuestionChange };
|
|
9804
|
+
}, [enabled, def, dimensions, measures, paths, question, answers, describeError, error, rowNoun, rootLabel, onQuestionChange]);
|
|
9805
|
+
return { config, def };
|
|
9648
9806
|
}
|
|
9649
9807
|
function questionFromGrouping(grouping) {
|
|
9650
9808
|
if (!grouping) return { by: [], across: null, show: ["count"], where: [] };
|
|
@@ -9705,110 +9863,49 @@ function filterWithTrail(fields, base, trail) {
|
|
|
9705
9863
|
}
|
|
9706
9864
|
return { op: "and", args };
|
|
9707
9865
|
}
|
|
9708
|
-
function useDrillAnswers(args) {
|
|
9709
|
-
const client = (0, import_react52.useRecordsClient)();
|
|
9710
|
-
const { tableId, question, enabled, version } = args;
|
|
9711
|
-
const [answers, setAnswers] = (0, import_react51.useState)({});
|
|
9712
|
-
const [error, setError] = (0, import_react51.useState)(null);
|
|
9713
|
-
const askKey2 = JSON.stringify({ by: question.by, across: question.across ?? null, show: question.show, filter: args.filter ?? null });
|
|
9714
|
-
(0, import_react51.useEffect)(() => {
|
|
9715
|
-
if (!enabled || question.by.length === 0) return;
|
|
9716
|
-
const asked2 = JSON.parse(askKey2);
|
|
9717
|
-
const measures = asked2.show.map(measureFor).filter((m) => m !== null);
|
|
9718
|
-
if (!measures.some((m) => m.op === "count")) measures.unshift({ op: "count" });
|
|
9719
|
-
let cancelled = false;
|
|
9720
|
-
setAnswers({});
|
|
9721
|
-
setError(null);
|
|
9722
|
-
const requests = (0, import_data_table8.drillRequests)({ by: asked2.by, across: asked2.across, show: asked2.show, where: [] });
|
|
9723
|
-
void Promise.all(
|
|
9724
|
-
requests.map(async (request) => {
|
|
9725
|
-
const time = request.by.find((ref) => (0, import_data_table8.parseDimensionRef)(ref).grain !== null) ?? null;
|
|
9726
|
-
const plain = request.by.filter((ref) => ref !== time);
|
|
9727
|
-
const grain = time ? (0, import_data_table8.parseDimensionRef)(time) : null;
|
|
9728
|
-
const got = await client.recordAggregate({
|
|
9729
|
-
table_id: tableId,
|
|
9730
|
-
groupBy: plain,
|
|
9731
|
-
measures,
|
|
9732
|
-
bucket: grain && grain.grain ? { key: grain.key, by: grain.grain } : null,
|
|
9733
|
-
...asked2.filter ? { filter: asked2.filter } : {},
|
|
9734
|
-
limit: 200
|
|
9735
|
-
});
|
|
9736
|
-
if (!got.ok) return { request, error: got.error.message || "The groups could not be read." };
|
|
9737
|
-
const rows = (got.data ?? []).map((row) => {
|
|
9738
|
-
const groups = {};
|
|
9739
|
-
for (const ref of plain) groups[ref] = row.groups[ref] ?? null;
|
|
9740
|
-
if (time && grain) groups[time] = row.groups[grain.key] ?? null;
|
|
9741
|
-
return { groups, measures: row.measures, row_count: row.row_count };
|
|
9742
|
-
});
|
|
9743
|
-
return { request, rows };
|
|
9744
|
-
})
|
|
9745
|
-
).then((results) => {
|
|
9746
|
-
if (cancelled) return;
|
|
9747
|
-
const failed = results.find((r) => "error" in r);
|
|
9748
|
-
if (failed) {
|
|
9749
|
-
setError(failed.error);
|
|
9750
|
-
return;
|
|
9751
|
-
}
|
|
9752
|
-
const out = {};
|
|
9753
|
-
for (const r of results) if ("rows" in r) out[r.request.key] = r.rows;
|
|
9754
|
-
setAnswers(out);
|
|
9755
|
-
});
|
|
9756
|
-
return () => {
|
|
9757
|
-
cancelled = true;
|
|
9758
|
-
};
|
|
9759
|
-
}, [client, tableId, askKey2, enabled, version, question.by.length]);
|
|
9760
|
-
return { answers, error };
|
|
9761
|
-
}
|
|
9762
9866
|
function useGridDrillQuestion(args) {
|
|
9763
|
-
const { fields, presentation, filter } = args;
|
|
9764
|
-
const
|
|
9765
|
-
const
|
|
9766
|
-
const dimensions = (0, import_react51.useMemo)(() => drillDimensionsFor(fields, options), [fields, options]);
|
|
9767
|
-
const measures = (0, import_react51.useMemo)(() => drillMeasuresFor(fields), [fields]);
|
|
9867
|
+
const { tableId, fields, presentation, filter } = args;
|
|
9868
|
+
const source = (0, import_react51.useMemo)(() => ({ kind: "table", id: tableId }), [tableId]);
|
|
9869
|
+
const { def } = useDrillDefinition(args.enabled ? source : null);
|
|
9768
9870
|
const saved = (0, import_react51.useMemo)(() => questionFromGrouping(presentation.grouping), [presentation.grouping]);
|
|
9769
9871
|
const url = (0, import_data_table8.useDrillUrlState)({ fallback: saved });
|
|
9770
|
-
const question = (0, import_react51.useMemo)(() =>
|
|
9771
|
-
|
|
9772
|
-
const show = url.question.show.filter((key) => measures.some((m) => m.key === key));
|
|
9773
|
-
return {
|
|
9774
|
-
...url.question,
|
|
9775
|
-
by: url.question.by.filter(known),
|
|
9776
|
-
across: url.question.across && known(url.question.across) ? url.question.across : null,
|
|
9777
|
-
show: show.length > 0 ? show : ["count"],
|
|
9778
|
-
where: url.question.where.filter((w) => known(w.dim))
|
|
9779
|
-
};
|
|
9780
|
-
}, [url.question, dimensions, measures]);
|
|
9781
|
-
const enabled = args.enabled && dimensions.length > 0;
|
|
9872
|
+
const question = (0, import_react51.useMemo)(() => drillQuestionFor(url.question, def), [url.question, def]);
|
|
9873
|
+
const enabled = args.enabled && def !== null && def.dimensions.length > 0;
|
|
9782
9874
|
const trailFilter = (0, import_react51.useMemo)(
|
|
9783
9875
|
() => enabled ? filterWithTrail(fields, filter, question.where) : filter,
|
|
9784
9876
|
[enabled, fields, filter, question.where]
|
|
9785
9877
|
);
|
|
9786
|
-
return { enabled,
|
|
9878
|
+
return { enabled, source, def, question, setQuestion: url.setQuestion, filter, trailFilter };
|
|
9787
9879
|
}
|
|
9788
9880
|
function useGridDrillConfig(args) {
|
|
9789
|
-
const {
|
|
9790
|
-
const {
|
|
9791
|
-
const
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
answers,
|
|
9799
|
-
error,
|
|
9800
|
-
rootLabel: "All records",
|
|
9801
|
-
rowNoun: "record",
|
|
9802
|
-
onQuestionChange: (next) => {
|
|
9803
|
-
setQuestion(next);
|
|
9804
|
-
if (onPresentationChange) {
|
|
9805
|
-
const grouping = groupingFromQuestion(next, presentation.grouping);
|
|
9806
|
-
const { grouping: _dropped, ...rest } = presentation;
|
|
9807
|
-
onPresentationChange(grouping ? { ...rest, grouping } : rest);
|
|
9808
|
-
}
|
|
9881
|
+
const { state, presentation, onPresentationChange, version } = args;
|
|
9882
|
+
const { setQuestion } = state;
|
|
9883
|
+
const onQuestionChange = (0, import_react51.useMemo)(
|
|
9884
|
+
() => (next) => {
|
|
9885
|
+
setQuestion(next);
|
|
9886
|
+
if (onPresentationChange) {
|
|
9887
|
+
const grouping = groupingFromQuestion(next, presentation.grouping);
|
|
9888
|
+
const { grouping: _dropped, ...rest } = presentation;
|
|
9889
|
+
onPresentationChange(grouping ? { ...rest, grouping } : rest);
|
|
9809
9890
|
}
|
|
9810
|
-
}
|
|
9811
|
-
|
|
9891
|
+
},
|
|
9892
|
+
[setQuestion, onPresentationChange, presentation]
|
|
9893
|
+
);
|
|
9894
|
+
const flat = state.filter && !(0, import_records17.isRuleFilter)(state.filter) ? state.filter : void 0;
|
|
9895
|
+
const rule = state.filter && (0, import_records17.isRuleFilter)(state.filter) ? filterWithTrailRuleOnly(state) : void 0;
|
|
9896
|
+
const { config } = useDrill({
|
|
9897
|
+
source: state.source,
|
|
9898
|
+
question: state.question,
|
|
9899
|
+
onQuestionChange,
|
|
9900
|
+
filter: flat,
|
|
9901
|
+
rule,
|
|
9902
|
+
version,
|
|
9903
|
+
enabled: state.enabled
|
|
9904
|
+
});
|
|
9905
|
+
return config;
|
|
9906
|
+
}
|
|
9907
|
+
function filterWithTrailRuleOnly(state) {
|
|
9908
|
+
return state.trailFilter;
|
|
9812
9909
|
}
|
|
9813
9910
|
|
|
9814
9911
|
// src/Enrich.tsx
|
|
@@ -11359,7 +11456,7 @@ function ImportWizard({ tableId, source, onDone, onWrote, className }) {
|
|
|
11359
11456
|
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-muted-foreground", children: table.data?.name }),
|
|
11360
11457
|
fields.data && table.data ? null : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "ml-auto text-muted-foreground", children: fields.data ? "Reading this table\u2026" : "Reading this table's fields\u2026" })
|
|
11361
11458
|
] }),
|
|
11362
|
-
source ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "text-muted-foreground", "data-import-source": "", children: [
|
|
11459
|
+
source && !afterWrite ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "text-muted-foreground", "data-import-source": "", children: [
|
|
11363
11460
|
"From ",
|
|
11364
11461
|
source.name,
|
|
11365
11462
|
" \u2014 ",
|
|
@@ -11393,8 +11490,8 @@ function ImportWizard({ tableId, source, onDone, onWrote, className }) {
|
|
|
11393
11490
|
phase === "reading" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-muted-foreground", children: "Reading the file\u2026" }) : null,
|
|
11394
11491
|
phase === "planning" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-muted-foreground", children: "Working out what each column is\u2026" }) : null,
|
|
11395
11492
|
plan && parsed && afterWrite ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "text-muted-foreground", "data-import-after-write": "", children: [
|
|
11396
|
-
fileName ? `${fileName} has been sent to this table` : "This file has been sent to this table",
|
|
11397
|
-
ledger && !ledger.final ? ", but the run stopped part-way. Importing it again would write the rows that already landed a second time, so fix the file (or keep only the rows below the ones that landed) and choose it again." : ". What landed and what was refused is below. To import another file, choose it above."
|
|
11493
|
+
source ? `These rows have been sent to this table${ledger && !ledger.final ? ", but the run stopped part-way." : ". What landed and what was refused is below."}` : fileName ? `${fileName} has been sent to this table` : "This file has been sent to this table",
|
|
11494
|
+
source ? null : ledger && !ledger.final ? ", but the run stopped part-way. Importing it again would write the rows that already landed a second time, so fix the file (or keep only the rows below the ones that landed) and choose it again." : ". What landed and what was refused is below. To import another file, choose it above."
|
|
11398
11495
|
] }) : null,
|
|
11399
11496
|
plan && parsed && !afterWrite ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
11400
11497
|
titleKey ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded border bg-muted/40 px-2 py-1.5", children: [
|
|
@@ -13554,7 +13651,7 @@ function useGridAssist(args) {
|
|
|
13554
13651
|
(ok, message) => ok ? host.notify?.success(message) : host.notify?.error(message),
|
|
13555
13652
|
[host.notify]
|
|
13556
13653
|
);
|
|
13557
|
-
const
|
|
13654
|
+
const rowOf2 = (0, import_react71.useCallback)((rowId) => rows.find((r) => r.id === rowId), [rows]);
|
|
13558
13655
|
const titleOf = (0, import_react71.useCallback)(
|
|
13559
13656
|
(row) => row ? recordNameIn(table, row.document ?? {}) : "",
|
|
13560
13657
|
[table]
|
|
@@ -13644,18 +13741,18 @@ function useGridAssist(args) {
|
|
|
13644
13741
|
);
|
|
13645
13742
|
const openWhole = (0, import_react71.useCallback)(
|
|
13646
13743
|
(rowId, key) => {
|
|
13647
|
-
const row =
|
|
13744
|
+
const row = rowOf2(rowId);
|
|
13648
13745
|
if (!row) return;
|
|
13649
13746
|
const document2 = row.document ?? {};
|
|
13650
13747
|
const value = editing.valueFor(row, fieldOf2(key));
|
|
13651
13748
|
const pointer = typeof document2[key] === "string" ? (0, import_core9.wholeValueOf)(document2, key) : null;
|
|
13652
13749
|
setWhole({ rowId, key, rowTitle: titleOf(row), value, pointer });
|
|
13653
13750
|
},
|
|
13654
|
-
[
|
|
13751
|
+
[rowOf2, fieldOf2, titleOf, editing]
|
|
13655
13752
|
);
|
|
13656
13753
|
const cellItems = (0, import_react71.useCallback)(
|
|
13657
13754
|
(rowId, columnId) => {
|
|
13658
|
-
const row =
|
|
13755
|
+
const row = rowOf2(rowId);
|
|
13659
13756
|
const field2 = fieldOf2(columnId);
|
|
13660
13757
|
if (!row || !field2) return [];
|
|
13661
13758
|
const items = [];
|
|
@@ -13680,11 +13777,11 @@ function useGridAssist(args) {
|
|
|
13680
13777
|
items.push(...refItem("cell-reference", "Copy cell reference", refFor.cell(row, field2), "The cell"));
|
|
13681
13778
|
return items;
|
|
13682
13779
|
},
|
|
13683
|
-
[
|
|
13780
|
+
[rowOf2, fieldOf2, openWhole, host.cleanText, editing, args, refItem, refFor]
|
|
13684
13781
|
);
|
|
13685
13782
|
const rowItems = (0, import_react71.useCallback)(
|
|
13686
13783
|
(rowId) => {
|
|
13687
|
-
const row =
|
|
13784
|
+
const row = rowOf2(rowId);
|
|
13688
13785
|
const askAgent = args.askAgent;
|
|
13689
13786
|
return [
|
|
13690
13787
|
...rowActionMenuItems({
|
|
@@ -13699,7 +13796,7 @@ function useGridAssist(args) {
|
|
|
13699
13796
|
...row ? refItem("row-reference", "Copy row reference", refFor.row(row), "The row") : []
|
|
13700
13797
|
];
|
|
13701
13798
|
},
|
|
13702
|
-
[
|
|
13799
|
+
[rowOf2, args, fields, refItem, refFor]
|
|
13703
13800
|
);
|
|
13704
13801
|
const tableItems = (0, import_react71.useCallback)(
|
|
13705
13802
|
() => refItem("table-reference", "Copy table reference", refFor.table(), "The table"),
|
|
@@ -14630,6 +14727,7 @@ function Grid({
|
|
|
14630
14727
|
[merged, fields.data, filter, query.columnFilters]
|
|
14631
14728
|
);
|
|
14632
14729
|
const drillState = useGridDrillQuestion({
|
|
14730
|
+
tableId,
|
|
14633
14731
|
fields: fields.data ?? NO_DRILL_FIELDS,
|
|
14634
14732
|
presentation,
|
|
14635
14733
|
filter: question.filter,
|