@ai-matrx/records-ui 0.101.11 → 0.101.14
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 +12 -0
- package/dist/index.cjs +138 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +138 -32
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -6699,6 +6699,7 @@ declare const MOST_NEW_COLUMNS = 40;
|
|
|
6699
6699
|
* The column NAMES a person typed or pasted, in order, each once. Empty when there are none.
|
|
6700
6700
|
* A tab means a spreadsheet header row; several lines mean a list; otherwise one line split on
|
|
6701
6701
|
* commas, semicolons, pipes and a last "and" — after "with" or a colon when it is a sentence.
|
|
6702
|
+
* Only OUTSIDE brackets: "Status (choice: a, b)" is one column.
|
|
6702
6703
|
*/
|
|
6703
6704
|
declare function columnNamesFrom(text: string): string[];
|
|
6704
6705
|
/** What a column of this NAME most likely holds. Text when nothing in the name says otherwise. */
|
package/dist/index.d.ts
CHANGED
|
@@ -6699,6 +6699,7 @@ declare const MOST_NEW_COLUMNS = 40;
|
|
|
6699
6699
|
* The column NAMES a person typed or pasted, in order, each once. Empty when there are none.
|
|
6700
6700
|
* A tab means a spreadsheet header row; several lines mean a list; otherwise one line split on
|
|
6701
6701
|
* commas, semicolons, pipes and a last "and" — after "with" or a colon when it is a sentence.
|
|
6702
|
+
* Only OUTSIDE brackets: "Status (choice: a, b)" is one column.
|
|
6702
6703
|
*/
|
|
6703
6704
|
declare function columnNamesFrom(text: string): string[];
|
|
6704
6705
|
/** What a column of this NAME most likely holds. Text when nothing in the name says otherwise. */
|
package/dist/index.js
CHANGED
|
@@ -13375,6 +13375,44 @@ function replanPastedBlock(plan, args, change = {}) {
|
|
|
13375
13375
|
droppedLines: (plan.droppedLines ?? 0) + dropped
|
|
13376
13376
|
});
|
|
13377
13377
|
}
|
|
13378
|
+
function storedValueAgrees(field2, stored, written, options) {
|
|
13379
|
+
const empty = (v) => v === void 0 || v === null || v === "";
|
|
13380
|
+
if (empty(stored) || empty(written)) return empty(stored) && empty(written);
|
|
13381
|
+
if (field2 !== void 0) {
|
|
13382
|
+
if (isDateField(field2)) {
|
|
13383
|
+
if (hasTimePart(written)) {
|
|
13384
|
+
const a = new Date(stored).getTime();
|
|
13385
|
+
const b = new Date(written).getTime();
|
|
13386
|
+
if (!Number.isNaN(a) && !Number.isNaN(b)) return a === b;
|
|
13387
|
+
} else {
|
|
13388
|
+
const dayOf = (v) => typeof v === "string" && /^\d{4}-\d{2}-\d{2}/.test(v.trim()) ? v.trim().slice(0, 10) : calendarDayOf(v);
|
|
13389
|
+
const a = dayOf(stored);
|
|
13390
|
+
const b = dayOf(written);
|
|
13391
|
+
if (a !== null && b !== null) return a === b;
|
|
13392
|
+
}
|
|
13393
|
+
}
|
|
13394
|
+
const kind = editorKindFor(field2);
|
|
13395
|
+
if (kind === "number" || kind === "currency" || kind === "percent") {
|
|
13396
|
+
const a = typeof stored === "number" ? stored : Number(String(stored).trim());
|
|
13397
|
+
const b = typeof written === "number" ? written : Number(String(written).trim());
|
|
13398
|
+
if (Number.isFinite(a) && Number.isFinite(b)) return a === b;
|
|
13399
|
+
}
|
|
13400
|
+
if (options !== void 0 && typeof stored === "string" && typeof written === "string") {
|
|
13401
|
+
const option = (v) => options.byWord.get(v.trim().toLowerCase()) ?? v.trim().toLowerCase();
|
|
13402
|
+
return option(stored) === option(written);
|
|
13403
|
+
}
|
|
13404
|
+
}
|
|
13405
|
+
return JSON.stringify(stored) === JSON.stringify(written);
|
|
13406
|
+
}
|
|
13407
|
+
function columnsTheGridTurnedAway(turnedAway, columnKeys, columnName, already) {
|
|
13408
|
+
const said = /* @__PURE__ */ new Map();
|
|
13409
|
+
for (const refused of turnedAway) {
|
|
13410
|
+
if (!columnKeys.includes(refused.columnId)) continue;
|
|
13411
|
+
if (already.some((r) => r.column === columnName(refused.columnId))) continue;
|
|
13412
|
+
said.set(refused.columnId, refused.reason);
|
|
13413
|
+
}
|
|
13414
|
+
return [...said].map(([columnId, why]) => ({ fromLine: 0, column: columnName(columnId), raw: "", why }));
|
|
13415
|
+
}
|
|
13378
13416
|
|
|
13379
13417
|
// src/gridControls.tsx
|
|
13380
13418
|
import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
@@ -15169,12 +15207,7 @@ function PastePreview({
|
|
|
15169
15207
|
plan.refusals.length > 0 ? /* @__PURE__ */ jsxs47("div", { "data-matrx-paste-refusals": true, className: "flex flex-col gap-1", children: [
|
|
15170
15208
|
/* @__PURE__ */ jsx51("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:` }),
|
|
15171
15209
|
/* @__PURE__ */ jsx51("ul", { className: "flex flex-col gap-1", children: plan.refusals.slice(0, 12).map((refusal3, index) => /* @__PURE__ */ jsxs47("li", { className: "text-xs text-muted-foreground", children: [
|
|
15172
|
-
/* @__PURE__ */
|
|
15173
|
-
"Row ",
|
|
15174
|
-
refusal3.fromLine,
|
|
15175
|
-
", ",
|
|
15176
|
-
refusal3.column
|
|
15177
|
-
] }),
|
|
15210
|
+
/* @__PURE__ */ jsx51("span", { className: "font-medium", children: refusal3.fromLine > 0 ? `Row ${refusal3.fromLine}, ${refusal3.column}` : refusal3.column }),
|
|
15178
15211
|
" \u2014 ",
|
|
15179
15212
|
refusal3.why
|
|
15180
15213
|
] }, index)) }),
|
|
@@ -21006,19 +21039,9 @@ function GridBody({
|
|
|
21006
21039
|
pastRightEdge: sheetPlan.pastRightEdge,
|
|
21007
21040
|
...headed ? { header: { unmatched: headed.unmatched } } : {}
|
|
21008
21041
|
});
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
notWritable.set(refused.columnId, refused.reason);
|
|
21013
|
-
}
|
|
21014
|
-
for (const [columnId, why] of notWritable) {
|
|
21015
|
-
built.refusals.push({
|
|
21016
|
-
fromLine: 0,
|
|
21017
|
-
column: columnLabel(fieldList, columnId),
|
|
21018
|
-
raw: "",
|
|
21019
|
-
why
|
|
21020
|
-
});
|
|
21021
|
-
}
|
|
21042
|
+
built.refusals.push(
|
|
21043
|
+
...columnsTheGridTurnedAway(sheetPlan.refusals, columnKeys, (id) => columnLabel(fieldList, id), built.refusals)
|
|
21044
|
+
);
|
|
21022
21045
|
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) {
|
|
21023
21046
|
const outcome = await pasteAtOnce.current(built);
|
|
21024
21047
|
if (outcome.refusals.length > 0 || outcome.missing > 0) {
|
|
@@ -21119,20 +21142,21 @@ function GridBody({
|
|
|
21119
21142
|
const reread = await client.listByIds({ table_id: tableId, ids: expected.map((e) => e.recordId) });
|
|
21120
21143
|
let readBack = 0;
|
|
21121
21144
|
let missing = 0;
|
|
21145
|
+
const fieldOf2 = new Map((fields.data ?? []).map((f) => [f.key, f]));
|
|
21122
21146
|
const refusals = [];
|
|
21123
21147
|
if (!reread.ok) refusals.push(`The rows were written and this could not read them back to check: ${refusalSentence(reread.error)}`);
|
|
21124
21148
|
const seen = new Map((reread.ok ? reread.data : []).map((r) => [r.id, r.document ?? {}]));
|
|
21125
21149
|
for (const entry of expected) {
|
|
21126
21150
|
const stored = seen.get(entry.recordId);
|
|
21127
21151
|
for (const [key, value] of Object.entries(entry.document)) {
|
|
21128
|
-
if (stored !== void 0 &&
|
|
21152
|
+
if (stored !== void 0 && storedValueAgrees(fieldOf2.get(key), stored[key], value, choiceOptions.current.get(key))) readBack += 1;
|
|
21129
21153
|
else missing += 1;
|
|
21130
21154
|
}
|
|
21131
21155
|
}
|
|
21132
21156
|
records.reload();
|
|
21133
21157
|
return { written: lines, readBack, missing, refusals };
|
|
21134
21158
|
},
|
|
21135
|
-
[rows, client, tableId, editing, undo, records, versions]
|
|
21159
|
+
[rows, client, tableId, editing, undo, records, versions, fields.data]
|
|
21136
21160
|
);
|
|
21137
21161
|
const pasteAtOnce = useRef28(applyPasteAsOne);
|
|
21138
21162
|
pasteAtOnce.current = applyPasteAsOne;
|
|
@@ -21207,6 +21231,7 @@ function GridBody({
|
|
|
21207
21231
|
}
|
|
21208
21232
|
let readBack = 0;
|
|
21209
21233
|
let missing = 0;
|
|
21234
|
+
const fieldOf2 = new Map((fields.data ?? []).map((f) => [f.key, f]));
|
|
21210
21235
|
const seen = /* @__PURE__ */ new Map();
|
|
21211
21236
|
const READ_BACK_PAGE = 500;
|
|
21212
21237
|
for (let offset = 0; ; offset += READ_BACK_PAGE) {
|
|
@@ -21226,7 +21251,7 @@ function GridBody({
|
|
|
21226
21251
|
for (const entry of expected) {
|
|
21227
21252
|
const stored = seen.get(entry.recordId);
|
|
21228
21253
|
for (const [key, value] of Object.entries(entry.document)) {
|
|
21229
|
-
if (stored !== void 0 &&
|
|
21254
|
+
if (stored !== void 0 && storedValueAgrees(fieldOf2.get(key), stored[key], value, choiceOptions.current.get(key))) {
|
|
21230
21255
|
readBack += 1;
|
|
21231
21256
|
} else {
|
|
21232
21257
|
missing += 1;
|
|
@@ -21235,7 +21260,7 @@ function GridBody({
|
|
|
21235
21260
|
}
|
|
21236
21261
|
records.reload();
|
|
21237
21262
|
return { written, readBack, missing, refusals };
|
|
21238
|
-
}, [pastePlan, client, tableId, records, merged, applyPasteAsOne, versions]);
|
|
21263
|
+
}, [pastePlan, client, tableId, records, merged, applyPasteAsOne, versions, fields.data]);
|
|
21239
21264
|
const columnIds = useMemo35(() => ordered.map((field2) => field2.key), [ordered]);
|
|
21240
21265
|
const lookWrites = useRef28(null);
|
|
21241
21266
|
const writeLook = useCallback24(
|
|
@@ -22869,6 +22894,7 @@ import { withTablePlacement as withTablePlacement2 } from "@ai-matrx/records";
|
|
|
22869
22894
|
import { BasicInput as BasicInput17, Button as Button49, Select as Select10, SelectContent as SelectContent10, SelectItem as SelectItem10, SelectTrigger as SelectTrigger10, SelectValue as SelectValue10, Skeleton as Skeleton6, Textarea as Textarea2, cn as cn39 } from "@ai-matrx/design-system";
|
|
22870
22895
|
|
|
22871
22896
|
// src/newTableColumns.ts
|
|
22897
|
+
import { RESOLVABLE_FIELD_TYPE_WORDS } from "@ai-matrx/records/templates";
|
|
22872
22898
|
var NEW_COLUMN_TYPES = [
|
|
22873
22899
|
{ type: "text", words: "Text" },
|
|
22874
22900
|
{ type: "rich_text", words: "Formatted text" },
|
|
@@ -22886,7 +22912,80 @@ var NEW_COLUMN_TYPES = [
|
|
|
22886
22912
|
];
|
|
22887
22913
|
var MOST_NEW_COLUMNS = 40;
|
|
22888
22914
|
var BULLET = /^\s*(?:[-*•]|\d+[.)])\s+/;
|
|
22889
|
-
|
|
22915
|
+
var TYPE_WORD_ALIASES = {
|
|
22916
|
+
choice: "select",
|
|
22917
|
+
dropdown: "select",
|
|
22918
|
+
status: "select",
|
|
22919
|
+
list: "select",
|
|
22920
|
+
choices: "multi_select",
|
|
22921
|
+
tags: "multi_select",
|
|
22922
|
+
money: "currency",
|
|
22923
|
+
boolean: "checkbox",
|
|
22924
|
+
bool: "checkbox",
|
|
22925
|
+
"yes/no": "checkbox",
|
|
22926
|
+
"yes / no": "checkbox",
|
|
22927
|
+
link: "url",
|
|
22928
|
+
integer: "number",
|
|
22929
|
+
decimal: "number",
|
|
22930
|
+
float: "number",
|
|
22931
|
+
string: "text",
|
|
22932
|
+
long_text: "rich_text",
|
|
22933
|
+
"formatted text": "rich_text",
|
|
22934
|
+
"date and time": "datetime",
|
|
22935
|
+
"date time": "datetime"
|
|
22936
|
+
};
|
|
22937
|
+
function typeFromWord(raw) {
|
|
22938
|
+
const word = raw.trim().toLowerCase();
|
|
22939
|
+
if (word === "") return void 0;
|
|
22940
|
+
const type = TYPE_WORD_ALIASES[word] ?? NEW_COLUMN_TYPES.find((t) => t.type === word.replace(/[\s-]+/g, "_"))?.type;
|
|
22941
|
+
if (!type) return void 0;
|
|
22942
|
+
return RESOLVABLE_FIELD_TYPE_WORDS.includes(type === "date" ? "datetime" : type) ? type : void 0;
|
|
22943
|
+
}
|
|
22944
|
+
function maskBrackets(text) {
|
|
22945
|
+
let depth = 0;
|
|
22946
|
+
let out = "";
|
|
22947
|
+
for (const ch of text) {
|
|
22948
|
+
if (ch === "(" || ch === "[") {
|
|
22949
|
+
depth++;
|
|
22950
|
+
out += depth === 1 ? ch : "\0";
|
|
22951
|
+
} else if ((ch === ")" || ch === "]") && depth > 0) {
|
|
22952
|
+
depth--;
|
|
22953
|
+
out += depth === 0 ? ch : "\0";
|
|
22954
|
+
} else out += depth > 0 ? "\0" : ch;
|
|
22955
|
+
}
|
|
22956
|
+
return out;
|
|
22957
|
+
}
|
|
22958
|
+
function splitOutsideBrackets(text, sep) {
|
|
22959
|
+
const masked = maskBrackets(text);
|
|
22960
|
+
const parts = [];
|
|
22961
|
+
let from = 0;
|
|
22962
|
+
const re = new RegExp(sep.source, sep.flags.includes("g") ? sep.flags : sep.flags + "g");
|
|
22963
|
+
for (const m of masked.matchAll(re)) {
|
|
22964
|
+
if (m[0] === "") continue;
|
|
22965
|
+
parts.push(text.slice(from, m.index));
|
|
22966
|
+
from = m.index + m[0].length;
|
|
22967
|
+
}
|
|
22968
|
+
parts.push(text.slice(from));
|
|
22969
|
+
return parts;
|
|
22970
|
+
}
|
|
22971
|
+
function specFromPart(part) {
|
|
22972
|
+
const clean = (t) => t.replace(/^["'\s]+|["'.\s]+$/g, "").replace(/\s+/g, " ");
|
|
22973
|
+
const m = /^(.*?)\s*[(\[]([^()\[\]]*)[)\]]\s*$/.exec(part.trim());
|
|
22974
|
+
if (m) {
|
|
22975
|
+
const inner2 = m[2];
|
|
22976
|
+
const colon = inner2.indexOf(":");
|
|
22977
|
+
const type = typeFromWord(colon >= 0 ? inner2.slice(0, colon) : inner2);
|
|
22978
|
+
const name = clean(m[1]);
|
|
22979
|
+
if (type && name !== "") {
|
|
22980
|
+
const options = colon >= 0 ? [...new Set(inner2.slice(colon + 1).split(/\s*[,;|]\s*/).map(clean).filter((o) => o !== ""))] : void 0;
|
|
22981
|
+
return { label: name, type, ...options && options.length > 0 && (type === "select" || type === "multi_select") ? { options } : {} };
|
|
22982
|
+
}
|
|
22983
|
+
}
|
|
22984
|
+
const withoutPairs = part.replace(/\([^()\[\]]*\)|\[[^()\[\]]*\]/g, "");
|
|
22985
|
+
const label = /[()\[\]]/.test(withoutPairs) ? part.replace(/[()\[\]]/g, " ") : part;
|
|
22986
|
+
return { label: clean(label) };
|
|
22987
|
+
}
|
|
22988
|
+
function specsFrom(text) {
|
|
22890
22989
|
const trimmed = text.trim();
|
|
22891
22990
|
if (trimmed === "") return [];
|
|
22892
22991
|
let parts;
|
|
@@ -22897,23 +22996,28 @@ function columnNamesFrom(text) {
|
|
|
22897
22996
|
parts = trimmed.split(/\r?\n/).map((line) => line.replace(BULLET, ""));
|
|
22898
22997
|
} else {
|
|
22899
22998
|
let line = trimmed;
|
|
22900
|
-
const
|
|
22999
|
+
const masked = maskBrackets(line);
|
|
23000
|
+
const colon = masked.indexOf(":");
|
|
22901
23001
|
if (colon >= 0) line = line.slice(colon + 1);
|
|
22902
23002
|
else {
|
|
22903
|
-
const withAt =
|
|
23003
|
+
const withAt = masked.toLowerCase().lastIndexOf(" with ");
|
|
22904
23004
|
if (withAt >= 0) line = line.slice(withAt + " with ".length);
|
|
22905
23005
|
}
|
|
22906
|
-
parts = line
|
|
23006
|
+
parts = splitOutsideBrackets(line, /\s*[,;|]\s*|\s+and\s+|\s*&\s*/i);
|
|
22907
23007
|
}
|
|
22908
|
-
const
|
|
23008
|
+
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);
|
|
22909
23009
|
const seen = /* @__PURE__ */ new Set();
|
|
22910
|
-
const once =
|
|
22911
|
-
const k =
|
|
23010
|
+
const once = specs.filter((c) => {
|
|
23011
|
+
const k = c.label.toLowerCase();
|
|
22912
23012
|
if (seen.has(k)) return false;
|
|
22913
23013
|
seen.add(k);
|
|
22914
23014
|
return true;
|
|
22915
23015
|
});
|
|
22916
|
-
|
|
23016
|
+
const labels = uniqueLabels(once.map((c) => c.label));
|
|
23017
|
+
return once.map((c, i) => ({ ...c, label: labels[i] })).slice(0, MOST_NEW_COLUMNS);
|
|
23018
|
+
}
|
|
23019
|
+
function columnNamesFrom(text) {
|
|
23020
|
+
return specsFrom(text).map((c) => c.label);
|
|
22917
23021
|
}
|
|
22918
23022
|
var STATUS_CHOICES = ["Not started", "In progress", "Done"];
|
|
22919
23023
|
var PRIORITY_CHOICES = ["Low", "Medium", "High"];
|
|
@@ -22938,7 +23042,9 @@ function columnFromName(label) {
|
|
|
22938
23042
|
return { label, type: "text" };
|
|
22939
23043
|
}
|
|
22940
23044
|
function columnsFrom(text) {
|
|
22941
|
-
return
|
|
23045
|
+
return specsFrom(text).map(
|
|
23046
|
+
(c) => c.type ? { label: c.label, type: c.type, ...c.options && c.options.length > 0 ? { options: c.options } : {} } : columnFromName(c.label)
|
|
23047
|
+
);
|
|
22942
23048
|
}
|
|
22943
23049
|
function fieldsForNewColumns(columns) {
|
|
22944
23050
|
const keys = /* @__PURE__ */ new Set();
|