@ai-matrx/records-ui 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/dist/index.cjs +248 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +256 -62
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1931,7 +1931,7 @@ function OpenCell({
|
|
|
1931
1931
|
}
|
|
1932
1932
|
|
|
1933
1933
|
// src/Grid.tsx
|
|
1934
|
-
import { useCallback as useCallback6, useMemo as useMemo8, useState as useState9 } from "react";
|
|
1934
|
+
import { useCallback as useCallback6, useMemo as useMemo8, useRef as useRef4, useState as useState9 } from "react";
|
|
1935
1935
|
import {
|
|
1936
1936
|
useFields as useFields2,
|
|
1937
1937
|
useRecords,
|
|
@@ -2539,9 +2539,18 @@ function EnrichPanel({ tableId, fieldId, className }) {
|
|
|
2539
2539
|
import { useState as useState8 } from "react";
|
|
2540
2540
|
import { Badge as Badge4, Button as Button6, Separator } from "@ai-matrx/design-system";
|
|
2541
2541
|
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2542
|
-
function PastePreview({
|
|
2542
|
+
function PastePreview({
|
|
2543
|
+
plan,
|
|
2544
|
+
noun,
|
|
2545
|
+
nounPlural,
|
|
2546
|
+
onConfirm,
|
|
2547
|
+
onCancel,
|
|
2548
|
+
onAddOptions
|
|
2549
|
+
}) {
|
|
2543
2550
|
const [busy, setBusy] = useState8(false);
|
|
2544
2551
|
const [outcome, setOutcome] = useState8(null);
|
|
2552
|
+
const [adding, setAdding] = useState8(null);
|
|
2553
|
+
const [addFailed, setAddFailed] = useState8(null);
|
|
2545
2554
|
const nothingToDo = plan.cells === 0;
|
|
2546
2555
|
return /* @__PURE__ */ jsx11(
|
|
2547
2556
|
"div",
|
|
@@ -2580,6 +2589,37 @@ function PastePreview({ plan, noun, nounPlural, onConfirm, onCancel }) {
|
|
|
2580
2589
|
" more of the same kinds."
|
|
2581
2590
|
] }) : null
|
|
2582
2591
|
] }) : null,
|
|
2592
|
+
onAddOptions && plan.unmatchedOptions.length > 0 ? /* @__PURE__ */ jsxs7("div", { "data-matrx-paste-add-options": true, className: "flex flex-col gap-2", children: [
|
|
2593
|
+
plan.unmatchedOptions.map((group) => /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2594
|
+
/* @__PURE__ */ jsxs7("p", { className: "text-xs", children: [
|
|
2595
|
+
/* @__PURE__ */ jsx11("span", { className: "font-medium", children: group.column }),
|
|
2596
|
+
" does not offer",
|
|
2597
|
+
" ",
|
|
2598
|
+
group.words.map((w) => `\u201C${w}\u201D`).join(", "),
|
|
2599
|
+
"."
|
|
2600
|
+
] }),
|
|
2601
|
+
/* @__PURE__ */ jsx11(
|
|
2602
|
+
Button6,
|
|
2603
|
+
{
|
|
2604
|
+
type: "button",
|
|
2605
|
+
size: "sm",
|
|
2606
|
+
variant: "outline",
|
|
2607
|
+
disabled: adding !== null || busy,
|
|
2608
|
+
onClick: () => {
|
|
2609
|
+
setAddFailed(null);
|
|
2610
|
+
setAdding(group.fieldKey);
|
|
2611
|
+
void onAddOptions(group.fieldKey, group.words).catch(
|
|
2612
|
+
(err) => setAddFailed(
|
|
2613
|
+
`Those options were not added: ${err instanceof Error ? err.message : String(err)}`
|
|
2614
|
+
)
|
|
2615
|
+
).finally(() => setAdding(null));
|
|
2616
|
+
},
|
|
2617
|
+
children: adding === group.fieldKey ? "Adding\u2026" : group.words.length === 1 ? `Add \u201C${group.words[0]}\u201D as an option` : `Add these ${group.words.length} options`
|
|
2618
|
+
}
|
|
2619
|
+
)
|
|
2620
|
+
] }, group.fieldKey)),
|
|
2621
|
+
addFailed ? /* @__PURE__ */ jsx11("p", { className: "text-xs text-destructive", children: addFailed }) : null
|
|
2622
|
+
] }) : null,
|
|
2583
2623
|
plan.pastRightEdge > 0 ? /* @__PURE__ */ jsxs7("p", { className: "text-xs text-muted-foreground", children: [
|
|
2584
2624
|
plan.pastRightEdge,
|
|
2585
2625
|
" ",
|
|
@@ -2671,9 +2711,26 @@ function confirmLabel(plan, noun, nounPlural) {
|
|
|
2671
2711
|
|
|
2672
2712
|
// src/pasteValues.ts
|
|
2673
2713
|
import { predictValueRefusals } from "@ai-matrx/records/core";
|
|
2714
|
+
import { optionKey as optionKey2 } from "@ai-matrx/records";
|
|
2715
|
+
function choiceOptionsOf(options) {
|
|
2716
|
+
const byWord = /* @__PURE__ */ new Map();
|
|
2717
|
+
const labels = [];
|
|
2718
|
+
for (const option of options) {
|
|
2719
|
+
const id = option.id;
|
|
2720
|
+
const key = optionKey2(option);
|
|
2721
|
+
const label = recordName(option.data, null, "");
|
|
2722
|
+
if (label) {
|
|
2723
|
+
labels.push(label);
|
|
2724
|
+
if (!byWord.has(label.toLowerCase())) byWord.set(label.toLowerCase(), id);
|
|
2725
|
+
}
|
|
2726
|
+
if (key && !byWord.has(String(key).toLowerCase())) byWord.set(String(key).toLowerCase(), id);
|
|
2727
|
+
if (id && !byWord.has(id.toLowerCase())) byWord.set(id.toLowerCase(), id);
|
|
2728
|
+
}
|
|
2729
|
+
return { byWord, labels };
|
|
2730
|
+
}
|
|
2674
2731
|
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
2675
2732
|
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
2676
|
-
function valueFromPastedText(field, raw) {
|
|
2733
|
+
function valueFromPastedText(field, raw, options) {
|
|
2677
2734
|
const label = fieldName(field);
|
|
2678
2735
|
const text = raw.trim();
|
|
2679
2736
|
const kind = editorKindFor(field);
|
|
@@ -2733,10 +2790,30 @@ function valueFromPastedText(field, raw) {
|
|
|
2733
2790
|
// stop agreeing with it. So the cell is left alone and the person is told
|
|
2734
2791
|
// which control does hold it.
|
|
2735
2792
|
case "select":
|
|
2736
|
-
case "multi_select":
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2793
|
+
case "multi_select": {
|
|
2794
|
+
if (!options) {
|
|
2795
|
+
return {
|
|
2796
|
+
refusal: `${label} is a list and its options have not been read yet, so nothing can be matched to \u201C${raw}\u201D. Reopen the paste once the column's choices have loaded.`
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2799
|
+
const wanted = kind === "multi_select" ? text.split(/[,;]/).map((w) => w.trim()).filter((w) => w.length > 0) : [text];
|
|
2800
|
+
if (wanted.length === 0) return { value: kind === "multi_select" ? [] : null };
|
|
2801
|
+
const matched = [];
|
|
2802
|
+
const unmatched = [];
|
|
2803
|
+
for (const word of wanted) {
|
|
2804
|
+
const hit = options.byWord.get(word.toLowerCase());
|
|
2805
|
+
if (hit === void 0) unmatched.push(word);
|
|
2806
|
+
else matched.push(hit);
|
|
2807
|
+
}
|
|
2808
|
+
if (unmatched.length > 0) {
|
|
2809
|
+
const offered = options.labels.length > 0 ? options.labels.join(", ") : "it has none yet";
|
|
2810
|
+
return {
|
|
2811
|
+
refusal: `${label} does not have ${unmatched.map((w) => `\u201C${w}\u201D`).join(" or ")} among its options. It offers: ${offered}.`,
|
|
2812
|
+
unmatched
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
return { value: kind === "multi_select" ? matched : matched[0] };
|
|
2816
|
+
}
|
|
2740
2817
|
case "member":
|
|
2741
2818
|
return {
|
|
2742
2819
|
refusal: `${label} names a person in this organization, so it is chosen rather than typed. Open the cell and pick them.`
|
|
@@ -2763,6 +2840,7 @@ function planPastedBlock(args) {
|
|
|
2763
2840
|
const byKey = new Map(args.fields.map((f) => [f.key, f]));
|
|
2764
2841
|
const rows = [];
|
|
2765
2842
|
const refusals = [];
|
|
2843
|
+
const unmatched = /* @__PURE__ */ new Map();
|
|
2766
2844
|
let cells = 0;
|
|
2767
2845
|
const lines = [
|
|
2768
2846
|
...args.onExisting.map((r) => ({ recordId: r.recordId, raw: r.raw })),
|
|
@@ -2778,8 +2856,15 @@ function planPastedBlock(args) {
|
|
|
2778
2856
|
const field = byKey.get(key);
|
|
2779
2857
|
const raw = line.raw[c];
|
|
2780
2858
|
if (field === void 0 || raw === void 0) continue;
|
|
2781
|
-
const judged = valueFromPastedText(field, raw);
|
|
2859
|
+
const judged = valueFromPastedText(field, raw, args.options?.get(key));
|
|
2782
2860
|
if ("refusal" in judged) {
|
|
2861
|
+
if ("unmatched" in judged) {
|
|
2862
|
+
const seen = unmatched.get(key) ?? { column: fieldName(field), words: [] };
|
|
2863
|
+
for (const word of judged.unmatched) {
|
|
2864
|
+
if (!seen.words.some((w) => w.toLowerCase() === word.toLowerCase())) seen.words.push(word);
|
|
2865
|
+
}
|
|
2866
|
+
unmatched.set(key, seen);
|
|
2867
|
+
}
|
|
2783
2868
|
built.push({ key, raw, value: null, refusal: judged.refusal });
|
|
2784
2869
|
refusals.push({ fromLine, column: fieldName(field), raw, why: judged.refusal });
|
|
2785
2870
|
continue;
|
|
@@ -2815,7 +2900,12 @@ function planPastedBlock(args) {
|
|
|
2815
2900
|
creates: keepers.filter((r) => r.recordId === null).length,
|
|
2816
2901
|
cells,
|
|
2817
2902
|
refusals,
|
|
2818
|
-
pastRightEdge: args.pastRightEdge ?? 0
|
|
2903
|
+
pastRightEdge: args.pastRightEdge ?? 0,
|
|
2904
|
+
unmatchedOptions: [...unmatched.entries()].map(([fieldKey, seen]) => ({
|
|
2905
|
+
fieldKey,
|
|
2906
|
+
column: seen.column,
|
|
2907
|
+
words: seen.words
|
|
2908
|
+
}))
|
|
2819
2909
|
};
|
|
2820
2910
|
}
|
|
2821
2911
|
function documentOf(row) {
|
|
@@ -2897,13 +2987,29 @@ function Grid({
|
|
|
2897
2987
|
[client, host, refreshEnrich]
|
|
2898
2988
|
);
|
|
2899
2989
|
const [pastePlan, setPastePlan] = useState9(null);
|
|
2990
|
+
const choiceOptions = useRef4(/* @__PURE__ */ new Map());
|
|
2991
|
+
const loadChoiceOptions = useCallback6(
|
|
2992
|
+
async (fieldList) => {
|
|
2993
|
+
const wanted = fieldList.filter(
|
|
2994
|
+
(f) => (editorKindFor(f) === "select" || editorKindFor(f) === "multi_select") && !choiceOptions.current.has(f.key)
|
|
2995
|
+
);
|
|
2996
|
+
await Promise.all(
|
|
2997
|
+
wanted.map(async (field) => {
|
|
2998
|
+
const got = await client.fieldOptions({ field_id: field.id });
|
|
2999
|
+
if (got.ok) choiceOptions.current.set(field.key, choiceOptionsOf(got.data ?? []));
|
|
3000
|
+
})
|
|
3001
|
+
);
|
|
3002
|
+
},
|
|
3003
|
+
[client]
|
|
3004
|
+
);
|
|
2900
3005
|
const pasteableKeys = useMemo8(
|
|
2901
3006
|
() => ordered.filter((f) => fieldIsEditable(f)).map((f) => f.key),
|
|
2902
3007
|
[ordered]
|
|
2903
3008
|
);
|
|
2904
3009
|
const receivePastePlan = useCallback6(
|
|
2905
|
-
(sheetPlan) => {
|
|
3010
|
+
async (sheetPlan) => {
|
|
2906
3011
|
const fieldList = fields.data ?? [];
|
|
3012
|
+
await loadChoiceOptions(fieldList);
|
|
2907
3013
|
const byRecord = /* @__PURE__ */ new Map();
|
|
2908
3014
|
const order = [];
|
|
2909
3015
|
const take = (rowId, columnId, value) => {
|
|
@@ -2931,6 +3037,7 @@ function Grid({
|
|
|
2931
3037
|
);
|
|
2932
3038
|
const built = planPastedBlock({
|
|
2933
3039
|
fields: fieldList,
|
|
3040
|
+
options: choiceOptions.current,
|
|
2934
3041
|
columnKeys,
|
|
2935
3042
|
onExisting: touched.map((recordId) => ({
|
|
2936
3043
|
recordId,
|
|
@@ -2954,7 +3061,37 @@ function Grid({
|
|
|
2954
3061
|
}
|
|
2955
3062
|
setPastePlan({ plan: built });
|
|
2956
3063
|
},
|
|
2957
|
-
[fields.data, rows]
|
|
3064
|
+
[fields.data, loadChoiceOptions, rows]
|
|
3065
|
+
);
|
|
3066
|
+
const addPastedOptions = useCallback6(
|
|
3067
|
+
async (fieldKey, words) => {
|
|
3068
|
+
const field = (fields.data ?? []).find((f) => f.key === fieldKey);
|
|
3069
|
+
if (!field) throw new Error(`This table has no column called ${fieldKey}.`);
|
|
3070
|
+
const existing = choiceOptions.current.get(fieldKey)?.labels ?? [];
|
|
3071
|
+
const written = await client.fieldUpdate({
|
|
3072
|
+
field_id: field.id,
|
|
3073
|
+
patch: { options: [...existing, ...words] }
|
|
3074
|
+
});
|
|
3075
|
+
if (!written.ok) throw new Error(written.error.message);
|
|
3076
|
+
choiceOptions.current.delete(fieldKey);
|
|
3077
|
+
await loadChoiceOptions(fields.data ?? []);
|
|
3078
|
+
setPastePlan(
|
|
3079
|
+
(held) => held ? {
|
|
3080
|
+
plan: planPastedBlock({
|
|
3081
|
+
fields: fields.data ?? [],
|
|
3082
|
+
options: choiceOptions.current,
|
|
3083
|
+
columnKeys: held.plan.rows[0]?.cells.map((c) => c.key) ?? [],
|
|
3084
|
+
onExisting: held.plan.rows.filter((r) => r.recordId !== null).map((r) => ({
|
|
3085
|
+
recordId: r.recordId,
|
|
3086
|
+
raw: r.cells.map((c) => c.raw)
|
|
3087
|
+
})),
|
|
3088
|
+
onNew: held.plan.rows.filter((r) => r.recordId === null).map((r) => r.cells.map((c) => c.raw)),
|
|
3089
|
+
pastRightEdge: held.plan.pastRightEdge
|
|
3090
|
+
})
|
|
3091
|
+
} : held
|
|
3092
|
+
);
|
|
3093
|
+
},
|
|
3094
|
+
[client, fields.data, loadChoiceOptions]
|
|
2958
3095
|
);
|
|
2959
3096
|
const applyPaste = useCallback6(async () => {
|
|
2960
3097
|
const held = pastePlan;
|
|
@@ -2962,39 +3099,56 @@ function Grid({
|
|
|
2962
3099
|
const refusals = [];
|
|
2963
3100
|
let written = 0;
|
|
2964
3101
|
const expected = [];
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
3102
|
+
const creates = held.plan.rows.filter((row) => row.recordId === null).map((row) => ({ row, document: documentOf(row) })).filter((c) => Object.keys(c.document).length > 0);
|
|
3103
|
+
const updates = held.plan.rows.filter((row) => row.recordId !== null).map((row) => ({ row, document: documentOf(row) })).filter((c) => Object.keys(c.document).length > 0);
|
|
3104
|
+
for (let at = 0; at < creates.length; at += pageSize) {
|
|
3105
|
+
const chunk = creates.slice(at, at + pageSize);
|
|
3106
|
+
const made = await client.recordWriteMany({
|
|
3107
|
+
table_id: tableId,
|
|
3108
|
+
rows: chunk.map((c) => c.document)
|
|
3109
|
+
});
|
|
3110
|
+
if (!made.ok) {
|
|
3111
|
+
refusals.push(
|
|
3112
|
+
`Rows ${chunk[0].row.fromLine}-${chunk[chunk.length - 1].row.fromLine}: ${made.error.message}`
|
|
3113
|
+
);
|
|
3114
|
+
continue;
|
|
3115
|
+
}
|
|
3116
|
+
chunk.forEach((c, index) => {
|
|
3117
|
+
const id = made.data[index];
|
|
3118
|
+
if (id === void 0) {
|
|
3119
|
+
refusals.push(`Row ${c.row.fromLine}: the store wrote the batch and named no id for this line.`);
|
|
3120
|
+
return;
|
|
2981
3121
|
}
|
|
2982
3122
|
written += 1;
|
|
2983
|
-
expected.push({ recordId:
|
|
3123
|
+
expected.push({ recordId: id, document: c.document });
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
3126
|
+
for (const { row, document: document2 } of updates) {
|
|
3127
|
+
const done = await client.recordUpdate({ record_id: row.recordId, patch: document2 });
|
|
3128
|
+
if (!done.ok) {
|
|
3129
|
+
refusals.push(`Row ${row.fromLine}: ${done.error.message}`);
|
|
3130
|
+
continue;
|
|
2984
3131
|
}
|
|
3132
|
+
written += 1;
|
|
3133
|
+
expected.push({ recordId: row.recordId, document: document2 });
|
|
2985
3134
|
}
|
|
2986
3135
|
let readBack = 0;
|
|
2987
3136
|
let missing = 0;
|
|
2988
3137
|
const seen = /* @__PURE__ */ new Map();
|
|
2989
|
-
const
|
|
2990
|
-
|
|
3138
|
+
const READ_BACK_PAGE = 500;
|
|
3139
|
+
for (let offset = 0; ; offset += READ_BACK_PAGE) {
|
|
3140
|
+
const reread = await client.list({ table_id: tableId, limit: READ_BACK_PAGE, offset });
|
|
3141
|
+
if (!reread.ok) {
|
|
3142
|
+
refusals.push(
|
|
3143
|
+
`The rows were written and this could not read them back to check: ${reread.error.message}`
|
|
3144
|
+
);
|
|
3145
|
+
break;
|
|
3146
|
+
}
|
|
2991
3147
|
for (const row of reread.data.rows) {
|
|
2992
3148
|
seen.set(row.id, row.document ?? {});
|
|
2993
3149
|
}
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
`The rows were written and this could not read them back to check: ${reread.error.message}`
|
|
2997
|
-
);
|
|
3150
|
+
if (reread.data.rows.length < READ_BACK_PAGE) break;
|
|
3151
|
+
if (expected.every((e) => seen.has(e.recordId))) break;
|
|
2998
3152
|
}
|
|
2999
3153
|
for (const entry of expected) {
|
|
3000
3154
|
const stored = seen.get(entry.recordId);
|
|
@@ -3267,6 +3421,7 @@ function Grid({
|
|
|
3267
3421
|
noun: table.data?.label_singular ?? "record",
|
|
3268
3422
|
nounPlural: table.data?.label_plural ?? `${table.data?.label_singular ?? "record"}s`,
|
|
3269
3423
|
onConfirm: applyPaste,
|
|
3424
|
+
onAddOptions: addPastedOptions,
|
|
3270
3425
|
onCancel: () => setPastePlan(null)
|
|
3271
3426
|
}
|
|
3272
3427
|
) : null,
|
|
@@ -5973,7 +6128,7 @@ import { useFields as useFields11, useRecords as useRecords4, useRecordsClient a
|
|
|
5973
6128
|
import { Button as Button18, Skeleton as Skeleton7, cn as cn19 } from "@ai-matrx/design-system";
|
|
5974
6129
|
|
|
5975
6130
|
// src/Pipeline.tsx
|
|
5976
|
-
import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMemo16, useRef as
|
|
6131
|
+
import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMemo16, useRef as useRef5, useState as useState21 } from "react";
|
|
5977
6132
|
import {
|
|
5978
6133
|
mayDrag,
|
|
5979
6134
|
useFields as useFields10,
|
|
@@ -6021,7 +6176,7 @@ function PipelineBoard({
|
|
|
6021
6176
|
const [waiting, setWaiting] = useState21(/* @__PURE__ */ new Map());
|
|
6022
6177
|
const [dragging, setDragging] = useState21(null);
|
|
6023
6178
|
const [over, setOver] = useState21(null);
|
|
6024
|
-
const alive =
|
|
6179
|
+
const alive = useRef5(true);
|
|
6025
6180
|
useEffect12(() => {
|
|
6026
6181
|
alive.current = true;
|
|
6027
6182
|
return () => {
|
|
@@ -6772,9 +6927,9 @@ import { useRecordsClient as useRecordsClient17 } from "@ai-matrx/records/react"
|
|
|
6772
6927
|
import { Button as Button19, Input as Input2, Skeleton as Skeleton8, cn as cn20 } from "@ai-matrx/design-system";
|
|
6773
6928
|
|
|
6774
6929
|
// src/seedOnce.ts
|
|
6775
|
-
import { useCallback as useCallback10, useRef as
|
|
6930
|
+
import { useCallback as useCallback10, useRef as useRef6 } from "react";
|
|
6776
6931
|
function useSeedGuard() {
|
|
6777
|
-
const claimed =
|
|
6932
|
+
const claimed = useRef6(/* @__PURE__ */ new Set());
|
|
6778
6933
|
return useCallback10((name) => {
|
|
6779
6934
|
if (claimed.current.has(name)) return false;
|
|
6780
6935
|
claimed.current.add(name);
|
|
@@ -7013,7 +7168,7 @@ function ProposalRow({
|
|
|
7013
7168
|
}
|
|
7014
7169
|
|
|
7015
7170
|
// src/ActionInbox.tsx
|
|
7016
|
-
import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo19, useRef as
|
|
7171
|
+
import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo19, useRef as useRef7, useState as useState26 } from "react";
|
|
7017
7172
|
import { useRecordsClient as useRecordsClient20 } from "@ai-matrx/records/react";
|
|
7018
7173
|
import { Badge as Badge9, Button as Button22, Skeleton as Skeleton10, cn as cn23 } from "@ai-matrx/design-system";
|
|
7019
7174
|
|
|
@@ -7763,7 +7918,7 @@ function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className
|
|
|
7763
7918
|
const [outcome, setOutcome] = useState26({});
|
|
7764
7919
|
const [busy, setBusy] = useState26(null);
|
|
7765
7920
|
const [cursor, setCursor] = useState26(0);
|
|
7766
|
-
const listRef =
|
|
7921
|
+
const listRef = useRef7(null);
|
|
7767
7922
|
const load = useCallback13(async () => {
|
|
7768
7923
|
const result = await client.workInbox({ limit: 200, includeDecided: includeSettled });
|
|
7769
7924
|
if (!result.ok) {
|
|
@@ -7911,7 +8066,7 @@ function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className
|
|
|
7911
8066
|
}
|
|
7912
8067
|
|
|
7913
8068
|
// src/HistoryPanel.tsx
|
|
7914
|
-
import { useCallback as useCallback14, useEffect as useEffect17, useRef as
|
|
8069
|
+
import { useCallback as useCallback14, useEffect as useEffect17, useRef as useRef8, useState as useState27 } from "react";
|
|
7915
8070
|
import {
|
|
7916
8071
|
useFields as useFields12,
|
|
7917
8072
|
useRecordsClient as useRecordsClient21,
|
|
@@ -7929,7 +8084,7 @@ function HistoryPanel({ tableId, recordId, onAskAboutField, className }) {
|
|
|
7929
8084
|
const [open, setOpen] = useState27(null);
|
|
7930
8085
|
const [pending, setPending] = useState27({ phase: "idle" });
|
|
7931
8086
|
const [said, setSaid] = useState27(null);
|
|
7932
|
-
const listRef =
|
|
8087
|
+
const listRef = useRef8(null);
|
|
7933
8088
|
const load = useCallback14(async () => {
|
|
7934
8089
|
const answered = await client.recordHistory({ record_id: recordId });
|
|
7935
8090
|
if (!answered.ok) {
|
|
@@ -8220,7 +8375,7 @@ function say(value, field) {
|
|
|
8220
8375
|
}
|
|
8221
8376
|
|
|
8222
8377
|
// src/CommentThread.tsx
|
|
8223
|
-
import { useCallback as useCallback15, useEffect as useEffect18, useMemo as useMemo20, useRef as
|
|
8378
|
+
import { useCallback as useCallback15, useEffect as useEffect18, useMemo as useMemo20, useRef as useRef9, useState as useState28 } from "react";
|
|
8224
8379
|
import {
|
|
8225
8380
|
useFields as useFields13,
|
|
8226
8381
|
useRecordsClient as useRecordsClient22,
|
|
@@ -8243,7 +8398,7 @@ function CommentThread({ tableId, recordId, fieldKey, className }) {
|
|
|
8243
8398
|
const [people, setPeople] = useState28([]);
|
|
8244
8399
|
const [mentionQuery, setMentionQuery] = useState28(null);
|
|
8245
8400
|
const [picked, setPicked] = useState28([]);
|
|
8246
|
-
const box =
|
|
8401
|
+
const box = useRef9(null);
|
|
8247
8402
|
const load = useCallback15(async () => {
|
|
8248
8403
|
const answered = await client.commentThread({ record_id: recordId, include_resolved: showResolved });
|
|
8249
8404
|
if (!answered.ok) {
|
|
@@ -10023,7 +10178,7 @@ import {
|
|
|
10023
10178
|
} from "@ai-matrx/design-system";
|
|
10024
10179
|
|
|
10025
10180
|
// src/FormRunner.tsx
|
|
10026
|
-
import { useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo24, useRef as
|
|
10181
|
+
import { useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo24, useRef as useRef10, useState as useState34 } from "react";
|
|
10027
10182
|
import { useFields as useFields15, useOptionalRecordsClient } from "@ai-matrx/records/react";
|
|
10028
10183
|
import { Button as Button31, Progress, Skeleton as Skeleton18, cn as cn32 } from "@ai-matrx/design-system";
|
|
10029
10184
|
import { Fragment as Fragment17, jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
@@ -10101,8 +10256,8 @@ function FormStage({
|
|
|
10101
10256
|
const [writing, setWriting] = useState34(false);
|
|
10102
10257
|
const [done, setDone] = useState34(null);
|
|
10103
10258
|
const [hidden, setHidden] = useState34({});
|
|
10104
|
-
const decoy =
|
|
10105
|
-
const stage =
|
|
10259
|
+
const decoy = useRef10("");
|
|
10260
|
+
const stage = useRef10(null);
|
|
10106
10261
|
const questions = useMemo24(() => {
|
|
10107
10262
|
const byKey = new Map((fields ?? []).map((f) => [f.key, f]));
|
|
10108
10263
|
return (form.questions ?? []).map((q) => {
|
|
@@ -10314,6 +10469,28 @@ function Question({
|
|
|
10314
10469
|
] });
|
|
10315
10470
|
}
|
|
10316
10471
|
|
|
10472
|
+
// src/publicQuestions.ts
|
|
10473
|
+
var CANNOT_ASK = {
|
|
10474
|
+
relation: "points at a record in another table, and somebody with no account cannot see that table to pick from it",
|
|
10475
|
+
member: "is a person in this organization, and somebody outside it has no way to choose one",
|
|
10476
|
+
attachment: "holds a file in your own store, and a public page has nowhere to put one yet",
|
|
10477
|
+
formula: "is worked out by the store, so there is nothing for anybody to answer",
|
|
10478
|
+
lookup: "is read through a relation, so the store fills it in",
|
|
10479
|
+
rollup: "is added up by the store, so there is nothing for anybody to answer"
|
|
10480
|
+
};
|
|
10481
|
+
function publiclyAnswerable(field) {
|
|
10482
|
+
return !(field.type in CANNOT_ASK);
|
|
10483
|
+
}
|
|
10484
|
+
function askableFields(fields, hidden = []) {
|
|
10485
|
+
return fields.filter((f) => publiclyAnswerable(f) && !hidden.includes(f.key));
|
|
10486
|
+
}
|
|
10487
|
+
function whyNotAskable(fields, hidden = []) {
|
|
10488
|
+
const left = fields.filter((f) => !publiclyAnswerable(f) && !hidden.includes(f.key));
|
|
10489
|
+
if (left.length === 0) return null;
|
|
10490
|
+
const said = left.map((f) => `${f.label || f.key} ${CANNOT_ASK[f.type]}`);
|
|
10491
|
+
return said.length === 1 ? `${said[0]}, so it is not offered here.` : `These are not offered here: ${said.join("; ")}.`;
|
|
10492
|
+
}
|
|
10493
|
+
|
|
10317
10494
|
// src/FormBuilder.tsx
|
|
10318
10495
|
import { Fragment as Fragment18, jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
10319
10496
|
function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
@@ -10546,7 +10723,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10546
10723
|
" fields"
|
|
10547
10724
|
] })
|
|
10548
10725
|
] }),
|
|
10549
|
-
(fields.data ?? []).map((field) => {
|
|
10726
|
+
askableFields(fields.data ?? []).map((field) => {
|
|
10550
10727
|
const index = draft.questions.findIndex((q) => q.field === field.key);
|
|
10551
10728
|
const asked = index >= 0;
|
|
10552
10729
|
const question = asked ? draft.questions[index] : null;
|
|
@@ -10598,6 +10775,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10598
10775
|
] }) : null
|
|
10599
10776
|
] }, field.id);
|
|
10600
10777
|
}),
|
|
10778
|
+
whyNotAskable(fields.data ?? []) ? /* @__PURE__ */ jsx39("p", { className: "text-xs text-muted-foreground", children: whyNotAskable(fields.data ?? []) }) : null,
|
|
10601
10779
|
draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */ jsxs35("p", { className: "text-xs text-destructive", children: [
|
|
10602
10780
|
'This form asks for "',
|
|
10603
10781
|
q.field,
|
|
@@ -10763,13 +10941,13 @@ function groupLabel(groups) {
|
|
|
10763
10941
|
import {
|
|
10764
10942
|
useEffect as useEffect26,
|
|
10765
10943
|
useId,
|
|
10766
|
-
useRef as
|
|
10944
|
+
useRef as useRef11,
|
|
10767
10945
|
useState as useState36
|
|
10768
10946
|
} from "react";
|
|
10769
10947
|
import { cn as cn34 } from "@ai-matrx/design-system";
|
|
10770
10948
|
import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
10771
10949
|
function useMeasuredWidth(fallback = 480) {
|
|
10772
|
-
const ref =
|
|
10950
|
+
const ref = useRef11(null);
|
|
10773
10951
|
const [width, setWidth] = useState36(fallback);
|
|
10774
10952
|
useEffect26(() => {
|
|
10775
10953
|
const node = ref.current;
|
|
@@ -11074,7 +11252,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
11074
11252
|
}
|
|
11075
11253
|
|
|
11076
11254
|
// src/DocRender.tsx
|
|
11077
|
-
import { useCallback as useCallback24, useEffect as useEffect28, useRef as
|
|
11255
|
+
import { useCallback as useCallback24, useEffect as useEffect28, useRef as useRef12, useState as useState38 } from "react";
|
|
11078
11256
|
import { useRecordsClient as useRecordsClient30 } from "@ai-matrx/records/react";
|
|
11079
11257
|
import { Button as Button34, Skeleton as Skeleton21, cn as cn36 } from "@ai-matrx/design-system";
|
|
11080
11258
|
import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
@@ -11085,7 +11263,7 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
11085
11263
|
const [showing, setShowing] = useState38(null);
|
|
11086
11264
|
const [error, setError] = useState38(null);
|
|
11087
11265
|
const [busy, setBusy] = useState38(null);
|
|
11088
|
-
const paper =
|
|
11266
|
+
const paper = useRef12(null);
|
|
11089
11267
|
const load = useCallback24(async () => {
|
|
11090
11268
|
const [body, held] = await Promise.all([
|
|
11091
11269
|
client.docRenderBody({ template_id: templateId, record_id: recordId }),
|
|
@@ -12275,6 +12453,7 @@ var DAYS = [
|
|
|
12275
12453
|
{ weekday: 0, label: "Sun" }
|
|
12276
12454
|
];
|
|
12277
12455
|
var LENGTHS = [15, 20, 30, 45, 60, 90, 120];
|
|
12456
|
+
var WORKING_WEEK = /* @__PURE__ */ new Set([1, 2, 3, 4, 5]);
|
|
12278
12457
|
function draftWindows(availability) {
|
|
12279
12458
|
return DAYS.map((day) => {
|
|
12280
12459
|
const found = availability?.windows.find((w) => w.weekday === day.weekday);
|
|
@@ -12282,7 +12461,7 @@ function draftWindows(availability) {
|
|
|
12282
12461
|
weekday: day.weekday,
|
|
12283
12462
|
from: found?.from ?? "09:00",
|
|
12284
12463
|
to: found?.to ?? "17:00",
|
|
12285
|
-
on: Boolean(found)
|
|
12464
|
+
on: availability ? Boolean(found) : WORKING_WEEK.has(day.weekday)
|
|
12286
12465
|
};
|
|
12287
12466
|
});
|
|
12288
12467
|
}
|
|
@@ -12311,9 +12490,11 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12311
12490
|
const [formId, setFormId] = useState43(bookingId ?? null);
|
|
12312
12491
|
const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
12313
12492
|
const askable = useMemo28(
|
|
12314
|
-
() => (fields.data ?? [])
|
|
12315
|
-
|
|
12316
|
-
|
|
12493
|
+
() => askableFields(fields.data ?? [], STORE_ANSWERS_THESE),
|
|
12494
|
+
[fields.data]
|
|
12495
|
+
);
|
|
12496
|
+
const leftOut = useMemo28(
|
|
12497
|
+
() => whyNotAskable(fields.data ?? [], STORE_ANSWERS_THESE),
|
|
12317
12498
|
[fields.data]
|
|
12318
12499
|
);
|
|
12319
12500
|
const load = useCallback29(async () => {
|
|
@@ -12339,6 +12520,15 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12339
12520
|
if (!existing) return;
|
|
12340
12521
|
setMinutes(existing.slot_minutes);
|
|
12341
12522
|
}, [existing]);
|
|
12523
|
+
useEffect33(() => {
|
|
12524
|
+
if (!offer) return;
|
|
12525
|
+
setWindows(draftWindows(offer));
|
|
12526
|
+
setMinutes(offer.slot_minutes);
|
|
12527
|
+
setBuffer(offer.buffer_minutes);
|
|
12528
|
+
setLead(offer.lead_minutes);
|
|
12529
|
+
setPerDay(offer.max_per_day);
|
|
12530
|
+
setDays(offer.days);
|
|
12531
|
+
}, [offer]);
|
|
12342
12532
|
const availability = useCallback29(
|
|
12343
12533
|
() => ({
|
|
12344
12534
|
slot_minutes: minutes,
|
|
@@ -12526,7 +12716,8 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12526
12716
|
),
|
|
12527
12717
|
fieldName(f)
|
|
12528
12718
|
] }, f.key)) }),
|
|
12529
|
-
/* @__PURE__ */ jsx48("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." })
|
|
12719
|
+
/* @__PURE__ */ jsx48("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." }),
|
|
12720
|
+
leftOut ? /* @__PURE__ */ jsx48("p", { className: "text-xs text-muted-foreground", children: leftOut }) : null
|
|
12530
12721
|
] }),
|
|
12531
12722
|
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12532
12723
|
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "What they see after booking" }),
|
|
@@ -12784,12 +12975,12 @@ function nextInWords(page) {
|
|
|
12784
12975
|
}
|
|
12785
12976
|
|
|
12786
12977
|
// src/CaptureSheet.tsx
|
|
12787
|
-
import { useCallback as useCallback32, useEffect as useEffect36, useRef as
|
|
12978
|
+
import { useCallback as useCallback32, useEffect as useEffect36, useRef as useRef14, useState as useState46 } from "react";
|
|
12788
12979
|
import { useFields as useFields21, useRecordsClient as useRecordsClient38, useTable as useTable20 } from "@ai-matrx/records/react";
|
|
12789
12980
|
import { Button as Button42, Input as Input4, Skeleton as Skeleton29, Textarea as Textarea3, cn as cn45 } from "@ai-matrx/design-system";
|
|
12790
12981
|
|
|
12791
12982
|
// src/CaptureRun.tsx
|
|
12792
|
-
import { useCallback as useCallback31, useEffect as useEffect35, useMemo as useMemo30, useRef as
|
|
12983
|
+
import { useCallback as useCallback31, useEffect as useEffect35, useMemo as useMemo30, useRef as useRef13, useState as useState45 } from "react";
|
|
12793
12984
|
import {
|
|
12794
12985
|
openCaptureQueue
|
|
12795
12986
|
} from "@ai-matrx/records";
|
|
@@ -12845,7 +13036,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12845
13036
|
const [items, setItems] = useState45([]);
|
|
12846
13037
|
const [lastSynced, setLastSynced] = useState45(null);
|
|
12847
13038
|
const [sending, setSending] = useState45(false);
|
|
12848
|
-
const queueRef =
|
|
13039
|
+
const queueRef = useRef13(null);
|
|
12849
13040
|
useEffect35(() => {
|
|
12850
13041
|
const q2 = openCaptureQueue({
|
|
12851
13042
|
onChange: (c, all) => {
|
|
@@ -13203,7 +13394,7 @@ function AdHocCaptureSheet({
|
|
|
13203
13394
|
const [error, setError] = useState46(null);
|
|
13204
13395
|
const [uploadError, setUploadError] = useState46(null);
|
|
13205
13396
|
const [flushing, setFlushing] = useState46(false);
|
|
13206
|
-
const queue =
|
|
13397
|
+
const queue = useRef14([]);
|
|
13207
13398
|
const keep = useCallback32(
|
|
13208
13399
|
async (next) => {
|
|
13209
13400
|
queue.current = next;
|
|
@@ -14460,6 +14651,7 @@ export {
|
|
|
14460
14651
|
actorBadge,
|
|
14461
14652
|
actorWords,
|
|
14462
14653
|
addFields,
|
|
14654
|
+
askableFields,
|
|
14463
14655
|
blockFromSpec,
|
|
14464
14656
|
bodyForReading,
|
|
14465
14657
|
bodyFromKeys,
|
|
@@ -14512,6 +14704,7 @@ export {
|
|
|
14512
14704
|
presentationDocument,
|
|
14513
14705
|
presentationIsEmpty,
|
|
14514
14706
|
previewLine,
|
|
14707
|
+
publiclyAnswerable,
|
|
14515
14708
|
recordName,
|
|
14516
14709
|
recordsDataSource,
|
|
14517
14710
|
refusalForAPerson,
|
|
@@ -14548,6 +14741,7 @@ export {
|
|
|
14548
14741
|
whatIsMissing,
|
|
14549
14742
|
whatYouMayDo,
|
|
14550
14743
|
whatYouMayDoWithTable,
|
|
14551
|
-
whenWords
|
|
14744
|
+
whenWords,
|
|
14745
|
+
whyNotAskable
|
|
14552
14746
|
};
|
|
14553
14747
|
//# sourceMappingURL=index.js.map
|