@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.js
CHANGED
|
@@ -524,7 +524,11 @@ import {
|
|
|
524
524
|
} from "@ai-matrx/design-system";
|
|
525
525
|
|
|
526
526
|
// src/parity.ts
|
|
527
|
-
import {
|
|
527
|
+
import {
|
|
528
|
+
KERNEL_TABLES,
|
|
529
|
+
PARITY_FIELD_TYPES as PARITY_FIELD_TYPES2,
|
|
530
|
+
fieldKindFor
|
|
531
|
+
} from "@ai-matrx/records";
|
|
528
532
|
|
|
529
533
|
// src/fieldTypes.ts
|
|
530
534
|
import { PARITY_FIELD_TYPES } from "@ai-matrx/records";
|
|
@@ -591,50 +595,9 @@ var PARITY_LABEL = {
|
|
|
591
595
|
var PARITY_MADE_OF = Object.fromEntries(
|
|
592
596
|
PARITY_FIELD_TYPES2.map((p) => [p.parity_type, p.made_of])
|
|
593
597
|
);
|
|
598
|
+
var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
|
|
594
599
|
function editorKindFor(field) {
|
|
595
|
-
|
|
596
|
-
const config = field.config ?? {};
|
|
597
|
-
switch (field.type) {
|
|
598
|
-
// LIMITS-FIX 2026-09-21: the tick box is a BEHAVIOUR of its own, so its editor is
|
|
599
|
-
// decided by the behaviour alone — no format, no unit, no target to read. A record
|
|
600
|
-
// that never answered holds no key at all, and `CheckboxControl` draws that third
|
|
601
|
-
// state rather than pretending it is an unticked box.
|
|
602
|
-
case "boolean":
|
|
603
|
-
return "checkbox";
|
|
604
|
-
case "text":
|
|
605
|
-
if (format === "email") return "email";
|
|
606
|
-
if (format === "phone") return "phone";
|
|
607
|
-
if (format === "url") return "url";
|
|
608
|
-
if (format === "json" || config["json"] === true) return "json";
|
|
609
|
-
if (format === "long" || config["multiline"] === true) return "long_text";
|
|
610
|
-
return "text";
|
|
611
|
-
case "range": {
|
|
612
|
-
const kind = String(config["kind"] ?? "number");
|
|
613
|
-
if (kind === "date" || kind === "datetime") return "datetime";
|
|
614
|
-
if (format === "currency") return "currency";
|
|
615
|
-
if (format === "percent" || field.unit === "%") return "percent";
|
|
616
|
-
return "number";
|
|
617
|
-
}
|
|
618
|
-
case "list":
|
|
619
|
-
return field.multi ? "multi_select" : "select";
|
|
620
|
-
case "relation":
|
|
621
|
-
return relationEditor(field);
|
|
622
|
-
case "formula": {
|
|
623
|
-
const via = config["via"];
|
|
624
|
-
if (via && config["agg"]) return "rollup";
|
|
625
|
-
if (via) return "lookup";
|
|
626
|
-
return "formula";
|
|
627
|
-
}
|
|
628
|
-
default:
|
|
629
|
-
return "text";
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
function relationEditor(field) {
|
|
633
|
-
const parity = String(field.config?.["parity"] ?? "");
|
|
634
|
-
if (parity === "attachment" || parity === "member") return parity;
|
|
635
|
-
if (field.relation_target === KERNEL_FILE_TABLE) return "attachment";
|
|
636
|
-
if (field.relation_target === KERNEL_PERSON_TABLE) return "member";
|
|
637
|
-
return "relation";
|
|
600
|
+
return fieldKindFor(field, KERNEL);
|
|
638
601
|
}
|
|
639
602
|
function fieldTypeLabel(field) {
|
|
640
603
|
const kind = editorKindFor(field);
|
|
@@ -1541,18 +1504,137 @@ function useLabelWait(field) {
|
|
|
1541
1504
|
return field ? waiting(field) : null;
|
|
1542
1505
|
}
|
|
1543
1506
|
|
|
1544
|
-
// src/
|
|
1545
|
-
|
|
1546
|
-
function
|
|
1547
|
-
|
|
1548
|
-
|
|
1507
|
+
// src/enumLabels.ts
|
|
1508
|
+
function exhaustiveValuesOf() {
|
|
1509
|
+
return function(values) {
|
|
1510
|
+
return values;
|
|
1511
|
+
};
|
|
1549
1512
|
}
|
|
1550
|
-
var
|
|
1513
|
+
var WORK_DUE_STATES = exhaustiveValuesOf()([
|
|
1514
|
+
"overdue",
|
|
1515
|
+
"due_today",
|
|
1516
|
+
"scheduled",
|
|
1517
|
+
"undated",
|
|
1518
|
+
"finished"
|
|
1519
|
+
]);
|
|
1520
|
+
var DUE_STATE_LABEL = {
|
|
1521
|
+
overdue: "Overdue",
|
|
1522
|
+
due_today: "Today",
|
|
1523
|
+
scheduled: "Scheduled",
|
|
1524
|
+
undated: "No date",
|
|
1525
|
+
finished: "Done"
|
|
1526
|
+
};
|
|
1527
|
+
var WORK_INBOX_KINDS = exhaustiveValuesOf()(["assignment", "approval", "proposal"]);
|
|
1528
|
+
var WORK_INBOX_KIND_LABEL = {
|
|
1529
|
+
assignment: "Yours",
|
|
1530
|
+
approval: "Approve",
|
|
1531
|
+
proposal: "Agent"
|
|
1532
|
+
};
|
|
1533
|
+
var CHECKLIST_REQUIREMENT_KINDS = exhaustiveValuesOf()([
|
|
1534
|
+
"none",
|
|
1535
|
+
"note",
|
|
1536
|
+
"answer",
|
|
1537
|
+
"record_field",
|
|
1538
|
+
"form",
|
|
1539
|
+
"document"
|
|
1540
|
+
]);
|
|
1541
|
+
var CHECKLIST_REQUIREMENT_LABEL = {
|
|
1542
|
+
none: "",
|
|
1543
|
+
note: "Say what you did",
|
|
1544
|
+
answer: "Fill this in",
|
|
1545
|
+
record_field: "This has to be filled in on the record",
|
|
1546
|
+
form: "This step is a form",
|
|
1547
|
+
document: "This step is a document"
|
|
1548
|
+
};
|
|
1549
|
+
var FIELD_SENSITIVITY_LABEL = {
|
|
1550
|
+
public: "Anyone who can open the record",
|
|
1551
|
+
internal: "People in this organization",
|
|
1552
|
+
confidential: "People who have been given the record",
|
|
1553
|
+
restricted: "Owners and administrators only"
|
|
1554
|
+
};
|
|
1555
|
+
var CONTEXT_POLICY_LABEL = {
|
|
1556
|
+
include: "Yes, an assistant can read it",
|
|
1557
|
+
summarize: "Only a summary of it",
|
|
1558
|
+
on_request: "Only when somebody asks for it",
|
|
1559
|
+
exclude: "No, keep it away from assistants"
|
|
1560
|
+
};
|
|
1561
|
+
var STAGE_RULE_ON_FAIL_LABEL = {
|
|
1562
|
+
refuse: "Turn it away",
|
|
1563
|
+
require_approval: "Ask for approval"
|
|
1564
|
+
};
|
|
1565
|
+
var SUBSCRIPTION_CADENCES = exhaustiveValuesOf()(["instant", "hourly", "daily", "weekly"]);
|
|
1566
|
+
var SUBSCRIPTION_CADENCE_LABEL = {
|
|
1567
|
+
instant: "as it happens",
|
|
1568
|
+
hourly: "hourly summary",
|
|
1569
|
+
daily: "daily summary",
|
|
1570
|
+
weekly: "weekly summary"
|
|
1571
|
+
};
|
|
1572
|
+
var SUBSCRIPTION_CHANNEL_VALUES = ["in_app", "email", "sms"];
|
|
1573
|
+
var SUBSCRIPTION_CHANNEL_LABEL = {
|
|
1574
|
+
in_app: "in the app",
|
|
1575
|
+
email: "by email \u2014 only if an address is on the account",
|
|
1576
|
+
sms: "by text \u2014 only if a number is on the account"
|
|
1577
|
+
};
|
|
1578
|
+
var ROLLUP_AGG_VALUES = ["count", "sum", "avg", "min", "max"];
|
|
1579
|
+
var ROLLUP_AGG_LABEL = {
|
|
1580
|
+
count: "How many there are",
|
|
1581
|
+
sum: "The total of",
|
|
1582
|
+
avg: "The average of",
|
|
1583
|
+
min: "The smallest",
|
|
1584
|
+
max: "The largest"
|
|
1585
|
+
};
|
|
1586
|
+
var FORMULA_OP_VALUES = ["concat", "add", "sub", "mul", "div"];
|
|
1587
|
+
var FORMULA_OP_LABEL = {
|
|
1588
|
+
concat: "Join them together",
|
|
1589
|
+
add: "Add them up",
|
|
1590
|
+
sub: "Take the second from the first",
|
|
1591
|
+
mul: "Multiply them",
|
|
1592
|
+
div: "Divide the first by the second"
|
|
1593
|
+
};
|
|
1594
|
+
var FORMULA_OP_JOINS = {
|
|
1595
|
+
concat: true,
|
|
1596
|
+
add: true,
|
|
1597
|
+
sub: false,
|
|
1598
|
+
mul: true,
|
|
1599
|
+
div: false
|
|
1600
|
+
};
|
|
1601
|
+
var FIELD_RULE_KIND_VALUES = ["min", "max", "length", "pattern", "equals_field", "differs_from_field"];
|
|
1602
|
+
var FIELD_RULE_KIND_LABEL = {
|
|
1603
|
+
min: "At least",
|
|
1604
|
+
max: "At most",
|
|
1605
|
+
length: "No longer than",
|
|
1606
|
+
pattern: "Looks like",
|
|
1607
|
+
equals_field: "Same as the column",
|
|
1608
|
+
differs_from_field: "Different from the column"
|
|
1609
|
+
};
|
|
1610
|
+
var PROPOSED_CHANGE_ACT_VALUES = ["add", "update", "remove"];
|
|
1611
|
+
var PROPOSED_CHANGE_ACT_LABEL = {
|
|
1612
|
+
add: "Add",
|
|
1613
|
+
update: "Update",
|
|
1614
|
+
remove: "Remove"
|
|
1615
|
+
};
|
|
1616
|
+
var BOOKING_PAGE_STATE_VALUES = ["draft", "open", "closed", "full"];
|
|
1617
|
+
var BOOKING_PAGE_STATE_LABEL = {
|
|
1618
|
+
draft: "Not open yet \u2014 nobody can book until you open it.",
|
|
1619
|
+
open: "Open. Anyone with the link can book a time.",
|
|
1620
|
+
closed: "Closed. The link still works and says you are not taking bookings.",
|
|
1621
|
+
full: "Every time you offered is taken."
|
|
1622
|
+
};
|
|
1623
|
+
var ABSENCE_WORD_VALUES = ["never asked", "none", "refused", "conflicting"];
|
|
1624
|
+
var ABSENCE_WORD_LABEL = {
|
|
1551
1625
|
"never asked": "never asked",
|
|
1552
1626
|
none: "none",
|
|
1553
1627
|
refused: "refused",
|
|
1554
1628
|
conflicting: "conflicting"
|
|
1555
1629
|
};
|
|
1630
|
+
|
|
1631
|
+
// src/values.tsx
|
|
1632
|
+
import { Fragment as Fragment3, jsx as jsx9 } from "react/jsx-runtime";
|
|
1633
|
+
function envelopeFor(document2, key) {
|
|
1634
|
+
const block = document2?._values;
|
|
1635
|
+
return block?.[key];
|
|
1636
|
+
}
|
|
1637
|
+
var ABSENCE_WORDS = ABSENCE_WORD_LABEL;
|
|
1556
1638
|
function renderValue(field, value, document2, labels, stillWaitingFor) {
|
|
1557
1639
|
const envelope = envelopeFor(document2, field.key);
|
|
1558
1640
|
if (envelope?.absent) {
|
|
@@ -2982,7 +3064,7 @@ function confirmLabel(plan, noun, nounPlural) {
|
|
|
2982
3064
|
|
|
2983
3065
|
// src/pasteValues.ts
|
|
2984
3066
|
import { predictValueRefusals } from "@ai-matrx/records/core";
|
|
2985
|
-
import { optionKey as optionKey2 } from "@ai-matrx/records";
|
|
3067
|
+
import { coerceTypedAnswer, optionKey as optionKey2 } from "@ai-matrx/records";
|
|
2986
3068
|
function choiceOptionsOf(options) {
|
|
2987
3069
|
const byWord = /* @__PURE__ */ new Map();
|
|
2988
3070
|
const labels = [];
|
|
@@ -2999,113 +3081,11 @@ function choiceOptionsOf(options) {
|
|
|
2999
3081
|
}
|
|
3000
3082
|
return { byWord, labels };
|
|
3001
3083
|
}
|
|
3002
|
-
var TRUE_WORDS = /* @__PURE__ */ new Set(["true", "yes", "y", "1", "\u2713", "x", "checked", "on"]);
|
|
3003
|
-
var FALSE_WORDS = /* @__PURE__ */ new Set(["false", "no", "n", "0", "", "unchecked", "off"]);
|
|
3004
3084
|
function valueFromPastedText(field, raw, options) {
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
switch (kind) {
|
|
3010
|
-
case "checkbox": {
|
|
3011
|
-
const word = text.toLowerCase();
|
|
3012
|
-
if (TRUE_WORDS.has(word)) return { value: true };
|
|
3013
|
-
if (FALSE_WORDS.has(word)) return { value: word === "" ? null : false };
|
|
3014
|
-
return {
|
|
3015
|
-
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.`
|
|
3016
|
-
};
|
|
3017
|
-
}
|
|
3018
|
-
case "number":
|
|
3019
|
-
case "currency":
|
|
3020
|
-
case "percent": {
|
|
3021
|
-
const negative = /^\(.*\)$/.test(text);
|
|
3022
|
-
const bare = text.replace(/^\(|\)$/g, "").replace(/[\s,]/g, "").replace(/^[^\d.\-+]+/, "").replace(/[^\d.\-+eE]+$/, "");
|
|
3023
|
-
const n = Number(bare);
|
|
3024
|
-
if (bare === "" || Number.isNaN(n)) {
|
|
3025
|
-
return {
|
|
3026
|
-
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.`
|
|
3027
|
-
};
|
|
3028
|
-
}
|
|
3029
|
-
return { value: negative ? -n : n };
|
|
3030
|
-
}
|
|
3031
|
-
case "datetime": {
|
|
3032
|
-
const wantsTime = String(field.config?.["kind"] ?? "date") === "datetime";
|
|
3033
|
-
const plainDay = /^\s*(\d{4})-(\d{2})-(\d{2})\s*$/.exec(raw);
|
|
3034
|
-
if (!wantsTime && plainDay) return { value: `${plainDay[1]}-${plainDay[2]}-${plainDay[3]}` };
|
|
3035
|
-
const at = Date.parse(text);
|
|
3036
|
-
if (Number.isNaN(at)) {
|
|
3037
|
-
return {
|
|
3038
|
-
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.`
|
|
3039
|
-
};
|
|
3040
|
-
}
|
|
3041
|
-
const parsed = new Date(at);
|
|
3042
|
-
if (wantsTime) return { value: parsed.toISOString() };
|
|
3043
|
-
const y = parsed.getFullYear();
|
|
3044
|
-
const m = String(parsed.getMonth() + 1).padStart(2, "0");
|
|
3045
|
-
const d = String(parsed.getDate()).padStart(2, "0");
|
|
3046
|
-
return { value: `${y}-${m}-${d}` };
|
|
3047
|
-
}
|
|
3048
|
-
case "json": {
|
|
3049
|
-
try {
|
|
3050
|
-
return { value: JSON.parse(text) };
|
|
3051
|
-
} catch {
|
|
3052
|
-
return {
|
|
3053
|
-
refusal: `${label} holds a document, and \u201C${raw}\u201D is not valid JSON. Paste the whole object, braces and all.`
|
|
3054
|
-
};
|
|
3055
|
-
}
|
|
3056
|
-
}
|
|
3057
|
-
// A LIST, A PERSON, A FILE OR ANOTHER RECORD IS AN IDENTITY, NOT A WORD.
|
|
3058
|
-
// The store keeps the id of the option or the record, and a word off a
|
|
3059
|
-
// clipboard is not that id — writing the word would put a string where an
|
|
3060
|
-
// id belongs and every filter, colour and rollup built on that column would
|
|
3061
|
-
// stop agreeing with it. So the cell is left alone and the person is told
|
|
3062
|
-
// which control does hold it.
|
|
3063
|
-
case "select":
|
|
3064
|
-
case "multi_select": {
|
|
3065
|
-
if (!options) {
|
|
3066
|
-
return {
|
|
3067
|
-
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.`
|
|
3068
|
-
};
|
|
3069
|
-
}
|
|
3070
|
-
const wanted = kind === "multi_select" ? text.split(/[,;]/).map((w) => w.trim()).filter((w) => w.length > 0) : [text];
|
|
3071
|
-
if (wanted.length === 0) return { value: kind === "multi_select" ? [] : null };
|
|
3072
|
-
const matched = [];
|
|
3073
|
-
const unmatched = [];
|
|
3074
|
-
for (const word of wanted) {
|
|
3075
|
-
const hit = options.byWord.get(word.toLowerCase());
|
|
3076
|
-
if (hit === void 0) unmatched.push(word);
|
|
3077
|
-
else matched.push(hit);
|
|
3078
|
-
}
|
|
3079
|
-
if (unmatched.length > 0) {
|
|
3080
|
-
const offered = options.labels.length > 0 ? options.labels.join(", ") : "it has none yet";
|
|
3081
|
-
return {
|
|
3082
|
-
refusal: `${label} does not have ${unmatched.map((w) => `\u201C${w}\u201D`).join(" or ")} among its options. It offers: ${offered}.`,
|
|
3083
|
-
unmatched
|
|
3084
|
-
};
|
|
3085
|
-
}
|
|
3086
|
-
return { value: kind === "multi_select" ? matched : matched[0] };
|
|
3087
|
-
}
|
|
3088
|
-
case "member":
|
|
3089
|
-
return {
|
|
3090
|
-
refusal: `${label} names a person in this organization, so it is chosen rather than typed. Open the cell and pick them.`
|
|
3091
|
-
};
|
|
3092
|
-
case "attachment":
|
|
3093
|
-
return {
|
|
3094
|
-
refusal: `${label} holds a file, which cannot arrive on a clipboard. Open the cell and attach it.`
|
|
3095
|
-
};
|
|
3096
|
-
case "relation":
|
|
3097
|
-
return {
|
|
3098
|
-
refusal: `${label} points at another record, so it is chosen rather than typed. Open the cell and pick the record.`
|
|
3099
|
-
};
|
|
3100
|
-
case "formula":
|
|
3101
|
-
case "lookup":
|
|
3102
|
-
case "rollup":
|
|
3103
|
-
return {
|
|
3104
|
-
refusal: `${label} is worked out by the system, so nothing can be pasted into it.`
|
|
3105
|
-
};
|
|
3106
|
-
default:
|
|
3107
|
-
return { value: raw };
|
|
3108
|
-
}
|
|
3085
|
+
return coerceTypedAnswer(field, raw, {
|
|
3086
|
+
label: fieldName(field),
|
|
3087
|
+
...options ? { options } : {}
|
|
3088
|
+
});
|
|
3109
3089
|
}
|
|
3110
3090
|
function planPastedBlock(args) {
|
|
3111
3091
|
const byKey = new Map(args.fields.map((f) => [f.key, f]));
|
|
@@ -4282,19 +4262,23 @@ import {
|
|
|
4282
4262
|
} from "@ai-matrx/records/react";
|
|
4283
4263
|
import { Button as Button11, Separator as Separator3, cn as cn12 } from "@ai-matrx/design-system";
|
|
4284
4264
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4285
|
-
var
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4265
|
+
var ADDABLE_TYPE_IDS = [
|
|
4266
|
+
"text",
|
|
4267
|
+
"long_text",
|
|
4268
|
+
"number",
|
|
4269
|
+
"currency",
|
|
4270
|
+
"percent",
|
|
4271
|
+
"datetime",
|
|
4272
|
+
"email",
|
|
4273
|
+
"phone",
|
|
4274
|
+
"url",
|
|
4275
|
+
"member",
|
|
4276
|
+
"attachment"
|
|
4297
4277
|
];
|
|
4278
|
+
var ADDABLE_TYPES = ADDABLE_TYPE_IDS.map((value) => ({
|
|
4279
|
+
value,
|
|
4280
|
+
label: fieldTypeChoice(value)?.label ?? value
|
|
4281
|
+
}));
|
|
4298
4282
|
function asField(f) {
|
|
4299
4283
|
return {
|
|
4300
4284
|
id: f.id,
|
|
@@ -4473,41 +4457,20 @@ import {
|
|
|
4473
4457
|
Separator as Separator4,
|
|
4474
4458
|
cn as cn13
|
|
4475
4459
|
} from "@ai-matrx/design-system";
|
|
4460
|
+
import { FIELD_SENSITIVITIES, CONTEXT_POLICIES } from "@ai-matrx/records";
|
|
4476
4461
|
import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
4477
|
-
var RULE_KINDS = [
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
{ value: "restricted", label: "Owners and administrators only" }
|
|
4490
|
-
];
|
|
4491
|
-
var AGENT_VISIBILITY = [
|
|
4492
|
-
{ value: "include", label: "Yes, an assistant can read it" },
|
|
4493
|
-
{ value: "summarize", label: "Only a summary of it" },
|
|
4494
|
-
{ value: "on_request", label: "Only when somebody asks for it" },
|
|
4495
|
-
{ value: "exclude", label: "No, keep it away from assistants" }
|
|
4496
|
-
];
|
|
4497
|
-
var ROLLUP_OPERATIONS = [
|
|
4498
|
-
{ value: "count", label: "How many there are" },
|
|
4499
|
-
{ value: "sum", label: "The total of" },
|
|
4500
|
-
{ value: "avg", label: "The average of" },
|
|
4501
|
-
{ value: "min", label: "The smallest" },
|
|
4502
|
-
{ value: "max", label: "The largest" }
|
|
4503
|
-
];
|
|
4504
|
-
var FORMULA_OPERATIONS = [
|
|
4505
|
-
{ value: "concat", label: "Join them together", joins: true },
|
|
4506
|
-
{ value: "add", label: "Add them up", joins: true },
|
|
4507
|
-
{ value: "sub", label: "Take the second from the first", joins: false },
|
|
4508
|
-
{ value: "mul", label: "Multiply them", joins: true },
|
|
4509
|
-
{ value: "div", label: "Divide the first by the second", joins: false }
|
|
4510
|
-
];
|
|
4462
|
+
var RULE_KINDS = FIELD_RULE_KIND_VALUES.map((kind) => ({ kind, label: FIELD_RULE_KIND_LABEL[kind] }));
|
|
4463
|
+
var SENSITIVITIES = FIELD_SENSITIVITIES.map((value) => ({ value, label: FIELD_SENSITIVITY_LABEL[value] }));
|
|
4464
|
+
var AGENT_VISIBILITY = CONTEXT_POLICIES.map((value) => ({ value, label: CONTEXT_POLICY_LABEL[value] }));
|
|
4465
|
+
var ROLLUP_OPERATIONS = ROLLUP_AGG_VALUES.map((value) => ({
|
|
4466
|
+
value,
|
|
4467
|
+
label: ROLLUP_AGG_LABEL[value]
|
|
4468
|
+
}));
|
|
4469
|
+
var FORMULA_OPERATIONS = FORMULA_OP_VALUES.map((value) => ({
|
|
4470
|
+
value,
|
|
4471
|
+
label: FORMULA_OP_LABEL[value],
|
|
4472
|
+
joins: FORMULA_OP_JOINS[value]
|
|
4473
|
+
}));
|
|
4511
4474
|
function keyFor(label) {
|
|
4512
4475
|
const token = label.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48);
|
|
4513
4476
|
if (token === "") return "";
|
|
@@ -5072,6 +5035,9 @@ var CONDITION_OPS = [
|
|
|
5072
5035
|
{ op: "gt", label: "is more than" },
|
|
5073
5036
|
{ op: "lt", label: "is less than" }
|
|
5074
5037
|
];
|
|
5038
|
+
function pointsAtARecord(f) {
|
|
5039
|
+
return !!f?.field && f.field.type === "relation" && !!f.field.relation_target;
|
|
5040
|
+
}
|
|
5075
5041
|
function conditionIsSimple(expr) {
|
|
5076
5042
|
if (expr === null || expr === void 0) return true;
|
|
5077
5043
|
const node = expr;
|
|
@@ -5142,6 +5108,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5142
5108
|
const op = node?.op ?? "";
|
|
5143
5109
|
const onField = node?.args?.[0]?.field ?? "";
|
|
5144
5110
|
const value = node?.args?.[1]?.const ?? "";
|
|
5111
|
+
const chosen = fields.find((f) => f.id === onField);
|
|
5145
5112
|
function write(next) {
|
|
5146
5113
|
const chosenOp = next.op ?? op;
|
|
5147
5114
|
const chosenField = next.field ?? onField;
|
|
@@ -5180,7 +5147,24 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5180
5147
|
children: CONDITION_OPS.map((c) => /* @__PURE__ */ jsx18("option", { value: c.op, children: c.label }, c.op))
|
|
5181
5148
|
}
|
|
5182
5149
|
),
|
|
5183
|
-
op
|
|
5150
|
+
op === "present" ? null : pointsAtARecord(chosen) ? (
|
|
5151
|
+
// A RECORD IS PICKED BY ITS WORDS, NEVER TYPED AS AN ID. The same picker the
|
|
5152
|
+
// cell uses, on the same `relation_words_many` the cell reads, so a filter and
|
|
5153
|
+
// the column it filters can never disagree about what a record is called. It
|
|
5154
|
+
// is asked for ONE record even when the column holds several: a clause compares
|
|
5155
|
+
// against one value, and a picker that let somebody choose three would be
|
|
5156
|
+
// writing an expression this row cannot draw back.
|
|
5157
|
+
/* @__PURE__ */ jsx18(
|
|
5158
|
+
RelationPicker,
|
|
5159
|
+
{
|
|
5160
|
+
field: { ...chosen.field, multi: false },
|
|
5161
|
+
value: value === "" ? null : value,
|
|
5162
|
+
onChange: (next) => write({ value: next === null || next === void 0 ? "" : String(next) }),
|
|
5163
|
+
id: "condition-value-record",
|
|
5164
|
+
className: "min-w-[8rem]"
|
|
5165
|
+
}
|
|
5166
|
+
)
|
|
5167
|
+
) : /* @__PURE__ */ jsx18(
|
|
5184
5168
|
BasicInput6,
|
|
5185
5169
|
{
|
|
5186
5170
|
className: "h-8 w-28 text-xs",
|
|
@@ -5188,7 +5172,7 @@ function ConditionRow({ lead, expr, fields, onChange, emptyLabel = "always", cla
|
|
|
5188
5172
|
value: String(value ?? ""),
|
|
5189
5173
|
onChange: (e) => write({ value: conditionValue(e.target.value) })
|
|
5190
5174
|
}
|
|
5191
|
-
)
|
|
5175
|
+
)
|
|
5192
5176
|
] }) : null
|
|
5193
5177
|
] });
|
|
5194
5178
|
}
|
|
@@ -5348,10 +5332,10 @@ var NO_RULES_YET = "Nothing has to be true to get here yet.";
|
|
|
5348
5332
|
var NEEDS_A_SENTENCE = "Write the sentence somebody reads when this stops them, the way you would say it out loud.";
|
|
5349
5333
|
var NOT_DRAWN_HERE = "This part of the rule is not something this builder can draw yet";
|
|
5350
5334
|
var ON_FAIL = [
|
|
5351
|
-
{ value: "refuse", label:
|
|
5335
|
+
{ value: "refuse", label: STAGE_RULE_ON_FAIL_LABEL.refuse, note: "The card stays where it is and the person is told why." },
|
|
5352
5336
|
{
|
|
5353
5337
|
value: "require_approval",
|
|
5354
|
-
label:
|
|
5338
|
+
label: STAGE_RULE_ON_FAIL_LABEL.require_approval,
|
|
5355
5339
|
note: "The card stays where it is, and the people who can approve it are asked. Nobody is turned away."
|
|
5356
5340
|
}
|
|
5357
5341
|
];
|
|
@@ -5402,7 +5386,7 @@ function StageRulesSection({ tableId, stage, className }) {
|
|
|
5402
5386
|
const stageLabel = stages.find((s) => s.key === stageKey)?.label ?? stageKey ?? "";
|
|
5403
5387
|
const gates = useMemo13(() => stageKey ? gatesOf(pipeline, stageKey) : [], [pipeline, stageKey]);
|
|
5404
5388
|
const conditionFields = useMemo13(
|
|
5405
|
-
() => (fields.data ?? []).map((f) => ({ id: String(f.id), key: f.key, label: fieldName(f) })),
|
|
5389
|
+
() => (fields.data ?? []).map((f) => ({ id: String(f.id), key: f.key, label: fieldName(f), field: f })),
|
|
5406
5390
|
[fields.data]
|
|
5407
5391
|
);
|
|
5408
5392
|
useEffect8(() => {
|
|
@@ -7103,7 +7087,7 @@ function offerableFields(all, want) {
|
|
|
7103
7087
|
return all.filter((field) => {
|
|
7104
7088
|
const kind = editorKindFor(field);
|
|
7105
7089
|
if (want === "choice") return kind === "select" || kind === "multi_select";
|
|
7106
|
-
return kind === "datetime"
|
|
7090
|
+
return kind === "datetime";
|
|
7107
7091
|
});
|
|
7108
7092
|
}
|
|
7109
7093
|
function useStageField(tableId) {
|
|
@@ -7521,11 +7505,7 @@ import { useState as useState26 } from "react";
|
|
|
7521
7505
|
import { useRecordsClient as useRecordsClient18 } from "@ai-matrx/records/react";
|
|
7522
7506
|
import { Badge as Badge7, Button as Button22, cn as cn22 } from "@ai-matrx/design-system";
|
|
7523
7507
|
import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
7524
|
-
var ACT_WORD =
|
|
7525
|
-
add: "Add",
|
|
7526
|
-
update: "Update",
|
|
7527
|
-
remove: "Remove"
|
|
7528
|
-
};
|
|
7508
|
+
var ACT_WORD = PROPOSED_CHANGE_ACT_LABEL;
|
|
7529
7509
|
function ProposalRow({
|
|
7530
7510
|
change,
|
|
7531
7511
|
outcome,
|
|
@@ -7632,21 +7612,8 @@ import { useCallback as useCallback12, useEffect as useEffect15, useMemo as useM
|
|
|
7632
7612
|
import { useRecordsClient as useRecordsClient19, useTable as useTable9 } from "@ai-matrx/records/react";
|
|
7633
7613
|
import { Badge as Badge8, BasicInput as BasicInput8, BasicTextarea as BasicTextarea4, Button as Button23, Skeleton as Skeleton9, cn as cn23 } from "@ai-matrx/design-system";
|
|
7634
7614
|
import { Fragment as Fragment13, jsx as jsx29, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
7635
|
-
var DUE_WORD =
|
|
7636
|
-
|
|
7637
|
-
due_today: "Today",
|
|
7638
|
-
scheduled: "Scheduled",
|
|
7639
|
-
undated: "No date",
|
|
7640
|
-
finished: "Done"
|
|
7641
|
-
};
|
|
7642
|
-
var REQUIRES_WORD = {
|
|
7643
|
-
none: "",
|
|
7644
|
-
note: "Say what you did",
|
|
7645
|
-
answer: "Fill this in",
|
|
7646
|
-
record_field: "This has to be filled in on the record",
|
|
7647
|
-
form: "This step is a form",
|
|
7648
|
-
document: "This step is a document"
|
|
7649
|
-
};
|
|
7615
|
+
var DUE_WORD = DUE_STATE_LABEL;
|
|
7616
|
+
var REQUIRES_WORD = CHECKLIST_REQUIREMENT_LABEL;
|
|
7650
7617
|
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.";
|
|
7651
7618
|
function ChecklistRunner({
|
|
7652
7619
|
tableId,
|
|
@@ -8354,18 +8321,8 @@ function roleKey(said) {
|
|
|
8354
8321
|
// src/ActionInbox.tsx
|
|
8355
8322
|
import { jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
8356
8323
|
var ACTION_KINDS = ["approval", "assignment", "proposal"];
|
|
8357
|
-
var KIND_WORD =
|
|
8358
|
-
|
|
8359
|
-
approval: "Approve",
|
|
8360
|
-
proposal: "Agent"
|
|
8361
|
-
};
|
|
8362
|
-
var DUE_WORD2 = {
|
|
8363
|
-
overdue: "Overdue",
|
|
8364
|
-
due_today: "Today",
|
|
8365
|
-
scheduled: "Scheduled",
|
|
8366
|
-
undated: "No date",
|
|
8367
|
-
finished: "Finished"
|
|
8368
|
-
};
|
|
8324
|
+
var KIND_WORD = WORK_INBOX_KIND_LABEL;
|
|
8325
|
+
var DUE_WORD2 = DUE_STATE_LABEL;
|
|
8369
8326
|
function ActionInbox({ tableId, includeSettled = false, onOpenRecord, className }) {
|
|
8370
8327
|
const client = useRecordsClient20();
|
|
8371
8328
|
const [items, setItems] = useState28(null);
|
|
@@ -9617,18 +9574,18 @@ function BuildOrAsk({
|
|
|
9617
9574
|
buildLabel,
|
|
9618
9575
|
className
|
|
9619
9576
|
}) {
|
|
9577
|
+
const mayAsk = mayBuild && Boolean(onAsk);
|
|
9620
9578
|
return /* @__PURE__ */ jsxs31("div", { className: cn29("rounded-md border border-dashed p-3", className), children: [
|
|
9621
9579
|
/* @__PURE__ */ jsx35("p", { className: "text-xs text-muted-foreground", children }),
|
|
9622
|
-
/* @__PURE__ */ jsxs31("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: [
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
] }),
|
|
9626
|
-
|
|
9580
|
+
mayBuild ? /* @__PURE__ */ jsxs31("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: [
|
|
9581
|
+
mayAsk ? /* @__PURE__ */ jsx35(Button29, { size: "sm", variant: "outline", onClick: onAsk, children: "Ask an agent" }) : null,
|
|
9582
|
+
/* @__PURE__ */ jsx35(Button29, { size: "sm", onClick: onBuild, children: buildLabel })
|
|
9583
|
+
] }) : null,
|
|
9584
|
+
!mayBuild ? whyNot ? /* @__PURE__ */ jsx35("p", { className: "mt-2 text-xs text-muted-foreground", children: whyNot }) : null : mayAsk ? /* @__PURE__ */ jsxs31("p", { className: "mt-2 text-xs text-muted-foreground", children: [
|
|
9627
9585
|
"You would say something like: \u201C",
|
|
9628
9586
|
suggestion,
|
|
9629
9587
|
"\u201D"
|
|
9630
|
-
] }) : /* @__PURE__ */ jsx35("p", { className: "mt-2 text-xs text-muted-foreground", children: NO_AGENT_PORT })
|
|
9631
|
-
!mayBuild && whyNot ? /* @__PURE__ */ jsx35("p", { className: "mt-2 text-xs text-muted-foreground", children: whyNot }) : null
|
|
9588
|
+
] }) : /* @__PURE__ */ jsx35("p", { className: "mt-2 text-xs text-muted-foreground", children: NO_AGENT_PORT })
|
|
9632
9589
|
] });
|
|
9633
9590
|
}
|
|
9634
9591
|
|
|
@@ -9667,30 +9624,41 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9667
9624
|
const client = useRecordsClient25();
|
|
9668
9625
|
const host = useRecordsUi();
|
|
9669
9626
|
const [portals, setPortals] = useState33(null);
|
|
9627
|
+
const [exposures, setExposures] = useState33([]);
|
|
9670
9628
|
const [listError, setListError] = useState33(null);
|
|
9671
9629
|
const [openId, setOpenId] = useState33(null);
|
|
9672
9630
|
const [building, setBuilding] = useState33(false);
|
|
9631
|
+
const [adding, setAdding] = useState33(null);
|
|
9673
9632
|
const load = useCallback18(async () => {
|
|
9674
|
-
const answered = await client.portals();
|
|
9633
|
+
const [answered, mapped] = await Promise.all([client.portals(), client.portalTables()]);
|
|
9675
9634
|
if (!answered.ok) {
|
|
9676
9635
|
setListError(answered.error);
|
|
9677
9636
|
setPortals([]);
|
|
9637
|
+
setExposures([]);
|
|
9678
9638
|
return;
|
|
9679
9639
|
}
|
|
9680
9640
|
setListError(null);
|
|
9681
9641
|
setPortals(answered.data);
|
|
9642
|
+
setExposures(mapped.ok ? mapped.data : []);
|
|
9682
9643
|
}, [client]);
|
|
9683
9644
|
useEffect21(() => {
|
|
9684
9645
|
void load();
|
|
9685
9646
|
}, [load]);
|
|
9686
9647
|
if (portals === null) return /* @__PURE__ */ jsx36(Skeleton15, { className: cn30("h-32 w-full", className) });
|
|
9648
|
+
const onATable = Boolean(tableId);
|
|
9649
|
+
const holdingThis = new Set(
|
|
9650
|
+
exposures.filter((e) => e.table_id === tableId).map((e) => e.portal_id)
|
|
9651
|
+
);
|
|
9652
|
+
const shown = onATable ? portals.filter((p) => holdingThis.has(p.portal_id)) : portals;
|
|
9653
|
+
const couldTakeIt = onATable ? portals.filter((p) => !holdingThis.has(p.portal_id)) : [];
|
|
9654
|
+
const elsewhere = couldTakeIt.length;
|
|
9687
9655
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
9688
9656
|
return /* @__PURE__ */ jsxs32("section", { className: cn30("flex flex-col gap-3", className), children: [
|
|
9689
9657
|
/* @__PURE__ */ jsxs32("header", { className: "flex items-center gap-2", children: [
|
|
9690
9658
|
/* @__PURE__ */ jsx36("h3", { className: "text-sm font-medium", children: "Portals" }),
|
|
9691
|
-
/* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children:
|
|
9659
|
+
/* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children: shown.length === 0 ? "none for this table" : `${shown.length}` }),
|
|
9692
9660
|
/* @__PURE__ */ jsx36("div", { className: "flex-1" }),
|
|
9693
|
-
|
|
9661
|
+
shown.length > 0 ? /* @__PURE__ */ jsx36(Button30, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a portal" }) : null
|
|
9694
9662
|
] }),
|
|
9695
9663
|
listError ? /* @__PURE__ */ jsx36(RefusalNotice, { error: listError }) : null,
|
|
9696
9664
|
building ? /* @__PURE__ */ jsx36(
|
|
@@ -9703,7 +9671,19 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9703
9671
|
onClose: () => setBuilding(false)
|
|
9704
9672
|
}
|
|
9705
9673
|
) : null,
|
|
9706
|
-
|
|
9674
|
+
adding ? /* @__PURE__ */ jsx36(
|
|
9675
|
+
PortalBuilder,
|
|
9676
|
+
{
|
|
9677
|
+
...tableId ? { tableId } : {},
|
|
9678
|
+
portalId: adding,
|
|
9679
|
+
onSaved: () => {
|
|
9680
|
+
setAdding(null);
|
|
9681
|
+
void load();
|
|
9682
|
+
},
|
|
9683
|
+
onClose: () => setAdding(null)
|
|
9684
|
+
}
|
|
9685
|
+
) : null,
|
|
9686
|
+
shown.length === 0 && !listError && !building && !adding ? /* @__PURE__ */ jsxs32(
|
|
9707
9687
|
BuildOrAsk,
|
|
9708
9688
|
{
|
|
9709
9689
|
mayBuild: true,
|
|
@@ -9712,11 +9692,37 @@ function PortalsPanel({ tableId, className }) {
|
|
|
9712
9692
|
onAsk: () => host.onAskForOne?.({ kind: "portal", tableId, suggestion: PORTAL_SUGGESTION })
|
|
9713
9693
|
} : {},
|
|
9714
9694
|
suggestion: PORTAL_SUGGESTION,
|
|
9715
|
-
buildLabel: "Build the portal",
|
|
9716
|
-
children:
|
|
9695
|
+
buildLabel: elsewhere > 0 ? "Build a new portal" : "Build the portal",
|
|
9696
|
+
children: [
|
|
9697
|
+
"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.",
|
|
9698
|
+
elsewhere > 0 ? /* @__PURE__ */ jsxs32(Fragment16, { children: [
|
|
9699
|
+
" ",
|
|
9700
|
+
"This table is not in",
|
|
9701
|
+
" ",
|
|
9702
|
+
elsewhere === 1 ? "the portal this organization already has" : `any of the ${elsewhere} portals this organization already has`,
|
|
9703
|
+
"."
|
|
9704
|
+
] }) : null
|
|
9705
|
+
]
|
|
9717
9706
|
}
|
|
9718
9707
|
) : null,
|
|
9719
|
-
/* @__PURE__ */
|
|
9708
|
+
shown.length === 0 && !listError && !building && !adding && elsewhere > 0 ? /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1.5 rounded-md border border-dashed border-border p-2.5", children: [
|
|
9709
|
+
/* @__PURE__ */ jsx36("p", { className: "text-xs text-muted-foreground", children: "Or add this table to a portal your clients already sign in to:" }),
|
|
9710
|
+
/* @__PURE__ */ jsx36("div", { className: "flex flex-wrap gap-1.5", children: couldTakeIt.map((portal) => /* @__PURE__ */ jsxs32(
|
|
9711
|
+
Button30,
|
|
9712
|
+
{
|
|
9713
|
+
size: "sm",
|
|
9714
|
+
variant: "outline",
|
|
9715
|
+
onClick: () => setAdding(portal.portal_id),
|
|
9716
|
+
children: [
|
|
9717
|
+
"Add to \u201C",
|
|
9718
|
+
portal.title,
|
|
9719
|
+
"\u201D"
|
|
9720
|
+
]
|
|
9721
|
+
},
|
|
9722
|
+
portal.portal_id
|
|
9723
|
+
)) })
|
|
9724
|
+
] }) : null,
|
|
9725
|
+
/* @__PURE__ */ jsx36("ul", { className: "flex flex-col gap-2", children: shown.map((portal) => {
|
|
9720
9726
|
const url = `${origin}${portalPath(portal.slug)}`;
|
|
9721
9727
|
const open = openId === portal.portal_id;
|
|
9722
9728
|
return /* @__PURE__ */ jsxs32("li", { className: "rounded-md border border-border bg-card p-2.5", children: [
|
|
@@ -10443,11 +10449,7 @@ function whenItFires(subscription) {
|
|
|
10443
10449
|
const every = subscription.cadence === "hourly" ? "an hourly summary" : subscription.cadence === "weekly" ? "a weekly summary" : "a daily summary";
|
|
10444
10450
|
return subscription.schedule ? `${every}, ${subscription.schedule}` : every;
|
|
10445
10451
|
}
|
|
10446
|
-
var CHANNEL_WORDS2 =
|
|
10447
|
-
in_app: "in the app",
|
|
10448
|
-
email: "by email \u2014 only if an address is on the account",
|
|
10449
|
-
sms: "by text \u2014 only if a number is on the account"
|
|
10450
|
-
};
|
|
10452
|
+
var CHANNEL_WORDS2 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
10451
10453
|
var DIGEST_SUGGESTION = "Email me a summary of this every Monday at 8 in the morning.";
|
|
10452
10454
|
function SubscriptionsPanel({ tableId, className }) {
|
|
10453
10455
|
const client = useRecordsClient27();
|
|
@@ -11223,7 +11225,12 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
11223
11225
|
Condition,
|
|
11224
11226
|
{
|
|
11225
11227
|
question,
|
|
11226
|
-
fieldKeys: fields.data ?? []
|
|
11228
|
+
fieldKeys: (fields.data ?? []).map((f) => ({
|
|
11229
|
+
id: String(f.id),
|
|
11230
|
+
key: f.key,
|
|
11231
|
+
label: f.label || f.key,
|
|
11232
|
+
field: f
|
|
11233
|
+
})),
|
|
11227
11234
|
onChange: (showIf) => patchQuestion(index, { showIf })
|
|
11228
11235
|
}
|
|
11229
11236
|
)
|
|
@@ -11961,17 +11968,8 @@ import { useCallback as useCallback26, useEffect as useEffect30, useState as use
|
|
|
11961
11968
|
import { useRecordsClient as useRecordsClient32, useTable as useTable16 } from "@ai-matrx/records/react";
|
|
11962
11969
|
import { Button as Button38, Skeleton as Skeleton23, cn as cn39 } from "@ai-matrx/design-system";
|
|
11963
11970
|
import { jsx as jsx45, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
11964
|
-
var CADENCE_WORDS2 =
|
|
11965
|
-
|
|
11966
|
-
hourly: "hourly summary",
|
|
11967
|
-
daily: "daily summary",
|
|
11968
|
-
weekly: "weekly summary"
|
|
11969
|
-
};
|
|
11970
|
-
var CHANNEL_WORDS3 = {
|
|
11971
|
-
in_app: "in the app",
|
|
11972
|
-
email: "by email",
|
|
11973
|
-
sms: "by text"
|
|
11974
|
-
};
|
|
11971
|
+
var CADENCE_WORDS2 = SUBSCRIPTION_CADENCE_LABEL;
|
|
11972
|
+
var CHANNEL_WORDS3 = SUBSCRIPTION_CHANNEL_LABEL;
|
|
11975
11973
|
function NotifyRuleEditor({ tableId, seed, className }) {
|
|
11976
11974
|
const client = useRecordsClient32();
|
|
11977
11975
|
const host = useRecordsUi();
|
|
@@ -13248,12 +13246,7 @@ function bookingSuggestion(tableName2) {
|
|
|
13248
13246
|
return `Let clients book a 30-minute ${subject} slot on Tuesday and Thursday afternoons.`;
|
|
13249
13247
|
}
|
|
13250
13248
|
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.";
|
|
13251
|
-
var STATE_WORDS =
|
|
13252
|
-
draft: "Not open yet \u2014 nobody can book until you open it.",
|
|
13253
|
-
open: "Open. Anyone with the link can book a time.",
|
|
13254
|
-
closed: "Closed. The link still works and says you are not taking bookings.",
|
|
13255
|
-
full: "Every time you offered is taken."
|
|
13256
|
-
};
|
|
13249
|
+
var STATE_WORDS = BOOKING_PAGE_STATE_LABEL;
|
|
13257
13250
|
function BookingSlots({ tableId, className }) {
|
|
13258
13251
|
const client = useRecordsClient36();
|
|
13259
13252
|
const host = useRecordsUi();
|
|
@@ -13277,10 +13270,21 @@ function BookingSlots({ tableId, className }) {
|
|
|
13277
13270
|
void load();
|
|
13278
13271
|
}, [load]);
|
|
13279
13272
|
const subjectIds = useMemo30(
|
|
13280
|
-
() => Array.from(
|
|
13281
|
-
|
|
13273
|
+
() => Array.from(
|
|
13274
|
+
/* @__PURE__ */ new Set([
|
|
13275
|
+
...(pages ?? []).map((p) => p.table_id),
|
|
13276
|
+
// THE EMPTY STATE ASKS THE SAME QUESTION. There is no page to read a
|
|
13277
|
+
// table off yet, and the empty state's two buttons need the answer
|
|
13278
|
+
// about the table this rail is standing in — otherwise the rail
|
|
13279
|
+
// offers a viewer both ways into an act the door will refuse.
|
|
13280
|
+
...tableId ? [tableId] : []
|
|
13281
|
+
])
|
|
13282
|
+
),
|
|
13283
|
+
[pages, tableId]
|
|
13282
13284
|
);
|
|
13283
13285
|
const levels = useMyLevels2(subjectIds);
|
|
13286
|
+
const levelsKnown = !levels.loading && Boolean(levels.data);
|
|
13287
|
+
const mayBuildHere = levelsKnown && Boolean(tableId) && levels.data?.[tableId] === "admin";
|
|
13284
13288
|
const toggle = useCallback30(
|
|
13285
13289
|
async (page) => {
|
|
13286
13290
|
setBusy(page.form_id);
|
|
@@ -13329,7 +13333,8 @@ function BookingSlots({ tableId, className }) {
|
|
|
13329
13333
|
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ jsx50(
|
|
13330
13334
|
BuildOrAsk,
|
|
13331
13335
|
{
|
|
13332
|
-
mayBuild:
|
|
13336
|
+
mayBuild: mayBuildHere,
|
|
13337
|
+
whyNot: mayBuildHere ? null : levelsKnown ? NO_ADMIN2 : null,
|
|
13333
13338
|
onBuild: () => setBuilding(true),
|
|
13334
13339
|
...host.onAskForOne ? {
|
|
13335
13340
|
onAsk: () => host.onAskForOne?.({
|
|
@@ -13437,6 +13442,8 @@ import { Button as Button44, Input as Input4, Skeleton as Skeleton29, Textarea a
|
|
|
13437
13442
|
// src/CaptureRun.tsx
|
|
13438
13443
|
import { useCallback as useCallback31, useEffect as useEffect35, useMemo as useMemo31, useRef as useRef13, useState as useState47 } from "react";
|
|
13439
13444
|
import {
|
|
13445
|
+
coerceTypedAnswer as coerceTypedAnswer2,
|
|
13446
|
+
coercionLabel,
|
|
13440
13447
|
openCaptureQueue
|
|
13441
13448
|
} from "@ai-matrx/records";
|
|
13442
13449
|
import { useRecordsClient as useRecordsClient37 } from "@ai-matrx/records/react";
|
|
@@ -13742,7 +13749,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
13742
13749
|
value: String(answers[q.field] ?? ""),
|
|
13743
13750
|
onChange: (e) => {
|
|
13744
13751
|
const raw = e.target.value;
|
|
13745
|
-
|
|
13752
|
+
const answered2 = field ? coerceTypedAnswer2(field, raw, { label: q.ask ?? coercionLabel(field) }) : { value: raw };
|
|
13753
|
+
setAnswers((held) => ({
|
|
13754
|
+
...held,
|
|
13755
|
+
[q.field]: raw === "" ? "" : "refusal" in answered2 ? raw : answered2.value
|
|
13756
|
+
}));
|
|
13746
13757
|
setMissing(null);
|
|
13747
13758
|
}
|
|
13748
13759
|
}
|
|
@@ -15016,8 +15027,12 @@ function TablePage({
|
|
|
15016
15027
|
] });
|
|
15017
15028
|
}
|
|
15018
15029
|
export {
|
|
15030
|
+
ABSENCE_WORD_LABEL,
|
|
15031
|
+
ABSENCE_WORD_VALUES,
|
|
15019
15032
|
ACTION_KINDS,
|
|
15020
15033
|
ActionInbox,
|
|
15034
|
+
BOOKING_PAGE_STATE_LABEL,
|
|
15035
|
+
BOOKING_PAGE_STATE_VALUES,
|
|
15021
15036
|
BookingBuilder,
|
|
15022
15037
|
BookingSlots,
|
|
15023
15038
|
BuildOrAsk,
|
|
@@ -15025,7 +15040,10 @@ export {
|
|
|
15025
15040
|
CHART_KINDS,
|
|
15026
15041
|
CHART_KIND_LABEL,
|
|
15027
15042
|
CHART_NEEDS,
|
|
15043
|
+
CHECKLIST_REQUIREMENT_KINDS,
|
|
15044
|
+
CHECKLIST_REQUIREMENT_LABEL,
|
|
15028
15045
|
CONDITION_OPS,
|
|
15046
|
+
CONTEXT_POLICY_LABEL,
|
|
15029
15047
|
CaptureRun,
|
|
15030
15048
|
CaptureSheet,
|
|
15031
15049
|
ChartBlock,
|
|
@@ -15041,6 +15059,7 @@ export {
|
|
|
15041
15059
|
CustomFieldsSection,
|
|
15042
15060
|
DEFAULT_FIELDS,
|
|
15043
15061
|
DEFAULT_VIEW_NAME,
|
|
15062
|
+
DUE_STATE_LABEL,
|
|
15044
15063
|
DashboardCanvas,
|
|
15045
15064
|
DigestScheduler,
|
|
15046
15065
|
DocRender,
|
|
@@ -15050,8 +15069,14 @@ export {
|
|
|
15050
15069
|
EnrichBadge,
|
|
15051
15070
|
EnrichPanel,
|
|
15052
15071
|
ExportMenu,
|
|
15072
|
+
FIELD_RULE_KIND_LABEL,
|
|
15073
|
+
FIELD_RULE_KIND_VALUES,
|
|
15074
|
+
FIELD_SENSITIVITY_LABEL,
|
|
15053
15075
|
FIELD_TYPE_CHOICES,
|
|
15054
15076
|
FIELD_TYPE_GROUPS,
|
|
15077
|
+
FORMULA_OP_JOINS,
|
|
15078
|
+
FORMULA_OP_LABEL,
|
|
15079
|
+
FORMULA_OP_VALUES,
|
|
15055
15080
|
FORM_FLOWS,
|
|
15056
15081
|
FROZEN_COLUMN_WIDTH,
|
|
15057
15082
|
FieldControl,
|
|
@@ -15099,6 +15124,8 @@ export {
|
|
|
15099
15124
|
PAGE_VIEW_LABEL,
|
|
15100
15125
|
PARITY_LABEL,
|
|
15101
15126
|
PARITY_MADE_OF,
|
|
15127
|
+
PROPOSED_CHANGE_ACT_LABEL,
|
|
15128
|
+
PROPOSED_CHANGE_ACT_VALUES,
|
|
15102
15129
|
Peek,
|
|
15103
15130
|
PersonPicker,
|
|
15104
15131
|
PipelineBoard,
|
|
@@ -15109,6 +15136,8 @@ export {
|
|
|
15109
15136
|
ProposalRow,
|
|
15110
15137
|
ProvenanceBadge,
|
|
15111
15138
|
PublicViewPage,
|
|
15139
|
+
ROLLUP_AGG_LABEL,
|
|
15140
|
+
ROLLUP_AGG_VALUES,
|
|
15112
15141
|
RecordChat,
|
|
15113
15142
|
RecordChip,
|
|
15114
15143
|
RecordForm,
|
|
@@ -15124,8 +15153,13 @@ export {
|
|
|
15124
15153
|
SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS,
|
|
15125
15154
|
SERIES_COLORS,
|
|
15126
15155
|
SOMEBODY,
|
|
15156
|
+
STAGE_RULE_ON_FAIL_LABEL,
|
|
15127
15157
|
STORE_ANSWERS_THESE,
|
|
15128
15158
|
STORE_DECIDES_REASON,
|
|
15159
|
+
SUBSCRIPTION_CADENCES,
|
|
15160
|
+
SUBSCRIPTION_CADENCE_LABEL,
|
|
15161
|
+
SUBSCRIPTION_CHANNEL_LABEL,
|
|
15162
|
+
SUBSCRIPTION_CHANNEL_VALUES,
|
|
15129
15163
|
ShareControl,
|
|
15130
15164
|
SignBlock,
|
|
15131
15165
|
StageRulesSection,
|
|
@@ -15143,6 +15177,9 @@ export {
|
|
|
15143
15177
|
ViewBar,
|
|
15144
15178
|
ViewSwitcher,
|
|
15145
15179
|
WITHHELD_RECORD_LABEL,
|
|
15180
|
+
WORK_DUE_STATES,
|
|
15181
|
+
WORK_INBOX_KINDS,
|
|
15182
|
+
WORK_INBOX_KIND_LABEL,
|
|
15146
15183
|
WhoChangedSource,
|
|
15147
15184
|
actorBadge,
|
|
15148
15185
|
actorWords,
|