@ai-matrx/records-ui 0.62.0 → 0.65.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 +133 -0
- package/dist/index.cjs +372 -357
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -10
- package/dist/index.d.ts +110 -10
- package/dist/index.js +366 -345
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,8 +31,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var src_exports = {};
|
|
33
33
|
__export(src_exports, {
|
|
34
|
+
ABSENCE_WORD_LABEL: () => ABSENCE_WORD_LABEL,
|
|
35
|
+
ABSENCE_WORD_VALUES: () => ABSENCE_WORD_VALUES,
|
|
34
36
|
ACTION_KINDS: () => ACTION_KINDS,
|
|
35
37
|
ActionInbox: () => ActionInbox,
|
|
38
|
+
BOOKING_PAGE_STATE_LABEL: () => BOOKING_PAGE_STATE_LABEL,
|
|
39
|
+
BOOKING_PAGE_STATE_VALUES: () => BOOKING_PAGE_STATE_VALUES,
|
|
36
40
|
BookingBuilder: () => BookingBuilder,
|
|
37
41
|
BookingSlots: () => BookingSlots,
|
|
38
42
|
BuildOrAsk: () => BuildOrAsk,
|
|
@@ -40,7 +44,10 @@ __export(src_exports, {
|
|
|
40
44
|
CHART_KINDS: () => CHART_KINDS,
|
|
41
45
|
CHART_KIND_LABEL: () => CHART_KIND_LABEL,
|
|
42
46
|
CHART_NEEDS: () => CHART_NEEDS,
|
|
47
|
+
CHECKLIST_REQUIREMENT_KINDS: () => CHECKLIST_REQUIREMENT_KINDS,
|
|
48
|
+
CHECKLIST_REQUIREMENT_LABEL: () => CHECKLIST_REQUIREMENT_LABEL,
|
|
43
49
|
CONDITION_OPS: () => CONDITION_OPS,
|
|
50
|
+
CONTEXT_POLICY_LABEL: () => CONTEXT_POLICY_LABEL,
|
|
44
51
|
CaptureRun: () => CaptureRun,
|
|
45
52
|
CaptureSheet: () => CaptureSheet,
|
|
46
53
|
ChartBlock: () => ChartBlock,
|
|
@@ -56,6 +63,7 @@ __export(src_exports, {
|
|
|
56
63
|
CustomFieldsSection: () => CustomFieldsSection,
|
|
57
64
|
DEFAULT_FIELDS: () => DEFAULT_FIELDS,
|
|
58
65
|
DEFAULT_VIEW_NAME: () => DEFAULT_VIEW_NAME,
|
|
66
|
+
DUE_STATE_LABEL: () => DUE_STATE_LABEL,
|
|
59
67
|
DashboardCanvas: () => DashboardCanvas,
|
|
60
68
|
DigestScheduler: () => DigestScheduler,
|
|
61
69
|
DocRender: () => DocRender,
|
|
@@ -65,8 +73,14 @@ __export(src_exports, {
|
|
|
65
73
|
EnrichBadge: () => EnrichBadge,
|
|
66
74
|
EnrichPanel: () => EnrichPanel,
|
|
67
75
|
ExportMenu: () => ExportMenu,
|
|
76
|
+
FIELD_RULE_KIND_LABEL: () => FIELD_RULE_KIND_LABEL,
|
|
77
|
+
FIELD_RULE_KIND_VALUES: () => FIELD_RULE_KIND_VALUES,
|
|
78
|
+
FIELD_SENSITIVITY_LABEL: () => FIELD_SENSITIVITY_LABEL,
|
|
68
79
|
FIELD_TYPE_CHOICES: () => FIELD_TYPE_CHOICES,
|
|
69
80
|
FIELD_TYPE_GROUPS: () => FIELD_TYPE_GROUPS,
|
|
81
|
+
FORMULA_OP_JOINS: () => FORMULA_OP_JOINS,
|
|
82
|
+
FORMULA_OP_LABEL: () => FORMULA_OP_LABEL,
|
|
83
|
+
FORMULA_OP_VALUES: () => FORMULA_OP_VALUES,
|
|
70
84
|
FORM_FLOWS: () => FORM_FLOWS,
|
|
71
85
|
FROZEN_COLUMN_WIDTH: () => FROZEN_COLUMN_WIDTH,
|
|
72
86
|
FieldControl: () => FieldControl,
|
|
@@ -114,6 +128,8 @@ __export(src_exports, {
|
|
|
114
128
|
PAGE_VIEW_LABEL: () => PAGE_VIEW_LABEL,
|
|
115
129
|
PARITY_LABEL: () => PARITY_LABEL,
|
|
116
130
|
PARITY_MADE_OF: () => PARITY_MADE_OF,
|
|
131
|
+
PROPOSED_CHANGE_ACT_LABEL: () => PROPOSED_CHANGE_ACT_LABEL,
|
|
132
|
+
PROPOSED_CHANGE_ACT_VALUES: () => PROPOSED_CHANGE_ACT_VALUES,
|
|
117
133
|
Peek: () => Peek,
|
|
118
134
|
PersonPicker: () => PersonPicker,
|
|
119
135
|
PipelineBoard: () => PipelineBoard,
|
|
@@ -124,6 +140,8 @@ __export(src_exports, {
|
|
|
124
140
|
ProposalRow: () => ProposalRow,
|
|
125
141
|
ProvenanceBadge: () => ProvenanceBadge,
|
|
126
142
|
PublicViewPage: () => PublicViewPage,
|
|
143
|
+
ROLLUP_AGG_LABEL: () => ROLLUP_AGG_LABEL,
|
|
144
|
+
ROLLUP_AGG_VALUES: () => ROLLUP_AGG_VALUES,
|
|
127
145
|
RecordChat: () => RecordChat,
|
|
128
146
|
RecordChip: () => RecordChip,
|
|
129
147
|
RecordForm: () => RecordForm,
|
|
@@ -139,8 +157,13 @@ __export(src_exports, {
|
|
|
139
157
|
SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS: () => SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS,
|
|
140
158
|
SERIES_COLORS: () => SERIES_COLORS,
|
|
141
159
|
SOMEBODY: () => SOMEBODY,
|
|
160
|
+
STAGE_RULE_ON_FAIL_LABEL: () => STAGE_RULE_ON_FAIL_LABEL,
|
|
142
161
|
STORE_ANSWERS_THESE: () => STORE_ANSWERS_THESE,
|
|
143
162
|
STORE_DECIDES_REASON: () => STORE_DECIDES_REASON,
|
|
163
|
+
SUBSCRIPTION_CADENCES: () => SUBSCRIPTION_CADENCES,
|
|
164
|
+
SUBSCRIPTION_CADENCE_LABEL: () => SUBSCRIPTION_CADENCE_LABEL,
|
|
165
|
+
SUBSCRIPTION_CHANNEL_LABEL: () => SUBSCRIPTION_CHANNEL_LABEL,
|
|
166
|
+
SUBSCRIPTION_CHANNEL_VALUES: () => SUBSCRIPTION_CHANNEL_VALUES,
|
|
144
167
|
ShareControl: () => ShareControl,
|
|
145
168
|
SignBlock: () => SignBlock,
|
|
146
169
|
StageRulesSection: () => StageRulesSection,
|
|
@@ -158,6 +181,9 @@ __export(src_exports, {
|
|
|
158
181
|
ViewBar: () => ViewBar,
|
|
159
182
|
ViewSwitcher: () => ViewSwitcher,
|
|
160
183
|
WITHHELD_RECORD_LABEL: () => WITHHELD_RECORD_LABEL,
|
|
184
|
+
WORK_DUE_STATES: () => WORK_DUE_STATES,
|
|
185
|
+
WORK_INBOX_KINDS: () => WORK_INBOX_KINDS,
|
|
186
|
+
WORK_INBOX_KIND_LABEL: () => WORK_INBOX_KIND_LABEL,
|
|
161
187
|
WhoChangedSource: () => WhoChangedSource,
|
|
162
188
|
actorBadge: () => actorBadge,
|
|
163
189
|
actorWords: () => actorWords,
|
|
@@ -223,12 +249,14 @@ __export(src_exports, {
|
|
|
223
249
|
previewWords: () => previewWords,
|
|
224
250
|
publiclyAnswerable: () => publiclyAnswerable,
|
|
225
251
|
recordName: () => recordName,
|
|
252
|
+
recordNameIn: () => recordNameIn,
|
|
226
253
|
recordsDataSource: () => recordsDataSource,
|
|
227
254
|
refusalForAPerson: () => refusalForAPerson,
|
|
228
255
|
refusalLineForAPerson: () => refusalLineForAPerson,
|
|
229
256
|
renderValue: () => renderValue,
|
|
230
257
|
revokeConsequence: () => revokeConsequence,
|
|
231
258
|
rowName: () => rowName,
|
|
259
|
+
rowNameIn: () => rowNameIn,
|
|
232
260
|
scalarText: () => scalarText,
|
|
233
261
|
shareUnavailableReason: () => shareUnavailableReason,
|
|
234
262
|
specFromBlock: () => specFromBlock,
|
|
@@ -541,6 +569,12 @@ function looksLikeId(value) {
|
|
|
541
569
|
function rowName(row, titleKey, fallback = "Untitled") {
|
|
542
570
|
return recordName(row?.document, titleKey, fallback);
|
|
543
571
|
}
|
|
572
|
+
function recordNameIn(table, document2, fallback = "Untitled") {
|
|
573
|
+
return recordName(document2, table?.title_field ?? null, fallback);
|
|
574
|
+
}
|
|
575
|
+
function rowNameIn(table, row, fallback = "Untitled") {
|
|
576
|
+
return recordName(row?.document, table?.title_field ?? null, fallback);
|
|
577
|
+
}
|
|
544
578
|
var WITHHELD_RECORD_LABEL = "A record you have not been given access to";
|
|
545
579
|
|
|
546
580
|
// src/ReferenceBuilder.tsx
|
|
@@ -818,50 +852,9 @@ var PARITY_LABEL = {
|
|
|
818
852
|
var PARITY_MADE_OF = Object.fromEntries(
|
|
819
853
|
import_records3.PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
|
|
820
854
|
);
|
|
855
|
+
var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
|
|
821
856
|
function editorKindFor(field) {
|
|
822
|
-
|
|
823
|
-
const config = field.config ?? {};
|
|
824
|
-
switch (field.type) {
|
|
825
|
-
// LIMITS-FIX 2026-09-21: the tick box is a BEHAVIOUR of its own, so its editor is
|
|
826
|
-
// decided by the behaviour alone — no format, no unit, no target to read. A record
|
|
827
|
-
// that never answered holds no key at all, and `CheckboxControl` draws that third
|
|
828
|
-
// state rather than pretending it is an unticked box.
|
|
829
|
-
case "boolean":
|
|
830
|
-
return "checkbox";
|
|
831
|
-
case "text":
|
|
832
|
-
if (format === "email") return "email";
|
|
833
|
-
if (format === "phone") return "phone";
|
|
834
|
-
if (format === "url") return "url";
|
|
835
|
-
if (format === "json" || config["json"] === true) return "json";
|
|
836
|
-
if (format === "long" || config["multiline"] === true) return "long_text";
|
|
837
|
-
return "text";
|
|
838
|
-
case "range": {
|
|
839
|
-
const kind = String(config["kind"] ?? "number");
|
|
840
|
-
if (kind === "date" || kind === "datetime") return "datetime";
|
|
841
|
-
if (format === "currency") return "currency";
|
|
842
|
-
if (format === "percent" || field.unit === "%") return "percent";
|
|
843
|
-
return "number";
|
|
844
|
-
}
|
|
845
|
-
case "list":
|
|
846
|
-
return field.multi ? "multi_select" : "select";
|
|
847
|
-
case "relation":
|
|
848
|
-
return relationEditor(field);
|
|
849
|
-
case "formula": {
|
|
850
|
-
const via = config["via"];
|
|
851
|
-
if (via && config["agg"]) return "rollup";
|
|
852
|
-
if (via) return "lookup";
|
|
853
|
-
return "formula";
|
|
854
|
-
}
|
|
855
|
-
default:
|
|
856
|
-
return "text";
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
function relationEditor(field) {
|
|
860
|
-
const parity = String(field.config?.["parity"] ?? "");
|
|
861
|
-
if (parity === "attachment" || parity === "member") return parity;
|
|
862
|
-
if (field.relation_target === KERNEL_FILE_TABLE) return "attachment";
|
|
863
|
-
if (field.relation_target === KERNEL_PERSON_TABLE) return "member";
|
|
864
|
-
return "relation";
|
|
857
|
+
return (0, import_records3.fieldKindFor)(field, KERNEL);
|
|
865
858
|
}
|
|
866
859
|
function fieldTypeLabel(field) {
|
|
867
860
|
const kind = editorKindFor(field);
|
|
@@ -886,8 +879,7 @@ var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
|
886
879
|
function RelationPicker({ field, value, onChange, disabled, id, className }) {
|
|
887
880
|
const client = (0, import_react6.useRecordsClient)();
|
|
888
881
|
const [rows, setRows] = (0, import_react5.useState)(null);
|
|
889
|
-
const [
|
|
890
|
-
const [elsewhere, setElsewhere] = (0, import_react5.useState)({});
|
|
882
|
+
const [words, setWords] = (0, import_react5.useState)({});
|
|
891
883
|
const [refusal, setRefusal] = (0, import_react5.useState)(null);
|
|
892
884
|
const [search, setSearch] = (0, import_react5.useState)("");
|
|
893
885
|
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
@@ -904,47 +896,37 @@ function RelationPicker({ field, value, onChange, disabled, id, className }) {
|
|
|
904
896
|
if (result.ok) setRows(result.data.rows);
|
|
905
897
|
else setRefusal(refusalLineForAPerson(result.error));
|
|
906
898
|
});
|
|
907
|
-
void client.tableList().then((result) => {
|
|
908
|
-
if (cancelled || !result.ok) return;
|
|
909
|
-
setTitleKey(result.data.find((table) => table.id === target)?.title_field ?? null);
|
|
910
|
-
});
|
|
911
899
|
return () => {
|
|
912
900
|
cancelled = true;
|
|
913
901
|
};
|
|
914
902
|
}, [client, field.relation_target]);
|
|
915
903
|
(0, import_react5.useEffect)(() => {
|
|
916
904
|
if (!rows) return;
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
|
|
905
|
+
const wanted = [.../* @__PURE__ */ new Set([...rows.map((row) => row.id), ...picked])].filter(
|
|
906
|
+
(id2) => words[id2] === void 0
|
|
907
|
+
);
|
|
908
|
+
if (wanted.length === 0) return;
|
|
920
909
|
let cancelled = false;
|
|
921
|
-
void
|
|
922
|
-
missing.map(async (id2) => {
|
|
923
|
-
const result = await client.recordRead({ record_id: id2 });
|
|
924
|
-
return [id2, result.ok ? rowName({ document: result.data.document }, titleKey) : WITHHELD_RECORD_LABEL];
|
|
925
|
-
})
|
|
926
|
-
).then((pairs) => {
|
|
910
|
+
void client.relationWordsMany({ field_id: field.id, record_ids: wanted }).then((result) => {
|
|
927
911
|
if (cancelled) return;
|
|
928
|
-
|
|
912
|
+
const learned = {};
|
|
913
|
+
for (const id2 of wanted) {
|
|
914
|
+
const said = result.ok ? result.data[id2] : void 0;
|
|
915
|
+
learned[id2] = typeof said === "string" && said !== "" ? said : WITHHELD_RECORD_LABEL;
|
|
916
|
+
}
|
|
917
|
+
setWords((current) => ({ ...current, ...learned }));
|
|
929
918
|
});
|
|
930
919
|
return () => {
|
|
931
920
|
cancelled = true;
|
|
932
921
|
};
|
|
933
|
-
}, [client, rows, picked,
|
|
922
|
+
}, [client, field.id, rows, picked, words]);
|
|
934
923
|
if (!field.relation_target) {
|
|
935
924
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
|
|
936
925
|
fieldName(field),
|
|
937
926
|
" points at records, but it does not say which Table yet, so there is nothing to pick from. A table admin sets its target in the field editor."
|
|
938
927
|
] });
|
|
939
928
|
}
|
|
940
|
-
const
|
|
941
|
-
const titleOf = (recordId) => {
|
|
942
|
-
const row = byId.get(recordId);
|
|
943
|
-
if (row) return rowName(row, titleKey, "Untitled");
|
|
944
|
-
const away = elsewhere[recordId];
|
|
945
|
-
if (away !== void 0) return away;
|
|
946
|
-
return "Loading\u2026";
|
|
947
|
-
};
|
|
929
|
+
const titleOf = (recordId) => words[recordId] ?? "Loading\u2026";
|
|
948
930
|
const full = field.multi && field.relation_max !== null && picked.length >= field.relation_max;
|
|
949
931
|
const toggle = (recordId) => {
|
|
950
932
|
if (!field.multi) {
|
|
@@ -1688,28 +1670,12 @@ function RecordLabelProvider({ children }) {
|
|
|
1688
1670
|
stopWaitClock(field.id);
|
|
1689
1671
|
return;
|
|
1690
1672
|
}
|
|
1691
|
-
|
|
1692
|
-
if (!target) {
|
|
1673
|
+
if (!field.relation_target) {
|
|
1693
1674
|
setSettled((current) => ({ ...current, [field.id]: true }));
|
|
1694
1675
|
stopWaitClock(field.id);
|
|
1695
1676
|
return;
|
|
1696
1677
|
}
|
|
1697
|
-
const [rows, tables] = await Promise.all([
|
|
1698
|
-
client.list({ table_id: target, limit: 200 }),
|
|
1699
|
-
client.tableList()
|
|
1700
|
-
]);
|
|
1701
|
-
const titleKey = tables.ok ? tables.data.find((table) => table.id === target)?.title_field ?? null : null;
|
|
1702
|
-
if (rows.ok) {
|
|
1703
|
-
setNames((current) => {
|
|
1704
|
-
const next = { ...current };
|
|
1705
|
-
for (const row of rows.data.rows) {
|
|
1706
|
-
next[row.id] = recordName(row.document, titleKey, "Untitled");
|
|
1707
|
-
}
|
|
1708
|
-
return next;
|
|
1709
|
-
});
|
|
1710
|
-
}
|
|
1711
1678
|
setSettled((current) => ({ ...current, [field.id]: true }));
|
|
1712
|
-
stopWaitClock(field.id);
|
|
1713
1679
|
})();
|
|
1714
1680
|
},
|
|
1715
1681
|
[client, startWaitClock, stopWaitClock]
|
|
@@ -1718,27 +1684,26 @@ function RecordLabelProvider({ children }) {
|
|
|
1718
1684
|
const flushing = (0, import_react13.useRef)(null);
|
|
1719
1685
|
const flush = (0, import_react13.useCallback)(() => {
|
|
1720
1686
|
flushing.current = null;
|
|
1721
|
-
const batch = [...queued.current.
|
|
1687
|
+
const batch = [...queued.current.values()];
|
|
1722
1688
|
queued.current.clear();
|
|
1723
1689
|
if (batch.length === 0) return;
|
|
1724
1690
|
void (async () => {
|
|
1725
1691
|
const learned = {};
|
|
1726
|
-
const LANES = 6;
|
|
1727
|
-
let at = 0;
|
|
1728
1692
|
await Promise.all(
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1693
|
+
batch.map(async ({ field, ids }) => {
|
|
1694
|
+
const wanted = [...ids];
|
|
1695
|
+
const result = await client.relationWordsMany({
|
|
1696
|
+
field_id: field.id,
|
|
1697
|
+
record_ids: wanted
|
|
1698
|
+
});
|
|
1699
|
+
for (const id of wanted) {
|
|
1700
|
+
const words = result.ok ? result.data[id] : void 0;
|
|
1701
|
+
learned[id] = typeof words === "string" && words !== "" ? words : WITHHELD_RECORD_LABEL;
|
|
1737
1702
|
}
|
|
1738
1703
|
})
|
|
1739
1704
|
);
|
|
1740
1705
|
setNames((current) => ({ ...current, ...learned }));
|
|
1741
|
-
for (const
|
|
1706
|
+
for (const { field } of batch) stopWaitClock(field.id);
|
|
1742
1707
|
})();
|
|
1743
1708
|
}, [client, stopWaitClock]);
|
|
1744
1709
|
const chase = (0, import_react13.useCallback)(
|
|
@@ -1746,7 +1711,9 @@ function RecordLabelProvider({ children }) {
|
|
|
1746
1711
|
const key = `${field.id}:${id}`;
|
|
1747
1712
|
if (chased.current.has(key)) return;
|
|
1748
1713
|
chased.current.add(key);
|
|
1749
|
-
queued.current.
|
|
1714
|
+
const pending = queued.current.get(field.id);
|
|
1715
|
+
if (pending) pending.ids.add(id);
|
|
1716
|
+
else queued.current.set(field.id, { field, ids: /* @__PURE__ */ new Set([id]) });
|
|
1750
1717
|
startWaitClock(field, null);
|
|
1751
1718
|
if (flushing.current === null) flushing.current = setTimeout(flush, 0);
|
|
1752
1719
|
},
|
|
@@ -1783,18 +1750,137 @@ function useLabelWait(field) {
|
|
|
1783
1750
|
return field ? waiting(field) : null;
|
|
1784
1751
|
}
|
|
1785
1752
|
|
|
1786
|
-
// src/
|
|
1787
|
-
|
|
1788
|
-
function
|
|
1789
|
-
|
|
1790
|
-
|
|
1753
|
+
// src/enumLabels.ts
|
|
1754
|
+
function exhaustiveValuesOf() {
|
|
1755
|
+
return function(values) {
|
|
1756
|
+
return values;
|
|
1757
|
+
};
|
|
1791
1758
|
}
|
|
1792
|
-
var
|
|
1759
|
+
var WORK_DUE_STATES = exhaustiveValuesOf()([
|
|
1760
|
+
"overdue",
|
|
1761
|
+
"due_today",
|
|
1762
|
+
"scheduled",
|
|
1763
|
+
"undated",
|
|
1764
|
+
"finished"
|
|
1765
|
+
]);
|
|
1766
|
+
var DUE_STATE_LABEL = {
|
|
1767
|
+
overdue: "Overdue",
|
|
1768
|
+
due_today: "Today",
|
|
1769
|
+
scheduled: "Scheduled",
|
|
1770
|
+
undated: "No date",
|
|
1771
|
+
finished: "Done"
|
|
1772
|
+
};
|
|
1773
|
+
var WORK_INBOX_KINDS = exhaustiveValuesOf()(["assignment", "approval", "proposal"]);
|
|
1774
|
+
var WORK_INBOX_KIND_LABEL = {
|
|
1775
|
+
assignment: "Yours",
|
|
1776
|
+
approval: "Approve",
|
|
1777
|
+
proposal: "Agent"
|
|
1778
|
+
};
|
|
1779
|
+
var CHECKLIST_REQUIREMENT_KINDS = exhaustiveValuesOf()([
|
|
1780
|
+
"none",
|
|
1781
|
+
"note",
|
|
1782
|
+
"answer",
|
|
1783
|
+
"record_field",
|
|
1784
|
+
"form",
|
|
1785
|
+
"document"
|
|
1786
|
+
]);
|
|
1787
|
+
var CHECKLIST_REQUIREMENT_LABEL = {
|
|
1788
|
+
none: "",
|
|
1789
|
+
note: "Say what you did",
|
|
1790
|
+
answer: "Fill this in",
|
|
1791
|
+
record_field: "This has to be filled in on the record",
|
|
1792
|
+
form: "This step is a form",
|
|
1793
|
+
document: "This step is a document"
|
|
1794
|
+
};
|
|
1795
|
+
var FIELD_SENSITIVITY_LABEL = {
|
|
1796
|
+
public: "Anyone who can open the record",
|
|
1797
|
+
internal: "People in this organization",
|
|
1798
|
+
confidential: "People who have been given the record",
|
|
1799
|
+
restricted: "Owners and administrators only"
|
|
1800
|
+
};
|
|
1801
|
+
var CONTEXT_POLICY_LABEL = {
|
|
1802
|
+
include: "Yes, an assistant can read it",
|
|
1803
|
+
summarize: "Only a summary of it",
|
|
1804
|
+
on_request: "Only when somebody asks for it",
|
|
1805
|
+
exclude: "No, keep it away from assistants"
|
|
1806
|
+
};
|
|
1807
|
+
var STAGE_RULE_ON_FAIL_LABEL = {
|
|
1808
|
+
refuse: "Turn it away",
|
|
1809
|
+
require_approval: "Ask for approval"
|
|
1810
|
+
};
|
|
1811
|
+
var SUBSCRIPTION_CADENCES = exhaustiveValuesOf()(["instant", "hourly", "daily", "weekly"]);
|
|
1812
|
+
var SUBSCRIPTION_CADENCE_LABEL = {
|
|
1813
|
+
instant: "as it happens",
|
|
1814
|
+
hourly: "hourly summary",
|
|
1815
|
+
daily: "daily summary",
|
|
1816
|
+
weekly: "weekly summary"
|
|
1817
|
+
};
|
|
1818
|
+
var SUBSCRIPTION_CHANNEL_VALUES = ["in_app", "email", "sms"];
|
|
1819
|
+
var SUBSCRIPTION_CHANNEL_LABEL = {
|
|
1820
|
+
in_app: "in the app",
|
|
1821
|
+
email: "by email \u2014 only if an address is on the account",
|
|
1822
|
+
sms: "by text \u2014 only if a number is on the account"
|
|
1823
|
+
};
|
|
1824
|
+
var ROLLUP_AGG_VALUES = ["count", "sum", "avg", "min", "max"];
|
|
1825
|
+
var ROLLUP_AGG_LABEL = {
|
|
1826
|
+
count: "How many there are",
|
|
1827
|
+
sum: "The total of",
|
|
1828
|
+
avg: "The average of",
|
|
1829
|
+
min: "The smallest",
|
|
1830
|
+
max: "The largest"
|
|
1831
|
+
};
|
|
1832
|
+
var FORMULA_OP_VALUES = ["concat", "add", "sub", "mul", "div"];
|
|
1833
|
+
var FORMULA_OP_LABEL = {
|
|
1834
|
+
concat: "Join them together",
|
|
1835
|
+
add: "Add them up",
|
|
1836
|
+
sub: "Take the second from the first",
|
|
1837
|
+
mul: "Multiply them",
|
|
1838
|
+
div: "Divide the first by the second"
|
|
1839
|
+
};
|
|
1840
|
+
var FORMULA_OP_JOINS = {
|
|
1841
|
+
concat: true,
|
|
1842
|
+
add: true,
|
|
1843
|
+
sub: false,
|
|
1844
|
+
mul: true,
|
|
1845
|
+
div: false
|
|
1846
|
+
};
|
|
1847
|
+
var FIELD_RULE_KIND_VALUES = ["min", "max", "length", "pattern", "equals_field", "differs_from_field"];
|
|
1848
|
+
var FIELD_RULE_KIND_LABEL = {
|
|
1849
|
+
min: "At least",
|
|
1850
|
+
max: "At most",
|
|
1851
|
+
length: "No longer than",
|
|
1852
|
+
pattern: "Looks like",
|
|
1853
|
+
equals_field: "Same as the column",
|
|
1854
|
+
differs_from_field: "Different from the column"
|
|
1855
|
+
};
|
|
1856
|
+
var PROPOSED_CHANGE_ACT_VALUES = ["add", "update", "remove"];
|
|
1857
|
+
var PROPOSED_CHANGE_ACT_LABEL = {
|
|
1858
|
+
add: "Add",
|
|
1859
|
+
update: "Update",
|
|
1860
|
+
remove: "Remove"
|
|
1861
|
+
};
|
|
1862
|
+
var BOOKING_PAGE_STATE_VALUES = ["draft", "open", "closed", "full"];
|
|
1863
|
+
var BOOKING_PAGE_STATE_LABEL = {
|
|
1864
|
+
draft: "Not open yet \u2014 nobody can book until you open it.",
|
|
1865
|
+
open: "Open. Anyone with the link can book a time.",
|
|
1866
|
+
closed: "Closed. The link still works and says you are not taking bookings.",
|
|
1867
|
+
full: "Every time you offered is taken."
|
|
1868
|
+
};
|
|
1869
|
+
var ABSENCE_WORD_VALUES = ["never asked", "none", "refused", "conflicting"];
|
|
1870
|
+
var ABSENCE_WORD_LABEL = {
|
|
1793
1871
|
"never asked": "never asked",
|
|
1794
1872
|
none: "none",
|
|
1795
1873
|
refused: "refused",
|
|
1796
1874
|
conflicting: "conflicting"
|
|
1797
1875
|
};
|
|
1876
|
+
|
|
1877
|
+
// src/values.tsx
|
|
1878
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1879
|
+
function envelopeFor(document2, key) {
|
|
1880
|
+
const block = document2?._values;
|
|
1881
|
+
return block?.[key];
|
|
1882
|
+
}
|
|
1883
|
+
var ABSENCE_WORDS = ABSENCE_WORD_LABEL;
|
|
1798
1884
|
function renderValue(field, value, document2, labels, stillWaitingFor) {
|
|
1799
1885
|
const envelope = envelopeFor(document2, field.key);
|
|
1800
1886
|
if (envelope?.absent) {
|
|
@@ -3217,113 +3303,11 @@ function choiceOptionsOf(options) {
|
|
|
3217
3303
|
}
|
|
3218
3304
|
return { byWord, labels };
|
|
3219
3305
|
}
|
|
3220
|
-
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
3221
|
-
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
3222
3306
|
function valueFromPastedText(field, raw, options) {
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
switch (kind) {
|
|
3228
|
-
case "checkbox": {
|
|
3229
|
-
const word = text.toLowerCase();
|
|
3230
|
-
if (TRUE_WORDS.has(word)) return { value: true };
|
|
3231
|
-
if (FALSE_WORDS.has(word)) return { value: word === "" ? null : false };
|
|
3232
|
-
return {
|
|
3233
|
-
refusal: `${label} is a tick box, so it takes yes or no \u2014 \u201C${raw}\u201D is neither. Paste TRUE/FALSE, yes/no or 1/0.`
|
|
3234
|
-
};
|
|
3235
|
-
}
|
|
3236
|
-
case "number":
|
|
3237
|
-
case "currency":
|
|
3238
|
-
case "percent": {
|
|
3239
|
-
const negative = /^\(.*\)$/.test(text);
|
|
3240
|
-
const bare = text.replace(/^\(|\)$/g, "").replace(/[\s,]/g, "").replace(/^[^\d.\-+]+/, "").replace(/[^\d.\-+eE]+$/, "");
|
|
3241
|
-
const n = Number(bare);
|
|
3242
|
-
if (bare === "" || Number.isNaN(n)) {
|
|
3243
|
-
return {
|
|
3244
|
-
refusal: `${label} holds a number, and \u201C${raw}\u201D is not one. Paste digits \u2014 a currency symbol, a percent sign, commas and brackets for a negative are all fine.`
|
|
3245
|
-
};
|
|
3246
|
-
}
|
|
3247
|
-
return { value: negative ? -n : n };
|
|
3248
|
-
}
|
|
3249
|
-
case "datetime": {
|
|
3250
|
-
const wantsTime = String(field.config?.["kind"] ?? "date") === "datetime";
|
|
3251
|
-
const plainDay = /^\s*(\d{4})-(\d{2})-(\d{2})\s*$/.exec(raw);
|
|
3252
|
-
if (!wantsTime && plainDay) return { value: `${plainDay[1]}-${plainDay[2]}-${plainDay[3]}` };
|
|
3253
|
-
const at = Date.parse(text);
|
|
3254
|
-
if (Number.isNaN(at)) {
|
|
3255
|
-
return {
|
|
3256
|
-
refusal: `${label} holds a date, and \u201C${raw}\u201D is not one this can read. Paste it as 2026-09-21, or as your spreadsheet's own date format.`
|
|
3257
|
-
};
|
|
3258
|
-
}
|
|
3259
|
-
const parsed = new Date(at);
|
|
3260
|
-
if (wantsTime) return { value: parsed.toISOString() };
|
|
3261
|
-
const y = parsed.getFullYear();
|
|
3262
|
-
const m = String(parsed.getMonth() + 1).padStart(2, "0");
|
|
3263
|
-
const d = String(parsed.getDate()).padStart(2, "0");
|
|
3264
|
-
return { value: `${y}-${m}-${d}` };
|
|
3265
|
-
}
|
|
3266
|
-
case "json": {
|
|
3267
|
-
try {
|
|
3268
|
-
return { value: JSON.parse(text) };
|
|
3269
|
-
} catch {
|
|
3270
|
-
return {
|
|
3271
|
-
refusal: `${label} holds a document, and \u201C${raw}\u201D is not valid JSON. Paste the whole object, braces and all.`
|
|
3272
|
-
};
|
|
3273
|
-
}
|
|
3274
|
-
}
|
|
3275
|
-
// A LIST, A PERSON, A FILE OR ANOTHER RECORD IS AN IDENTITY, NOT A WORD.
|
|
3276
|
-
// The store keeps the id of the option or the record, and a word off a
|
|
3277
|
-
// clipboard is not that id — writing the word would put a string where an
|
|
3278
|
-
// id belongs and every filter, colour and rollup built on that column would
|
|
3279
|
-
// stop agreeing with it. So the cell is left alone and the person is told
|
|
3280
|
-
// which control does hold it.
|
|
3281
|
-
case "select":
|
|
3282
|
-
case "multi_select": {
|
|
3283
|
-
if (!options) {
|
|
3284
|
-
return {
|
|
3285
|
-
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.`
|
|
3286
|
-
};
|
|
3287
|
-
}
|
|
3288
|
-
const wanted = kind === "multi_select" ? text.split(/[,;]/).map((w) => w.trim()).filter((w) => w.length > 0) : [text];
|
|
3289
|
-
if (wanted.length === 0) return { value: kind === "multi_select" ? [] : null };
|
|
3290
|
-
const matched = [];
|
|
3291
|
-
const unmatched = [];
|
|
3292
|
-
for (const word of wanted) {
|
|
3293
|
-
const hit = options.byWord.get(word.toLowerCase());
|
|
3294
|
-
if (hit === void 0) unmatched.push(word);
|
|
3295
|
-
else matched.push(hit);
|
|
3296
|
-
}
|
|
3297
|
-
if (unmatched.length > 0) {
|
|
3298
|
-
const offered = options.labels.length > 0 ? options.labels.join(", ") : "it has none yet";
|
|
3299
|
-
return {
|
|
3300
|
-
refusal: `${label} does not have ${unmatched.map((w) => `\u201C${w}\u201D`).join(" or ")} among its options. It offers: ${offered}.`,
|
|
3301
|
-
unmatched
|
|
3302
|
-
};
|
|
3303
|
-
}
|
|
3304
|
-
return { value: kind === "multi_select" ? matched : matched[0] };
|
|
3305
|
-
}
|
|
3306
|
-
case "member":
|
|
3307
|
-
return {
|
|
3308
|
-
refusal: `${label} names a person in this organization, so it is chosen rather than typed. Open the cell and pick them.`
|
|
3309
|
-
};
|
|
3310
|
-
case "attachment":
|
|
3311
|
-
return {
|
|
3312
|
-
refusal: `${label} holds a file, which cannot arrive on a clipboard. Open the cell and attach it.`
|
|
3313
|
-
};
|
|
3314
|
-
case "relation":
|
|
3315
|
-
return {
|
|
3316
|
-
refusal: `${label} points at another record, so it is chosen rather than typed. Open the cell and pick the record.`
|
|
3317
|
-
};
|
|
3318
|
-
case "formula":
|
|
3319
|
-
case "lookup":
|
|
3320
|
-
case "rollup":
|
|
3321
|
-
return {
|
|
3322
|
-
refusal: `${label} is worked out by the system, so nothing can be pasted into it.`
|
|
3323
|
-
};
|
|
3324
|
-
default:
|
|
3325
|
-
return { value: raw };
|
|
3326
|
-
}
|
|
3307
|
+
return (0, import_records5.coerceTypedAnswer)(field, raw, {
|
|
3308
|
+
label: fieldName(field),
|
|
3309
|
+
...options ? { options } : {}
|
|
3310
|
+
});
|
|
3327
3311
|
}
|
|
3328
3312
|
function planPastedBlock(args) {
|
|
3329
3313
|
const byKey = new Map(args.fields.map((f) => [f.key, f]));
|
|
@@ -3868,9 +3852,11 @@ function Grid({
|
|
|
3868
3852
|
onClick: () => host.talkToRecord?.({
|
|
3869
3853
|
tableId,
|
|
3870
3854
|
recordId: row.id,
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3855
|
+
// ONE NAMING CALL (`names.ts`), not this file's own join
|
|
3856
|
+
// of a Table's title column to a document.
|
|
3857
|
+
title: recordNameIn(
|
|
3858
|
+
table.data,
|
|
3859
|
+
row.document ?? {}
|
|
3874
3860
|
)
|
|
3875
3861
|
}),
|
|
3876
3862
|
children: "Talk"
|
|
@@ -4491,19 +4477,23 @@ var import_react27 = require("react");
|
|
|
4491
4477
|
var import_react28 = require("@ai-matrx/records/react");
|
|
4492
4478
|
var import_design_system13 = require("@ai-matrx/design-system");
|
|
4493
4479
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
4494
|
-
var
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4480
|
+
var ADDABLE_TYPE_IDS = [
|
|
4481
|
+
"text",
|
|
4482
|
+
"long_text",
|
|
4483
|
+
"number",
|
|
4484
|
+
"currency",
|
|
4485
|
+
"percent",
|
|
4486
|
+
"datetime",
|
|
4487
|
+
"email",
|
|
4488
|
+
"phone",
|
|
4489
|
+
"url",
|
|
4490
|
+
"member",
|
|
4491
|
+
"attachment"
|
|
4506
4492
|
];
|
|
4493
|
+
var ADDABLE_TYPES = ADDABLE_TYPE_IDS.map((value) => ({
|
|
4494
|
+
value,
|
|
4495
|
+
label: fieldTypeChoice(value)?.label ?? value
|
|
4496
|
+
}));
|
|
4507
4497
|
function asField(f) {
|
|
4508
4498
|
return {
|
|
4509
4499
|
id: f.id,
|
|
@@ -4667,41 +4657,20 @@ function CustomFieldsSection({
|
|
|
4667
4657
|
var import_react29 = require("react");
|
|
4668
4658
|
var import_react30 = require("@ai-matrx/records/react");
|
|
4669
4659
|
var import_design_system14 = require("@ai-matrx/design-system");
|
|
4660
|
+
var import_records6 = require("@ai-matrx/records");
|
|
4670
4661
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4671
|
-
var RULE_KINDS = [
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
{ value: "restricted", label: "Owners and administrators only" }
|
|
4684
|
-
];
|
|
4685
|
-
var AGENT_VISIBILITY = [
|
|
4686
|
-
{ value: "include", label: "Yes, an assistant can read it" },
|
|
4687
|
-
{ value: "summarize", label: "Only a summary of it" },
|
|
4688
|
-
{ value: "on_request", label: "Only when somebody asks for it" },
|
|
4689
|
-
{ value: "exclude", label: "No, keep it away from assistants" }
|
|
4690
|
-
];
|
|
4691
|
-
var ROLLUP_OPERATIONS = [
|
|
4692
|
-
{ value: "count", label: "How many there are" },
|
|
4693
|
-
{ value: "sum", label: "The total of" },
|
|
4694
|
-
{ value: "avg", label: "The average of" },
|
|
4695
|
-
{ value: "min", label: "The smallest" },
|
|
4696
|
-
{ value: "max", label: "The largest" }
|
|
4697
|
-
];
|
|
4698
|
-
var FORMULA_OPERATIONS = [
|
|
4699
|
-
{ value: "concat", label: "Join them together", joins: true },
|
|
4700
|
-
{ value: "add", label: "Add them up", joins: true },
|
|
4701
|
-
{ value: "sub", label: "Take the second from the first", joins: false },
|
|
4702
|
-
{ value: "mul", label: "Multiply them", joins: true },
|
|
4703
|
-
{ value: "div", label: "Divide the first by the second", joins: false }
|
|
4704
|
-
];
|
|
4662
|
+
var RULE_KINDS = FIELD_RULE_KIND_VALUES.map((kind) => ({ kind, label: FIELD_RULE_KIND_LABEL[kind] }));
|
|
4663
|
+
var SENSITIVITIES = import_records6.FIELD_SENSITIVITIES.map((value) => ({ value, label: FIELD_SENSITIVITY_LABEL[value] }));
|
|
4664
|
+
var AGENT_VISIBILITY = import_records6.CONTEXT_POLICIES.map((value) => ({ value, label: CONTEXT_POLICY_LABEL[value] }));
|
|
4665
|
+
var ROLLUP_OPERATIONS = ROLLUP_AGG_VALUES.map((value) => ({
|
|
4666
|
+
value,
|
|
4667
|
+
label: ROLLUP_AGG_LABEL[value]
|
|
4668
|
+
}));
|
|
4669
|
+
var FORMULA_OPERATIONS = FORMULA_OP_VALUES.map((value) => ({
|
|
4670
|
+
value,
|
|
4671
|
+
label: FORMULA_OP_LABEL[value],
|
|
4672
|
+
joins: FORMULA_OP_JOINS[value]
|
|
4673
|
+
}));
|
|
4705
4674
|
function keyFor(label) {
|
|
4706
4675
|
const token = label.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48);
|
|
4707
4676
|
if (token === "") return "";
|
|
@@ -5266,6 +5235,9 @@ var CONDITION_OPS = [
|
|
|
5266
5235
|
{ op: "gt", label: "is more than" },
|
|
5267
5236
|
{ op: "lt", label: "is less than" }
|
|
5268
5237
|
];
|
|
5238
|
+
function pointsAtARecord(f) {
|
|
5239
|
+
return !!f?.field && f.field.type === "relation" && !!f.field.relation_target;
|
|
5240
|
+
}
|
|
5269
5241
|
function conditionIsSimple(expr) {
|
|
5270
5242
|
if (expr === null || expr === void 0) return true;
|
|
5271
5243
|
const node = expr;
|
|
@@ -5336,6 +5308,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5336
5308
|
const op = node?.op ?? "";
|
|
5337
5309
|
const onField = node?.args?.[0]?.field ?? "";
|
|
5338
5310
|
const value = node?.args?.[1]?.const ?? "";
|
|
5311
|
+
const chosen = fields.find((f) => f.id === onField);
|
|
5339
5312
|
function write(next) {
|
|
5340
5313
|
const chosenOp = next.op ?? op;
|
|
5341
5314
|
const chosenField = next.field ?? onField;
|
|
@@ -5374,7 +5347,24 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5374
5347
|
children: CONDITION_OPS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: c.op, children: c.label }, c.op))
|
|
5375
5348
|
}
|
|
5376
5349
|
),
|
|
5377
|
-
op
|
|
5350
|
+
op === "present" ? null : pointsAtARecord(chosen) ? (
|
|
5351
|
+
// A RECORD IS PICKED BY ITS WORDS, NEVER TYPED AS AN ID. The same picker the
|
|
5352
|
+
// cell uses, on the same `relation_words_many` the cell reads, so a filter and
|
|
5353
|
+
// the column it filters can never disagree about what a record is called. It
|
|
5354
|
+
// is asked for ONE record even when the column holds several: a clause compares
|
|
5355
|
+
// against one value, and a picker that let somebody choose three would be
|
|
5356
|
+
// writing an expression this row cannot draw back.
|
|
5357
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5358
|
+
RelationPicker,
|
|
5359
|
+
{
|
|
5360
|
+
field: { ...chosen.field, multi: false },
|
|
5361
|
+
value: value === "" ? null : value,
|
|
5362
|
+
onChange: (next) => write({ value: next === null || next === void 0 ? "" : String(next) }),
|
|
5363
|
+
id: "condition-value-record",
|
|
5364
|
+
className: "min-w-[8rem]"
|
|
5365
|
+
}
|
|
5366
|
+
)
|
|
5367
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5378
5368
|
import_design_system15.BasicInput,
|
|
5379
5369
|
{
|
|
5380
5370
|
className: "h-8 w-28 text-xs",
|
|
@@ -5382,7 +5372,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5382
5372
|
value: String(value ?? ""),
|
|
5383
5373
|
onChange: (e) => write({ value: conditionValue(e.target.value) })
|
|
5384
5374
|
}
|
|
5385
|
-
)
|
|
5375
|
+
)
|
|
5386
5376
|
] }) : null
|
|
5387
5377
|
] });
|
|
5388
5378
|
}
|
|
@@ -5542,10 +5532,10 @@ var NO_RULES_YET = "Nothing has to be true to get here yet.";
|
|
|
5542
5532
|
var NEEDS_A_SENTENCE = "Write the sentence somebody reads when this stops them, the way you would say it out loud.";
|
|
5543
5533
|
var NOT_DRAWN_HERE = "This part of the rule is not something this builder can draw yet";
|
|
5544
5534
|
var ON_FAIL = [
|
|
5545
|
-
{ value: "refuse", label:
|
|
5535
|
+
{ value: "refuse", label: STAGE_RULE_ON_FAIL_LABEL.refuse, note: "The card stays where it is and the person is told why." },
|
|
5546
5536
|
{
|
|
5547
5537
|
value: "require_approval",
|
|
5548
|
-
label:
|
|
5538
|
+
label: STAGE_RULE_ON_FAIL_LABEL.require_approval,
|
|
5549
5539
|
note: "The card stays where it is, and the people who can approve it are asked. Nobody is turned away."
|
|
5550
5540
|
}
|
|
5551
5541
|
];
|
|
@@ -5596,7 +5586,7 @@ function StageRulesSection({ tableId, stage, className }) {
|
|
|
5596
5586
|
const stageLabel = stages.find((s) => s.key === stageKey)?.label ?? stageKey ?? "";
|
|
5597
5587
|
const gates = (0, import_react32.useMemo)(() => stageKey ? gatesOf(pipeline, stageKey) : [], [pipeline, stageKey]);
|
|
5598
5588
|
const conditionFields = (0, import_react32.useMemo)(
|
|
5599
|
-
() => (fields.data ?? []).map((f) => ({ id: String(f.id), key: f.key, label: fieldName(f) })),
|
|
5589
|
+
() => (fields.data ?? []).map((f) => ({ id: String(f.id), key: f.key, label: fieldName(f), field: f })),
|
|
5600
5590
|
[fields.data]
|
|
5601
5591
|
);
|
|
5602
5592
|
(0, import_react32.useEffect)(() => {
|
|
@@ -6528,7 +6518,7 @@ function Peek({ tableId, recordId, onClose, className }) {
|
|
|
6528
6518
|
if (record.error) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RefusalNotice, { error: record.error, className });
|
|
6529
6519
|
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(RefusalNotice, { error: fields.error, className });
|
|
6530
6520
|
const document2 = record.data?.document;
|
|
6531
|
-
const title = document2 ?
|
|
6521
|
+
const title = document2 ? recordNameIn(table.data, document2) : "";
|
|
6532
6522
|
const href = host.hrefForRecord && table.data ? host.hrefForRecord({ table: table.data, recordId }) : void 0;
|
|
6533
6523
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: (0, import_design_system21.cn)("flex min-w-0 flex-col gap-2 text-xs", className), children: [
|
|
6534
6524
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -7284,7 +7274,7 @@ function offerableFields(all, want) {
|
|
|
7284
7274
|
return all.filter((field) => {
|
|
7285
7275
|
const kind = editorKindFor(field);
|
|
7286
7276
|
if (want === "choice") return kind === "select" || kind === "multi_select";
|
|
7287
|
-
return kind === "datetime"
|
|
7277
|
+
return kind === "datetime";
|
|
7288
7278
|
});
|
|
7289
7279
|
}
|
|
7290
7280
|
function useStageField(tableId) {
|
|
@@ -7702,11 +7692,7 @@ var import_react54 = require("react");
|
|
|
7702
7692
|
var import_react55 = require("@ai-matrx/records/react");
|
|
7703
7693
|
var import_design_system25 = require("@ai-matrx/design-system");
|
|
7704
7694
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
7705
|
-
var ACT_WORD =
|
|
7706
|
-
add: "Add",
|
|
7707
|
-
update: "Update",
|
|
7708
|
-
remove: "Remove"
|
|
7709
|
-
};
|
|
7695
|
+
var ACT_WORD = PROPOSED_CHANGE_ACT_LABEL;
|
|
7710
7696
|
function ProposalRow({
|
|
7711
7697
|
change,
|
|
7712
7698
|
outcome,
|
|
@@ -7813,21 +7799,8 @@ var import_react56 = require("react");
|
|
|
7813
7799
|
var import_react57 = require("@ai-matrx/records/react");
|
|
7814
7800
|
var import_design_system26 = require("@ai-matrx/design-system");
|
|
7815
7801
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
7816
|
-
var DUE_WORD =
|
|
7817
|
-
|
|
7818
|
-
due_today: "Today",
|
|
7819
|
-
scheduled: "Scheduled",
|
|
7820
|
-
undated: "No date",
|
|
7821
|
-
finished: "Done"
|
|
7822
|
-
};
|
|
7823
|
-
var REQUIRES_WORD = {
|
|
7824
|
-
none: "",
|
|
7825
|
-
note: "Say what you did",
|
|
7826
|
-
answer: "Fill this in",
|
|
7827
|
-
record_field: "This has to be filled in on the record",
|
|
7828
|
-
form: "This step is a form",
|
|
7829
|
-
document: "This step is a document"
|
|
7830
|
-
};
|
|
7802
|
+
var DUE_WORD = DUE_STATE_LABEL;
|
|
7803
|
+
var REQUIRES_WORD = CHECKLIST_REQUIREMENT_LABEL;
|
|
7831
7804
|
var NO_TEMPLATES = "No checklist has been written for this table yet. Ask an agent for one in a sentence \u2014 the steps, who each belongs to, and how many days in each is due \u2014 and it is stored whole, judged before a single step is written.";
|
|
7832
7805
|
function ChecklistRunner({
|
|
7833
7806
|
tableId,
|
|
@@ -8535,18 +8508,8 @@ function roleKey(said) {
|
|
|
8535
8508
|
// src/ActionInbox.tsx
|
|
8536
8509
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
8537
8510
|
var ACTION_KINDS = ["approval", "assignment", "proposal"];
|
|
8538
|
-
var KIND_WORD =
|
|
8539
|
-
|
|
8540
|
-
approval: "Approve",
|
|
8541
|
-
proposal: "Agent"
|
|
8542
|
-
};
|
|
8543
|
-
var DUE_WORD2 = {
|
|
8544
|
-
overdue: "Overdue",
|
|
8545
|
-
due_today: "Today",
|
|
8546
|
-
scheduled: "Scheduled",
|
|
8547
|
-
undated: "No date",
|
|
8548
|
-
finished: "Finished"
|
|
8549
|
-
};
|
|
8511
|
+
var KIND_WORD = WORK_INBOX_KIND_LABEL;
|
|
8512
|
+
var DUE_WORD2 = DUE_STATE_LABEL;
|
|
8550
8513
|
function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className }) {
|
|
8551
8514
|
const client = (0, import_react59.useRecordsClient)();
|
|
8552
8515
|
const [items, setItems] = (0, import_react58.useState)(null);
|
|
@@ -9767,7 +9730,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
|
|
|
9767
9730
|
// src/PortalsPanel.tsx
|
|
9768
9731
|
var import_react68 = require("react");
|
|
9769
9732
|
var import_react69 = require("@ai-matrx/records/react");
|
|
9770
|
-
var
|
|
9733
|
+
var import_records7 = require("@ai-matrx/records");
|
|
9771
9734
|
var import_design_system33 = require("@ai-matrx/design-system");
|
|
9772
9735
|
|
|
9773
9736
|
// src/BuildOrAsk.tsx
|
|
@@ -9784,18 +9747,18 @@ function BuildOrAsk({
|
|
|
9784
9747
|
buildLabel,
|
|
9785
9748
|
className
|
|
9786
9749
|
}) {
|
|
9750
|
+
const mayAsk = mayBuild && Boolean(onAsk);
|
|
9787
9751
|
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: (0, import_design_system32.cn)("rounded-md border border-dashed p-3", className), children: [
|
|
9788
9752
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", children }),
|
|
9789
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: [
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
] }),
|
|
9793
|
-
|
|
9753
|
+
mayBuild ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: [
|
|
9754
|
+
mayAsk ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_design_system32.Button, { size: "sm", variant: "outline", onClick: onAsk, children: "Ask an agent" }) : null,
|
|
9755
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_design_system32.Button, { size: "sm", onClick: onBuild, children: buildLabel })
|
|
9756
|
+
] }) : null,
|
|
9757
|
+
!mayBuild ? whyNot ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: whyNot }) : null : mayAsk ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("p", { className: "mt-2 text-xs text-muted-foreground", children: [
|
|
9794
9758
|
"You would say something like: \u201C",
|
|
9795
9759
|
suggestion,
|
|
9796
9760
|
"\u201D"
|
|
9797
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: NO_AGENT_PORT })
|
|
9798
|
-
!mayBuild && whyNot ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: whyNot }) : null
|
|
9761
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: NO_AGENT_PORT })
|
|
9799
9762
|
] });
|
|
9800
9763
|
}
|
|
9801
9764
|
|
|
@@ -9834,30 +9797,41 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9834
9797
|
const client = (0, import_react69.useRecordsClient)();
|
|
9835
9798
|
const host = useRecordsUi();
|
|
9836
9799
|
const [portals, setPortals] = (0, import_react68.useState)(null);
|
|
9800
|
+
const [exposures, setExposures] = (0, import_react68.useState)([]);
|
|
9837
9801
|
const [listError, setListError] = (0, import_react68.useState)(null);
|
|
9838
9802
|
const [openId, setOpenId] = (0, import_react68.useState)(null);
|
|
9839
9803
|
const [building, setBuilding] = (0, import_react68.useState)(false);
|
|
9804
|
+
const [adding, setAdding] = (0, import_react68.useState)(null);
|
|
9840
9805
|
const load = (0, import_react68.useCallback)(async () => {
|
|
9841
|
-
const answered = await client.portals();
|
|
9806
|
+
const [answered, mapped] = await Promise.all([client.portals(), client.portalTables()]);
|
|
9842
9807
|
if (!answered.ok) {
|
|
9843
9808
|
setListError(answered.error);
|
|
9844
9809
|
setPortals([]);
|
|
9810
|
+
setExposures([]);
|
|
9845
9811
|
return;
|
|
9846
9812
|
}
|
|
9847
9813
|
setListError(null);
|
|
9848
9814
|
setPortals(answered.data);
|
|
9815
|
+
setExposures(mapped.ok ? mapped.data : []);
|
|
9849
9816
|
}, [client]);
|
|
9850
9817
|
(0, import_react68.useEffect)(() => {
|
|
9851
9818
|
void load();
|
|
9852
9819
|
}, [load]);
|
|
9853
9820
|
if (portals === null) return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Skeleton, { className: (0, import_design_system33.cn)("h-32 w-full", className) });
|
|
9821
|
+
const onATable = Boolean(tableId);
|
|
9822
|
+
const holdingThis = new Set(
|
|
9823
|
+
exposures.filter((e) => e.table_id === tableId).map((e) => e.portal_id)
|
|
9824
|
+
);
|
|
9825
|
+
const shown = onATable ? portals.filter((p) => holdingThis.has(p.portal_id)) : portals;
|
|
9826
|
+
const couldTakeIt = onATable ? portals.filter((p) => !holdingThis.has(p.portal_id)) : [];
|
|
9827
|
+
const elsewhere = couldTakeIt.length;
|
|
9854
9828
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
9855
9829
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("flex flex-col gap-3", className), children: [
|
|
9856
9830
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
9857
9831
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-sm font-medium", children: "Portals" }),
|
|
9858
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children:
|
|
9832
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: shown.length === 0 ? "none for this table" : `${shown.length}` }),
|
|
9859
9833
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1" }),
|
|
9860
|
-
|
|
9834
|
+
shown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Button, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a portal" }) : null
|
|
9861
9835
|
] }),
|
|
9862
9836
|
listError ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(RefusalNotice, { error: listError }) : null,
|
|
9863
9837
|
building ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -9870,7 +9844,19 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9870
9844
|
onClose: () => setBuilding(false)
|
|
9871
9845
|
}
|
|
9872
9846
|
) : null,
|
|
9873
|
-
|
|
9847
|
+
adding ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9848
|
+
PortalBuilder,
|
|
9849
|
+
{
|
|
9850
|
+
...tableId ? { tableId } : {},
|
|
9851
|
+
portalId: adding,
|
|
9852
|
+
onSaved: () => {
|
|
9853
|
+
setAdding(null);
|
|
9854
|
+
void load();
|
|
9855
|
+
},
|
|
9856
|
+
onClose: () => setAdding(null)
|
|
9857
|
+
}
|
|
9858
|
+
) : null,
|
|
9859
|
+
shown.length === 0 && !listError && !building && !adding ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
9874
9860
|
BuildOrAsk,
|
|
9875
9861
|
{
|
|
9876
9862
|
mayBuild: true,
|
|
@@ -9879,12 +9865,38 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9879
9865
|
onAsk: () => host.onAskForOne?.({ kind: "portal", tableId, suggestion: PORTAL_SUGGESTION })
|
|
9880
9866
|
} : {},
|
|
9881
9867
|
suggestion: PORTAL_SUGGESTION,
|
|
9882
|
-
buildLabel: "Build the portal",
|
|
9883
|
-
children:
|
|
9868
|
+
buildLabel: elsewhere > 0 ? "Build a new portal" : "Build the portal",
|
|
9869
|
+
children: [
|
|
9870
|
+
"A portal is how one of your clients signs in and sees the records that name them \u2014 their jobs, their invoices \u2014 and nothing else.",
|
|
9871
|
+
elsewhere > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
9872
|
+
" ",
|
|
9873
|
+
"This table is not in",
|
|
9874
|
+
" ",
|
|
9875
|
+
elsewhere === 1 ? "the portal this organization already has" : `any of the ${elsewhere} portals this organization already has`,
|
|
9876
|
+
"."
|
|
9877
|
+
] }) : null
|
|
9878
|
+
]
|
|
9884
9879
|
}
|
|
9885
9880
|
) : null,
|
|
9886
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.
|
|
9887
|
-
|
|
9881
|
+
shown.length === 0 && !listError && !building && !adding && elsewhere > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1.5 rounded-md border border-dashed border-border p-2.5", children: [
|
|
9882
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-xs text-muted-foreground", children: "Or add this table to a portal your clients already sign in to:" }),
|
|
9883
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex flex-wrap gap-1.5", children: couldTakeIt.map((portal) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
9884
|
+
import_design_system33.Button,
|
|
9885
|
+
{
|
|
9886
|
+
size: "sm",
|
|
9887
|
+
variant: "outline",
|
|
9888
|
+
onClick: () => setAdding(portal.portal_id),
|
|
9889
|
+
children: [
|
|
9890
|
+
"Add to \u201C",
|
|
9891
|
+
portal.title,
|
|
9892
|
+
"\u201D"
|
|
9893
|
+
]
|
|
9894
|
+
},
|
|
9895
|
+
portal.portal_id
|
|
9896
|
+
)) })
|
|
9897
|
+
] }) : null,
|
|
9898
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ul", { className: "flex flex-col gap-2", children: shown.map((portal) => {
|
|
9899
|
+
const url = `${origin}${(0, import_records7.portalPath)(portal.slug)}`;
|
|
9888
9900
|
const open = openId === portal.portal_id;
|
|
9889
9901
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "rounded-md border border-border bg-card p-2.5", children: [
|
|
9890
9902
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -10198,7 +10210,7 @@ function Preview({
|
|
|
10198
10210
|
function Invite({ card, onInvited }) {
|
|
10199
10211
|
const client = (0, import_react69.useRecordsClient)();
|
|
10200
10212
|
const [rows, setRows] = (0, import_react68.useState)(null);
|
|
10201
|
-
const [
|
|
10213
|
+
const [clientTable, setClientTable] = (0, import_react68.useState)(null);
|
|
10202
10214
|
const [search, setSearch] = (0, import_react68.useState)("");
|
|
10203
10215
|
const [picked, setPicked] = (0, import_react68.useState)(null);
|
|
10204
10216
|
const [email, setEmail] = (0, import_react68.useState)("");
|
|
@@ -10217,17 +10229,17 @@ function Invite({ card, onInvited }) {
|
|
|
10217
10229
|
});
|
|
10218
10230
|
void client.tableList().then((answered) => {
|
|
10219
10231
|
if (cancelled || !answered.ok) return;
|
|
10220
|
-
|
|
10232
|
+
setClientTable(answered.data.find((t) => t.id === card.client_table_id) ?? null);
|
|
10221
10233
|
});
|
|
10222
10234
|
return () => {
|
|
10223
10235
|
cancelled = true;
|
|
10224
10236
|
};
|
|
10225
10237
|
}, [client, card.client_table_id]);
|
|
10226
10238
|
const options = (0, import_react68.useMemo)(() => {
|
|
10227
|
-
const all = (rows ?? []).map((row) => ({ id: row.id, name:
|
|
10239
|
+
const all = (rows ?? []).map((row) => ({ id: row.id, name: rowNameIn(clientTable, row) }));
|
|
10228
10240
|
const needle = search.trim().toLowerCase();
|
|
10229
10241
|
return needle === "" ? all.slice(0, 25) : all.filter((o) => o.name.toLowerCase().includes(needle)).slice(0, 25);
|
|
10230
|
-
}, [rows,
|
|
10242
|
+
}, [rows, clientTable, search]);
|
|
10231
10243
|
const send = (0, import_react68.useCallback)(async () => {
|
|
10232
10244
|
if (!picked) return;
|
|
10233
10245
|
setBusy(true);
|
|
@@ -10610,11 +10622,7 @@ function whenItFires(subscription) {
|
|
|
10610
10622
|
const every = subscription.cadence === "hourly" ? "an hourly summary" : subscription.cadence === "weekly" ? "a weekly summary" : "a daily summary";
|
|
10611
10623
|
return subscription.schedule ? `${every}, ${subscription.schedule}` : every;
|
|
10612
10624
|
}
|
|
10613
|
-
var CHANNEL_WORDS2 =
|
|
10614
|
-
in_app: "in the app",
|
|
10615
|
-
email: "by email \u2014 only if an address is on the account",
|
|
10616
|
-
sms: "by text \u2014 only if a number is on the account"
|
|
10617
|
-
};
|
|
10625
|
+
var CHANNEL_WORDS2 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
10618
10626
|
var DIGEST_SUGGESTION = "Email me a summary of this every Monday at 8 in the morning.";
|
|
10619
10627
|
function SubscriptionsPanel({ tableId, className }) {
|
|
10620
10628
|
const client = (0, import_react73.useRecordsClient)();
|
|
@@ -10788,7 +10796,7 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
10788
10796
|
// src/FormBuilder.tsx
|
|
10789
10797
|
var import_react76 = require("react");
|
|
10790
10798
|
var import_react77 = require("@ai-matrx/records/react");
|
|
10791
|
-
var
|
|
10799
|
+
var import_records8 = require("@ai-matrx/records");
|
|
10792
10800
|
var import_design_system37 = require("@ai-matrx/design-system");
|
|
10793
10801
|
|
|
10794
10802
|
// src/FormRunner.tsx
|
|
@@ -11263,7 +11271,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
11263
11271
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
11264
11272
|
PublishRow,
|
|
11265
11273
|
{
|
|
11266
|
-
url: `${publicOrigin}${(0,
|
|
11274
|
+
url: `${publicOrigin}${(0, import_records8.publicFormPath)(draft.id)}`,
|
|
11267
11275
|
state: draft.state,
|
|
11268
11276
|
mayPublish: rights.structure,
|
|
11269
11277
|
why: rights.why("structure"),
|
|
@@ -11382,7 +11390,12 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
11382
11390
|
Condition,
|
|
11383
11391
|
{
|
|
11384
11392
|
question,
|
|
11385
|
-
fieldKeys: fields.data ?? []
|
|
11393
|
+
fieldKeys: (fields.data ?? []).map((f) => ({
|
|
11394
|
+
id: String(f.id),
|
|
11395
|
+
key: f.key,
|
|
11396
|
+
label: f.label || f.key,
|
|
11397
|
+
field: f
|
|
11398
|
+
})),
|
|
11386
11399
|
onChange: (showIf) => patchQuestion(index, { showIf })
|
|
11387
11400
|
}
|
|
11388
11401
|
)
|
|
@@ -12115,17 +12128,8 @@ var import_react86 = require("react");
|
|
|
12115
12128
|
var import_react87 = require("@ai-matrx/records/react");
|
|
12116
12129
|
var import_design_system42 = require("@ai-matrx/design-system");
|
|
12117
12130
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
12118
|
-
var CADENCE_WORDS2 =
|
|
12119
|
-
|
|
12120
|
-
hourly: "hourly summary",
|
|
12121
|
-
daily: "daily summary",
|
|
12122
|
-
weekly: "weekly summary"
|
|
12123
|
-
};
|
|
12124
|
-
var CHANNEL_WORDS3 = {
|
|
12125
|
-
in_app: "in the app",
|
|
12126
|
-
email: "by email",
|
|
12127
|
-
sms: "by text"
|
|
12128
|
-
};
|
|
12131
|
+
var CADENCE_WORDS2 = SUBSCRIPTION_CADENCE_LABEL;
|
|
12132
|
+
var CHANNEL_WORDS3 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
12129
12133
|
function NotifyRuleEditor({ tableId, seed, className }) {
|
|
12130
12134
|
const client = (0, import_react87.useRecordsClient)();
|
|
12131
12135
|
const host = useRecordsUi();
|
|
@@ -12329,7 +12333,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
12329
12333
|
// src/ChartBlock.tsx
|
|
12330
12334
|
var import_react88 = require("react");
|
|
12331
12335
|
var import_recharts = require("recharts");
|
|
12332
|
-
var
|
|
12336
|
+
var import_records9 = require("@ai-matrx/records");
|
|
12333
12337
|
var import_core6 = require("@ai-matrx/records/core");
|
|
12334
12338
|
var import_design_system43 = require("@ai-matrx/design-system");
|
|
12335
12339
|
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
@@ -12350,7 +12354,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
12350
12354
|
const kind = block.kind;
|
|
12351
12355
|
const tableId = block.table_id ?? subject;
|
|
12352
12356
|
const measures = block.measures && block.measures.length > 0 ? block.measures : [{ op: "count" }];
|
|
12353
|
-
const primary = (0,
|
|
12357
|
+
const primary = (0, import_records9.measureKey)(measures[0]);
|
|
12354
12358
|
const series = [primary];
|
|
12355
12359
|
const points = (0, import_react88.useMemo)(() => {
|
|
12356
12360
|
if (kind === "stuck") return [];
|
|
@@ -12884,7 +12888,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
12884
12888
|
// src/FormsPanel.tsx
|
|
12885
12889
|
var import_react91 = require("react");
|
|
12886
12890
|
var import_react92 = require("@ai-matrx/records/react");
|
|
12887
|
-
var
|
|
12891
|
+
var import_records10 = require("@ai-matrx/records");
|
|
12888
12892
|
var import_design_system45 = require("@ai-matrx/design-system");
|
|
12889
12893
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
12890
12894
|
var WHAT_A_FORM_IS = "A form asks for this table's own fields, and its answers land here as ordinary records stamped with the form they came through.";
|
|
@@ -12979,7 +12983,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
12979
12983
|
}
|
|
12980
12984
|
) : null,
|
|
12981
12985
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("ul", { className: "flex flex-col gap-2", children: forms.map((form) => {
|
|
12982
|
-
const url = `${origin}${(0,
|
|
12986
|
+
const url = `${origin}${(0, import_records10.publicFormPath)(form.form_id)}`;
|
|
12983
12987
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("li", { className: "rounded-md border p-2.5", children: [
|
|
12984
12988
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12985
12989
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: form.title ?? form.slug }),
|
|
@@ -13031,7 +13035,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
13031
13035
|
// src/BookingBuilder.tsx
|
|
13032
13036
|
var import_react93 = require("react");
|
|
13033
13037
|
var import_react94 = require("@ai-matrx/records/react");
|
|
13034
|
-
var
|
|
13038
|
+
var import_records11 = require("@ai-matrx/records");
|
|
13035
13039
|
var import_design_system46 = require("@ai-matrx/design-system");
|
|
13036
13040
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
13037
13041
|
var STORE_ANSWERS_THESE = ["slot", "status", "booked_with"];
|
|
@@ -13174,7 +13178,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
13174
13178
|
if (!rights.structure) {
|
|
13175
13179
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: (0, import_design_system46.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") ?? "Making a booking page needs the admin level on this table, because it lets people with no account take time in your calendar." });
|
|
13176
13180
|
}
|
|
13177
|
-
const url = formId ? `${publicOrigin}${(0,
|
|
13181
|
+
const url = formId ? `${publicOrigin}${(0, import_records11.bookingPath)(formId)}` : null;
|
|
13178
13182
|
const shown = offer ?? null;
|
|
13179
13183
|
return (
|
|
13180
13184
|
// THE RAIL IS 384px WIDE AND THE VIEWPORT IS NOT (walk 1, 2026-09-21):
|
|
@@ -13376,7 +13380,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
13376
13380
|
// src/BookingSlots.tsx
|
|
13377
13381
|
var import_react95 = require("react");
|
|
13378
13382
|
var import_react96 = require("@ai-matrx/records/react");
|
|
13379
|
-
var
|
|
13383
|
+
var import_records12 = require("@ai-matrx/records");
|
|
13380
13384
|
var import_design_system47 = require("@ai-matrx/design-system");
|
|
13381
13385
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
13382
13386
|
var WHAT_A_BOOKING_PAGE_IS = "A booking page offers times you are free and writes each appointment into this table as an ordinary record.";
|
|
@@ -13385,12 +13389,7 @@ function bookingSuggestion(tableName2) {
|
|
|
13385
13389
|
return `Let clients book a 30-minute ${subject} slot on Tuesday and Thursday afternoons.`;
|
|
13386
13390
|
}
|
|
13387
13391
|
var NO_ADMIN2 = "Opening a booking page lets people with no account take time in your calendar, so it needs the admin level on the table the appointments land in.";
|
|
13388
|
-
var STATE_WORDS =
|
|
13389
|
-
draft: "Not open yet \u2014 nobody can book until you open it.",
|
|
13390
|
-
open: "Open. Anyone with the link can book a time.",
|
|
13391
|
-
closed: "Closed. The link still works and says you are not taking bookings.",
|
|
13392
|
-
full: "Every time you offered is taken."
|
|
13393
|
-
};
|
|
13392
|
+
var STATE_WORDS = BOOKING_PAGE_STATE_LABEL;
|
|
13394
13393
|
function BookingSlots({ tableId, className }) {
|
|
13395
13394
|
const client = (0, import_react96.useRecordsClient)();
|
|
13396
13395
|
const host = useRecordsUi();
|
|
@@ -13414,10 +13413,21 @@ function BookingSlots({ tableId, className }) {
|
|
|
13414
13413
|
void load();
|
|
13415
13414
|
}, [load]);
|
|
13416
13415
|
const subjectIds = (0, import_react95.useMemo)(
|
|
13417
|
-
() => Array.from(
|
|
13418
|
-
|
|
13416
|
+
() => Array.from(
|
|
13417
|
+
/* @__PURE__ */ new Set([
|
|
13418
|
+
...(pages ?? []).map((p) => p.table_id),
|
|
13419
|
+
// THE EMPTY STATE ASKS THE SAME QUESTION. There is no page to read a
|
|
13420
|
+
// table off yet, and the empty state's two buttons need the answer
|
|
13421
|
+
// about the table this rail is standing in — otherwise the rail
|
|
13422
|
+
// offers a viewer both ways into an act the door will refuse.
|
|
13423
|
+
...tableId ? [tableId] : []
|
|
13424
|
+
])
|
|
13425
|
+
),
|
|
13426
|
+
[pages, tableId]
|
|
13419
13427
|
);
|
|
13420
13428
|
const levels = (0, import_react96.useMyLevels)(subjectIds);
|
|
13429
|
+
const levelsKnown = !levels.loading && Boolean(levels.data);
|
|
13430
|
+
const mayBuildHere = levelsKnown && Boolean(tableId) && levels.data?.[tableId] === "admin";
|
|
13421
13431
|
const toggle = (0, import_react95.useCallback)(
|
|
13422
13432
|
async (page) => {
|
|
13423
13433
|
setBusy(page.form_id);
|
|
@@ -13466,7 +13476,8 @@ function BookingSlots({ tableId, className }) {
|
|
|
13466
13476
|
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13467
13477
|
BuildOrAsk,
|
|
13468
13478
|
{
|
|
13469
|
-
mayBuild:
|
|
13479
|
+
mayBuild: mayBuildHere,
|
|
13480
|
+
whyNot: mayBuildHere ? null : levelsKnown ? NO_ADMIN2 : null,
|
|
13470
13481
|
onBuild: () => setBuilding(true),
|
|
13471
13482
|
...host.onAskForOne ? {
|
|
13472
13483
|
onAsk: () => host.onAskForOne?.({
|
|
@@ -13484,7 +13495,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
13484
13495
|
" Open the table the appointments should land in to make one."
|
|
13485
13496
|
] }) : null,
|
|
13486
13497
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ul", { className: "flex flex-col gap-2", children: pages.map((page) => {
|
|
13487
|
-
const url = `${origin}${(0,
|
|
13498
|
+
const url = `${origin}${(0, import_records12.bookingPath)(page.form_id)}`;
|
|
13488
13499
|
const mayOpen = levels.data?.[page.table_id] === "admin";
|
|
13489
13500
|
const open = page.published_at !== null && page.closed_at === null;
|
|
13490
13501
|
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("li", { className: "rounded-md border p-2.5", "data-testid": "booking-page", children: [
|
|
@@ -13573,7 +13584,7 @@ var import_design_system49 = require("@ai-matrx/design-system");
|
|
|
13573
13584
|
|
|
13574
13585
|
// src/CaptureRun.tsx
|
|
13575
13586
|
var import_react97 = require("react");
|
|
13576
|
-
var
|
|
13587
|
+
var import_records13 = require("@ai-matrx/records");
|
|
13577
13588
|
var import_react98 = require("@ai-matrx/records/react");
|
|
13578
13589
|
var import_design_system48 = require("@ai-matrx/design-system");
|
|
13579
13590
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
@@ -13628,7 +13639,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
13628
13639
|
const [sending, setSending] = (0, import_react97.useState)(false);
|
|
13629
13640
|
const queueRef = (0, import_react97.useRef)(null);
|
|
13630
13641
|
(0, import_react97.useEffect)(() => {
|
|
13631
|
-
const q2 = (0,
|
|
13642
|
+
const q2 = (0, import_records13.openCaptureQueue)({
|
|
13632
13643
|
onChange: (c, all) => {
|
|
13633
13644
|
setCounts(c);
|
|
13634
13645
|
setItems(all);
|
|
@@ -13877,7 +13888,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
13877
13888
|
value: String(answers[q.field] ?? ""),
|
|
13878
13889
|
onChange: (e) => {
|
|
13879
13890
|
const raw = e.target.value;
|
|
13880
|
-
|
|
13891
|
+
const answered2 = field ? (0, import_records13.coerceTypedAnswer)(field, raw, { label: q.ask ?? (0, import_records13.coercionLabel)(field) }) : { value: raw };
|
|
13892
|
+
setAnswers((held) => ({
|
|
13893
|
+
...held,
|
|
13894
|
+
[q.field]: raw === "" ? "" : "refusal" in answered2 ? raw : answered2.value
|
|
13895
|
+
}));
|
|
13881
13896
|
setMissing(null);
|
|
13882
13897
|
}
|
|
13883
13898
|
}
|