@ai-matrx/records-ui 0.101.11 → 0.101.15
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 +18 -0
- package/dist/index.cjs +165 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +165 -47
- package/dist/index.js.map +1 -1
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.101.15
|
|
4
|
+
|
|
5
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
6
|
+
`git diff npm/records-ui/v0.101.14..npm/records-ui/v0.101.15 -- apps/shared/records-ui`).
|
|
7
|
+
No source changes intended and no consumer action required.
|
|
8
|
+
|
|
9
|
+
## 0.101.14
|
|
10
|
+
|
|
11
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
12
|
+
`git diff npm/records-ui/v0.101.11..npm/records-ui/v0.101.14 -- apps/shared/records-ui`).
|
|
13
|
+
No source changes intended and no consumer action required.
|
|
14
|
+
|
|
15
|
+
## 0.101.12
|
|
16
|
+
|
|
17
|
+
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
18
|
+
`git diff npm/records-ui/v0.101.11..npm/records-ui/v0.101.12 -- apps/shared/records-ui`).
|
|
19
|
+
No source changes intended and no consumer action required.
|
|
20
|
+
|
|
3
21
|
## 0.101.11
|
|
4
22
|
|
|
5
23
|
- **The Action Inbox key hints answer to the inbox's width, not the screen's.** In a ~360px window on
|
package/dist/index.cjs
CHANGED
|
@@ -7696,6 +7696,7 @@ function containsPattern(text) {
|
|
|
7696
7696
|
var BLANK_VALUE = "__empty__";
|
|
7697
7697
|
var field = (f) => ({ field: f.id });
|
|
7698
7698
|
var constant = (value) => ({ const: value });
|
|
7699
|
+
var withinWindow = (f, window2) => ({ op: "within", args: [field(f), constant(window2)] });
|
|
7699
7700
|
var op = (name, ...args) => ({ op: name, args });
|
|
7700
7701
|
function clauseFor(f, value, now = /* @__PURE__ */ new Date()) {
|
|
7701
7702
|
const name = fieldName(f);
|
|
@@ -7725,12 +7726,12 @@ function clauseFor(f, value, now = /* @__PURE__ */ new Date()) {
|
|
|
7725
7726
|
const kind = String(editorKindFor(f));
|
|
7726
7727
|
if (kind === "datetime" || kind === "date") {
|
|
7727
7728
|
if (words2.length === 0) return { rule: value.negated ? present : not(present) };
|
|
7728
|
-
if (words2.length > 1 || blank || value.negated) {
|
|
7729
|
-
return `${name} is asked one ticked day at a time. Use the date range for more.`;
|
|
7730
|
-
}
|
|
7731
|
-
const day = words2[0];
|
|
7732
7729
|
const holdsDays = String((f.config ?? {})["kind"] ?? "") === "date";
|
|
7733
|
-
return { flat: { [f.key]: dayWindow(
|
|
7730
|
+
if (words2.length === 1 && !blank && !value.negated) return { flat: { [f.key]: dayWindow(words2[0], holdsDays) } };
|
|
7731
|
+
const leaves = words2.map((day) => withinWindow(f, dayWindow(day, holdsDays)));
|
|
7732
|
+
const anyDay = leaves.length === 1 ? leaves[0] : op("or", ...leaves);
|
|
7733
|
+
if (!value.negated) return { rule: blank ? op("or", not(present), anyDay) : anyDay };
|
|
7734
|
+
return { rule: blank ? op("and", present, not(anyDay)) : not(anyDay) };
|
|
7734
7735
|
}
|
|
7735
7736
|
const asStored = (w) => holdsNumbers(f) || kind === "rating" ? Number.isFinite(Number(w)) ? Number(w) : w : kind === "checkbox" && (w === "true" || w === "false") ? w === "true" : w;
|
|
7736
7737
|
const stored = words2.map(asStored);
|
|
@@ -7813,7 +7814,7 @@ function storeQuestion(fields, base, columnFilters, now = /* @__PURE__ */ new Da
|
|
|
7813
7814
|
const value = flat[key];
|
|
7814
7815
|
if (!f) continue;
|
|
7815
7816
|
if (value !== null && typeof value === "object") {
|
|
7816
|
-
|
|
7817
|
+
rules.push(withinWindow(f, value));
|
|
7817
7818
|
continue;
|
|
7818
7819
|
}
|
|
7819
7820
|
rules.push(value === null ? op("not", op("present", field(f))) : op("eq", field(f), constant(value)));
|
|
@@ -13732,6 +13733,44 @@ function replanPastedBlock(plan, args, change = {}) {
|
|
|
13732
13733
|
droppedLines: (plan.droppedLines ?? 0) + dropped
|
|
13733
13734
|
});
|
|
13734
13735
|
}
|
|
13736
|
+
function storedValueAgrees(field2, stored, written, options) {
|
|
13737
|
+
const empty = (v) => v === void 0 || v === null || v === "";
|
|
13738
|
+
if (empty(stored) || empty(written)) return empty(stored) && empty(written);
|
|
13739
|
+
if (field2 !== void 0) {
|
|
13740
|
+
if (isDateField(field2)) {
|
|
13741
|
+
if (hasTimePart(written)) {
|
|
13742
|
+
const a = new Date(stored).getTime();
|
|
13743
|
+
const b = new Date(written).getTime();
|
|
13744
|
+
if (!Number.isNaN(a) && !Number.isNaN(b)) return a === b;
|
|
13745
|
+
} else {
|
|
13746
|
+
const dayOf = (v) => typeof v === "string" && /^\d{4}-\d{2}-\d{2}/.test(v.trim()) ? v.trim().slice(0, 10) : calendarDayOf(v);
|
|
13747
|
+
const a = dayOf(stored);
|
|
13748
|
+
const b = dayOf(written);
|
|
13749
|
+
if (a !== null && b !== null) return a === b;
|
|
13750
|
+
}
|
|
13751
|
+
}
|
|
13752
|
+
const kind = editorKindFor(field2);
|
|
13753
|
+
if (kind === "number" || kind === "currency" || kind === "percent") {
|
|
13754
|
+
const a = typeof stored === "number" ? stored : Number(String(stored).trim());
|
|
13755
|
+
const b = typeof written === "number" ? written : Number(String(written).trim());
|
|
13756
|
+
if (Number.isFinite(a) && Number.isFinite(b)) return a === b;
|
|
13757
|
+
}
|
|
13758
|
+
if (options !== void 0 && typeof stored === "string" && typeof written === "string") {
|
|
13759
|
+
const option = (v) => options.byWord.get(v.trim().toLowerCase()) ?? v.trim().toLowerCase();
|
|
13760
|
+
return option(stored) === option(written);
|
|
13761
|
+
}
|
|
13762
|
+
}
|
|
13763
|
+
return JSON.stringify(stored) === JSON.stringify(written);
|
|
13764
|
+
}
|
|
13765
|
+
function columnsTheGridTurnedAway(turnedAway, columnKeys, columnName, already) {
|
|
13766
|
+
const said = /* @__PURE__ */ new Map();
|
|
13767
|
+
for (const refused of turnedAway) {
|
|
13768
|
+
if (!columnKeys.includes(refused.columnId)) continue;
|
|
13769
|
+
if (already.some((r) => r.column === columnName(refused.columnId))) continue;
|
|
13770
|
+
said.set(refused.columnId, refused.reason);
|
|
13771
|
+
}
|
|
13772
|
+
return [...said].map(([columnId, why]) => ({ fromLine: 0, column: columnName(columnId), raw: "", why }));
|
|
13773
|
+
}
|
|
13735
13774
|
|
|
13736
13775
|
// src/gridControls.tsx
|
|
13737
13776
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
@@ -13840,26 +13879,26 @@ function useMergedGridControls(args) {
|
|
|
13840
13879
|
);
|
|
13841
13880
|
const choiceKeys = (0, import_react77.useMemo)(() => enabled ? fields.filter(isChoiceField).map((f) => f.key) : [], [enabled, fields]);
|
|
13842
13881
|
const choiceOptions = useChoiceOptions(fields, choiceKeys);
|
|
13843
|
-
const
|
|
13844
|
-
const countQuestionKey = JSON.stringify([choiceKeys, query.columnFilters, args.filter ?? null]);
|
|
13882
|
+
const searchWords = (args.search ?? "").trim();
|
|
13883
|
+
const countQuestionKey = JSON.stringify([choiceKeys, query.columnFilters, args.filter ?? null, searchWords]);
|
|
13845
13884
|
const rowsKey = rows.map((row) => `${row.id}:${row.version ?? ""}`).join(",");
|
|
13846
13885
|
const fieldsRef = (0, import_react77.useRef)(fields);
|
|
13847
13886
|
fieldsRef.current = fields;
|
|
13848
13887
|
const [choiceCounts, setChoiceCounts] = (0, import_react77.useState)({});
|
|
13849
13888
|
(0, import_react77.useEffect)(() => {
|
|
13850
|
-
if (!enabled ||
|
|
13889
|
+
if (!enabled || choiceKeys.length === 0) {
|
|
13851
13890
|
setChoiceCounts({});
|
|
13852
13891
|
return;
|
|
13853
13892
|
}
|
|
13854
13893
|
let cancelled = false;
|
|
13855
|
-
const [keys, filters, base] = JSON.parse(countQuestionKey);
|
|
13894
|
+
const [keys, filters, base, searched] = JSON.parse(countQuestionKey);
|
|
13856
13895
|
for (const key of keys) {
|
|
13857
13896
|
const { [key]: _own, ...others } = filters;
|
|
13858
13897
|
const asked3 = storeQuestion(fieldsRef.current, base ?? void 0, others);
|
|
13859
13898
|
void askOnce(
|
|
13860
13899
|
client,
|
|
13861
|
-
`value_counts:${tableId}:${key}:${JSON.stringify(asked3.filter ?? null)}`,
|
|
13862
|
-
() => client.recordAggregate({ table_id: tableId, groupBy: [key], measures: [{ op: "count" }], ...asked3.filter ? { filter: asked3.filter } : {}, limit: 500 }),
|
|
13900
|
+
`value_counts:${tableId}:${key}:${searched}:${JSON.stringify(asked3.filter ?? null)}`,
|
|
13901
|
+
() => client.recordAggregate({ table_id: tableId, groupBy: [key], measures: [{ op: "count" }], ...asked3.filter ? { filter: asked3.filter } : {}, ...searched ? { search: searched } : {}, limit: 500 }),
|
|
13863
13902
|
VALUE_COUNTS_FRESH_MS
|
|
13864
13903
|
).then((answer) => {
|
|
13865
13904
|
if (cancelled || !answer.ok) return;
|
|
@@ -13875,7 +13914,7 @@ function useMergedGridControls(args) {
|
|
|
13875
13914
|
return () => {
|
|
13876
13915
|
cancelled = true;
|
|
13877
13916
|
};
|
|
13878
|
-
}, [enabled,
|
|
13917
|
+
}, [enabled, countQuestionKey, client, tableId, rowsKey]);
|
|
13879
13918
|
const filterFor = (0, import_react77.useCallback)(
|
|
13880
13919
|
(key) => {
|
|
13881
13920
|
if (!enabled) return void 0;
|
|
@@ -15503,12 +15542,7 @@ function PastePreview({
|
|
|
15503
15542
|
plan.refusals.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { "data-matrx-paste-refusals": true, className: "flex flex-col gap-1", children: [
|
|
15504
15543
|
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "text-xs font-medium", children: plan.refusals.length === 1 ? "One cell will be left alone:" : `${plan.refusals.length} cells will be left alone:` }),
|
|
15505
15544
|
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("ul", { className: "flex flex-col gap-1", children: plan.refusals.slice(0, 12).map((refusal3, index) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("li", { className: "text-xs text-muted-foreground", children: [
|
|
15506
|
-
/* @__PURE__ */ (0, import_jsx_runtime51.
|
|
15507
|
-
"Row ",
|
|
15508
|
-
refusal3.fromLine,
|
|
15509
|
-
", ",
|
|
15510
|
-
refusal3.column
|
|
15511
|
-
] }),
|
|
15545
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "font-medium", children: refusal3.fromLine > 0 ? `Row ${refusal3.fromLine}, ${refusal3.column}` : refusal3.column }),
|
|
15512
15546
|
" \u2014 ",
|
|
15513
15547
|
refusal3.why
|
|
15514
15548
|
] }, index)) }),
|
|
@@ -19192,7 +19226,8 @@ async function askColumnValues(inputs, args) {
|
|
|
19192
19226
|
const field2 = inputs.fields.find((f) => f.key === args.columnId);
|
|
19193
19227
|
const kind = valueListKind(field2);
|
|
19194
19228
|
if (kind === "none") return noValueList(args.columnId);
|
|
19195
|
-
if (kind === "loaded"
|
|
19229
|
+
if (kind === "loaded") return null;
|
|
19230
|
+
const searched = args.search.trim();
|
|
19196
19231
|
const { [args.columnId]: _own, ...others } = inputs.columnFilters;
|
|
19197
19232
|
const asked3 = storeQuestion(inputs.fields, inputs.filter, others);
|
|
19198
19233
|
const limit = Math.min(Math.max(args.limit, 1), MOST_VALUES);
|
|
@@ -19201,6 +19236,7 @@ async function askColumnValues(inputs, args) {
|
|
|
19201
19236
|
...kind === "days" ? { bucket: { key: field2.key, by: "day" } } : { groupBy: [field2.key] },
|
|
19202
19237
|
measures: [{ op: "count" }],
|
|
19203
19238
|
...asked3.filter ? { filter: asked3.filter } : {},
|
|
19239
|
+
...searched ? { search: searched } : {},
|
|
19204
19240
|
limit: MOST_VALUES
|
|
19205
19241
|
});
|
|
19206
19242
|
if (!answer.ok) throw new Error(refusalSentence(answer.error));
|
|
@@ -19212,7 +19248,8 @@ async function askColumnValues(inputs, args) {
|
|
|
19212
19248
|
const unique = await inputs.client.recordAggregate({
|
|
19213
19249
|
table_id: inputs.tableId,
|
|
19214
19250
|
measures: [{ op: "unique", key: field2.key }],
|
|
19215
|
-
...asked3.filter ? { filter: asked3.filter } : {}
|
|
19251
|
+
...asked3.filter ? { filter: asked3.filter } : {},
|
|
19252
|
+
...searched ? { search: searched } : {}
|
|
19216
19253
|
});
|
|
19217
19254
|
if (unique.ok) {
|
|
19218
19255
|
const n = Number(unique.data?.[0]?.measures?.[`unique_${field2.key}`]);
|
|
@@ -21280,19 +21317,9 @@ function GridBody({
|
|
|
21280
21317
|
pastRightEdge: sheetPlan.pastRightEdge,
|
|
21281
21318
|
...headed ? { header: { unmatched: headed.unmatched } } : {}
|
|
21282
21319
|
});
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
|
|
21286
|
-
notWritable.set(refused.columnId, refused.reason);
|
|
21287
|
-
}
|
|
21288
|
-
for (const [columnId, why] of notWritable) {
|
|
21289
|
-
built.refusals.push({
|
|
21290
|
-
fromLine: 0,
|
|
21291
|
-
column: columnLabel(fieldList, columnId),
|
|
21292
|
-
raw: "",
|
|
21293
|
-
why
|
|
21294
|
-
});
|
|
21295
|
-
}
|
|
21320
|
+
built.refusals.push(
|
|
21321
|
+
...columnsTheGridTurnedAway(sheetPlan.refusals, columnKeys, (id) => columnLabel(fieldList, id), built.refusals)
|
|
21322
|
+
);
|
|
21296
21323
|
if (merged && built.cells > 0 && built.creates === 0 && built.refusals.length === 0 && built.pastRightEdge === 0 && (built.header?.unmatched.length ?? 0) === 0 && built.unmatchedOptions.length === 0) {
|
|
21297
21324
|
const outcome = await pasteAtOnce.current(built);
|
|
21298
21325
|
if (outcome.refusals.length > 0 || outcome.missing > 0) {
|
|
@@ -21393,20 +21420,21 @@ function GridBody({
|
|
|
21393
21420
|
const reread = await client.listByIds({ table_id: tableId, ids: expected.map((e) => e.recordId) });
|
|
21394
21421
|
let readBack = 0;
|
|
21395
21422
|
let missing = 0;
|
|
21423
|
+
const fieldOf2 = new Map((fields.data ?? []).map((f) => [f.key, f]));
|
|
21396
21424
|
const refusals = [];
|
|
21397
21425
|
if (!reread.ok) refusals.push(`The rows were written and this could not read them back to check: ${refusalSentence(reread.error)}`);
|
|
21398
21426
|
const seen = new Map((reread.ok ? reread.data : []).map((r) => [r.id, r.document ?? {}]));
|
|
21399
21427
|
for (const entry of expected) {
|
|
21400
21428
|
const stored = seen.get(entry.recordId);
|
|
21401
21429
|
for (const [key, value] of Object.entries(entry.document)) {
|
|
21402
|
-
if (stored !== void 0 &&
|
|
21430
|
+
if (stored !== void 0 && storedValueAgrees(fieldOf2.get(key), stored[key], value, choiceOptions.current.get(key))) readBack += 1;
|
|
21403
21431
|
else missing += 1;
|
|
21404
21432
|
}
|
|
21405
21433
|
}
|
|
21406
21434
|
records.reload();
|
|
21407
21435
|
return { written: lines, readBack, missing, refusals };
|
|
21408
21436
|
},
|
|
21409
|
-
[rows, client, tableId, editing, undo, records, versions]
|
|
21437
|
+
[rows, client, tableId, editing, undo, records, versions, fields.data]
|
|
21410
21438
|
);
|
|
21411
21439
|
const pasteAtOnce = (0, import_react107.useRef)(applyPasteAsOne);
|
|
21412
21440
|
pasteAtOnce.current = applyPasteAsOne;
|
|
@@ -21481,6 +21509,7 @@ function GridBody({
|
|
|
21481
21509
|
}
|
|
21482
21510
|
let readBack = 0;
|
|
21483
21511
|
let missing = 0;
|
|
21512
|
+
const fieldOf2 = new Map((fields.data ?? []).map((f) => [f.key, f]));
|
|
21484
21513
|
const seen = /* @__PURE__ */ new Map();
|
|
21485
21514
|
const READ_BACK_PAGE = 500;
|
|
21486
21515
|
for (let offset = 0; ; offset += READ_BACK_PAGE) {
|
|
@@ -21500,7 +21529,7 @@ function GridBody({
|
|
|
21500
21529
|
for (const entry of expected) {
|
|
21501
21530
|
const stored = seen.get(entry.recordId);
|
|
21502
21531
|
for (const [key, value] of Object.entries(entry.document)) {
|
|
21503
|
-
if (stored !== void 0 &&
|
|
21532
|
+
if (stored !== void 0 && storedValueAgrees(fieldOf2.get(key), stored[key], value, choiceOptions.current.get(key))) {
|
|
21504
21533
|
readBack += 1;
|
|
21505
21534
|
} else {
|
|
21506
21535
|
missing += 1;
|
|
@@ -21509,7 +21538,7 @@ function GridBody({
|
|
|
21509
21538
|
}
|
|
21510
21539
|
records.reload();
|
|
21511
21540
|
return { written, readBack, missing, refusals };
|
|
21512
|
-
}, [pastePlan, client, tableId, records, merged, applyPasteAsOne, versions]);
|
|
21541
|
+
}, [pastePlan, client, tableId, records, merged, applyPasteAsOne, versions, fields.data]);
|
|
21513
21542
|
const columnIds = (0, import_react107.useMemo)(() => ordered.map((field2) => field2.key), [ordered]);
|
|
21514
21543
|
const lookWrites = (0, import_react107.useRef)(null);
|
|
21515
21544
|
const writeLook = (0, import_react107.useCallback)(
|
|
@@ -21631,6 +21660,7 @@ function GridBody({
|
|
|
21631
21660
|
writeLook,
|
|
21632
21661
|
query,
|
|
21633
21662
|
...filter ? { filter } : {},
|
|
21663
|
+
search: searchTerm,
|
|
21634
21664
|
setQuery,
|
|
21635
21665
|
duplicate: (row) => void duplicate(row),
|
|
21636
21666
|
askDelete: setDeleting,
|
|
@@ -23132,6 +23162,7 @@ var import_records40 = require("@ai-matrx/records");
|
|
|
23132
23162
|
var import_design_system67 = require("@ai-matrx/design-system");
|
|
23133
23163
|
|
|
23134
23164
|
// src/newTableColumns.ts
|
|
23165
|
+
var import_templates = require("@ai-matrx/records/templates");
|
|
23135
23166
|
var NEW_COLUMN_TYPES = [
|
|
23136
23167
|
{ type: "text", words: "Text" },
|
|
23137
23168
|
{ type: "rich_text", words: "Formatted text" },
|
|
@@ -23149,7 +23180,80 @@ var NEW_COLUMN_TYPES = [
|
|
|
23149
23180
|
];
|
|
23150
23181
|
var MOST_NEW_COLUMNS = 40;
|
|
23151
23182
|
var BULLET = /^\s*(?:[-*•]|\d+[.)])\s+/;
|
|
23152
|
-
|
|
23183
|
+
var TYPE_WORD_ALIASES = {
|
|
23184
|
+
choice: "select",
|
|
23185
|
+
dropdown: "select",
|
|
23186
|
+
status: "select",
|
|
23187
|
+
list: "select",
|
|
23188
|
+
choices: "multi_select",
|
|
23189
|
+
tags: "multi_select",
|
|
23190
|
+
money: "currency",
|
|
23191
|
+
boolean: "checkbox",
|
|
23192
|
+
bool: "checkbox",
|
|
23193
|
+
"yes/no": "checkbox",
|
|
23194
|
+
"yes / no": "checkbox",
|
|
23195
|
+
link: "url",
|
|
23196
|
+
integer: "number",
|
|
23197
|
+
decimal: "number",
|
|
23198
|
+
float: "number",
|
|
23199
|
+
string: "text",
|
|
23200
|
+
long_text: "rich_text",
|
|
23201
|
+
"formatted text": "rich_text",
|
|
23202
|
+
"date and time": "datetime",
|
|
23203
|
+
"date time": "datetime"
|
|
23204
|
+
};
|
|
23205
|
+
function typeFromWord(raw) {
|
|
23206
|
+
const word = raw.trim().toLowerCase();
|
|
23207
|
+
if (word === "") return void 0;
|
|
23208
|
+
const type = TYPE_WORD_ALIASES[word] ?? NEW_COLUMN_TYPES.find((t) => t.type === word.replace(/[\s-]+/g, "_"))?.type;
|
|
23209
|
+
if (!type) return void 0;
|
|
23210
|
+
return import_templates.RESOLVABLE_FIELD_TYPE_WORDS.includes(type === "date" ? "datetime" : type) ? type : void 0;
|
|
23211
|
+
}
|
|
23212
|
+
function maskBrackets(text) {
|
|
23213
|
+
let depth = 0;
|
|
23214
|
+
let out = "";
|
|
23215
|
+
for (const ch of text) {
|
|
23216
|
+
if (ch === "(" || ch === "[") {
|
|
23217
|
+
depth++;
|
|
23218
|
+
out += depth === 1 ? ch : "\0";
|
|
23219
|
+
} else if ((ch === ")" || ch === "]") && depth > 0) {
|
|
23220
|
+
depth--;
|
|
23221
|
+
out += depth === 0 ? ch : "\0";
|
|
23222
|
+
} else out += depth > 0 ? "\0" : ch;
|
|
23223
|
+
}
|
|
23224
|
+
return out;
|
|
23225
|
+
}
|
|
23226
|
+
function splitOutsideBrackets(text, sep) {
|
|
23227
|
+
const masked = maskBrackets(text);
|
|
23228
|
+
const parts = [];
|
|
23229
|
+
let from = 0;
|
|
23230
|
+
const re = new RegExp(sep.source, sep.flags.includes("g") ? sep.flags : sep.flags + "g");
|
|
23231
|
+
for (const m of masked.matchAll(re)) {
|
|
23232
|
+
if (m[0] === "") continue;
|
|
23233
|
+
parts.push(text.slice(from, m.index));
|
|
23234
|
+
from = m.index + m[0].length;
|
|
23235
|
+
}
|
|
23236
|
+
parts.push(text.slice(from));
|
|
23237
|
+
return parts;
|
|
23238
|
+
}
|
|
23239
|
+
function specFromPart(part) {
|
|
23240
|
+
const clean = (t) => t.replace(/^["'\s]+|["'.\s]+$/g, "").replace(/\s+/g, " ");
|
|
23241
|
+
const m = /^(.*?)\s*[(\[]([^()\[\]]*)[)\]]\s*$/.exec(part.trim());
|
|
23242
|
+
if (m) {
|
|
23243
|
+
const inner2 = m[2];
|
|
23244
|
+
const colon = inner2.indexOf(":");
|
|
23245
|
+
const type = typeFromWord(colon >= 0 ? inner2.slice(0, colon) : inner2);
|
|
23246
|
+
const name = clean(m[1]);
|
|
23247
|
+
if (type && name !== "") {
|
|
23248
|
+
const options = colon >= 0 ? [...new Set(inner2.slice(colon + 1).split(/\s*[,;|]\s*/).map(clean).filter((o) => o !== ""))] : void 0;
|
|
23249
|
+
return { label: name, type, ...options && options.length > 0 && (type === "select" || type === "multi_select") ? { options } : {} };
|
|
23250
|
+
}
|
|
23251
|
+
}
|
|
23252
|
+
const withoutPairs = part.replace(/\([^()\[\]]*\)|\[[^()\[\]]*\]/g, "");
|
|
23253
|
+
const label = /[()\[\]]/.test(withoutPairs) ? part.replace(/[()\[\]]/g, " ") : part;
|
|
23254
|
+
return { label: clean(label) };
|
|
23255
|
+
}
|
|
23256
|
+
function specsFrom(text) {
|
|
23153
23257
|
const trimmed = text.trim();
|
|
23154
23258
|
if (trimmed === "") return [];
|
|
23155
23259
|
let parts;
|
|
@@ -23160,23 +23264,28 @@ function columnNamesFrom(text) {
|
|
|
23160
23264
|
parts = trimmed.split(/\r?\n/).map((line) => line.replace(BULLET, ""));
|
|
23161
23265
|
} else {
|
|
23162
23266
|
let line = trimmed;
|
|
23163
|
-
const
|
|
23267
|
+
const masked = maskBrackets(line);
|
|
23268
|
+
const colon = masked.indexOf(":");
|
|
23164
23269
|
if (colon >= 0) line = line.slice(colon + 1);
|
|
23165
23270
|
else {
|
|
23166
|
-
const withAt =
|
|
23271
|
+
const withAt = masked.toLowerCase().lastIndexOf(" with ");
|
|
23167
23272
|
if (withAt >= 0) line = line.slice(withAt + " with ".length);
|
|
23168
23273
|
}
|
|
23169
|
-
parts = line
|
|
23274
|
+
parts = splitOutsideBrackets(line, /\s*[,;|]\s*|\s+and\s+|\s*&\s*/i);
|
|
23170
23275
|
}
|
|
23171
|
-
const
|
|
23276
|
+
const specs = parts.map(specFromPart).filter((c) => c.label !== "").map((c) => c.label === c.label.toLowerCase() ? { ...c, label: c.label[0].toUpperCase() + c.label.slice(1) } : c);
|
|
23172
23277
|
const seen = /* @__PURE__ */ new Set();
|
|
23173
|
-
const once =
|
|
23174
|
-
const k =
|
|
23278
|
+
const once = specs.filter((c) => {
|
|
23279
|
+
const k = c.label.toLowerCase();
|
|
23175
23280
|
if (seen.has(k)) return false;
|
|
23176
23281
|
seen.add(k);
|
|
23177
23282
|
return true;
|
|
23178
23283
|
});
|
|
23179
|
-
|
|
23284
|
+
const labels = uniqueLabels(once.map((c) => c.label));
|
|
23285
|
+
return once.map((c, i) => ({ ...c, label: labels[i] })).slice(0, MOST_NEW_COLUMNS);
|
|
23286
|
+
}
|
|
23287
|
+
function columnNamesFrom(text) {
|
|
23288
|
+
return specsFrom(text).map((c) => c.label);
|
|
23180
23289
|
}
|
|
23181
23290
|
var STATUS_CHOICES = ["Not started", "In progress", "Done"];
|
|
23182
23291
|
var PRIORITY_CHOICES = ["Low", "Medium", "High"];
|
|
@@ -23201,7 +23310,9 @@ function columnFromName(label) {
|
|
|
23201
23310
|
return { label, type: "text" };
|
|
23202
23311
|
}
|
|
23203
23312
|
function columnsFrom(text) {
|
|
23204
|
-
return
|
|
23313
|
+
return specsFrom(text).map(
|
|
23314
|
+
(c) => c.type ? { label: c.label, type: c.type, ...c.options && c.options.length > 0 ? { options: c.options } : {} } : columnFromName(c.label)
|
|
23315
|
+
);
|
|
23205
23316
|
}
|
|
23206
23317
|
function fieldsForNewColumns(columns) {
|
|
23207
23318
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -27032,8 +27143,15 @@ function bodyFieldOf(fields) {
|
|
|
27032
27143
|
var BODY_COLUMN_NAME = "Notes";
|
|
27033
27144
|
var BODY_SAVE_PAUSE_MS = 900;
|
|
27034
27145
|
function RecordBody({ tableId, recordId, className }) {
|
|
27146
|
+
const host = useRecordsUi();
|
|
27035
27147
|
const fields = (0, import_react150.useFields)(tableId);
|
|
27148
|
+
const hostRecord = (0, import_react150.useRecord)(recordId, true, { tableId });
|
|
27149
|
+
const hostMay = useRecordRights(recordId);
|
|
27036
27150
|
const field2 = bodyFieldOf(fields.data ?? []);
|
|
27151
|
+
const hostBody = host.renderRecordBody && hostRecord.data ? host.renderRecordBody({ tableId, recordId, record: hostRecord.data, readOnly: !hostMay.write }) : null;
|
|
27152
|
+
if (hostBody !== null && hostBody !== void 0) {
|
|
27153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("section", { className: (0, import_design_system80.cn)("flex min-w-0 flex-col gap-1.5", className), "data-record-body": "host", children: hostBody });
|
|
27154
|
+
}
|
|
27037
27155
|
if (fields.loading && !fields.data) return null;
|
|
27038
27156
|
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("section", { className: (0, import_design_system80.cn)("flex min-w-0 flex-col gap-1.5", className), "data-record-body": field2?.key ?? "", children: field2 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BodyEditor, { tableId, recordId, field: field2 }, `${recordId}:${field2.key}`) : /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(AddBody, { tableId }) });
|
|
27039
27157
|
}
|