@ai-matrx/records-ui 0.63.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 +62 -0
- package/dist/index.cjs +325 -294
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -10
- package/dist/index.d.ts +97 -10
- package/dist/index.js +319 -282
- 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,
|
|
@@ -826,50 +852,9 @@ var PARITY_LABEL = {
|
|
|
826
852
|
var PARITY_MADE_OF = Object.fromEntries(
|
|
827
853
|
import_records3.PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
|
|
828
854
|
);
|
|
855
|
+
var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
|
|
829
856
|
function editorKindFor(field) {
|
|
830
|
-
|
|
831
|
-
const config = field.config ?? {};
|
|
832
|
-
switch (field.type) {
|
|
833
|
-
// LIMITS-FIX 2026-09-21: the tick box is a BEHAVIOUR of its own, so its editor is
|
|
834
|
-
// decided by the behaviour alone — no format, no unit, no target to read. A record
|
|
835
|
-
// that never answered holds no key at all, and `CheckboxControl` draws that third
|
|
836
|
-
// state rather than pretending it is an unticked box.
|
|
837
|
-
case "boolean":
|
|
838
|
-
return "checkbox";
|
|
839
|
-
case "text":
|
|
840
|
-
if (format === "email") return "email";
|
|
841
|
-
if (format === "phone") return "phone";
|
|
842
|
-
if (format === "url") return "url";
|
|
843
|
-
if (format === "json" || config["json"] === true) return "json";
|
|
844
|
-
if (format === "long" || config["multiline"] === true) return "long_text";
|
|
845
|
-
return "text";
|
|
846
|
-
case "range": {
|
|
847
|
-
const kind = String(config["kind"] ?? "number");
|
|
848
|
-
if (kind === "date" || kind === "datetime") return "datetime";
|
|
849
|
-
if (format === "currency") return "currency";
|
|
850
|
-
if (format === "percent" || field.unit === "%") return "percent";
|
|
851
|
-
return "number";
|
|
852
|
-
}
|
|
853
|
-
case "list":
|
|
854
|
-
return field.multi ? "multi_select" : "select";
|
|
855
|
-
case "relation":
|
|
856
|
-
return relationEditor(field);
|
|
857
|
-
case "formula": {
|
|
858
|
-
const via = config["via"];
|
|
859
|
-
if (via && config["agg"]) return "rollup";
|
|
860
|
-
if (via) return "lookup";
|
|
861
|
-
return "formula";
|
|
862
|
-
}
|
|
863
|
-
default:
|
|
864
|
-
return "text";
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
function relationEditor(field) {
|
|
868
|
-
const parity = String(field.config?.["parity"] ?? "");
|
|
869
|
-
if (parity === "attachment" || parity === "member") return parity;
|
|
870
|
-
if (field.relation_target === KERNEL_FILE_TABLE) return "attachment";
|
|
871
|
-
if (field.relation_target === KERNEL_PERSON_TABLE) return "member";
|
|
872
|
-
return "relation";
|
|
857
|
+
return (0, import_records3.fieldKindFor)(field, KERNEL);
|
|
873
858
|
}
|
|
874
859
|
function fieldTypeLabel(field) {
|
|
875
860
|
const kind = editorKindFor(field);
|
|
@@ -1765,18 +1750,137 @@ function useLabelWait(field) {
|
|
|
1765
1750
|
return field ? waiting(field) : null;
|
|
1766
1751
|
}
|
|
1767
1752
|
|
|
1768
|
-
// src/
|
|
1769
|
-
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1753
|
+
// src/enumLabels.ts
|
|
1754
|
+
function exhaustiveValuesOf() {
|
|
1755
|
+
return function(values) {
|
|
1756
|
+
return values;
|
|
1757
|
+
};
|
|
1773
1758
|
}
|
|
1774
|
-
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 = {
|
|
1775
1871
|
"never asked": "never asked",
|
|
1776
1872
|
none: "none",
|
|
1777
1873
|
refused: "refused",
|
|
1778
1874
|
conflicting: "conflicting"
|
|
1779
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;
|
|
1780
1884
|
function renderValue(field, value, document2, labels, stillWaitingFor) {
|
|
1781
1885
|
const envelope = envelopeFor(document2, field.key);
|
|
1782
1886
|
if (envelope?.absent) {
|
|
@@ -3199,113 +3303,11 @@ function choiceOptionsOf(options) {
|
|
|
3199
3303
|
}
|
|
3200
3304
|
return { byWord, labels };
|
|
3201
3305
|
}
|
|
3202
|
-
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
3203
|
-
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
3204
3306
|
function valueFromPastedText(field, raw, options) {
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
switch (kind) {
|
|
3210
|
-
case "checkbox": {
|
|
3211
|
-
const word = text.toLowerCase();
|
|
3212
|
-
if (TRUE_WORDS.has(word)) return { value: true };
|
|
3213
|
-
if (FALSE_WORDS.has(word)) return { value: word === "" ? null : false };
|
|
3214
|
-
return {
|
|
3215
|
-
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.`
|
|
3216
|
-
};
|
|
3217
|
-
}
|
|
3218
|
-
case "number":
|
|
3219
|
-
case "currency":
|
|
3220
|
-
case "percent": {
|
|
3221
|
-
const negative = /^\(.*\)$/.test(text);
|
|
3222
|
-
const bare = text.replace(/^\(|\)$/g, "").replace(/[\s,]/g, "").replace(/^[^\d.\-+]+/, "").replace(/[^\d.\-+eE]+$/, "");
|
|
3223
|
-
const n = Number(bare);
|
|
3224
|
-
if (bare === "" || Number.isNaN(n)) {
|
|
3225
|
-
return {
|
|
3226
|
-
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.`
|
|
3227
|
-
};
|
|
3228
|
-
}
|
|
3229
|
-
return { value: negative ? -n : n };
|
|
3230
|
-
}
|
|
3231
|
-
case "datetime": {
|
|
3232
|
-
const wantsTime = String(field.config?.["kind"] ?? "date") === "datetime";
|
|
3233
|
-
const plainDay = /^\s*(\d{4})-(\d{2})-(\d{2})\s*$/.exec(raw);
|
|
3234
|
-
if (!wantsTime && plainDay) return { value: `${plainDay[1]}-${plainDay[2]}-${plainDay[3]}` };
|
|
3235
|
-
const at = Date.parse(text);
|
|
3236
|
-
if (Number.isNaN(at)) {
|
|
3237
|
-
return {
|
|
3238
|
-
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.`
|
|
3239
|
-
};
|
|
3240
|
-
}
|
|
3241
|
-
const parsed = new Date(at);
|
|
3242
|
-
if (wantsTime) return { value: parsed.toISOString() };
|
|
3243
|
-
const y = parsed.getFullYear();
|
|
3244
|
-
const m = String(parsed.getMonth() + 1).padStart(2, "0");
|
|
3245
|
-
const d = String(parsed.getDate()).padStart(2, "0");
|
|
3246
|
-
return { value: `${y}-${m}-${d}` };
|
|
3247
|
-
}
|
|
3248
|
-
case "json": {
|
|
3249
|
-
try {
|
|
3250
|
-
return { value: JSON.parse(text) };
|
|
3251
|
-
} catch {
|
|
3252
|
-
return {
|
|
3253
|
-
refusal: `${label} holds a document, and \u201C${raw}\u201D is not valid JSON. Paste the whole object, braces and all.`
|
|
3254
|
-
};
|
|
3255
|
-
}
|
|
3256
|
-
}
|
|
3257
|
-
// A LIST, A PERSON, A FILE OR ANOTHER RECORD IS AN IDENTITY, NOT A WORD.
|
|
3258
|
-
// The store keeps the id of the option or the record, and a word off a
|
|
3259
|
-
// clipboard is not that id — writing the word would put a string where an
|
|
3260
|
-
// id belongs and every filter, colour and rollup built on that column would
|
|
3261
|
-
// stop agreeing with it. So the cell is left alone and the person is told
|
|
3262
|
-
// which control does hold it.
|
|
3263
|
-
case "select":
|
|
3264
|
-
case "multi_select": {
|
|
3265
|
-
if (!options) {
|
|
3266
|
-
return {
|
|
3267
|
-
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.`
|
|
3268
|
-
};
|
|
3269
|
-
}
|
|
3270
|
-
const wanted = kind === "multi_select" ? text.split(/[,;]/).map((w) => w.trim()).filter((w) => w.length > 0) : [text];
|
|
3271
|
-
if (wanted.length === 0) return { value: kind === "multi_select" ? [] : null };
|
|
3272
|
-
const matched = [];
|
|
3273
|
-
const unmatched = [];
|
|
3274
|
-
for (const word of wanted) {
|
|
3275
|
-
const hit = options.byWord.get(word.toLowerCase());
|
|
3276
|
-
if (hit === void 0) unmatched.push(word);
|
|
3277
|
-
else matched.push(hit);
|
|
3278
|
-
}
|
|
3279
|
-
if (unmatched.length > 0) {
|
|
3280
|
-
const offered = options.labels.length > 0 ? options.labels.join(", ") : "it has none yet";
|
|
3281
|
-
return {
|
|
3282
|
-
refusal: `${label} does not have ${unmatched.map((w) => `\u201C${w}\u201D`).join(" or ")} among its options. It offers: ${offered}.`,
|
|
3283
|
-
unmatched
|
|
3284
|
-
};
|
|
3285
|
-
}
|
|
3286
|
-
return { value: kind === "multi_select" ? matched : matched[0] };
|
|
3287
|
-
}
|
|
3288
|
-
case "member":
|
|
3289
|
-
return {
|
|
3290
|
-
refusal: `${label} names a person in this organization, so it is chosen rather than typed. Open the cell and pick them.`
|
|
3291
|
-
};
|
|
3292
|
-
case "attachment":
|
|
3293
|
-
return {
|
|
3294
|
-
refusal: `${label} holds a file, which cannot arrive on a clipboard. Open the cell and attach it.`
|
|
3295
|
-
};
|
|
3296
|
-
case "relation":
|
|
3297
|
-
return {
|
|
3298
|
-
refusal: `${label} points at another record, so it is chosen rather than typed. Open the cell and pick the record.`
|
|
3299
|
-
};
|
|
3300
|
-
case "formula":
|
|
3301
|
-
case "lookup":
|
|
3302
|
-
case "rollup":
|
|
3303
|
-
return {
|
|
3304
|
-
refusal: `${label} is worked out by the system, so nothing can be pasted into it.`
|
|
3305
|
-
};
|
|
3306
|
-
default:
|
|
3307
|
-
return { value: raw };
|
|
3308
|
-
}
|
|
3307
|
+
return (0, import_records5.coerceTypedAnswer)(field, raw, {
|
|
3308
|
+
label: fieldName(field),
|
|
3309
|
+
...options ? { options } : {}
|
|
3310
|
+
});
|
|
3309
3311
|
}
|
|
3310
3312
|
function planPastedBlock(args) {
|
|
3311
3313
|
const byKey = new Map(args.fields.map((f) => [f.key, f]));
|
|
@@ -4475,19 +4477,23 @@ var import_react27 = require("react");
|
|
|
4475
4477
|
var import_react28 = require("@ai-matrx/records/react");
|
|
4476
4478
|
var import_design_system13 = require("@ai-matrx/design-system");
|
|
4477
4479
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
4478
|
-
var
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
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"
|
|
4490
4492
|
];
|
|
4493
|
+
var ADDABLE_TYPES = ADDABLE_TYPE_IDS.map((value) => ({
|
|
4494
|
+
value,
|
|
4495
|
+
label: fieldTypeChoice(value)?.label ?? value
|
|
4496
|
+
}));
|
|
4491
4497
|
function asField(f) {
|
|
4492
4498
|
return {
|
|
4493
4499
|
id: f.id,
|
|
@@ -4651,41 +4657,20 @@ function CustomFieldsSection({
|
|
|
4651
4657
|
var import_react29 = require("react");
|
|
4652
4658
|
var import_react30 = require("@ai-matrx/records/react");
|
|
4653
4659
|
var import_design_system14 = require("@ai-matrx/design-system");
|
|
4660
|
+
var import_records6 = require("@ai-matrx/records");
|
|
4654
4661
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4655
|
-
var RULE_KINDS = [
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
{ value: "restricted", label: "Owners and administrators only" }
|
|
4668
|
-
];
|
|
4669
|
-
var AGENT_VISIBILITY = [
|
|
4670
|
-
{ value: "include", label: "Yes, an assistant can read it" },
|
|
4671
|
-
{ value: "summarize", label: "Only a summary of it" },
|
|
4672
|
-
{ value: "on_request", label: "Only when somebody asks for it" },
|
|
4673
|
-
{ value: "exclude", label: "No, keep it away from assistants" }
|
|
4674
|
-
];
|
|
4675
|
-
var ROLLUP_OPERATIONS = [
|
|
4676
|
-
{ value: "count", label: "How many there are" },
|
|
4677
|
-
{ value: "sum", label: "The total of" },
|
|
4678
|
-
{ value: "avg", label: "The average of" },
|
|
4679
|
-
{ value: "min", label: "The smallest" },
|
|
4680
|
-
{ value: "max", label: "The largest" }
|
|
4681
|
-
];
|
|
4682
|
-
var FORMULA_OPERATIONS = [
|
|
4683
|
-
{ value: "concat", label: "Join them together", joins: true },
|
|
4684
|
-
{ value: "add", label: "Add them up", joins: true },
|
|
4685
|
-
{ value: "sub", label: "Take the second from the first", joins: false },
|
|
4686
|
-
{ value: "mul", label: "Multiply them", joins: true },
|
|
4687
|
-
{ value: "div", label: "Divide the first by the second", joins: false }
|
|
4688
|
-
];
|
|
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
|
+
}));
|
|
4689
4674
|
function keyFor(label) {
|
|
4690
4675
|
const token = label.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48);
|
|
4691
4676
|
if (token === "") return "";
|
|
@@ -5250,6 +5235,9 @@ var CONDITION_OPS = [
|
|
|
5250
5235
|
{ op: "gt", label: "is more than" },
|
|
5251
5236
|
{ op: "lt", label: "is less than" }
|
|
5252
5237
|
];
|
|
5238
|
+
function pointsAtARecord(f) {
|
|
5239
|
+
return !!f?.field && f.field.type === "relation" && !!f.field.relation_target;
|
|
5240
|
+
}
|
|
5253
5241
|
function conditionIsSimple(expr) {
|
|
5254
5242
|
if (expr === null || expr === void 0) return true;
|
|
5255
5243
|
const node = expr;
|
|
@@ -5320,6 +5308,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5320
5308
|
const op = node?.op ?? "";
|
|
5321
5309
|
const onField = node?.args?.[0]?.field ?? "";
|
|
5322
5310
|
const value = node?.args?.[1]?.const ?? "";
|
|
5311
|
+
const chosen = fields.find((f) => f.id === onField);
|
|
5323
5312
|
function write(next) {
|
|
5324
5313
|
const chosenOp = next.op ?? op;
|
|
5325
5314
|
const chosenField = next.field ?? onField;
|
|
@@ -5358,7 +5347,24 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5358
5347
|
children: CONDITION_OPS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: c.op, children: c.label }, c.op))
|
|
5359
5348
|
}
|
|
5360
5349
|
),
|
|
5361
|
-
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)(
|
|
5362
5368
|
import_design_system15.BasicInput,
|
|
5363
5369
|
{
|
|
5364
5370
|
className: "h-8 w-28 text-xs",
|
|
@@ -5366,7 +5372,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5366
5372
|
value: String(value ?? ""),
|
|
5367
5373
|
onChange: (e) => write({ value: conditionValue(e.target.value) })
|
|
5368
5374
|
}
|
|
5369
|
-
)
|
|
5375
|
+
)
|
|
5370
5376
|
] }) : null
|
|
5371
5377
|
] });
|
|
5372
5378
|
}
|
|
@@ -5526,10 +5532,10 @@ var NO_RULES_YET = "Nothing has to be true to get here yet.";
|
|
|
5526
5532
|
var NEEDS_A_SENTENCE = "Write the sentence somebody reads when this stops them, the way you would say it out loud.";
|
|
5527
5533
|
var NOT_DRAWN_HERE = "This part of the rule is not something this builder can draw yet";
|
|
5528
5534
|
var ON_FAIL = [
|
|
5529
|
-
{ 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." },
|
|
5530
5536
|
{
|
|
5531
5537
|
value: "require_approval",
|
|
5532
|
-
label:
|
|
5538
|
+
label: STAGE_RULE_ON_FAIL_LABEL.require_approval,
|
|
5533
5539
|
note: "The card stays where it is, and the people who can approve it are asked. Nobody is turned away."
|
|
5534
5540
|
}
|
|
5535
5541
|
];
|
|
@@ -5580,7 +5586,7 @@ function StageRulesSection({ tableId, stage, className }) {
|
|
|
5580
5586
|
const stageLabel = stages.find((s) => s.key === stageKey)?.label ?? stageKey ?? "";
|
|
5581
5587
|
const gates = (0, import_react32.useMemo)(() => stageKey ? gatesOf(pipeline, stageKey) : [], [pipeline, stageKey]);
|
|
5582
5588
|
const conditionFields = (0, import_react32.useMemo)(
|
|
5583
|
-
() => (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 })),
|
|
5584
5590
|
[fields.data]
|
|
5585
5591
|
);
|
|
5586
5592
|
(0, import_react32.useEffect)(() => {
|
|
@@ -7268,7 +7274,7 @@ function offerableFields(all, want) {
|
|
|
7268
7274
|
return all.filter((field) => {
|
|
7269
7275
|
const kind = editorKindFor(field);
|
|
7270
7276
|
if (want === "choice") return kind === "select" || kind === "multi_select";
|
|
7271
|
-
return kind === "datetime"
|
|
7277
|
+
return kind === "datetime";
|
|
7272
7278
|
});
|
|
7273
7279
|
}
|
|
7274
7280
|
function useStageField(tableId) {
|
|
@@ -7686,11 +7692,7 @@ var import_react54 = require("react");
|
|
|
7686
7692
|
var import_react55 = require("@ai-matrx/records/react");
|
|
7687
7693
|
var import_design_system25 = require("@ai-matrx/design-system");
|
|
7688
7694
|
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
7689
|
-
var ACT_WORD =
|
|
7690
|
-
add: "Add",
|
|
7691
|
-
update: "Update",
|
|
7692
|
-
remove: "Remove"
|
|
7693
|
-
};
|
|
7695
|
+
var ACT_WORD = PROPOSED_CHANGE_ACT_LABEL;
|
|
7694
7696
|
function ProposalRow({
|
|
7695
7697
|
change,
|
|
7696
7698
|
outcome,
|
|
@@ -7797,21 +7799,8 @@ var import_react56 = require("react");
|
|
|
7797
7799
|
var import_react57 = require("@ai-matrx/records/react");
|
|
7798
7800
|
var import_design_system26 = require("@ai-matrx/design-system");
|
|
7799
7801
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
7800
|
-
var DUE_WORD =
|
|
7801
|
-
|
|
7802
|
-
due_today: "Today",
|
|
7803
|
-
scheduled: "Scheduled",
|
|
7804
|
-
undated: "No date",
|
|
7805
|
-
finished: "Done"
|
|
7806
|
-
};
|
|
7807
|
-
var REQUIRES_WORD = {
|
|
7808
|
-
none: "",
|
|
7809
|
-
note: "Say what you did",
|
|
7810
|
-
answer: "Fill this in",
|
|
7811
|
-
record_field: "This has to be filled in on the record",
|
|
7812
|
-
form: "This step is a form",
|
|
7813
|
-
document: "This step is a document"
|
|
7814
|
-
};
|
|
7802
|
+
var DUE_WORD = DUE_STATE_LABEL;
|
|
7803
|
+
var REQUIRES_WORD = CHECKLIST_REQUIREMENT_LABEL;
|
|
7815
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.";
|
|
7816
7805
|
function ChecklistRunner({
|
|
7817
7806
|
tableId,
|
|
@@ -8519,18 +8508,8 @@ function roleKey(said) {
|
|
|
8519
8508
|
// src/ActionInbox.tsx
|
|
8520
8509
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
8521
8510
|
var ACTION_KINDS = ["approval", "assignment", "proposal"];
|
|
8522
|
-
var KIND_WORD =
|
|
8523
|
-
|
|
8524
|
-
approval: "Approve",
|
|
8525
|
-
proposal: "Agent"
|
|
8526
|
-
};
|
|
8527
|
-
var DUE_WORD2 = {
|
|
8528
|
-
overdue: "Overdue",
|
|
8529
|
-
due_today: "Today",
|
|
8530
|
-
scheduled: "Scheduled",
|
|
8531
|
-
undated: "No date",
|
|
8532
|
-
finished: "Finished"
|
|
8533
|
-
};
|
|
8511
|
+
var KIND_WORD = WORK_INBOX_KIND_LABEL;
|
|
8512
|
+
var DUE_WORD2 = DUE_STATE_LABEL;
|
|
8534
8513
|
function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className }) {
|
|
8535
8514
|
const client = (0, import_react59.useRecordsClient)();
|
|
8536
8515
|
const [items, setItems] = (0, import_react58.useState)(null);
|
|
@@ -9751,7 +9730,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
|
|
|
9751
9730
|
// src/PortalsPanel.tsx
|
|
9752
9731
|
var import_react68 = require("react");
|
|
9753
9732
|
var import_react69 = require("@ai-matrx/records/react");
|
|
9754
|
-
var
|
|
9733
|
+
var import_records7 = require("@ai-matrx/records");
|
|
9755
9734
|
var import_design_system33 = require("@ai-matrx/design-system");
|
|
9756
9735
|
|
|
9757
9736
|
// src/BuildOrAsk.tsx
|
|
@@ -9768,18 +9747,18 @@ function BuildOrAsk({
|
|
|
9768
9747
|
buildLabel,
|
|
9769
9748
|
className
|
|
9770
9749
|
}) {
|
|
9750
|
+
const mayAsk = mayBuild && Boolean(onAsk);
|
|
9771
9751
|
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: (0, import_design_system32.cn)("rounded-md border border-dashed p-3", className), children: [
|
|
9772
9752
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", children }),
|
|
9773
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: [
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
] }),
|
|
9777
|
-
|
|
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: [
|
|
9778
9758
|
"You would say something like: \u201C",
|
|
9779
9759
|
suggestion,
|
|
9780
9760
|
"\u201D"
|
|
9781
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: NO_AGENT_PORT })
|
|
9782
|
-
!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 })
|
|
9783
9762
|
] });
|
|
9784
9763
|
}
|
|
9785
9764
|
|
|
@@ -9818,30 +9797,41 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9818
9797
|
const client = (0, import_react69.useRecordsClient)();
|
|
9819
9798
|
const host = useRecordsUi();
|
|
9820
9799
|
const [portals, setPortals] = (0, import_react68.useState)(null);
|
|
9800
|
+
const [exposures, setExposures] = (0, import_react68.useState)([]);
|
|
9821
9801
|
const [listError, setListError] = (0, import_react68.useState)(null);
|
|
9822
9802
|
const [openId, setOpenId] = (0, import_react68.useState)(null);
|
|
9823
9803
|
const [building, setBuilding] = (0, import_react68.useState)(false);
|
|
9804
|
+
const [adding, setAdding] = (0, import_react68.useState)(null);
|
|
9824
9805
|
const load = (0, import_react68.useCallback)(async () => {
|
|
9825
|
-
const answered = await client.portals();
|
|
9806
|
+
const [answered, mapped] = await Promise.all([client.portals(), client.portalTables()]);
|
|
9826
9807
|
if (!answered.ok) {
|
|
9827
9808
|
setListError(answered.error);
|
|
9828
9809
|
setPortals([]);
|
|
9810
|
+
setExposures([]);
|
|
9829
9811
|
return;
|
|
9830
9812
|
}
|
|
9831
9813
|
setListError(null);
|
|
9832
9814
|
setPortals(answered.data);
|
|
9815
|
+
setExposures(mapped.ok ? mapped.data : []);
|
|
9833
9816
|
}, [client]);
|
|
9834
9817
|
(0, import_react68.useEffect)(() => {
|
|
9835
9818
|
void load();
|
|
9836
9819
|
}, [load]);
|
|
9837
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;
|
|
9838
9828
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
9839
9829
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("flex flex-col gap-3", className), children: [
|
|
9840
9830
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
9841
9831
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-sm font-medium", children: "Portals" }),
|
|
9842
|
-
/* @__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}` }),
|
|
9843
9833
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1" }),
|
|
9844
|
-
|
|
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
|
|
9845
9835
|
] }),
|
|
9846
9836
|
listError ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(RefusalNotice, { error: listError }) : null,
|
|
9847
9837
|
building ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -9854,7 +9844,19 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9854
9844
|
onClose: () => setBuilding(false)
|
|
9855
9845
|
}
|
|
9856
9846
|
) : null,
|
|
9857
|
-
|
|
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)(
|
|
9858
9860
|
BuildOrAsk,
|
|
9859
9861
|
{
|
|
9860
9862
|
mayBuild: true,
|
|
@@ -9863,12 +9865,38 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9863
9865
|
onAsk: () => host.onAskForOne?.({ kind: "portal", tableId, suggestion: PORTAL_SUGGESTION })
|
|
9864
9866
|
} : {},
|
|
9865
9867
|
suggestion: PORTAL_SUGGESTION,
|
|
9866
|
-
buildLabel: "Build the portal",
|
|
9867
|
-
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
|
+
]
|
|
9868
9879
|
}
|
|
9869
9880
|
) : null,
|
|
9870
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.
|
|
9871
|
-
|
|
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)}`;
|
|
9872
9900
|
const open = openId === portal.portal_id;
|
|
9873
9901
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("li", { className: "rounded-md border border-border bg-card p-2.5", children: [
|
|
9874
9902
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -10594,11 +10622,7 @@ function whenItFires(subscription) {
|
|
|
10594
10622
|
const every = subscription.cadence === "hourly" ? "an hourly summary" : subscription.cadence === "weekly" ? "a weekly summary" : "a daily summary";
|
|
10595
10623
|
return subscription.schedule ? `${every}, ${subscription.schedule}` : every;
|
|
10596
10624
|
}
|
|
10597
|
-
var CHANNEL_WORDS2 =
|
|
10598
|
-
in_app: "in the app",
|
|
10599
|
-
email: "by email \u2014 only if an address is on the account",
|
|
10600
|
-
sms: "by text \u2014 only if a number is on the account"
|
|
10601
|
-
};
|
|
10625
|
+
var CHANNEL_WORDS2 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
10602
10626
|
var DIGEST_SUGGESTION = "Email me a summary of this every Monday at 8 in the morning.";
|
|
10603
10627
|
function SubscriptionsPanel({ tableId, className }) {
|
|
10604
10628
|
const client = (0, import_react73.useRecordsClient)();
|
|
@@ -10772,7 +10796,7 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
10772
10796
|
// src/FormBuilder.tsx
|
|
10773
10797
|
var import_react76 = require("react");
|
|
10774
10798
|
var import_react77 = require("@ai-matrx/records/react");
|
|
10775
|
-
var
|
|
10799
|
+
var import_records8 = require("@ai-matrx/records");
|
|
10776
10800
|
var import_design_system37 = require("@ai-matrx/design-system");
|
|
10777
10801
|
|
|
10778
10802
|
// src/FormRunner.tsx
|
|
@@ -11247,7 +11271,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
11247
11271
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
11248
11272
|
PublishRow,
|
|
11249
11273
|
{
|
|
11250
|
-
url: `${publicOrigin}${(0,
|
|
11274
|
+
url: `${publicOrigin}${(0, import_records8.publicFormPath)(draft.id)}`,
|
|
11251
11275
|
state: draft.state,
|
|
11252
11276
|
mayPublish: rights.structure,
|
|
11253
11277
|
why: rights.why("structure"),
|
|
@@ -11366,7 +11390,12 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
11366
11390
|
Condition,
|
|
11367
11391
|
{
|
|
11368
11392
|
question,
|
|
11369
|
-
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
|
+
})),
|
|
11370
11399
|
onChange: (showIf) => patchQuestion(index, { showIf })
|
|
11371
11400
|
}
|
|
11372
11401
|
)
|
|
@@ -12099,17 +12128,8 @@ var import_react86 = require("react");
|
|
|
12099
12128
|
var import_react87 = require("@ai-matrx/records/react");
|
|
12100
12129
|
var import_design_system42 = require("@ai-matrx/design-system");
|
|
12101
12130
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
12102
|
-
var CADENCE_WORDS2 =
|
|
12103
|
-
|
|
12104
|
-
hourly: "hourly summary",
|
|
12105
|
-
daily: "daily summary",
|
|
12106
|
-
weekly: "weekly summary"
|
|
12107
|
-
};
|
|
12108
|
-
var CHANNEL_WORDS3 = {
|
|
12109
|
-
in_app: "in the app",
|
|
12110
|
-
email: "by email",
|
|
12111
|
-
sms: "by text"
|
|
12112
|
-
};
|
|
12131
|
+
var CADENCE_WORDS2 = SUBSCRIPTION_CADENCE_LABEL;
|
|
12132
|
+
var CHANNEL_WORDS3 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
12113
12133
|
function NotifyRuleEditor({ tableId, seed, className }) {
|
|
12114
12134
|
const client = (0, import_react87.useRecordsClient)();
|
|
12115
12135
|
const host = useRecordsUi();
|
|
@@ -12313,7 +12333,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
12313
12333
|
// src/ChartBlock.tsx
|
|
12314
12334
|
var import_react88 = require("react");
|
|
12315
12335
|
var import_recharts = require("recharts");
|
|
12316
|
-
var
|
|
12336
|
+
var import_records9 = require("@ai-matrx/records");
|
|
12317
12337
|
var import_core6 = require("@ai-matrx/records/core");
|
|
12318
12338
|
var import_design_system43 = require("@ai-matrx/design-system");
|
|
12319
12339
|
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
@@ -12334,7 +12354,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
12334
12354
|
const kind = block.kind;
|
|
12335
12355
|
const tableId = block.table_id ?? subject;
|
|
12336
12356
|
const measures = block.measures && block.measures.length > 0 ? block.measures : [{ op: "count" }];
|
|
12337
|
-
const primary = (0,
|
|
12357
|
+
const primary = (0, import_records9.measureKey)(measures[0]);
|
|
12338
12358
|
const series = [primary];
|
|
12339
12359
|
const points = (0, import_react88.useMemo)(() => {
|
|
12340
12360
|
if (kind === "stuck") return [];
|
|
@@ -12868,7 +12888,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
12868
12888
|
// src/FormsPanel.tsx
|
|
12869
12889
|
var import_react91 = require("react");
|
|
12870
12890
|
var import_react92 = require("@ai-matrx/records/react");
|
|
12871
|
-
var
|
|
12891
|
+
var import_records10 = require("@ai-matrx/records");
|
|
12872
12892
|
var import_design_system45 = require("@ai-matrx/design-system");
|
|
12873
12893
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
12874
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.";
|
|
@@ -12963,7 +12983,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
12963
12983
|
}
|
|
12964
12984
|
) : null,
|
|
12965
12985
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("ul", { className: "flex flex-col gap-2", children: forms.map((form) => {
|
|
12966
|
-
const url = `${origin}${(0,
|
|
12986
|
+
const url = `${origin}${(0, import_records10.publicFormPath)(form.form_id)}`;
|
|
12967
12987
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("li", { className: "rounded-md border p-2.5", children: [
|
|
12968
12988
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12969
12989
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: form.title ?? form.slug }),
|
|
@@ -13015,7 +13035,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
13015
13035
|
// src/BookingBuilder.tsx
|
|
13016
13036
|
var import_react93 = require("react");
|
|
13017
13037
|
var import_react94 = require("@ai-matrx/records/react");
|
|
13018
|
-
var
|
|
13038
|
+
var import_records11 = require("@ai-matrx/records");
|
|
13019
13039
|
var import_design_system46 = require("@ai-matrx/design-system");
|
|
13020
13040
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
13021
13041
|
var STORE_ANSWERS_THESE = ["slot", "status", "booked_with"];
|
|
@@ -13158,7 +13178,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
13158
13178
|
if (!rights.structure) {
|
|
13159
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." });
|
|
13160
13180
|
}
|
|
13161
|
-
const url = formId ? `${publicOrigin}${(0,
|
|
13181
|
+
const url = formId ? `${publicOrigin}${(0, import_records11.bookingPath)(formId)}` : null;
|
|
13162
13182
|
const shown = offer ?? null;
|
|
13163
13183
|
return (
|
|
13164
13184
|
// THE RAIL IS 384px WIDE AND THE VIEWPORT IS NOT (walk 1, 2026-09-21):
|
|
@@ -13360,7 +13380,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
13360
13380
|
// src/BookingSlots.tsx
|
|
13361
13381
|
var import_react95 = require("react");
|
|
13362
13382
|
var import_react96 = require("@ai-matrx/records/react");
|
|
13363
|
-
var
|
|
13383
|
+
var import_records12 = require("@ai-matrx/records");
|
|
13364
13384
|
var import_design_system47 = require("@ai-matrx/design-system");
|
|
13365
13385
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
13366
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.";
|
|
@@ -13369,12 +13389,7 @@ function bookingSuggestion(tableName2) {
|
|
|
13369
13389
|
return `Let clients book a 30-minute ${subject} slot on Tuesday and Thursday afternoons.`;
|
|
13370
13390
|
}
|
|
13371
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.";
|
|
13372
|
-
var STATE_WORDS =
|
|
13373
|
-
draft: "Not open yet \u2014 nobody can book until you open it.",
|
|
13374
|
-
open: "Open. Anyone with the link can book a time.",
|
|
13375
|
-
closed: "Closed. The link still works and says you are not taking bookings.",
|
|
13376
|
-
full: "Every time you offered is taken."
|
|
13377
|
-
};
|
|
13392
|
+
var STATE_WORDS = BOOKING_PAGE_STATE_LABEL;
|
|
13378
13393
|
function BookingSlots({ tableId, className }) {
|
|
13379
13394
|
const client = (0, import_react96.useRecordsClient)();
|
|
13380
13395
|
const host = useRecordsUi();
|
|
@@ -13398,10 +13413,21 @@ function BookingSlots({ tableId, className }) {
|
|
|
13398
13413
|
void load();
|
|
13399
13414
|
}, [load]);
|
|
13400
13415
|
const subjectIds = (0, import_react95.useMemo)(
|
|
13401
|
-
() => Array.from(
|
|
13402
|
-
|
|
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]
|
|
13403
13427
|
);
|
|
13404
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";
|
|
13405
13431
|
const toggle = (0, import_react95.useCallback)(
|
|
13406
13432
|
async (page) => {
|
|
13407
13433
|
setBusy(page.form_id);
|
|
@@ -13450,7 +13476,8 @@ function BookingSlots({ tableId, className }) {
|
|
|
13450
13476
|
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13451
13477
|
BuildOrAsk,
|
|
13452
13478
|
{
|
|
13453
|
-
mayBuild:
|
|
13479
|
+
mayBuild: mayBuildHere,
|
|
13480
|
+
whyNot: mayBuildHere ? null : levelsKnown ? NO_ADMIN2 : null,
|
|
13454
13481
|
onBuild: () => setBuilding(true),
|
|
13455
13482
|
...host.onAskForOne ? {
|
|
13456
13483
|
onAsk: () => host.onAskForOne?.({
|
|
@@ -13468,7 +13495,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
13468
13495
|
" Open the table the appointments should land in to make one."
|
|
13469
13496
|
] }) : null,
|
|
13470
13497
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ul", { className: "flex flex-col gap-2", children: pages.map((page) => {
|
|
13471
|
-
const url = `${origin}${(0,
|
|
13498
|
+
const url = `${origin}${(0, import_records12.bookingPath)(page.form_id)}`;
|
|
13472
13499
|
const mayOpen = levels.data?.[page.table_id] === "admin";
|
|
13473
13500
|
const open = page.published_at !== null && page.closed_at === null;
|
|
13474
13501
|
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("li", { className: "rounded-md border p-2.5", "data-testid": "booking-page", children: [
|
|
@@ -13557,7 +13584,7 @@ var import_design_system49 = require("@ai-matrx/design-system");
|
|
|
13557
13584
|
|
|
13558
13585
|
// src/CaptureRun.tsx
|
|
13559
13586
|
var import_react97 = require("react");
|
|
13560
|
-
var
|
|
13587
|
+
var import_records13 = require("@ai-matrx/records");
|
|
13561
13588
|
var import_react98 = require("@ai-matrx/records/react");
|
|
13562
13589
|
var import_design_system48 = require("@ai-matrx/design-system");
|
|
13563
13590
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
@@ -13612,7 +13639,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
13612
13639
|
const [sending, setSending] = (0, import_react97.useState)(false);
|
|
13613
13640
|
const queueRef = (0, import_react97.useRef)(null);
|
|
13614
13641
|
(0, import_react97.useEffect)(() => {
|
|
13615
|
-
const q2 = (0,
|
|
13642
|
+
const q2 = (0, import_records13.openCaptureQueue)({
|
|
13616
13643
|
onChange: (c, all) => {
|
|
13617
13644
|
setCounts(c);
|
|
13618
13645
|
setItems(all);
|
|
@@ -13861,7 +13888,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
13861
13888
|
value: String(answers[q.field] ?? ""),
|
|
13862
13889
|
onChange: (e) => {
|
|
13863
13890
|
const raw = e.target.value;
|
|
13864
|
-
|
|
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
|
+
}));
|
|
13865
13896
|
setMissing(null);
|
|
13866
13897
|
}
|
|
13867
13898
|
}
|