@ai-matrx/records-ui 0.51.0 → 0.52.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 +45 -0
- package/dist/index.cjs +1366 -1017
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +1334 -985
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,7 @@ __export(src_exports, {
|
|
|
56
56
|
DEFAULT_FIELDS: () => DEFAULT_FIELDS,
|
|
57
57
|
DEFAULT_VIEW_NAME: () => DEFAULT_VIEW_NAME,
|
|
58
58
|
DashboardCanvas: () => DashboardCanvas,
|
|
59
|
+
DigestScheduler: () => DigestScheduler,
|
|
59
60
|
DocRender: () => DocRender,
|
|
60
61
|
DocTemplate: () => DocTemplate,
|
|
61
62
|
EMPTY_PRESENTATION: () => EMPTY_PRESENTATION,
|
|
@@ -9537,28 +9538,325 @@ function Invite({ card, onInvited }) {
|
|
|
9537
9538
|
] });
|
|
9538
9539
|
}
|
|
9539
9540
|
|
|
9540
|
-
// src/
|
|
9541
|
+
// src/DigestScheduler.tsx
|
|
9541
9542
|
var import_react67 = require("react");
|
|
9542
9543
|
var import_react68 = require("@ai-matrx/records/react");
|
|
9543
9544
|
var import_design_system33 = require("@ai-matrx/design-system");
|
|
9544
9545
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
9546
|
+
var WEEKDAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
|
9547
|
+
var CADENCE_WORDS = {
|
|
9548
|
+
instant: "the moment something arrives",
|
|
9549
|
+
hourly: "every hour",
|
|
9550
|
+
daily: "every day",
|
|
9551
|
+
weekly: "every week"
|
|
9552
|
+
};
|
|
9553
|
+
var CHANNEL_WORDS = {
|
|
9554
|
+
in_app: "in the app",
|
|
9555
|
+
email: "by email \u2014 only if an address is on their account",
|
|
9556
|
+
sms: "by text \u2014 only if a number is on their account"
|
|
9557
|
+
};
|
|
9558
|
+
function DigestScheduler({
|
|
9559
|
+
tableId,
|
|
9560
|
+
savedViewId,
|
|
9561
|
+
subjectName,
|
|
9562
|
+
filters,
|
|
9563
|
+
onScheduled,
|
|
9564
|
+
onClose,
|
|
9565
|
+
className
|
|
9566
|
+
}) {
|
|
9567
|
+
const client = (0, import_react68.useRecordsClient)();
|
|
9568
|
+
const host = useRecordsUi();
|
|
9569
|
+
const [views, setViews] = (0, import_react67.useState)(null);
|
|
9570
|
+
const [cadences, setCadences] = (0, import_react67.useState)([]);
|
|
9571
|
+
const [members, setMembers] = (0, import_react67.useState)(null);
|
|
9572
|
+
const [error, setError] = (0, import_react67.useState)(null);
|
|
9573
|
+
const [viewId, setViewId] = (0, import_react67.useState)(savedViewId ?? "");
|
|
9574
|
+
const [name, setName] = (0, import_react67.useState)(subjectName?.trim() ? `${subjectName.trim()} summary` : "");
|
|
9575
|
+
const [cadence, setCadence] = (0, import_react67.useState)("weekly");
|
|
9576
|
+
const [weekday, setWeekday] = (0, import_react67.useState)("monday");
|
|
9577
|
+
const [time, setTime] = (0, import_react67.useState)("08:00");
|
|
9578
|
+
const [channel, setChannel] = (0, import_react67.useState)("in_app");
|
|
9579
|
+
const [quiet, setQuiet] = (0, import_react67.useState)(false);
|
|
9580
|
+
const [quietFrom, setQuietFrom] = (0, import_react67.useState)("22:00");
|
|
9581
|
+
const [quietTo, setQuietTo] = (0, import_react67.useState)("07:00");
|
|
9582
|
+
const [recipients, setRecipients] = (0, import_react67.useState)([]);
|
|
9583
|
+
const [saving, setSaving] = (0, import_react67.useState)(false);
|
|
9584
|
+
const [outcomes, setOutcomes] = (0, import_react67.useState)(null);
|
|
9585
|
+
const [preview, setPreview] = (0, import_react67.useState)(null);
|
|
9586
|
+
const [previewing, setPreviewing] = (0, import_react67.useState)(false);
|
|
9587
|
+
const load = (0, import_react67.useCallback)(async () => {
|
|
9588
|
+
const [saved, offered] = await Promise.all([
|
|
9589
|
+
// The store's own door onto `platform.saved_view`, narrowed in SQL to
|
|
9590
|
+
// Tables this person can already open — never a grant on the table behind it.
|
|
9591
|
+
client.views({ table_id: tableId }),
|
|
9592
|
+
// The cadences are ASKED, never typed into this file, so a picker can
|
|
9593
|
+
// never offer a cadence the digest runner does not honour.
|
|
9594
|
+
client.subscriptionCadences()
|
|
9595
|
+
]);
|
|
9596
|
+
if (!saved.ok) setError(saved.error);
|
|
9597
|
+
else setViews(saved.data);
|
|
9598
|
+
if (offered.ok) setCadences(offered.data.filter((c) => c !== "instant"));
|
|
9599
|
+
if (host.members) {
|
|
9600
|
+
const who = await host.members();
|
|
9601
|
+
setMembers(who.map((m) => ({ userId: m.userId, name: m.name ?? m.email ?? m.userId })));
|
|
9602
|
+
} else {
|
|
9603
|
+
setMembers([]);
|
|
9604
|
+
}
|
|
9605
|
+
}, [client, tableId, host]);
|
|
9606
|
+
(0, import_react67.useEffect)(() => {
|
|
9607
|
+
void load();
|
|
9608
|
+
}, [load]);
|
|
9609
|
+
const schedule = (0, import_react67.useMemo)(() => {
|
|
9610
|
+
if (cadence === "weekly") return `${weekday} ${time}`;
|
|
9611
|
+
if (cadence === "daily") return time;
|
|
9612
|
+
return null;
|
|
9613
|
+
}, [cadence, weekday, time]);
|
|
9614
|
+
const quietHours = (0, import_react67.useMemo)(
|
|
9615
|
+
() => quiet ? { start: quietFrom, end: quietTo } : null,
|
|
9616
|
+
[quiet, quietFrom, quietTo]
|
|
9617
|
+
);
|
|
9618
|
+
async function scheduleIt() {
|
|
9619
|
+
setSaving(true);
|
|
9620
|
+
setError(null);
|
|
9621
|
+
setOutcomes(null);
|
|
9622
|
+
let subject = viewId;
|
|
9623
|
+
if (subject === "" || subject === "new") {
|
|
9624
|
+
const declared = await client.viewDeclare({
|
|
9625
|
+
table_id: tableId,
|
|
9626
|
+
spec: {
|
|
9627
|
+
name: subjectName?.trim() ? subjectName.trim() : name.trim() || "Weekly summary",
|
|
9628
|
+
filters: filters ?? {}
|
|
9629
|
+
}
|
|
9630
|
+
});
|
|
9631
|
+
if (!declared.ok) {
|
|
9632
|
+
setSaving(false);
|
|
9633
|
+
setError(declared.error);
|
|
9634
|
+
return;
|
|
9635
|
+
}
|
|
9636
|
+
subject = declared.data;
|
|
9637
|
+
setViewId(declared.data);
|
|
9638
|
+
}
|
|
9639
|
+
const who = recipients.length > 0 ? recipients : [""];
|
|
9640
|
+
const done = [];
|
|
9641
|
+
for (const userId of who) {
|
|
9642
|
+
const label = members?.find((m) => m.userId === userId)?.name ?? (userId === "" ? "you" : userId);
|
|
9643
|
+
const written = await client.subscriptionDeclare({
|
|
9644
|
+
table_id: tableId,
|
|
9645
|
+
spec: {
|
|
9646
|
+
name: name.trim() === "" ? "Weekly summary" : name.trim(),
|
|
9647
|
+
saved_view_id: subject,
|
|
9648
|
+
cadence,
|
|
9649
|
+
schedule,
|
|
9650
|
+
channel,
|
|
9651
|
+
quiet_hours: quietHours,
|
|
9652
|
+
...userId === "" ? {} : { recipient_user_id: userId }
|
|
9653
|
+
}
|
|
9654
|
+
});
|
|
9655
|
+
if (written.ok) done.push({ userId, who: label, ruleId: written.data });
|
|
9656
|
+
else done.push({ userId, who: label, refused: written.error });
|
|
9657
|
+
}
|
|
9658
|
+
setSaving(false);
|
|
9659
|
+
setOutcomes(done);
|
|
9660
|
+
if (done.some((d) => d.ruleId)) onScheduled?.();
|
|
9661
|
+
}
|
|
9662
|
+
async function showOne(ruleId) {
|
|
9663
|
+
setPreviewing(true);
|
|
9664
|
+
const answered = await client.subscriptionPreview({ rule_id: ruleId });
|
|
9665
|
+
setPreviewing(false);
|
|
9666
|
+
if (!answered.ok) {
|
|
9667
|
+
setError(answered.error);
|
|
9668
|
+
return;
|
|
9669
|
+
}
|
|
9670
|
+
setPreview(answered.data);
|
|
9671
|
+
}
|
|
9672
|
+
if (views === null && !error) return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Skeleton, { className: (0, import_design_system33.cn)("h-56 w-full", className) });
|
|
9673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("flex flex-col gap-3", className), children: [
|
|
9674
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
9675
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-sm font-medium", children: "Send this on a schedule" }),
|
|
9676
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1" }),
|
|
9677
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Button, { size: "sm", disabled: saving, onClick: () => void scheduleIt(), children: saving ? "Scheduling\u2026" : "Schedule it" }),
|
|
9678
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Button, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
|
|
9679
|
+
] }),
|
|
9680
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(RefusalNotice, { error }) : null,
|
|
9681
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9682
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "What to call it" }),
|
|
9683
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9684
|
+
import_design_system33.BasicInput,
|
|
9685
|
+
{
|
|
9686
|
+
value: name,
|
|
9687
|
+
placeholder: "Monday donor summary",
|
|
9688
|
+
onChange: (e) => setName(e.target.value)
|
|
9689
|
+
}
|
|
9690
|
+
)
|
|
9691
|
+
] }),
|
|
9692
|
+
savedViewId ? null : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9693
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "What it summarises" }),
|
|
9694
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
9695
|
+
"select",
|
|
9696
|
+
{
|
|
9697
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9698
|
+
value: viewId,
|
|
9699
|
+
onChange: (e) => setViewId(e.target.value),
|
|
9700
|
+
children: [
|
|
9701
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: "new", children: subjectName?.trim() ? `What I am looking at now (${subjectName.trim()})` : "What I am looking at now" }),
|
|
9702
|
+
(views ?? []).map((v) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: v.view_id, children: v.name }, v.view_id))
|
|
9703
|
+
]
|
|
9704
|
+
}
|
|
9705
|
+
),
|
|
9706
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: "The first choice saves what is on screen as a view, so the summary and the screen stay the same thing." })
|
|
9707
|
+
] }),
|
|
9708
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
9709
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9710
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "How often" }),
|
|
9711
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9712
|
+
"select",
|
|
9713
|
+
{
|
|
9714
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9715
|
+
value: cadence,
|
|
9716
|
+
onChange: (e) => setCadence(e.target.value),
|
|
9717
|
+
children: (cadences.length > 0 ? cadences : ["hourly", "daily", "weekly"]).map((c) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: c, children: CADENCE_WORDS[c] ?? c }, c))
|
|
9718
|
+
}
|
|
9719
|
+
)
|
|
9720
|
+
] }),
|
|
9721
|
+
cadence === "weekly" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9722
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "Which day" }),
|
|
9723
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9724
|
+
"select",
|
|
9725
|
+
{
|
|
9726
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9727
|
+
value: weekday,
|
|
9728
|
+
onChange: (e) => setWeekday(e.target.value),
|
|
9729
|
+
children: WEEKDAYS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: d, children: d[0].toUpperCase() + d.slice(1) }, d))
|
|
9730
|
+
}
|
|
9731
|
+
)
|
|
9732
|
+
] }) : null,
|
|
9733
|
+
cadence === "weekly" || cadence === "daily" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9734
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "At" }),
|
|
9735
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.BasicInput, { type: "time", value: time, onChange: (e) => setTime(e.target.value) })
|
|
9736
|
+
] }) : null,
|
|
9737
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9738
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "Where it arrives" }),
|
|
9739
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9740
|
+
"select",
|
|
9741
|
+
{
|
|
9742
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9743
|
+
value: channel,
|
|
9744
|
+
onChange: (e) => setChannel(e.target.value),
|
|
9745
|
+
children: Object.entries(CHANNEL_WORDS).map(([key, words]) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("option", { value: key, children: words }, key))
|
|
9746
|
+
}
|
|
9747
|
+
)
|
|
9748
|
+
] })
|
|
9749
|
+
] }),
|
|
9750
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
9751
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "Who to send it to" }),
|
|
9752
|
+
members === null ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Skeleton, { className: "h-8 w-full" }) : members.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-xs text-muted-foreground", children: "Nobody else is offered here, so this will be addressed to you. Who the people are is the platform's answer and this screen reaches it through its host's `members` port, which is not bound here." }) : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
9753
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: members.map((m) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
9754
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9755
|
+
import_design_system33.Checkbox,
|
|
9756
|
+
{
|
|
9757
|
+
checked: recipients.includes(m.userId),
|
|
9758
|
+
onCheckedChange: (on) => setRecipients(
|
|
9759
|
+
(prev) => on ? [...prev, m.userId] : prev.filter((u) => u !== m.userId)
|
|
9760
|
+
)
|
|
9761
|
+
}
|
|
9762
|
+
),
|
|
9763
|
+
m.name
|
|
9764
|
+
] }, m.userId)) }),
|
|
9765
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "text-xs text-muted-foreground", children: recipients.length === 0 ? "Nobody picked \u2014 it will be addressed to you." : `${recipients.length} ${recipients.length === 1 ? "person" : "people"}, and each one's summary holds only what that person may see.` })
|
|
9766
|
+
] })
|
|
9767
|
+
] }),
|
|
9768
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
9769
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Checkbox, { checked: quiet, onCheckedChange: (on) => setQuiet(Boolean(on)) }),
|
|
9770
|
+
"Not between certain hours"
|
|
9771
|
+
] }),
|
|
9772
|
+
quiet ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
9773
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9774
|
+
import_design_system33.BasicInput,
|
|
9775
|
+
{
|
|
9776
|
+
type: "time",
|
|
9777
|
+
className: "h-8 w-28",
|
|
9778
|
+
value: quietFrom,
|
|
9779
|
+
onChange: (e) => setQuietFrom(e.target.value)
|
|
9780
|
+
}
|
|
9781
|
+
),
|
|
9782
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: "and" }),
|
|
9783
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9784
|
+
import_design_system33.BasicInput,
|
|
9785
|
+
{
|
|
9786
|
+
type: "time",
|
|
9787
|
+
className: "h-8 w-28",
|
|
9788
|
+
value: quietTo,
|
|
9789
|
+
onChange: (e) => setQuietTo(e.target.value)
|
|
9790
|
+
}
|
|
9791
|
+
),
|
|
9792
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: "A send inside these hours waits until they end \u2014 it is never dropped." })
|
|
9793
|
+
] }) : null,
|
|
9794
|
+
outcomes ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
9795
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Separator, {}),
|
|
9796
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex flex-col gap-1.5", children: outcomes.map((o) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "text-xs", children: o.ruleId ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
|
|
9797
|
+
o.who,
|
|
9798
|
+
" will get it ",
|
|
9799
|
+
CADENCE_WORDS[cadence] ?? cadence,
|
|
9800
|
+
schedule ? `, ${schedule}` : "",
|
|
9801
|
+
".",
|
|
9802
|
+
" ",
|
|
9803
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
9804
|
+
import_design_system33.Button,
|
|
9805
|
+
{
|
|
9806
|
+
size: "sm",
|
|
9807
|
+
variant: "ghost",
|
|
9808
|
+
disabled: previewing,
|
|
9809
|
+
onClick: () => void showOne(o.ruleId),
|
|
9810
|
+
children: "Send me one now"
|
|
9811
|
+
}
|
|
9812
|
+
)
|
|
9813
|
+
] }) : o.refused ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(RefusalNotice, { error: o.refused }) : null }, o.userId || "me")) })
|
|
9814
|
+
] }) : null,
|
|
9815
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
9816
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "font-medium", children: preview.subject }),
|
|
9817
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "mt-1 text-muted-foreground", children: preview.body }),
|
|
9818
|
+
preview.incomplete ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "mt-1 text-destructive", children: preview.incomplete }) : null,
|
|
9819
|
+
preview.entered.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { className: "mt-1", children: [
|
|
9820
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-medium", children: "Arrived:" }),
|
|
9821
|
+
" ",
|
|
9822
|
+
preview.entered.map((e) => e.name).join(", ")
|
|
9823
|
+
] }) : null,
|
|
9824
|
+
preview.changed.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { className: "mt-1", children: [
|
|
9825
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "font-medium", children: "Changed:" }),
|
|
9826
|
+
" ",
|
|
9827
|
+
preview.changed.map((e) => e.name).join(", ")
|
|
9828
|
+
] }) : null,
|
|
9829
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "mt-1.5 text-muted-foreground", children: "Nothing was sent and nothing was recorded \u2014 this is what the next one would say." }),
|
|
9830
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Button, { size: "sm", variant: "ghost", className: "mt-1", onClick: () => setPreview(null), children: "Close" })
|
|
9831
|
+
] }) : null
|
|
9832
|
+
] });
|
|
9833
|
+
}
|
|
9834
|
+
|
|
9835
|
+
// src/SubscriptionsPanel.tsx
|
|
9836
|
+
var import_react69 = require("react");
|
|
9837
|
+
var import_react70 = require("@ai-matrx/records/react");
|
|
9838
|
+
var import_design_system34 = require("@ai-matrx/design-system");
|
|
9839
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
9545
9840
|
function whenItFires(subscription) {
|
|
9546
9841
|
if (subscription.cadence === "instant") return "as it happens";
|
|
9547
9842
|
const every = subscription.cadence === "hourly" ? "an hourly summary" : subscription.cadence === "weekly" ? "a weekly summary" : "a daily summary";
|
|
9548
9843
|
return subscription.schedule ? `${every}, ${subscription.schedule}` : every;
|
|
9549
9844
|
}
|
|
9550
|
-
var
|
|
9845
|
+
var CHANNEL_WORDS2 = {
|
|
9551
9846
|
in_app: "in the app",
|
|
9552
9847
|
email: "by email \u2014 only if an address is on the account",
|
|
9553
9848
|
sms: "by text \u2014 only if a number is on the account"
|
|
9554
9849
|
};
|
|
9850
|
+
var DIGEST_SUGGESTION = "Email me a summary of this every Monday at 8 in the morning.";
|
|
9555
9851
|
function SubscriptionsPanel({ tableId, className }) {
|
|
9556
|
-
const client = (0,
|
|
9557
|
-
const [rows, setRows] = (0,
|
|
9558
|
-
const [error, setError] = (0,
|
|
9559
|
-
const [busy, setBusy] = (0,
|
|
9560
|
-
const [preview, setPreview] = (0,
|
|
9561
|
-
const
|
|
9852
|
+
const client = (0, import_react70.useRecordsClient)();
|
|
9853
|
+
const [rows, setRows] = (0, import_react69.useState)(null);
|
|
9854
|
+
const [error, setError] = (0, import_react69.useState)(null);
|
|
9855
|
+
const [busy, setBusy] = (0, import_react69.useState)(null);
|
|
9856
|
+
const [preview, setPreview] = (0, import_react69.useState)(null);
|
|
9857
|
+
const [scheduling, setScheduling] = (0, import_react69.useState)(false);
|
|
9858
|
+
const host = useRecordsUi();
|
|
9859
|
+
const load = (0, import_react69.useCallback)(async () => {
|
|
9562
9860
|
const answered = await client.subscriptions({ table_id: tableId });
|
|
9563
9861
|
if (!answered.ok) {
|
|
9564
9862
|
setError(answered.error);
|
|
@@ -9568,10 +9866,10 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9568
9866
|
setError(null);
|
|
9569
9867
|
setRows(answered.data);
|
|
9570
9868
|
}, [client, tableId]);
|
|
9571
|
-
(0,
|
|
9869
|
+
(0, import_react69.useEffect)(() => {
|
|
9572
9870
|
void load();
|
|
9573
9871
|
}, [load]);
|
|
9574
|
-
const flip = (0,
|
|
9872
|
+
const flip = (0, import_react69.useCallback)(
|
|
9575
9873
|
async (subscription, on) => {
|
|
9576
9874
|
setBusy(subscription.rule_id);
|
|
9577
9875
|
const answered = await client.subscriptionMute({
|
|
@@ -9587,7 +9885,7 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9587
9885
|
},
|
|
9588
9886
|
[client, load]
|
|
9589
9887
|
);
|
|
9590
|
-
const showOne = (0,
|
|
9888
|
+
const showOne = (0, import_react69.useCallback)(
|
|
9591
9889
|
async (subscription) => {
|
|
9592
9890
|
setBusy(subscription.rule_id);
|
|
9593
9891
|
const answered = await client.subscriptionPreview({ rule_id: subscription.rule_id });
|
|
@@ -9601,53 +9899,85 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9601
9899
|
},
|
|
9602
9900
|
[client]
|
|
9603
9901
|
);
|
|
9604
|
-
if (rows === null) return /* @__PURE__ */ (0,
|
|
9605
|
-
return /* @__PURE__ */ (0,
|
|
9606
|
-
/* @__PURE__ */ (0,
|
|
9607
|
-
/* @__PURE__ */ (0,
|
|
9608
|
-
/* @__PURE__ */ (0,
|
|
9902
|
+
if (rows === null) return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_design_system34.Skeleton, { className: (0, import_design_system34.cn)("h-32 w-full", className) });
|
|
9903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("section", { className: (0, import_design_system34.cn)("flex flex-col gap-3", className), children: [
|
|
9904
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
9905
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h3", { className: "text-sm font-medium", children: "Notifications" }),
|
|
9906
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-xs text-muted-foreground", children: rows.length === 0 ? "none" : `${rows.filter((r) => !r.muted).length} on` }),
|
|
9907
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex-1" }),
|
|
9908
|
+
rows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
9909
|
+
import_design_system34.Button,
|
|
9910
|
+
{
|
|
9911
|
+
size: "sm",
|
|
9912
|
+
variant: scheduling ? "secondary" : "ghost",
|
|
9913
|
+
onClick: () => setScheduling((s) => !s),
|
|
9914
|
+
children: scheduling ? "Done" : "Schedule a summary"
|
|
9915
|
+
}
|
|
9916
|
+
) : null
|
|
9609
9917
|
] }),
|
|
9610
|
-
error ? /* @__PURE__ */ (0,
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9918
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(RefusalNotice, { error }) : null,
|
|
9919
|
+
scheduling ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
9920
|
+
DigestScheduler,
|
|
9921
|
+
{
|
|
9922
|
+
tableId,
|
|
9923
|
+
onScheduled: () => {
|
|
9924
|
+
void load();
|
|
9925
|
+
},
|
|
9926
|
+
onClose: () => setScheduling(false)
|
|
9927
|
+
}
|
|
9928
|
+
) : null,
|
|
9929
|
+
rows.length === 0 && !scheduling ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
9930
|
+
BuildOrAsk,
|
|
9931
|
+
{
|
|
9932
|
+
mayBuild: true,
|
|
9933
|
+
onBuild: () => setScheduling(true),
|
|
9934
|
+
...host.onAskForOne ? {
|
|
9935
|
+
onAsk: () => host.onAskForOne?.({ kind: "digest", tableId, suggestion: DIGEST_SUGGESTION })
|
|
9936
|
+
} : {},
|
|
9937
|
+
suggestion: DIGEST_SUGGESTION,
|
|
9938
|
+
buildLabel: "Schedule a summary",
|
|
9939
|
+
children: "Nothing is telling you about this table. A summary arrives on a schedule you set and names what arrived, what left and what changed since the last one."
|
|
9940
|
+
}
|
|
9941
|
+
) : null,
|
|
9942
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { className: "flex flex-col gap-2", children: rows.map((subscription) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("li", { className: "rounded-md border p-2.5", children: [
|
|
9943
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-start gap-2", children: [
|
|
9944
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
9945
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "truncate text-sm font-medium", children: subscription.name }),
|
|
9946
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
9947
|
+
CHANNEL_WORDS2[subscription.channel] ?? `on the ${subscription.channel} channel`,
|
|
9618
9948
|
" \xB7 ",
|
|
9619
9949
|
whenItFires(subscription)
|
|
9620
9950
|
] })
|
|
9621
9951
|
] }),
|
|
9622
|
-
subscription.i_may_mute ? /* @__PURE__ */ (0,
|
|
9623
|
-
|
|
9952
|
+
subscription.i_may_mute ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
9953
|
+
import_design_system34.Switch,
|
|
9624
9954
|
{
|
|
9625
9955
|
checked: !subscription.muted,
|
|
9626
9956
|
disabled: busy === subscription.rule_id,
|
|
9627
9957
|
"aria-label": `Tell me about ${subscription.name}`,
|
|
9628
9958
|
onCheckedChange: (on) => void flip(subscription, on)
|
|
9629
9959
|
}
|
|
9630
|
-
) : /* @__PURE__ */ (0,
|
|
9960
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_design_system34.Badge, { variant: "secondary", children: "someone else's" })
|
|
9631
9961
|
] }),
|
|
9632
|
-
/* @__PURE__ */ (0,
|
|
9633
|
-
/* @__PURE__ */ (0,
|
|
9634
|
-
subscription.next_digest_at ? /* @__PURE__ */ (0,
|
|
9962
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-1.5 text-xs text-muted-foreground", children: subscription.muted ? "Off \u2014 it stays here and tells nobody until you switch it back on." : subscription.mine ? "On, and addressed to you." : "On, and addressed to somebody else in this organization." }),
|
|
9963
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-1.5 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
9964
|
+
subscription.next_digest_at ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
|
|
9635
9965
|
"Next summary ",
|
|
9636
9966
|
new Date(subscription.next_digest_at).toLocaleString()
|
|
9637
|
-
] }) : subscription.cadence === "instant" ? null : subscription.muted ? /* @__PURE__ */ (0,
|
|
9638
|
-
subscription.last_sent_at ? /* @__PURE__ */ (0,
|
|
9967
|
+
] }) : subscription.cadence === "instant" ? null : subscription.muted ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: "No next summary while it is off." }) : null,
|
|
9968
|
+
subscription.last_sent_at ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
|
|
9639
9969
|
"Last told you ",
|
|
9640
9970
|
new Date(subscription.last_sent_at).toLocaleString()
|
|
9641
|
-
] }) : /* @__PURE__ */ (0,
|
|
9642
|
-
subscription.quiet_hours ? /* @__PURE__ */ (0,
|
|
9971
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: "It has not told you anything yet." }),
|
|
9972
|
+
subscription.quiet_hours ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { children: [
|
|
9643
9973
|
"Not between ",
|
|
9644
9974
|
subscription.quiet_hours.start,
|
|
9645
9975
|
" and ",
|
|
9646
9976
|
subscription.quiet_hours.end,
|
|
9647
9977
|
" \u2014 a send inside those hours waits until they end."
|
|
9648
9978
|
] }) : null,
|
|
9649
|
-
subscription.cadence === "instant" ? null : /* @__PURE__ */ (0,
|
|
9650
|
-
|
|
9979
|
+
subscription.cadence === "instant" ? null : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
9980
|
+
import_design_system34.Button,
|
|
9651
9981
|
{
|
|
9652
9982
|
size: "sm",
|
|
9653
9983
|
variant: "ghost",
|
|
@@ -9657,58 +9987,58 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9657
9987
|
}
|
|
9658
9988
|
)
|
|
9659
9989
|
] }),
|
|
9660
|
-
preview && preview.rule_id === subscription.rule_id ? /* @__PURE__ */ (0,
|
|
9661
|
-
/* @__PURE__ */ (0,
|
|
9662
|
-
/* @__PURE__ */ (0,
|
|
9990
|
+
preview && preview.rule_id === subscription.rule_id ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-2 rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
9991
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "font-medium", children: preview.subject }),
|
|
9992
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-1 text-muted-foreground", children: preview.body }),
|
|
9663
9993
|
preview.incomplete ? (
|
|
9664
9994
|
// Absent or honest: a subscription that cannot produce a summary
|
|
9665
9995
|
// says which piece is missing instead of showing an empty one.
|
|
9666
|
-
/* @__PURE__ */ (0,
|
|
9996
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-1 text-destructive", children: preview.incomplete })
|
|
9667
9997
|
) : null,
|
|
9668
|
-
preview.entered.length > 0 ? /* @__PURE__ */ (0,
|
|
9669
|
-
/* @__PURE__ */ (0,
|
|
9998
|
+
preview.entered.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mt-1", children: [
|
|
9999
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: "Arrived:" }),
|
|
9670
10000
|
" ",
|
|
9671
10001
|
preview.entered.map((e) => e.name).join(", ")
|
|
9672
10002
|
] }) : null,
|
|
9673
|
-
preview.left.length > 0 ? /* @__PURE__ */ (0,
|
|
9674
|
-
/* @__PURE__ */ (0,
|
|
10003
|
+
preview.left.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mt-1", children: [
|
|
10004
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: "Left:" }),
|
|
9675
10005
|
" ",
|
|
9676
10006
|
preview.left.map((e) => e.name).join(", ")
|
|
9677
10007
|
] }) : null,
|
|
9678
|
-
preview.changed.length > 0 ? /* @__PURE__ */ (0,
|
|
9679
|
-
/* @__PURE__ */ (0,
|
|
10008
|
+
preview.changed.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "mt-1", children: [
|
|
10009
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: "Changed:" }),
|
|
9680
10010
|
" ",
|
|
9681
10011
|
preview.changed.map((e) => e.name).join(", ")
|
|
9682
10012
|
] }) : null,
|
|
9683
|
-
/* @__PURE__ */ (0,
|
|
9684
|
-
/* @__PURE__ */ (0,
|
|
10013
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-1.5 text-muted-foreground", children: "Nothing was sent and nothing was recorded \u2014 this is what the next one would say." }),
|
|
10014
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_design_system34.Button, { size: "sm", variant: "ghost", className: "mt-1", onClick: () => setPreview(null), children: "Close" })
|
|
9685
10015
|
] }) : null
|
|
9686
10016
|
] }, subscription.rule_id)) })
|
|
9687
10017
|
] });
|
|
9688
10018
|
}
|
|
9689
10019
|
|
|
9690
10020
|
// src/FormBuilder.tsx
|
|
9691
|
-
var
|
|
9692
|
-
var
|
|
10021
|
+
var import_react73 = require("react");
|
|
10022
|
+
var import_react74 = require("@ai-matrx/records/react");
|
|
9693
10023
|
var import_records6 = require("@ai-matrx/records");
|
|
9694
|
-
var
|
|
10024
|
+
var import_design_system36 = require("@ai-matrx/design-system");
|
|
9695
10025
|
|
|
9696
10026
|
// src/FormRunner.tsx
|
|
9697
|
-
var
|
|
9698
|
-
var
|
|
9699
|
-
var
|
|
9700
|
-
var
|
|
10027
|
+
var import_react71 = require("react");
|
|
10028
|
+
var import_react72 = require("@ai-matrx/records/react");
|
|
10029
|
+
var import_design_system35 = require("@ai-matrx/design-system");
|
|
10030
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
9701
10031
|
function FormRunner(props) {
|
|
9702
10032
|
if (props.fields && props.onSubmit) {
|
|
9703
|
-
return /* @__PURE__ */ (0,
|
|
10033
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FormStage, { ...props, fields: props.fields, onSubmit: props.onSubmit });
|
|
9704
10034
|
}
|
|
9705
|
-
return /* @__PURE__ */ (0,
|
|
10035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ConnectedFormRunner, { ...props });
|
|
9706
10036
|
}
|
|
9707
10037
|
function ConnectedFormRunner(props) {
|
|
9708
|
-
const client = (0,
|
|
9709
|
-
const fields = (0,
|
|
10038
|
+
const client = (0, import_react72.useOptionalRecordsClient)();
|
|
10039
|
+
const fields = (0, import_react72.useFields)(props.form.subject);
|
|
9710
10040
|
const { form, className } = props;
|
|
9711
|
-
const submit = (0,
|
|
10041
|
+
const submit = (0, import_react71.useCallback)(
|
|
9712
10042
|
async (values) => {
|
|
9713
10043
|
if (!client) {
|
|
9714
10044
|
return {
|
|
@@ -9731,7 +10061,7 @@ function ConnectedFormRunner(props) {
|
|
|
9731
10061
|
},
|
|
9732
10062
|
[client, form]
|
|
9733
10063
|
);
|
|
9734
|
-
const evaluate = (0,
|
|
10064
|
+
const evaluate = (0, import_react71.useCallback)(
|
|
9735
10065
|
async (expr, values) => {
|
|
9736
10066
|
if (!client) return null;
|
|
9737
10067
|
const answered = await client.ruleEval({ expr, values });
|
|
@@ -9740,9 +10070,9 @@ function ConnectedFormRunner(props) {
|
|
|
9740
10070
|
},
|
|
9741
10071
|
[client]
|
|
9742
10072
|
);
|
|
9743
|
-
if (fields.error) return /* @__PURE__ */ (0,
|
|
9744
|
-
if (fields.loading) return /* @__PURE__ */ (0,
|
|
9745
|
-
return /* @__PURE__ */ (0,
|
|
10073
|
+
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RefusalNotice, { error: fields.error, className });
|
|
10074
|
+
if (fields.loading) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system35.Skeleton, { className: (0, import_design_system35.cn)("h-40 w-full", className) });
|
|
10075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
9746
10076
|
FormStage,
|
|
9747
10077
|
{
|
|
9748
10078
|
...props,
|
|
@@ -9765,16 +10095,16 @@ function FormStage({
|
|
|
9765
10095
|
connected = false
|
|
9766
10096
|
}) {
|
|
9767
10097
|
const host = useRecordsUi();
|
|
9768
|
-
const [answers, setAnswers] = (0,
|
|
9769
|
-
const [at, setAt] = (0,
|
|
9770
|
-
const [error, setError] = (0,
|
|
9771
|
-
const [refusal, setRefusal] = (0,
|
|
9772
|
-
const [writing, setWriting] = (0,
|
|
9773
|
-
const [done, setDone] = (0,
|
|
9774
|
-
const [hidden, setHidden] = (0,
|
|
9775
|
-
const decoy = (0,
|
|
9776
|
-
const stage = (0,
|
|
9777
|
-
const questions = (0,
|
|
10098
|
+
const [answers, setAnswers] = (0, import_react71.useState)({});
|
|
10099
|
+
const [at, setAt] = (0, import_react71.useState)(0);
|
|
10100
|
+
const [error, setError] = (0, import_react71.useState)(null);
|
|
10101
|
+
const [refusal, setRefusal] = (0, import_react71.useState)(null);
|
|
10102
|
+
const [writing, setWriting] = (0, import_react71.useState)(false);
|
|
10103
|
+
const [done, setDone] = (0, import_react71.useState)(null);
|
|
10104
|
+
const [hidden, setHidden] = (0, import_react71.useState)({});
|
|
10105
|
+
const decoy = (0, import_react71.useRef)("");
|
|
10106
|
+
const stage = (0, import_react71.useRef)(null);
|
|
10107
|
+
const questions = (0, import_react71.useMemo)(() => {
|
|
9778
10108
|
const byKey = new Map((fields ?? []).map((f) => [f.key, f]));
|
|
9779
10109
|
return (form.questions ?? []).map((q) => {
|
|
9780
10110
|
const field = byKey.get(q.field) ?? null;
|
|
@@ -9788,7 +10118,7 @@ function FormStage({
|
|
|
9788
10118
|
};
|
|
9789
10119
|
});
|
|
9790
10120
|
}, [fields, form.questions]);
|
|
9791
|
-
(0,
|
|
10121
|
+
(0, import_react71.useEffect)(() => {
|
|
9792
10122
|
let cancelled = false;
|
|
9793
10123
|
const conditional = questions.filter((q) => q.showIf);
|
|
9794
10124
|
if (conditional.length === 0 || !evaluate) return;
|
|
@@ -9822,7 +10152,7 @@ function FormStage({
|
|
|
9822
10152
|
const v = answers[q.key];
|
|
9823
10153
|
return q.required && (v === void 0 || v === null || v === "");
|
|
9824
10154
|
});
|
|
9825
|
-
const submit = (0,
|
|
10155
|
+
const submit = (0, import_react71.useCallback)(async () => {
|
|
9826
10156
|
if (preview) {
|
|
9827
10157
|
setDone("preview");
|
|
9828
10158
|
return;
|
|
@@ -9859,51 +10189,51 @@ function FormStage({
|
|
|
9859
10189
|
if (event.shiftKey) retreat();
|
|
9860
10190
|
else advance();
|
|
9861
10191
|
}
|
|
9862
|
-
(0,
|
|
10192
|
+
(0, import_react71.useEffect)(() => {
|
|
9863
10193
|
const input = stage.current?.querySelector(
|
|
9864
10194
|
"input:not([tabindex='-1']), textarea, select, [role='combobox']"
|
|
9865
10195
|
);
|
|
9866
10196
|
input?.focus();
|
|
9867
10197
|
}, [index, done]);
|
|
9868
10198
|
if (done) {
|
|
9869
|
-
return /* @__PURE__ */ (0,
|
|
9870
|
-
/* @__PURE__ */ (0,
|
|
9871
|
-
form.thankYou?.body ? /* @__PURE__ */ (0,
|
|
9872
|
-
/* @__PURE__ */ (0,
|
|
10199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("section", { className: (0, import_design_system35.cn)("mx-auto max-w-xl py-10", centred && "text-center", className), children: [
|
|
10200
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h2", { className: "text-lg font-medium", children: form.thankYou?.title ?? "Thank you" }),
|
|
10201
|
+
form.thankYou?.body ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: form.thankYou.body }) : null,
|
|
10202
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "mt-3 text-xs text-muted-foreground", children: done === "preview" ? "This was a preview, so nothing was written." : done === "sent" ? `Saved to ${form.name}, with this form stamped on it.` : done })
|
|
9873
10203
|
] });
|
|
9874
10204
|
}
|
|
9875
10205
|
const unresolved = questions.filter((q) => !q.field);
|
|
9876
10206
|
const unanswerable = !evaluate && questions.some((q) => q.showIf);
|
|
9877
10207
|
const signedInPublic = connected && form.isPublic === true;
|
|
9878
|
-
return /* @__PURE__ */ (0,
|
|
10208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
9879
10209
|
"section",
|
|
9880
10210
|
{
|
|
9881
|
-
className: (0,
|
|
10211
|
+
className: (0, import_design_system35.cn)("mx-auto flex max-w-xl flex-col gap-3 py-4", centred && "text-center", className),
|
|
9882
10212
|
onKeyDown,
|
|
9883
10213
|
children: [
|
|
9884
|
-
/* @__PURE__ */ (0,
|
|
9885
|
-
/* @__PURE__ */ (0,
|
|
9886
|
-
|
|
10214
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("header", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
|
|
10215
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
10216
|
+
import_design_system35.Progress,
|
|
9887
10217
|
{
|
|
9888
10218
|
value: live.length === 0 ? 0 : (oneAtATime ? index + 1 : answered) / live.length * 100,
|
|
9889
10219
|
className: "h-1 flex-1"
|
|
9890
10220
|
}
|
|
9891
10221
|
),
|
|
9892
|
-
/* @__PURE__ */ (0,
|
|
10222
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "tabular-nums", children: oneAtATime ? `${index + 1} of ${live.length}` : `${answered} of ${live.length}` })
|
|
9893
10223
|
] }),
|
|
9894
|
-
signedInPublic ? /* @__PURE__ */ (0,
|
|
9895
|
-
unanswerable ? /* @__PURE__ */ (0,
|
|
9896
|
-
unresolved.length > 0 ? /* @__PURE__ */ (0,
|
|
10224
|
+
signedInPublic ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-left text-xs text-muted-foreground", children: "You are answering this signed in, so the record will carry your name. A stranger answers the same form at its public link, where the answer arrives through the anonymous door instead." }) : null,
|
|
10225
|
+
unanswerable ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-left text-xs text-muted-foreground", children: "This form has questions that only appear in certain cases. Nothing here can work out which ones, so all of them are being shown rather than any being skipped." }) : null,
|
|
10226
|
+
unresolved.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "rounded border border-dashed px-2 py-1 text-left text-xs text-destructive", children: [
|
|
9897
10227
|
unresolved.map((q) => q.key).join(", "),
|
|
9898
10228
|
" ",
|
|
9899
10229
|
unresolved.length === 1 ? "is a question" : "are questions",
|
|
9900
10230
|
" this form asks for and this table has no such Field. Add the Field, or take the question out \u2014 it is shown here rather than quietly dropped, because a dropped question is an answer nobody gave."
|
|
9901
10231
|
] }) : null,
|
|
9902
|
-
form.intro && index === 0 ? /* @__PURE__ */ (0,
|
|
9903
|
-
error ? /* @__PURE__ */ (0,
|
|
9904
|
-
refusal ? /* @__PURE__ */ (0,
|
|
9905
|
-
/* @__PURE__ */ (0,
|
|
9906
|
-
(oneAtATime ? current ? [current] : [] : live).map((q) => /* @__PURE__ */ (0,
|
|
10232
|
+
form.intro && index === 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-sm text-muted-foreground", children: form.intro }) : null,
|
|
10233
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(RefusalNotice, { error, className: "text-left" }) : null,
|
|
10234
|
+
refusal ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { role: "alert", className: "rounded border border-destructive/40 px-2 py-1 text-left text-xs text-destructive", children: refusal }) : null,
|
|
10235
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { ref: stage, className: "flex flex-col gap-4 text-left", children: [
|
|
10236
|
+
(oneAtATime ? current ? [current] : [] : live).map((q) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
9907
10237
|
Question,
|
|
9908
10238
|
{
|
|
9909
10239
|
question: q,
|
|
@@ -9913,11 +10243,11 @@ function FormStage({
|
|
|
9913
10243
|
},
|
|
9914
10244
|
q.key
|
|
9915
10245
|
)),
|
|
9916
|
-
live.length === 0 ? /* @__PURE__ */ (0,
|
|
10246
|
+
live.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-xs text-muted-foreground", children: "Every question in this form is hidden by its own condition right now, so there is nothing to answer yet." }) : null
|
|
9917
10247
|
] }),
|
|
9918
|
-
honeypotKey ? /* @__PURE__ */ (0,
|
|
9919
|
-
/* @__PURE__ */ (0,
|
|
9920
|
-
/* @__PURE__ */ (0,
|
|
10248
|
+
honeypotKey ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { "aria-hidden": true, className: "pointer-events-none absolute left-[-9999px] h-px w-px overflow-hidden", children: [
|
|
10249
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("label", { htmlFor: `hp-${honeypotKey}`, children: "Leave this field empty" }),
|
|
10250
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
9921
10251
|
"input",
|
|
9922
10252
|
{
|
|
9923
10253
|
id: `hp-${honeypotKey}`,
|
|
@@ -9932,16 +10262,16 @@ function FormStage({
|
|
|
9932
10262
|
}
|
|
9933
10263
|
)
|
|
9934
10264
|
] }) : null,
|
|
9935
|
-
/* @__PURE__ */ (0,
|
|
9936
|
-
oneAtATime && index > 0 ? /* @__PURE__ */ (0,
|
|
9937
|
-
oneAtATime && index < live.length - 1 ? /* @__PURE__ */ (0,
|
|
9938
|
-
missing.length > 0 && (!oneAtATime || index === live.length - 1) ? /* @__PURE__ */ (0,
|
|
10265
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("footer", { className: (0, import_design_system35.cn)("flex flex-wrap items-center gap-2", centred && "justify-center"), children: [
|
|
10266
|
+
oneAtATime && index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system35.Button, { size: "sm", variant: "ghost", onClick: retreat, children: "Back" }) : null,
|
|
10267
|
+
oneAtATime && index < live.length - 1 ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system35.Button, { size: "sm", onClick: advance, children: "Next" }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_design_system35.Button, { size: "sm", disabled: writing || missing.length > 0, onClick: () => void submit(), children: writing ? "Sending\u2026" : form.submitLabel ?? "Submit" }),
|
|
10268
|
+
missing.length > 0 && (!oneAtATime || index === live.length - 1) ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
9939
10269
|
missing.map((q) => q.ask).join(", "),
|
|
9940
10270
|
" still ",
|
|
9941
10271
|
missing.length === 1 ? "needs" : "need",
|
|
9942
10272
|
" an answer."
|
|
9943
10273
|
] }) : null,
|
|
9944
|
-
preview ? /* @__PURE__ */ (0,
|
|
10274
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-xs text-muted-foreground", children: "Preview \u2014 nothing is written." }) : null
|
|
9945
10275
|
] })
|
|
9946
10276
|
]
|
|
9947
10277
|
}
|
|
@@ -9953,16 +10283,16 @@ function Question({
|
|
|
9953
10283
|
onChange,
|
|
9954
10284
|
upload
|
|
9955
10285
|
}) {
|
|
9956
|
-
const [uploadError, setUploadError] = (0,
|
|
10286
|
+
const [uploadError, setUploadError] = (0, import_react71.useState)(null);
|
|
9957
10287
|
const field = question.field;
|
|
9958
10288
|
if (!field) return null;
|
|
9959
10289
|
const id = `form-${field.key}`;
|
|
9960
10290
|
const isAttachment = editorKindFor(field) === "attachment";
|
|
9961
|
-
return /* @__PURE__ */ (0,
|
|
9962
|
-
/* @__PURE__ */ (0,
|
|
9963
|
-
question.help ? /* @__PURE__ */ (0,
|
|
9964
|
-
isAttachment && !upload ? /* @__PURE__ */ (0,
|
|
9965
|
-
/* @__PURE__ */ (0,
|
|
10291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
10292
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FieldLabel, { field: { ...field, label: question.ask, required: question.required }, htmlFor: id }),
|
|
10293
|
+
question.help ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-xs text-muted-foreground", children: question.help }) : null,
|
|
10294
|
+
isAttachment && !upload ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : isAttachment ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
10295
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
9966
10296
|
"input",
|
|
9967
10297
|
{
|
|
9968
10298
|
id,
|
|
@@ -9980,31 +10310,31 @@ function Question({
|
|
|
9980
10310
|
}
|
|
9981
10311
|
}
|
|
9982
10312
|
),
|
|
9983
|
-
uploadError ? /* @__PURE__ */ (0,
|
|
9984
|
-
] }) : /* @__PURE__ */ (0,
|
|
10313
|
+
uploadError ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "text-xs text-destructive", children: uploadError }) : null
|
|
10314
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FieldControl, { field, value, onChange, id })
|
|
9985
10315
|
] });
|
|
9986
10316
|
}
|
|
9987
10317
|
|
|
9988
10318
|
// src/FormBuilder.tsx
|
|
9989
|
-
var
|
|
10319
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
9990
10320
|
function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
9991
|
-
const client = (0,
|
|
10321
|
+
const client = (0, import_react74.useRecordsClient)();
|
|
9992
10322
|
const host = useRecordsUi();
|
|
9993
10323
|
const claimSeed = useSeedGuard();
|
|
9994
|
-
const table = (0,
|
|
10324
|
+
const table = (0, import_react74.useTable)(tableId);
|
|
9995
10325
|
const rights = useTableRights(table.data);
|
|
9996
|
-
const fields = (0,
|
|
9997
|
-
const [forms, setForms] = (0,
|
|
9998
|
-
const [error, setError] = (0,
|
|
9999
|
-
const [activeId, setActiveId] = (0,
|
|
10000
|
-
const [draft, setDraft] = (0,
|
|
10001
|
-
const [saving, setSaving] = (0,
|
|
10002
|
-
const [saved, setSaved] = (0,
|
|
10003
|
-
const [publishing, setPublishing] = (0,
|
|
10004
|
-
const [copied, setCopied] = (0,
|
|
10005
|
-
const [shownUrl, setShownUrl] = (0,
|
|
10326
|
+
const fields = (0, import_react74.useFields)(tableId);
|
|
10327
|
+
const [forms, setForms] = (0, import_react73.useState)(null);
|
|
10328
|
+
const [error, setError] = (0, import_react73.useState)(null);
|
|
10329
|
+
const [activeId, setActiveId] = (0, import_react73.useState)(activeFormId ?? null);
|
|
10330
|
+
const [draft, setDraft] = (0, import_react73.useState)(null);
|
|
10331
|
+
const [saving, setSaving] = (0, import_react73.useState)(false);
|
|
10332
|
+
const [saved, setSaved] = (0, import_react73.useState)(null);
|
|
10333
|
+
const [publishing, setPublishing] = (0, import_react73.useState)(false);
|
|
10334
|
+
const [copied, setCopied] = (0, import_react73.useState)(false);
|
|
10335
|
+
const [shownUrl, setShownUrl] = (0, import_react73.useState)(null);
|
|
10006
10336
|
const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
10007
|
-
const load = (0,
|
|
10337
|
+
const load = (0, import_react73.useCallback)(async () => {
|
|
10008
10338
|
const answered = await client.forms({ table_id: tableId });
|
|
10009
10339
|
if (!answered.ok) {
|
|
10010
10340
|
setError(answered.error);
|
|
@@ -10031,17 +10361,17 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10031
10361
|
setError(null);
|
|
10032
10362
|
setForms(mine);
|
|
10033
10363
|
}, [client, tableId, seed, claimSeed]);
|
|
10034
|
-
(0,
|
|
10364
|
+
(0, import_react73.useEffect)(() => {
|
|
10035
10365
|
void load();
|
|
10036
10366
|
}, [load]);
|
|
10037
|
-
(0,
|
|
10367
|
+
(0, import_react73.useEffect)(() => {
|
|
10038
10368
|
if (!forms || forms.length === 0) return;
|
|
10039
10369
|
const chosen = forms.find((f) => f.id === (activeFormId ?? activeId)) ?? forms[0];
|
|
10040
10370
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
10041
10371
|
setDraft(chosen);
|
|
10042
10372
|
onActiveForm?.(chosen);
|
|
10043
10373
|
}, [forms, activeFormId]);
|
|
10044
|
-
const byKey = (0,
|
|
10374
|
+
const byKey = (0, import_react73.useMemo)(() => new Map((fields.data ?? []).map((f) => [f.key, f])), [fields.data]);
|
|
10045
10375
|
function patch(change) {
|
|
10046
10376
|
setDraft((prev) => prev ? { ...prev, ...change } : prev);
|
|
10047
10377
|
setSaved(null);
|
|
@@ -10101,26 +10431,26 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10101
10431
|
setActiveId(written.data);
|
|
10102
10432
|
await load();
|
|
10103
10433
|
}
|
|
10104
|
-
if (fields.error) return /* @__PURE__ */ (0,
|
|
10434
|
+
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(RefusalNotice, { error: fields.error, className });
|
|
10105
10435
|
if (error) {
|
|
10106
|
-
return /* @__PURE__ */ (0,
|
|
10436
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10107
10437
|
RefusalNotice,
|
|
10108
10438
|
{
|
|
10109
10439
|
error,
|
|
10110
10440
|
className,
|
|
10111
|
-
actions: /* @__PURE__ */ (0,
|
|
10441
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10112
10442
|
}
|
|
10113
10443
|
);
|
|
10114
10444
|
}
|
|
10115
|
-
if (fields.loading || forms === null) return /* @__PURE__ */ (0,
|
|
10445
|
+
if (fields.loading || forms === null) return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Skeleton, { className: (0, import_design_system36.cn)("h-64 w-full", className) });
|
|
10116
10446
|
if (!rights.admin) {
|
|
10117
|
-
return /* @__PURE__ */ (0,
|
|
10447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: (0, import_design_system36.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") });
|
|
10118
10448
|
}
|
|
10119
|
-
return /* @__PURE__ */ (0,
|
|
10120
|
-
/* @__PURE__ */ (0,
|
|
10121
|
-
/* @__PURE__ */ (0,
|
|
10122
|
-
forms.map((form) => /* @__PURE__ */ (0,
|
|
10123
|
-
|
|
10449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: (0, import_design_system36.cn)("flex min-h-0 gap-3", className), children: [
|
|
10450
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-2 overflow-auto", children: [
|
|
10451
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Forms", children: [
|
|
10452
|
+
forms.map((form) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10453
|
+
import_design_system36.Button,
|
|
10124
10454
|
{
|
|
10125
10455
|
size: "sm",
|
|
10126
10456
|
variant: form.id === activeId ? "secondary" : "ghost",
|
|
@@ -10133,14 +10463,14 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10133
10463
|
},
|
|
10134
10464
|
form.id
|
|
10135
10465
|
)),
|
|
10136
|
-
(fields.data ?? []).length > 0 ? /* @__PURE__ */ (0,
|
|
10137
|
-
/* @__PURE__ */ (0,
|
|
10138
|
-
saved ? /* @__PURE__ */ (0,
|
|
10139
|
-
/* @__PURE__ */ (0,
|
|
10466
|
+
(fields.data ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Button, { size: "sm", variant: "ghost", onClick: () => void create(`Form ${forms.length + 1}`), children: "New form" }) : null,
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-auto flex items-center gap-2", children: [
|
|
10468
|
+
saved ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs text-muted-foreground", children: saved }) : null,
|
|
10469
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Button, { size: "sm", disabled: saving || !draft, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" })
|
|
10140
10470
|
] })
|
|
10141
10471
|
] }),
|
|
10142
|
-
!draft ? /* @__PURE__ */ (0,
|
|
10143
|
-
/* @__PURE__ */ (0,
|
|
10472
|
+
!draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: (fields.data ?? []).length === 0 ? "This table has no fields yet, so there is nothing a form could ask for. Add a field first \u2014 every question is one of this table's own fields." : 'No form collects into this table yet. "New form" makes one, or you ask an agent for the whole thing in a sentence.' }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
|
|
10473
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10144
10474
|
PublishRow,
|
|
10145
10475
|
{
|
|
10146
10476
|
url: `${publicOrigin}${(0, import_records6.publicFormPath)(draft.id)}`,
|
|
@@ -10154,27 +10484,27 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10154
10484
|
onCopy: (url) => void copyLink(url)
|
|
10155
10485
|
}
|
|
10156
10486
|
),
|
|
10157
|
-
/* @__PURE__ */ (0,
|
|
10158
|
-
/* @__PURE__ */ (0,
|
|
10159
|
-
/* @__PURE__ */ (0,
|
|
10160
|
-
/* @__PURE__ */ (0,
|
|
10487
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
10488
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
10489
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Label, { className: "text-xs font-medium", children: "Name" }),
|
|
10490
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.BasicInput, { value: draft.name, onChange: (e) => patch({ name: e.target.value }) })
|
|
10161
10491
|
] }),
|
|
10162
|
-
/* @__PURE__ */ (0,
|
|
10163
|
-
/* @__PURE__ */ (0,
|
|
10164
|
-
/* @__PURE__ */ (0,
|
|
10492
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
10493
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Label, { className: "text-xs font-medium", children: "Flow" }),
|
|
10494
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10165
10495
|
"select",
|
|
10166
10496
|
{
|
|
10167
10497
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
10168
10498
|
value: draft.flow ?? "one-at-a-time",
|
|
10169
10499
|
onChange: (e) => patch({ flow: e.target.value }),
|
|
10170
|
-
children: FORM_FLOWS.map((flow) => /* @__PURE__ */ (0,
|
|
10500
|
+
children: FORM_FLOWS.map((flow) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("option", { value: flow, children: flow === "one-at-a-time" ? "One question at a time" : "All on one page" }, flow))
|
|
10171
10501
|
}
|
|
10172
10502
|
)
|
|
10173
10503
|
] }),
|
|
10174
|
-
/* @__PURE__ */ (0,
|
|
10175
|
-
/* @__PURE__ */ (0,
|
|
10176
|
-
/* @__PURE__ */ (0,
|
|
10177
|
-
|
|
10504
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "col-span-2 flex flex-col gap-1", children: [
|
|
10505
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Label, { className: "text-xs font-medium", children: "Intro" }),
|
|
10506
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10507
|
+
import_design_system36.BasicTextarea,
|
|
10178
10508
|
{
|
|
10179
10509
|
rows: 2,
|
|
10180
10510
|
value: draft.intro ?? "",
|
|
@@ -10182,10 +10512,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10182
10512
|
}
|
|
10183
10513
|
)
|
|
10184
10514
|
] }),
|
|
10185
|
-
/* @__PURE__ */ (0,
|
|
10186
|
-
/* @__PURE__ */ (0,
|
|
10187
|
-
/* @__PURE__ */ (0,
|
|
10188
|
-
|
|
10515
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
10516
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Label, { className: "text-xs font-medium", children: "Submit button" }),
|
|
10517
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10518
|
+
import_design_system36.BasicInput,
|
|
10189
10519
|
{
|
|
10190
10520
|
value: draft.submitLabel ?? "",
|
|
10191
10521
|
placeholder: "Submit",
|
|
@@ -10193,10 +10523,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10193
10523
|
}
|
|
10194
10524
|
)
|
|
10195
10525
|
] }),
|
|
10196
|
-
/* @__PURE__ */ (0,
|
|
10197
|
-
/* @__PURE__ */ (0,
|
|
10198
|
-
/* @__PURE__ */ (0,
|
|
10199
|
-
|
|
10526
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
10527
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Label, { className: "text-xs font-medium", children: "Thank-you title" }),
|
|
10528
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10529
|
+
import_design_system36.BasicInput,
|
|
10200
10530
|
{
|
|
10201
10531
|
value: draft.thankYou?.title ?? "",
|
|
10202
10532
|
placeholder: "Thank you",
|
|
@@ -10207,10 +10537,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10207
10537
|
)
|
|
10208
10538
|
] })
|
|
10209
10539
|
] }),
|
|
10210
|
-
/* @__PURE__ */ (0,
|
|
10211
|
-
/* @__PURE__ */ (0,
|
|
10212
|
-
/* @__PURE__ */ (0,
|
|
10213
|
-
/* @__PURE__ */ (0,
|
|
10540
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
10541
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
10542
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium text-foreground", children: "Questions" }),
|
|
10543
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
|
|
10214
10544
|
draft.questions.length,
|
|
10215
10545
|
" of this table's ",
|
|
10216
10546
|
fields.data?.length ?? 0,
|
|
@@ -10221,10 +10551,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10221
10551
|
const index = draft.questions.findIndex((q) => q.field === field.key);
|
|
10222
10552
|
const asked = index >= 0;
|
|
10223
10553
|
const question = asked ? draft.questions[index] : null;
|
|
10224
|
-
return /* @__PURE__ */ (0,
|
|
10225
|
-
/* @__PURE__ */ (0,
|
|
10226
|
-
/* @__PURE__ */ (0,
|
|
10227
|
-
|
|
10554
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "rounded border px-2 py-1.5", children: [
|
|
10555
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10556
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10557
|
+
import_design_system36.Checkbox,
|
|
10228
10558
|
{
|
|
10229
10559
|
checked: asked,
|
|
10230
10560
|
"aria-label": `Ask for ${fieldName(field)}`,
|
|
@@ -10233,13 +10563,13 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10233
10563
|
})
|
|
10234
10564
|
}
|
|
10235
10565
|
),
|
|
10236
|
-
/* @__PURE__ */ (0,
|
|
10237
|
-
/* @__PURE__ */ (0,
|
|
10238
|
-
field.required ? /* @__PURE__ */ (0,
|
|
10566
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs font-medium", children: fieldName(field) }),
|
|
10567
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs text-muted-foreground", children: field.key }),
|
|
10568
|
+
field.required ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-xs text-destructive", children: "required" }) : null
|
|
10239
10569
|
] }),
|
|
10240
|
-
asked && question ? /* @__PURE__ */ (0,
|
|
10241
|
-
/* @__PURE__ */ (0,
|
|
10242
|
-
|
|
10570
|
+
asked && question ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "mt-1.5 grid grid-cols-2 gap-2 pl-6", children: [
|
|
10571
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10572
|
+
import_design_system36.BasicInput,
|
|
10243
10573
|
{
|
|
10244
10574
|
className: "h-8 text-xs",
|
|
10245
10575
|
placeholder: fieldName(field),
|
|
@@ -10248,8 +10578,8 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10248
10578
|
onChange: (e) => patchQuestion(index, { ask: e.target.value || null })
|
|
10249
10579
|
}
|
|
10250
10580
|
),
|
|
10251
|
-
/* @__PURE__ */ (0,
|
|
10252
|
-
|
|
10581
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10582
|
+
import_design_system36.BasicInput,
|
|
10253
10583
|
{
|
|
10254
10584
|
className: "h-8 text-xs",
|
|
10255
10585
|
placeholder: "Help text",
|
|
@@ -10258,7 +10588,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10258
10588
|
onChange: (e) => patchQuestion(index, { help: e.target.value || null })
|
|
10259
10589
|
}
|
|
10260
10590
|
),
|
|
10261
|
-
/* @__PURE__ */ (0,
|
|
10591
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10262
10592
|
Condition,
|
|
10263
10593
|
{
|
|
10264
10594
|
question,
|
|
@@ -10269,7 +10599,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10269
10599
|
] }) : null
|
|
10270
10600
|
] }, field.id);
|
|
10271
10601
|
}),
|
|
10272
|
-
draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */ (0,
|
|
10602
|
+
draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "text-xs text-destructive", children: [
|
|
10273
10603
|
'This form asks for "',
|
|
10274
10604
|
q.field,
|
|
10275
10605
|
'" and this table has no such Field. It is shown here rather than quietly dropped.'
|
|
@@ -10277,9 +10607,9 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10277
10607
|
] })
|
|
10278
10608
|
] })
|
|
10279
10609
|
] }),
|
|
10280
|
-
draft ? /* @__PURE__ */ (0,
|
|
10281
|
-
/* @__PURE__ */ (0,
|
|
10282
|
-
/* @__PURE__ */ (0,
|
|
10610
|
+
draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { className: "w-96 shrink-0 overflow-auto rounded border p-2", children: [
|
|
10611
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("h4", { className: "px-1 text-sm font-medium", children: draft.name }),
|
|
10612
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FormRunner, { form: draft, preview: true })
|
|
10283
10613
|
] }) : null
|
|
10284
10614
|
] });
|
|
10285
10615
|
}
|
|
@@ -10295,10 +10625,10 @@ function PublishRow({
|
|
|
10295
10625
|
onCopy
|
|
10296
10626
|
}) {
|
|
10297
10627
|
const open = state === "open";
|
|
10298
|
-
return /* @__PURE__ */ (0,
|
|
10299
|
-
/* @__PURE__ */ (0,
|
|
10300
|
-
mayPublish ? /* @__PURE__ */ (0,
|
|
10301
|
-
|
|
10628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-col gap-1.5 rounded border px-2.5 py-2", children: [
|
|
10629
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
10630
|
+
mayPublish ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10631
|
+
import_design_system36.Button,
|
|
10302
10632
|
{
|
|
10303
10633
|
size: "sm",
|
|
10304
10634
|
variant: open ? "ghost" : "default",
|
|
@@ -10307,8 +10637,8 @@ function PublishRow({
|
|
|
10307
10637
|
children: busy ? "\u2026" : open ? "Unpublish" : "Publish"
|
|
10308
10638
|
}
|
|
10309
10639
|
) : null,
|
|
10310
|
-
state !== "draft" ? /* @__PURE__ */ (0,
|
|
10311
|
-
/* @__PURE__ */ (0,
|
|
10640
|
+
state !== "draft" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
|
|
10641
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10312
10642
|
"a",
|
|
10313
10643
|
{
|
|
10314
10644
|
href: url,
|
|
@@ -10318,12 +10648,12 @@ function PublishRow({
|
|
|
10318
10648
|
children: url
|
|
10319
10649
|
}
|
|
10320
10650
|
),
|
|
10321
|
-
/* @__PURE__ */ (0,
|
|
10651
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_design_system36.Button, { size: "sm", variant: "outline", onClick: () => onCopy(url), children: copied ? "Copied" : "Copy link" })
|
|
10322
10652
|
] }) : null
|
|
10323
10653
|
] }),
|
|
10324
|
-
/* @__PURE__ */ (0,
|
|
10325
|
-
!mayPublish ? /* @__PURE__ */ (0,
|
|
10326
|
-
shownUrl ? /* @__PURE__ */ (0,
|
|
10654
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: FORM_STATE_WORDS[state] }),
|
|
10655
|
+
!mayPublish ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: why }) : null,
|
|
10656
|
+
shownUrl ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
10327
10657
|
"This browser would not let the page copy for you, so here it is to copy by hand: ",
|
|
10328
10658
|
shownUrl
|
|
10329
10659
|
] }) : null
|
|
@@ -10334,7 +10664,7 @@ function Condition({
|
|
|
10334
10664
|
fieldKeys,
|
|
10335
10665
|
onChange
|
|
10336
10666
|
}) {
|
|
10337
|
-
return /* @__PURE__ */ (0,
|
|
10667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
10338
10668
|
ConditionRow,
|
|
10339
10669
|
{
|
|
10340
10670
|
lead: "Ask only when",
|
|
@@ -10431,13 +10761,13 @@ function groupLabel(groups) {
|
|
|
10431
10761
|
}
|
|
10432
10762
|
|
|
10433
10763
|
// src/chartFrame.tsx
|
|
10434
|
-
var
|
|
10435
|
-
var
|
|
10436
|
-
var
|
|
10764
|
+
var import_react75 = require("react");
|
|
10765
|
+
var import_design_system37 = require("@ai-matrx/design-system");
|
|
10766
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
10437
10767
|
function useMeasuredWidth(fallback = 480) {
|
|
10438
|
-
const ref = (0,
|
|
10439
|
-
const [width, setWidth] = (0,
|
|
10440
|
-
(0,
|
|
10768
|
+
const ref = (0, import_react75.useRef)(null);
|
|
10769
|
+
const [width, setWidth] = (0, import_react75.useState)(fallback);
|
|
10770
|
+
(0, import_react75.useEffect)(() => {
|
|
10441
10771
|
const node = ref.current;
|
|
10442
10772
|
if (!node) return;
|
|
10443
10773
|
const apply = () => {
|
|
@@ -10467,14 +10797,14 @@ function ChartFrame({
|
|
|
10467
10797
|
children
|
|
10468
10798
|
}) {
|
|
10469
10799
|
const [ref, width] = useMeasuredWidth();
|
|
10470
|
-
const chartId = `records-chart-${(0,
|
|
10471
|
-
return /* @__PURE__ */ (0,
|
|
10800
|
+
const chartId = `records-chart-${(0, import_react75.useId)().replace(/:/g, "")}`;
|
|
10801
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
10472
10802
|
"div",
|
|
10473
10803
|
{
|
|
10474
10804
|
ref,
|
|
10475
10805
|
"data-chart": chartId,
|
|
10476
10806
|
style: { height, ...chartVariables(config) },
|
|
10477
|
-
className: (0,
|
|
10807
|
+
className: (0, import_design_system37.cn)(
|
|
10478
10808
|
"w-full min-w-0 overflow-hidden text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-layer]:outline-none [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
|
|
10479
10809
|
className
|
|
10480
10810
|
),
|
|
@@ -10490,27 +10820,27 @@ function ChartTooltipContent({
|
|
|
10490
10820
|
className
|
|
10491
10821
|
}) {
|
|
10492
10822
|
if (!active || !payload || payload.length === 0) return null;
|
|
10493
|
-
return /* @__PURE__ */ (0,
|
|
10823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
10494
10824
|
"div",
|
|
10495
10825
|
{
|
|
10496
|
-
className: (0,
|
|
10826
|
+
className: (0, import_design_system37.cn)(
|
|
10497
10827
|
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
|
|
10498
10828
|
className
|
|
10499
10829
|
),
|
|
10500
10830
|
children: [
|
|
10501
|
-
label ? /* @__PURE__ */ (0,
|
|
10502
|
-
/* @__PURE__ */ (0,
|
|
10831
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "font-medium", children: label }) : null,
|
|
10832
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "grid gap-1.5", children: payload.map((entry, index) => {
|
|
10503
10833
|
const key = String(entry.dataKey ?? entry.name ?? index);
|
|
10504
|
-
return /* @__PURE__ */ (0,
|
|
10505
|
-
/* @__PURE__ */ (0,
|
|
10834
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
|
|
10835
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
10506
10836
|
"span",
|
|
10507
10837
|
{
|
|
10508
10838
|
className: "h-2.5 w-2.5 shrink-0 rounded-[2px] bg-[--color-swatch]",
|
|
10509
10839
|
style: { "--color-swatch": entry.color }
|
|
10510
10840
|
}
|
|
10511
10841
|
),
|
|
10512
|
-
/* @__PURE__ */ (0,
|
|
10513
|
-
/* @__PURE__ */ (0,
|
|
10842
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-muted-foreground", children: config[key]?.label ?? key }),
|
|
10843
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "ml-auto font-mono font-medium tabular-nums text-foreground", children: typeof entry.value === "number" ? entry.value.toLocaleString() : entry.value })
|
|
10514
10844
|
] }, key);
|
|
10515
10845
|
}) })
|
|
10516
10846
|
]
|
|
@@ -10523,10 +10853,10 @@ function ChartLegendContent({
|
|
|
10523
10853
|
className
|
|
10524
10854
|
}) {
|
|
10525
10855
|
if (!payload || payload.length === 0) return null;
|
|
10526
|
-
return /* @__PURE__ */ (0,
|
|
10856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: (0, import_design_system37.cn)("flex flex-wrap items-center justify-center gap-3 pt-2", className), children: payload.map((entry, index) => {
|
|
10527
10857
|
const key = String(entry.dataKey ?? entry.value ?? index);
|
|
10528
|
-
return /* @__PURE__ */ (0,
|
|
10529
|
-
/* @__PURE__ */ (0,
|
|
10858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
10859
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
10530
10860
|
"span",
|
|
10531
10861
|
{
|
|
10532
10862
|
className: "h-2 w-2 shrink-0 rounded-[2px] bg-[--color-swatch]",
|
|
@@ -10561,24 +10891,24 @@ function isSignatureField(field) {
|
|
|
10561
10891
|
}
|
|
10562
10892
|
|
|
10563
10893
|
// src/DocTemplate.tsx
|
|
10564
|
-
var
|
|
10565
|
-
var
|
|
10566
|
-
var
|
|
10567
|
-
var
|
|
10894
|
+
var import_react76 = require("react");
|
|
10895
|
+
var import_react77 = require("@ai-matrx/records/react");
|
|
10896
|
+
var import_design_system38 = require("@ai-matrx/design-system");
|
|
10897
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
10568
10898
|
function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, className }) {
|
|
10569
|
-
const client = (0,
|
|
10899
|
+
const client = (0, import_react77.useRecordsClient)();
|
|
10570
10900
|
const claimSeed = useSeedGuard();
|
|
10571
|
-
const table = (0,
|
|
10901
|
+
const table = (0, import_react77.useTable)(tableId);
|
|
10572
10902
|
const rights = useTableRights(table.data);
|
|
10573
|
-
const fields = (0,
|
|
10574
|
-
const [templates, setTemplates] = (0,
|
|
10575
|
-
const [error, setError] = (0,
|
|
10576
|
-
const [activeId, setActiveId] = (0,
|
|
10577
|
-
const [draftName, setDraftName] = (0,
|
|
10578
|
-
const [draftBody, setDraftBody] = (0,
|
|
10579
|
-
const [unresolved, setUnresolved] = (0,
|
|
10580
|
-
const [saving, setSaving] = (0,
|
|
10581
|
-
const load = (0,
|
|
10903
|
+
const fields = (0, import_react77.useFields)(tableId);
|
|
10904
|
+
const [templates, setTemplates] = (0, import_react76.useState)(null);
|
|
10905
|
+
const [error, setError] = (0, import_react76.useState)(null);
|
|
10906
|
+
const [activeId, setActiveId] = (0, import_react76.useState)(activeTemplateId ?? null);
|
|
10907
|
+
const [draftName, setDraftName] = (0, import_react76.useState)("");
|
|
10908
|
+
const [draftBody, setDraftBody] = (0, import_react76.useState)("");
|
|
10909
|
+
const [unresolved, setUnresolved] = (0, import_react76.useState)([]);
|
|
10910
|
+
const [saving, setSaving] = (0, import_react76.useState)(false);
|
|
10911
|
+
const load = (0, import_react76.useCallback)(async () => {
|
|
10582
10912
|
const held = await client.docTemplates({ table_id: tableId });
|
|
10583
10913
|
if (!held.ok) {
|
|
10584
10914
|
setError(held.error);
|
|
@@ -10609,10 +10939,10 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10609
10939
|
setError(null);
|
|
10610
10940
|
setTemplates(rows);
|
|
10611
10941
|
}, [client, tableId, seed, fields.data]);
|
|
10612
|
-
(0,
|
|
10942
|
+
(0, import_react76.useEffect)(() => {
|
|
10613
10943
|
void load();
|
|
10614
10944
|
}, [load]);
|
|
10615
|
-
(0,
|
|
10945
|
+
(0, import_react76.useEffect)(() => {
|
|
10616
10946
|
if (!templates || templates.length === 0) return;
|
|
10617
10947
|
const chosen = templates.find((t) => t.id === (activeTemplateId ?? activeId)) ?? templates[0];
|
|
10618
10948
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
@@ -10620,7 +10950,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10620
10950
|
setDraftBody(chosen.body);
|
|
10621
10951
|
onActiveTemplate?.(chosen);
|
|
10622
10952
|
}, [templates, activeTemplateId]);
|
|
10623
|
-
(0,
|
|
10953
|
+
(0, import_react76.useEffect)(() => {
|
|
10624
10954
|
let cancelled = false;
|
|
10625
10955
|
if (draftBody.trim() === "") {
|
|
10626
10956
|
setUnresolved([]);
|
|
@@ -10650,25 +10980,25 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10650
10980
|
setActiveId(saved.data);
|
|
10651
10981
|
await load();
|
|
10652
10982
|
}
|
|
10653
|
-
if (fields.error) return /* @__PURE__ */ (0,
|
|
10983
|
+
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(RefusalNotice, { error: fields.error, className });
|
|
10654
10984
|
if (error) {
|
|
10655
|
-
return /* @__PURE__ */ (0,
|
|
10985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
10656
10986
|
RefusalNotice,
|
|
10657
10987
|
{
|
|
10658
10988
|
error,
|
|
10659
10989
|
className,
|
|
10660
|
-
actions: /* @__PURE__ */ (0,
|
|
10990
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_design_system38.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10661
10991
|
}
|
|
10662
10992
|
);
|
|
10663
10993
|
}
|
|
10664
|
-
if (templates === null || fields.loading) return /* @__PURE__ */ (0,
|
|
10994
|
+
if (templates === null || fields.loading) return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_design_system38.Skeleton, { className: (0, import_design_system38.cn)("h-64 w-full", className) });
|
|
10665
10995
|
if (!rights.admin) {
|
|
10666
|
-
return /* @__PURE__ */ (0,
|
|
10996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: (0, import_design_system38.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") });
|
|
10667
10997
|
}
|
|
10668
|
-
return /* @__PURE__ */ (0,
|
|
10669
|
-
/* @__PURE__ */ (0,
|
|
10670
|
-
templates.map((t) => /* @__PURE__ */ (0,
|
|
10671
|
-
|
|
10998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: (0, import_design_system38.cn)("flex flex-col gap-2", className), children: [
|
|
10999
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Templates", children: [
|
|
11000
|
+
templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
11001
|
+
import_design_system38.Button,
|
|
10672
11002
|
{
|
|
10673
11003
|
size: "sm",
|
|
10674
11004
|
variant: t.id === activeId ? "secondary" : "ghost",
|
|
@@ -10680,7 +11010,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10680
11010
|
},
|
|
10681
11011
|
children: [
|
|
10682
11012
|
t.name,
|
|
10683
|
-
/* @__PURE__ */ (0,
|
|
11013
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "ml-1 text-[10px] text-muted-foreground", children: [
|
|
10684
11014
|
"v",
|
|
10685
11015
|
t.template_version
|
|
10686
11016
|
] })
|
|
@@ -10688,8 +11018,8 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10688
11018
|
},
|
|
10689
11019
|
t.id
|
|
10690
11020
|
)),
|
|
10691
|
-
/* @__PURE__ */ (0,
|
|
10692
|
-
|
|
11021
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
11022
|
+
import_design_system38.Button,
|
|
10693
11023
|
{
|
|
10694
11024
|
size: "sm",
|
|
10695
11025
|
variant: "ghost",
|
|
@@ -10701,16 +11031,16 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10701
11031
|
children: "New template"
|
|
10702
11032
|
}
|
|
10703
11033
|
),
|
|
10704
|
-
/* @__PURE__ */ (0,
|
|
11034
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_design_system38.Button, { size: "sm", className: "ml-auto", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" })
|
|
10705
11035
|
] }),
|
|
10706
|
-
/* @__PURE__ */ (0,
|
|
10707
|
-
/* @__PURE__ */ (0,
|
|
10708
|
-
/* @__PURE__ */ (0,
|
|
11036
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
11037
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_design_system38.Label, { className: "text-xs font-medium", children: "Name" }),
|
|
11038
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_design_system38.BasicInput, { value: draftName, onChange: (e) => setDraftName(e.target.value), placeholder: "Agreement" })
|
|
10709
11039
|
] }),
|
|
10710
|
-
/* @__PURE__ */ (0,
|
|
10711
|
-
/* @__PURE__ */ (0,
|
|
10712
|
-
(fields.data ?? []).map((field) => /* @__PURE__ */ (0,
|
|
10713
|
-
|
|
11040
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
11041
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-xs text-muted-foreground", children: "Insert" }),
|
|
11042
|
+
(fields.data ?? []).map((field) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
11043
|
+
import_design_system38.Button,
|
|
10714
11044
|
{
|
|
10715
11045
|
size: "sm",
|
|
10716
11046
|
variant: "ghost",
|
|
@@ -10721,8 +11051,8 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10721
11051
|
field.id
|
|
10722
11052
|
))
|
|
10723
11053
|
] }),
|
|
10724
|
-
/* @__PURE__ */ (0,
|
|
10725
|
-
|
|
11054
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
11055
|
+
import_design_system38.BasicTextarea,
|
|
10726
11056
|
{
|
|
10727
11057
|
rows: 10,
|
|
10728
11058
|
"aria-label": "Template body",
|
|
@@ -10731,28 +11061,28 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10731
11061
|
onChange: (e) => setDraftBody(e.target.value)
|
|
10732
11062
|
}
|
|
10733
11063
|
),
|
|
10734
|
-
unresolved.length > 0 ? /* @__PURE__ */ (0,
|
|
10735
|
-
/* @__PURE__ */ (0,
|
|
11064
|
+
unresolved.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("ul", { className: "flex flex-col gap-0.5 rounded border border-dashed px-2 py-1 text-xs", children: unresolved.map((token) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("li", { className: "text-destructive", children: [
|
|
11065
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("code", { children: token.raw }),
|
|
10736
11066
|
" \u2014 ",
|
|
10737
11067
|
token.why
|
|
10738
|
-
] }, token.raw)) }) : draftBody.trim() !== "" ? /* @__PURE__ */ (0,
|
|
11068
|
+
] }, token.raw)) }) : draftBody.trim() !== "" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-xs text-muted-foreground", children: "Every token in this body points at a Field this table can answer." }) : null
|
|
10739
11069
|
] });
|
|
10740
11070
|
}
|
|
10741
11071
|
|
|
10742
11072
|
// src/DocRender.tsx
|
|
10743
|
-
var
|
|
10744
|
-
var
|
|
10745
|
-
var
|
|
10746
|
-
var
|
|
11073
|
+
var import_react78 = require("react");
|
|
11074
|
+
var import_react79 = require("@ai-matrx/records/react");
|
|
11075
|
+
var import_design_system39 = require("@ai-matrx/design-system");
|
|
11076
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
10747
11077
|
function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
10748
|
-
const client = (0,
|
|
10749
|
-
const [preview, setPreview] = (0,
|
|
10750
|
-
const [renders, setRenders] = (0,
|
|
10751
|
-
const [showing, setShowing] = (0,
|
|
10752
|
-
const [error, setError] = (0,
|
|
10753
|
-
const [busy, setBusy] = (0,
|
|
10754
|
-
const paper = (0,
|
|
10755
|
-
const load = (0,
|
|
11078
|
+
const client = (0, import_react79.useRecordsClient)();
|
|
11079
|
+
const [preview, setPreview] = (0, import_react78.useState)(null);
|
|
11080
|
+
const [renders, setRenders] = (0, import_react78.useState)(null);
|
|
11081
|
+
const [showing, setShowing] = (0, import_react78.useState)(null);
|
|
11082
|
+
const [error, setError] = (0, import_react78.useState)(null);
|
|
11083
|
+
const [busy, setBusy] = (0, import_react78.useState)(null);
|
|
11084
|
+
const paper = (0, import_react78.useRef)(null);
|
|
11085
|
+
const load = (0, import_react78.useCallback)(async () => {
|
|
10756
11086
|
const [body, held] = await Promise.all([
|
|
10757
11087
|
client.docRenderBody({ template_id: templateId, record_id: recordId }),
|
|
10758
11088
|
client.docRenders({ record_id: recordId })
|
|
@@ -10769,7 +11099,7 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10769
11099
|
setPreview(body.data);
|
|
10770
11100
|
setRenders(held.data.filter((r) => r.template_id === templateId));
|
|
10771
11101
|
}, [client, templateId, recordId]);
|
|
10772
|
-
(0,
|
|
11102
|
+
(0, import_react78.useEffect)(() => {
|
|
10773
11103
|
void load();
|
|
10774
11104
|
}, [load]);
|
|
10775
11105
|
async function freeze() {
|
|
@@ -10806,22 +11136,22 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10806
11136
|
}
|
|
10807
11137
|
}
|
|
10808
11138
|
if (error) {
|
|
10809
|
-
return /* @__PURE__ */ (0,
|
|
11139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
10810
11140
|
RefusalNotice,
|
|
10811
11141
|
{
|
|
10812
11142
|
error,
|
|
10813
11143
|
className,
|
|
10814
|
-
actions: /* @__PURE__ */ (0,
|
|
11144
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system39.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10815
11145
|
}
|
|
10816
11146
|
);
|
|
10817
11147
|
}
|
|
10818
|
-
if (preview === null || renders === null) return /* @__PURE__ */ (0,
|
|
11148
|
+
if (preview === null || renders === null) return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system39.Skeleton, { className: (0, import_design_system39.cn)("h-64 w-full", className) });
|
|
10819
11149
|
const frozen = showing ? renders.find((r) => r.id === showing) ?? null : null;
|
|
10820
11150
|
const text = frozen ? frozen.body : preview;
|
|
10821
|
-
return /* @__PURE__ */ (0,
|
|
10822
|
-
/* @__PURE__ */ (0,
|
|
10823
|
-
/* @__PURE__ */ (0,
|
|
10824
|
-
|
|
11151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: (0, import_design_system39.cn)("flex flex-col gap-2", className), children: [
|
|
11152
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1 text-xs", children: [
|
|
11153
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11154
|
+
import_design_system39.Button,
|
|
10825
11155
|
{
|
|
10826
11156
|
size: "sm",
|
|
10827
11157
|
variant: frozen ? "ghost" : "secondary",
|
|
@@ -10830,8 +11160,8 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10830
11160
|
children: "As it reads now"
|
|
10831
11161
|
}
|
|
10832
11162
|
),
|
|
10833
|
-
renders.map((render) => /* @__PURE__ */ (0,
|
|
10834
|
-
|
|
11163
|
+
renders.map((render) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
11164
|
+
import_design_system39.Button,
|
|
10835
11165
|
{
|
|
10836
11166
|
size: "sm",
|
|
10837
11167
|
variant: render.id === showing ? "secondary" : "ghost",
|
|
@@ -10842,33 +11172,33 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10842
11172
|
},
|
|
10843
11173
|
render.id
|
|
10844
11174
|
)),
|
|
10845
|
-
/* @__PURE__ */ (0,
|
|
10846
|
-
/* @__PURE__ */ (0,
|
|
10847
|
-
/* @__PURE__ */ (0,
|
|
11175
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-auto flex items-center gap-1", children: [
|
|
11176
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system39.Button, { size: "sm", disabled: busy !== null, onClick: () => void freeze(), children: busy === "freeze" ? "Freezing\u2026" : "Freeze this version" }),
|
|
11177
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_design_system39.Button, { size: "sm", variant: "ghost", disabled: busy !== null, onClick: () => void toPdf(), children: busy === "pdf" ? "Making the PDF\u2026" : "PDF" })
|
|
10848
11178
|
] })
|
|
10849
11179
|
] }),
|
|
10850
|
-
/* @__PURE__ */ (0,
|
|
10851
|
-
/* @__PURE__ */ (0,
|
|
11180
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ref: paper, className: "whitespace-pre-wrap rounded border bg-background p-4 text-sm text-foreground", children: text }),
|
|
11181
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-xs text-muted-foreground", children: frozen ? `Frozen ${new Date(frozen.rendered_at).toLocaleString()} from template v${frozen.template_version}. Its text and its SHA-256 (${frozen.content_hash.slice(0, 12)}\u2026) are what any signature seals.` : "This is how the template reads against this record right now. Nothing has been frozen, so there is no version for anyone to sign yet." })
|
|
10852
11182
|
] });
|
|
10853
11183
|
}
|
|
10854
11184
|
|
|
10855
11185
|
// src/SignBlock.tsx
|
|
10856
|
-
var
|
|
10857
|
-
var
|
|
10858
|
-
var
|
|
10859
|
-
var
|
|
10860
|
-
var
|
|
11186
|
+
var import_react80 = require("react");
|
|
11187
|
+
var import_react81 = require("@ai-matrx/records/react");
|
|
11188
|
+
var import_design_system40 = require("@ai-matrx/design-system");
|
|
11189
|
+
var import_react82 = require("@ai-matrx/records/react");
|
|
11190
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
10861
11191
|
function SignBlock({ tableId, recordId, render, className }) {
|
|
10862
|
-
const client = (0,
|
|
10863
|
-
const table = (0,
|
|
11192
|
+
const client = (0, import_react81.useRecordsClient)();
|
|
11193
|
+
const table = (0, import_react82.useTable)(tableId);
|
|
10864
11194
|
const rights = useTableRights(table.data);
|
|
10865
|
-
const fields = (0,
|
|
10866
|
-
const [signatures, setSignatures] = (0,
|
|
10867
|
-
const [verdicts, setVerdicts] = (0,
|
|
10868
|
-
const [error, setError] = (0,
|
|
10869
|
-
const [name, setName] = (0,
|
|
10870
|
-
const [busy, setBusy] = (0,
|
|
10871
|
-
const load = (0,
|
|
11195
|
+
const fields = (0, import_react81.useFields)(tableId);
|
|
11196
|
+
const [signatures, setSignatures] = (0, import_react80.useState)(null);
|
|
11197
|
+
const [verdicts, setVerdicts] = (0, import_react80.useState)({});
|
|
11198
|
+
const [error, setError] = (0, import_react80.useState)(null);
|
|
11199
|
+
const [name, setName] = (0, import_react80.useState)("");
|
|
11200
|
+
const [busy, setBusy] = (0, import_react80.useState)(false);
|
|
11201
|
+
const load = (0, import_react80.useCallback)(async () => {
|
|
10872
11202
|
const held = await client.docSignatures({ record_id: recordId });
|
|
10873
11203
|
if (!held.ok) {
|
|
10874
11204
|
setError(held.error);
|
|
@@ -10883,7 +11213,7 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10883
11213
|
}
|
|
10884
11214
|
setVerdicts(answers);
|
|
10885
11215
|
}, [client, recordId]);
|
|
10886
|
-
(0,
|
|
11216
|
+
(0, import_react80.useEffect)(() => {
|
|
10887
11217
|
void load();
|
|
10888
11218
|
}, [load]);
|
|
10889
11219
|
async function sign(field) {
|
|
@@ -10903,58 +11233,58 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10903
11233
|
setName("");
|
|
10904
11234
|
await load();
|
|
10905
11235
|
}
|
|
10906
|
-
if (fields.error) return /* @__PURE__ */ (0,
|
|
11236
|
+
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(RefusalNotice, { error: fields.error, className });
|
|
10907
11237
|
if (error) {
|
|
10908
|
-
return /* @__PURE__ */ (0,
|
|
11238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
10909
11239
|
RefusalNotice,
|
|
10910
11240
|
{
|
|
10911
11241
|
error,
|
|
10912
11242
|
className,
|
|
10913
|
-
actions: /* @__PURE__ */ (0,
|
|
11243
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_design_system40.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10914
11244
|
}
|
|
10915
11245
|
);
|
|
10916
11246
|
}
|
|
10917
|
-
if (fields.loading || signatures === null) return /* @__PURE__ */ (0,
|
|
11247
|
+
if (fields.loading || signatures === null) return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_design_system40.Skeleton, { className: (0, import_design_system40.cn)("h-32 w-full", className) });
|
|
10918
11248
|
const signable = (fields.data ?? []).filter(isSignatureField);
|
|
10919
|
-
return /* @__PURE__ */ (0,
|
|
10920
|
-
/* @__PURE__ */ (0,
|
|
10921
|
-
/* @__PURE__ */ (0,
|
|
10922
|
-
/* @__PURE__ */ (0,
|
|
11249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: (0, import_design_system40.cn)("flex flex-col gap-2", className), children: [
|
|
11250
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
11251
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "font-medium text-foreground", children: "Signatures" }),
|
|
11252
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { children: [
|
|
10923
11253
|
signatures.length,
|
|
10924
11254
|
" on this record"
|
|
10925
11255
|
] })
|
|
10926
11256
|
] }),
|
|
10927
|
-
signatures.length > 0 ? /* @__PURE__ */ (0,
|
|
11257
|
+
signatures.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "flex flex-col gap-1", children: signatures.map((signature) => {
|
|
10928
11258
|
const verdict = verdicts[signature.id];
|
|
10929
11259
|
const intact = typeof verdict === "object" && verdict !== null ? verdict.intact : void 0;
|
|
10930
|
-
return /* @__PURE__ */ (0,
|
|
10931
|
-
/* @__PURE__ */ (0,
|
|
10932
|
-
/* @__PURE__ */ (0,
|
|
10933
|
-
/* @__PURE__ */ (0,
|
|
10934
|
-
/* @__PURE__ */ (0,
|
|
10935
|
-
/* @__PURE__ */ (0,
|
|
11260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("li", { className: "rounded border px-2 py-1.5 text-xs", children: [
|
|
11261
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
11262
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "font-medium", children: signature.signer_name }),
|
|
11263
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-muted-foreground", children: signature.field_key }),
|
|
11264
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-muted-foreground", children: new Date(signature.signed_at).toLocaleString() }),
|
|
11265
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground", children: [
|
|
10936
11266
|
"v",
|
|
10937
11267
|
signature.document_version,
|
|
10938
11268
|
" \xB7 ",
|
|
10939
11269
|
signature.document_hash.slice(0, 12)
|
|
10940
11270
|
] })
|
|
10941
11271
|
] }),
|
|
10942
|
-
/* @__PURE__ */ (0,
|
|
11272
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: (0, import_design_system40.cn)("mt-0.5", intact === false ? "text-destructive" : "text-muted-foreground"), children: intact === true ? "The store says what was signed is still exactly what is there." : intact === false ? typeof verdict === "object" && verdict !== null && "reason" in verdict ? String(verdict.reason) : "The store says what is there no longer matches what was signed." : String(verdict ?? "") })
|
|
10943
11273
|
] }, signature.id);
|
|
10944
11274
|
}) }) : null,
|
|
10945
|
-
!render ? /* @__PURE__ */ (0,
|
|
11275
|
+
!render ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-xs text-muted-foreground", children: 'Nothing has been frozen yet, so there is no version to sign. A signature seals one exact document version and its hash \u2014 "the document as it reads today" is not something anyone can agree to.' }) : signable.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
|
|
10946
11276
|
"This table has no signature Field, so there is nowhere to write a signature. A signature is a Value on a text Field whose format is ",
|
|
10947
|
-
/* @__PURE__ */ (0,
|
|
11277
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("code", { children: "signature" }),
|
|
10948
11278
|
" \u2014 add one and the signing appears."
|
|
10949
|
-
] }) : !rights.write ? /* @__PURE__ */ (0,
|
|
11279
|
+
] }) : !rights.write ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-xs text-muted-foreground", children: rights.why("write") }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex flex-col gap-1", children: signable.map((field) => {
|
|
10950
11280
|
const already = signatures.find((s) => s.field_key === field.key);
|
|
10951
11281
|
if (already) {
|
|
10952
|
-
return /* @__PURE__ */ (0,
|
|
11282
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
|
|
10953
11283
|
fieldName(field),
|
|
10954
11284
|
" is signed, and a signature is immutable once made. A further agreement is a further Field with its own signature, or a further version with its own seal."
|
|
10955
11285
|
] }, field.id);
|
|
10956
11286
|
}
|
|
10957
|
-
return /* @__PURE__ */ (0,
|
|
11287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
10958
11288
|
"form",
|
|
10959
11289
|
{
|
|
10960
11290
|
className: "flex items-center gap-1",
|
|
@@ -10963,8 +11293,8 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10963
11293
|
if (name.trim() !== "") void sign(field);
|
|
10964
11294
|
},
|
|
10965
11295
|
children: [
|
|
10966
|
-
/* @__PURE__ */ (0,
|
|
10967
|
-
|
|
11296
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
11297
|
+
import_design_system40.BasicInput,
|
|
10968
11298
|
{
|
|
10969
11299
|
className: "h-8 w-56 text-xs",
|
|
10970
11300
|
"aria-label": `Sign ${fieldName(field)}`,
|
|
@@ -10973,8 +11303,8 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10973
11303
|
onChange: (e) => setName(e.target.value)
|
|
10974
11304
|
}
|
|
10975
11305
|
),
|
|
10976
|
-
/* @__PURE__ */ (0,
|
|
10977
|
-
/* @__PURE__ */ (0,
|
|
11306
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_design_system40.Button, { size: "sm", type: "submit", disabled: busy || name.trim() === "", children: "Sign" }),
|
|
11307
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
10978
11308
|
"seals version ",
|
|
10979
11309
|
render.template_version,
|
|
10980
11310
|
" \xB7 ",
|
|
@@ -10990,32 +11320,32 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10990
11320
|
}
|
|
10991
11321
|
|
|
10992
11322
|
// src/NotifyRuleEditor.tsx
|
|
10993
|
-
var
|
|
10994
|
-
var
|
|
10995
|
-
var
|
|
10996
|
-
var
|
|
10997
|
-
var
|
|
11323
|
+
var import_react83 = require("react");
|
|
11324
|
+
var import_react84 = require("@ai-matrx/records/react");
|
|
11325
|
+
var import_design_system41 = require("@ai-matrx/design-system");
|
|
11326
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
11327
|
+
var CADENCE_WORDS2 = {
|
|
10998
11328
|
instant: "as it happens",
|
|
10999
11329
|
hourly: "hourly summary",
|
|
11000
11330
|
daily: "daily summary",
|
|
11001
11331
|
weekly: "weekly summary"
|
|
11002
11332
|
};
|
|
11003
|
-
var
|
|
11333
|
+
var CHANNEL_WORDS3 = {
|
|
11004
11334
|
in_app: "in the app",
|
|
11005
11335
|
email: "by email",
|
|
11006
11336
|
sms: "by text"
|
|
11007
11337
|
};
|
|
11008
11338
|
function NotifyRuleEditor({ tableId, seed, className }) {
|
|
11009
|
-
const client = (0,
|
|
11339
|
+
const client = (0, import_react84.useRecordsClient)();
|
|
11010
11340
|
const host = useRecordsUi();
|
|
11011
|
-
const table = (0,
|
|
11341
|
+
const table = (0, import_react84.useTable)(tableId);
|
|
11012
11342
|
const rights = useTableRights(table.data);
|
|
11013
|
-
const [subscriptions, setSubscriptions] = (0,
|
|
11014
|
-
const [cadences, setCadences] = (0,
|
|
11015
|
-
const [views, setViews] = (0,
|
|
11016
|
-
const [error, setError] = (0,
|
|
11017
|
-
const [busy, setBusy] = (0,
|
|
11018
|
-
const load = (0,
|
|
11343
|
+
const [subscriptions, setSubscriptions] = (0, import_react83.useState)(null);
|
|
11344
|
+
const [cadences, setCadences] = (0, import_react83.useState)([]);
|
|
11345
|
+
const [views, setViews] = (0, import_react83.useState)(null);
|
|
11346
|
+
const [error, setError] = (0, import_react83.useState)(null);
|
|
11347
|
+
const [busy, setBusy] = (0, import_react83.useState)(false);
|
|
11348
|
+
const load = (0, import_react83.useCallback)(async () => {
|
|
11019
11349
|
const [held, offered] = await Promise.all([
|
|
11020
11350
|
// THE PERSON'S OWN DOOR, not the notifier's. It answers what is addressed
|
|
11021
11351
|
// to them plus — only where they hold admin on this Table — anyone's over
|
|
@@ -11035,10 +11365,10 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11035
11365
|
if (host.savedViews) setViews(await host.savedViews());
|
|
11036
11366
|
else setViews(null);
|
|
11037
11367
|
}, [client, host, tableId]);
|
|
11038
|
-
(0,
|
|
11368
|
+
(0, import_react83.useEffect)(() => {
|
|
11039
11369
|
void load();
|
|
11040
11370
|
}, [load]);
|
|
11041
|
-
const write = (0,
|
|
11371
|
+
const write = (0, import_react83.useCallback)(
|
|
11042
11372
|
async (spec) => {
|
|
11043
11373
|
const declared = await client.subscriptionDeclare({
|
|
11044
11374
|
table_id: tableId,
|
|
@@ -11063,7 +11393,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11063
11393
|
},
|
|
11064
11394
|
[client, tableId]
|
|
11065
11395
|
);
|
|
11066
|
-
(0,
|
|
11396
|
+
(0, import_react83.useEffect)(() => {
|
|
11067
11397
|
if (!subscriptions || !seed || seed.length === 0) return;
|
|
11068
11398
|
const missing = seed.filter((s) => !subscriptions.some((held) => held.name === s.name));
|
|
11069
11399
|
if (missing.length === 0) return;
|
|
@@ -11077,7 +11407,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11077
11407
|
async function subscribe(viewId, viewName, cadence, channel, schedule, quiet) {
|
|
11078
11408
|
setBusy(true);
|
|
11079
11409
|
const ok = await write({
|
|
11080
|
-
name: `${viewName} \u2014 ${
|
|
11410
|
+
name: `${viewName} \u2014 ${CADENCE_WORDS2[cadence] ?? cadence}`,
|
|
11081
11411
|
savedViewId: viewId,
|
|
11082
11412
|
cadence,
|
|
11083
11413
|
channel,
|
|
@@ -11098,45 +11428,45 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11098
11428
|
await load();
|
|
11099
11429
|
}
|
|
11100
11430
|
if (error) {
|
|
11101
|
-
return /* @__PURE__ */ (0,
|
|
11431
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
11102
11432
|
RefusalNotice,
|
|
11103
11433
|
{
|
|
11104
11434
|
error,
|
|
11105
11435
|
className,
|
|
11106
|
-
actions: /* @__PURE__ */ (0,
|
|
11436
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_design_system41.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
11107
11437
|
}
|
|
11108
11438
|
);
|
|
11109
11439
|
}
|
|
11110
|
-
if (subscriptions === null) return /* @__PURE__ */ (0,
|
|
11111
|
-
return /* @__PURE__ */ (0,
|
|
11112
|
-
/* @__PURE__ */ (0,
|
|
11113
|
-
/* @__PURE__ */ (0,
|
|
11114
|
-
/* @__PURE__ */ (0,
|
|
11440
|
+
if (subscriptions === null) return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_design_system41.Skeleton, { className: (0, import_design_system41.cn)("h-40 w-full", className) });
|
|
11441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: (0, import_design_system41.cn)("flex flex-col gap-2", className), children: [
|
|
11442
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
11443
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium text-foreground", children: "Tell me when" }),
|
|
11444
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { children: [
|
|
11115
11445
|
subscriptions.length,
|
|
11116
11446
|
" subscription",
|
|
11117
11447
|
subscriptions.length === 1 ? "" : "s"
|
|
11118
11448
|
] })
|
|
11119
11449
|
] }),
|
|
11120
|
-
subscriptions.length === 0 ? /* @__PURE__ */ (0,
|
|
11121
|
-
/* @__PURE__ */ (0,
|
|
11122
|
-
/* @__PURE__ */ (0,
|
|
11123
|
-
/* @__PURE__ */ (0,
|
|
11124
|
-
held.schedule ? /* @__PURE__ */ (0,
|
|
11125
|
-
held.next_digest_at ? /* @__PURE__ */ (0,
|
|
11450
|
+
subscriptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-xs text-muted-foreground", children: "Nothing is telling anyone about this yet. A subscription is a Rule over a saved view, so what you are told about is exactly what that view holds." }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("ul", { className: "flex flex-col gap-1", children: subscriptions.map((held) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("li", { className: "flex items-center gap-2 rounded border px-2 py-1.5 text-xs", children: [
|
|
11451
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "truncate font-medium", children: held.name }),
|
|
11452
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-muted-foreground", children: CADENCE_WORDS2[held.cadence] ?? held.cadence }),
|
|
11453
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-muted-foreground", children: CHANNEL_WORDS3[held.channel] ?? held.channel }),
|
|
11454
|
+
held.schedule ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-muted-foreground", children: held.schedule }) : null,
|
|
11455
|
+
held.next_digest_at ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
11126
11456
|
"next ",
|
|
11127
11457
|
new Date(held.next_digest_at).toLocaleString()
|
|
11128
11458
|
] }) : null,
|
|
11129
|
-
held.quiet_hours ? /* @__PURE__ */ (0,
|
|
11459
|
+
held.quiet_hours ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
11130
11460
|
"quiet ",
|
|
11131
11461
|
held.quiet_hours.start,
|
|
11132
11462
|
"\u2013",
|
|
11133
11463
|
held.quiet_hours.end
|
|
11134
11464
|
] }) : null,
|
|
11135
|
-
held.recipient_user_id === null ? /* @__PURE__ */ (0,
|
|
11136
|
-
held.saved_view_id === null ? /* @__PURE__ */ (0,
|
|
11137
|
-
held.muted ? /* @__PURE__ */ (0,
|
|
11138
|
-
rights.write ? /* @__PURE__ */ (0,
|
|
11139
|
-
|
|
11465
|
+
held.recipient_user_id === null ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-destructive", children: "This one has nobody to tell, so it fires at nobody." }) : null,
|
|
11466
|
+
held.saved_view_id === null ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-destructive", children: "This one names no view, so the store never admits a record to it." }) : null,
|
|
11467
|
+
held.muted ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-muted-foreground", children: "Switched off \u2014 it tells nobody until somebody switches it back on." }) : null,
|
|
11468
|
+
rights.write ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
11469
|
+
import_design_system41.Button,
|
|
11140
11470
|
{
|
|
11141
11471
|
size: "sm",
|
|
11142
11472
|
variant: "ghost",
|
|
@@ -11147,7 +11477,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11147
11477
|
}
|
|
11148
11478
|
) : null
|
|
11149
11479
|
] }, held.rule_id)) }),
|
|
11150
|
-
views === null ? /* @__PURE__ */ (0,
|
|
11480
|
+
views === null ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_SAVED_VIEWS_REASON }) : views.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-xs text-muted-foreground", children: "This organization has no saved views yet, so there is nothing to subscribe to. Save a view first." }) : rights.write ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
11151
11481
|
"form",
|
|
11152
11482
|
{
|
|
11153
11483
|
className: "flex flex-wrap items-center gap-1",
|
|
@@ -11165,10 +11495,10 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11165
11495
|
if (view) void subscribe(view, name, cadence, channel, schedule, quiet);
|
|
11166
11496
|
},
|
|
11167
11497
|
children: [
|
|
11168
|
-
/* @__PURE__ */ (0,
|
|
11169
|
-
/* @__PURE__ */ (0,
|
|
11170
|
-
/* @__PURE__ */ (0,
|
|
11171
|
-
/* @__PURE__ */ (0,
|
|
11498
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { name: "view", "aria-label": "View to be told about", className: "h-7 rounded border bg-background px-1 text-xs", children: views.map((view) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: view.id, children: view.name }, view.id)) }),
|
|
11499
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { name: "cadence", "aria-label": "How often", className: "h-7 rounded border bg-background px-1 text-xs", children: (cadences.length > 0 ? cadences : ["instant"]).map((cadence) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: cadence, children: CADENCE_WORDS2[cadence] ?? cadence }, cadence)) }),
|
|
11500
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { name: "channel", "aria-label": "Where it arrives", className: "h-7 rounded border bg-background px-1 text-xs", children: ["in_app", "email", "sms"].map((channel) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: channel, children: CHANNEL_WORDS3[channel] }, channel)) }),
|
|
11501
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
11172
11502
|
"input",
|
|
11173
11503
|
{
|
|
11174
11504
|
name: "schedule",
|
|
@@ -11177,8 +11507,8 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11177
11507
|
className: "h-7 w-28 rounded border bg-background px-1 text-xs"
|
|
11178
11508
|
}
|
|
11179
11509
|
),
|
|
11180
|
-
/* @__PURE__ */ (0,
|
|
11181
|
-
/* @__PURE__ */ (0,
|
|
11510
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-xs text-muted-foreground", children: "not between" }),
|
|
11511
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
11182
11512
|
"input",
|
|
11183
11513
|
{
|
|
11184
11514
|
name: "quiet_start",
|
|
@@ -11187,8 +11517,8 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11187
11517
|
className: "h-7 rounded border bg-background px-1 text-xs"
|
|
11188
11518
|
}
|
|
11189
11519
|
),
|
|
11190
|
-
/* @__PURE__ */ (0,
|
|
11191
|
-
/* @__PURE__ */ (0,
|
|
11520
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-xs text-muted-foreground", children: "and" }),
|
|
11521
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
11192
11522
|
"input",
|
|
11193
11523
|
{
|
|
11194
11524
|
name: "quiet_end",
|
|
@@ -11197,21 +11527,21 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11197
11527
|
className: "h-7 rounded border bg-background px-1 text-xs"
|
|
11198
11528
|
}
|
|
11199
11529
|
),
|
|
11200
|
-
/* @__PURE__ */ (0,
|
|
11201
|
-
/* @__PURE__ */ (0,
|
|
11530
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_design_system41.Button, { size: "sm", type: "submit", disabled: busy, children: "Tell me" }),
|
|
11531
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: "A send inside your quiet hours is held until they end \u2014 it is never dropped. Leave the schedule blank for the store's own default of 08:00." })
|
|
11202
11532
|
]
|
|
11203
11533
|
}
|
|
11204
|
-
) : /* @__PURE__ */ (0,
|
|
11534
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "text-xs text-muted-foreground", children: rights.why("write") })
|
|
11205
11535
|
] });
|
|
11206
11536
|
}
|
|
11207
11537
|
|
|
11208
11538
|
// src/ChartBlock.tsx
|
|
11209
|
-
var
|
|
11539
|
+
var import_react85 = require("react");
|
|
11210
11540
|
var import_recharts = require("recharts");
|
|
11211
11541
|
var import_records7 = require("@ai-matrx/records");
|
|
11212
11542
|
var import_core6 = require("@ai-matrx/records/core");
|
|
11213
|
-
var
|
|
11214
|
-
var
|
|
11543
|
+
var import_design_system42 = require("@ai-matrx/design-system");
|
|
11544
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
11215
11545
|
function pretty(n) {
|
|
11216
11546
|
return Number.isInteger(n) ? n.toLocaleString() : n.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
11217
11547
|
}
|
|
@@ -11231,7 +11561,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11231
11561
|
const measures = block.measures && block.measures.length > 0 ? block.measures : [{ op: "count" }];
|
|
11232
11562
|
const primary = (0, import_records7.measureKey)(measures[0]);
|
|
11233
11563
|
const series = [primary];
|
|
11234
|
-
const points = (0,
|
|
11564
|
+
const points = (0, import_react85.useMemo)(() => {
|
|
11235
11565
|
if (kind === "stuck") return [];
|
|
11236
11566
|
const rows = block.rows ?? [];
|
|
11237
11567
|
return rows.map((row) => ({
|
|
@@ -11243,7 +11573,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11243
11573
|
n: row.row_count
|
|
11244
11574
|
}));
|
|
11245
11575
|
}, [block.rows, kind, series.join("|")]);
|
|
11246
|
-
const config = (0,
|
|
11576
|
+
const config = (0, import_react85.useMemo)(() => {
|
|
11247
11577
|
const out = {};
|
|
11248
11578
|
series.forEach((key, index) => {
|
|
11249
11579
|
out[key] = {
|
|
@@ -11267,18 +11597,18 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11267
11597
|
label: point.label === "All records" ? block.title : `${block.title} \xB7 ${point.label}`
|
|
11268
11598
|
});
|
|
11269
11599
|
} : null;
|
|
11270
|
-
return /* @__PURE__ */ (0,
|
|
11271
|
-
/* @__PURE__ */ (0,
|
|
11272
|
-
/* @__PURE__ */ (0,
|
|
11273
|
-
/* @__PURE__ */ (0,
|
|
11274
|
-
typeof block.ms === "number" ? /* @__PURE__ */ (0,
|
|
11600
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("figure", { className: (0, import_design_system42.cn)("flex min-w-0 flex-col gap-1.5 rounded border p-2", className), children: [
|
|
11601
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("figcaption", { className: "flex items-baseline gap-2 text-xs", children: [
|
|
11602
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "truncate font-medium", children: block.title || CHART_KIND_LABEL[kind] }),
|
|
11603
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "ml-auto shrink-0 text-muted-foreground", children: kind === "stuck" ? `${block.days ?? 14} days` : primary.replace("_", " of ") }),
|
|
11604
|
+
typeof block.ms === "number" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "shrink-0 tabular-nums text-muted-foreground/70", title: "how long the store took", children: [
|
|
11275
11605
|
pretty(block.ms),
|
|
11276
11606
|
" ms"
|
|
11277
11607
|
] }) : null
|
|
11278
11608
|
] }),
|
|
11279
|
-
block.refused ? /* @__PURE__ */ (0,
|
|
11280
|
-
/* @__PURE__ */ (0,
|
|
11281
|
-
/* @__PURE__ */ (0,
|
|
11609
|
+
block.refused ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(RefusalNotice, { error: asRefusal(block) }) : needs ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "px-1 py-3 text-xs text-muted-foreground", children: needs }) : kind === "stuck" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(StuckList, { rows: block.rows ?? [] }) : points.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "px-1 py-3 text-xs text-muted-foreground", children: "The store answered this question with no groups at all, so there is nothing to draw yet." }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_jsx_runtime45.Fragment, { children: kind === "number" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(BigNumber, { points, measure: primary, onDrill: drill }) : kind === "table" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(GroupTable, { points, series, onDrill: drill }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
11610
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Drawing, { kind, points, series, config, onDrill: drill }),
|
|
11611
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Values, { points, measure: primary, config, onDrill: drill })
|
|
11282
11612
|
] }) })
|
|
11283
11613
|
] });
|
|
11284
11614
|
}
|
|
@@ -11289,16 +11619,16 @@ function BigNumber({
|
|
|
11289
11619
|
}) {
|
|
11290
11620
|
const total = points.reduce((sum, p) => sum + (p.values[measure] ?? 0), 0);
|
|
11291
11621
|
const records = points.reduce((sum, p) => sum + p.n, 0);
|
|
11292
|
-
const body = /* @__PURE__ */ (0,
|
|
11293
|
-
/* @__PURE__ */ (0,
|
|
11294
|
-
/* @__PURE__ */ (0,
|
|
11622
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
11623
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-2xl font-semibold tabular-nums", children: pretty(total) }),
|
|
11624
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
11295
11625
|
"from ",
|
|
11296
11626
|
records.toLocaleString(),
|
|
11297
11627
|
" records"
|
|
11298
11628
|
] })
|
|
11299
11629
|
] });
|
|
11300
|
-
if (!onDrill || !points[0]) return /* @__PURE__ */ (0,
|
|
11301
|
-
return /* @__PURE__ */ (0,
|
|
11630
|
+
if (!onDrill || !points[0]) return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex items-baseline gap-2 px-1 py-2", children: body });
|
|
11631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11302
11632
|
"button",
|
|
11303
11633
|
{
|
|
11304
11634
|
type: "button",
|
|
@@ -11314,19 +11644,19 @@ function Values({
|
|
|
11314
11644
|
config,
|
|
11315
11645
|
onDrill
|
|
11316
11646
|
}) {
|
|
11317
|
-
return /* @__PURE__ */ (0,
|
|
11318
|
-
const text = /* @__PURE__ */ (0,
|
|
11319
|
-
/* @__PURE__ */ (0,
|
|
11647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "flex flex-wrap gap-x-2 gap-y-0.5", children: points.map((point) => {
|
|
11648
|
+
const text = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
11649
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11320
11650
|
"span",
|
|
11321
11651
|
{
|
|
11322
11652
|
className: "h-2 w-2 shrink-0 rounded-[2px]",
|
|
11323
11653
|
style: { background: String(config[point.label]?.color ?? SERIES_COLORS[0]) }
|
|
11324
11654
|
}
|
|
11325
11655
|
),
|
|
11326
|
-
/* @__PURE__ */ (0,
|
|
11327
|
-
/* @__PURE__ */ (0,
|
|
11656
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "truncate", children: point.label }),
|
|
11657
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "tabular-nums text-muted-foreground", children: pretty(point.values[measure] ?? 0) })
|
|
11328
11658
|
] });
|
|
11329
|
-
return /* @__PURE__ */ (0,
|
|
11659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("li", { className: "min-w-0", children: onDrill ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11330
11660
|
"button",
|
|
11331
11661
|
{
|
|
11332
11662
|
type: "button",
|
|
@@ -11334,7 +11664,7 @@ function Values({
|
|
|
11334
11664
|
onClick: () => onDrill(point),
|
|
11335
11665
|
children: text
|
|
11336
11666
|
}
|
|
11337
|
-
) : /* @__PURE__ */ (0,
|
|
11667
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "flex min-w-0 items-center gap-1.5 px-1 py-0.5 text-xs", children: text }) }, point.label);
|
|
11338
11668
|
}) });
|
|
11339
11669
|
}
|
|
11340
11670
|
function GroupTable({
|
|
@@ -11342,8 +11672,8 @@ function GroupTable({
|
|
|
11342
11672
|
series,
|
|
11343
11673
|
onDrill
|
|
11344
11674
|
}) {
|
|
11345
|
-
return /* @__PURE__ */ (0,
|
|
11346
|
-
/* @__PURE__ */ (0,
|
|
11675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("table", { className: "w-full text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("tbody", { children: points.map((point) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { className: "border-t first:border-t-0", children: [
|
|
11676
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "min-w-0 truncate py-0.5 pr-2", children: onDrill ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11347
11677
|
"button",
|
|
11348
11678
|
{
|
|
11349
11679
|
type: "button",
|
|
@@ -11352,29 +11682,29 @@ function GroupTable({
|
|
|
11352
11682
|
children: point.label
|
|
11353
11683
|
}
|
|
11354
11684
|
) : point.label }),
|
|
11355
|
-
series.map((key) => /* @__PURE__ */ (0,
|
|
11356
|
-
/* @__PURE__ */ (0,
|
|
11685
|
+
series.map((key) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "py-0.5 pl-2 text-right tabular-nums", children: pretty(point.values[key] ?? 0) }, key)),
|
|
11686
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "py-0.5 pl-2 text-right tabular-nums text-muted-foreground", children: point.n })
|
|
11357
11687
|
] }, point.label)) }) });
|
|
11358
11688
|
}
|
|
11359
11689
|
function StuckList({ rows }) {
|
|
11360
11690
|
if (rows.length === 0) {
|
|
11361
|
-
return /* @__PURE__ */ (0,
|
|
11691
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "px-1 py-3 text-xs text-muted-foreground", children: "Nothing has sat still this long. This block goes quiet when the work is moving." });
|
|
11362
11692
|
}
|
|
11363
|
-
return /* @__PURE__ */ (0,
|
|
11364
|
-
/* @__PURE__ */ (0,
|
|
11365
|
-
/* @__PURE__ */ (0,
|
|
11366
|
-
/* @__PURE__ */ (0,
|
|
11367
|
-
/* @__PURE__ */ (0,
|
|
11693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("table", { className: "w-full table-fixed text-xs", children: [
|
|
11694
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("colgroup", { children: [
|
|
11695
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("col", { className: "w-[45%]" }),
|
|
11696
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("col", { className: "w-[33%]" }),
|
|
11697
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("col", { className: "w-[22%]" })
|
|
11368
11698
|
] }),
|
|
11369
|
-
/* @__PURE__ */ (0,
|
|
11370
|
-
/* @__PURE__ */ (0,
|
|
11371
|
-
/* @__PURE__ */ (0,
|
|
11372
|
-
/* @__PURE__ */ (0,
|
|
11699
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("thead", { className: "sr-only", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { children: [
|
|
11700
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { children: "Record" }),
|
|
11701
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { children: "Where it is" }),
|
|
11702
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("th", { children: "Days unchanged" })
|
|
11373
11703
|
] }) }),
|
|
11374
|
-
/* @__PURE__ */ (0,
|
|
11375
|
-
/* @__PURE__ */ (0,
|
|
11376
|
-
/* @__PURE__ */ (0,
|
|
11377
|
-
/* @__PURE__ */ (0,
|
|
11704
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("tr", { className: "border-t first:border-t-0", children: [
|
|
11705
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "truncate py-0.5 pr-2", title: row.title ?? void 0, children: row.title ?? row.record_id.slice(0, 8) }),
|
|
11706
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("td", { className: "truncate py-0.5 pr-2 text-muted-foreground", title: row.state ?? void 0, children: row.state ?? "\u2014" }),
|
|
11707
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
11378
11708
|
"td",
|
|
11379
11709
|
{
|
|
11380
11710
|
className: "whitespace-nowrap py-0.5 text-right tabular-nums",
|
|
@@ -11424,12 +11754,12 @@ function Drawing({
|
|
|
11424
11754
|
axisLine: false,
|
|
11425
11755
|
tickFormatter: compactTick
|
|
11426
11756
|
};
|
|
11427
|
-
const tooltip = /* @__PURE__ */ (0,
|
|
11428
|
-
const legend = series.length > 1 ? /* @__PURE__ */ (0,
|
|
11757
|
+
const tooltip = /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartTooltipContent, { config }), cursor: false });
|
|
11758
|
+
const legend = series.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.Legend, { content: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartLegendContent, { config }) }) : null;
|
|
11429
11759
|
if (kind === "donut") {
|
|
11430
|
-
return /* @__PURE__ */ (0,
|
|
11760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_recharts.PieChart, { width, height: HEIGHT, children: [
|
|
11431
11761
|
tooltip,
|
|
11432
|
-
/* @__PURE__ */ (0,
|
|
11762
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11433
11763
|
import_recharts.Pie,
|
|
11434
11764
|
{
|
|
11435
11765
|
data,
|
|
@@ -11439,19 +11769,19 @@ function Drawing({
|
|
|
11439
11769
|
outerRadius: 58,
|
|
11440
11770
|
isAnimationActive: false,
|
|
11441
11771
|
...click ? { onClick: click, className: "cursor-pointer" } : {},
|
|
11442
|
-
children: points.map((point) => /* @__PURE__ */ (0,
|
|
11772
|
+
children: points.map((point) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.Cell, { fill: String(config[point.label]?.color ?? SERIES_COLORS[0]) }, point.label))
|
|
11443
11773
|
}
|
|
11444
11774
|
)
|
|
11445
11775
|
] }) });
|
|
11446
11776
|
}
|
|
11447
11777
|
if (kind === "line") {
|
|
11448
|
-
return /* @__PURE__ */ (0,
|
|
11449
|
-
/* @__PURE__ */ (0,
|
|
11450
|
-
/* @__PURE__ */ (0,
|
|
11451
|
-
/* @__PURE__ */ (0,
|
|
11778
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_recharts.LineChart, { width, height: HEIGHT, data, margin: { top: 6, right: 6, bottom: 0, left: 0 }, children: [
|
|
11779
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.CartesianGrid, { vertical: false }),
|
|
11780
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.XAxis, { dataKey: "label", ...axis }),
|
|
11781
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.YAxis, { width: 44, ...axis }),
|
|
11452
11782
|
tooltip,
|
|
11453
11783
|
legend,
|
|
11454
|
-
series.map((key) => /* @__PURE__ */ (0,
|
|
11784
|
+
series.map((key) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11455
11785
|
import_recharts.Line,
|
|
11456
11786
|
{
|
|
11457
11787
|
type: "monotone",
|
|
@@ -11467,7 +11797,7 @@ function Drawing({
|
|
|
11467
11797
|
] }) });
|
|
11468
11798
|
}
|
|
11469
11799
|
const horizontal = kind === "bar";
|
|
11470
|
-
return /* @__PURE__ */ (0,
|
|
11800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
11471
11801
|
import_recharts.BarChart,
|
|
11472
11802
|
{
|
|
11473
11803
|
width,
|
|
@@ -11476,17 +11806,17 @@ function Drawing({
|
|
|
11476
11806
|
layout: horizontal ? "vertical" : "horizontal",
|
|
11477
11807
|
margin: { top: 6, right: 6, bottom: 0, left: 0 },
|
|
11478
11808
|
children: [
|
|
11479
|
-
/* @__PURE__ */ (0,
|
|
11480
|
-
horizontal ? /* @__PURE__ */ (0,
|
|
11481
|
-
/* @__PURE__ */ (0,
|
|
11482
|
-
/* @__PURE__ */ (0,
|
|
11483
|
-
] }) : /* @__PURE__ */ (0,
|
|
11484
|
-
/* @__PURE__ */ (0,
|
|
11485
|
-
/* @__PURE__ */ (0,
|
|
11809
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.CartesianGrid, { vertical: horizontal, horizontal: !horizontal }),
|
|
11810
|
+
horizontal ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
11811
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.XAxis, { type: "number", ...axis }),
|
|
11812
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.YAxis, { type: "category", dataKey: "label", width: 88, ...axis })
|
|
11813
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
|
|
11814
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.XAxis, { dataKey: "label", ...axis }),
|
|
11815
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.YAxis, { width: 44, ...axis })
|
|
11486
11816
|
] }),
|
|
11487
11817
|
tooltip,
|
|
11488
11818
|
legend,
|
|
11489
|
-
series.map((key, index) => /* @__PURE__ */ (0,
|
|
11819
|
+
series.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
11490
11820
|
import_recharts.Bar,
|
|
11491
11821
|
{
|
|
11492
11822
|
dataKey: key,
|
|
@@ -11494,7 +11824,7 @@ function Drawing({
|
|
|
11494
11824
|
isAnimationActive: false,
|
|
11495
11825
|
fill: `var(--color-${key})`,
|
|
11496
11826
|
...click ? { onClick: click, className: "cursor-pointer" } : {},
|
|
11497
|
-
children: series.length === 1 ? points.map((point) => /* @__PURE__ */ (0,
|
|
11827
|
+
children: series.length === 1 ? points.map((point) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_recharts.Cell, { fill: String(config[point.label]?.color ?? SERIES_COLORS[index]) }, point.label)) : null
|
|
11498
11828
|
},
|
|
11499
11829
|
key
|
|
11500
11830
|
))
|
|
@@ -11504,24 +11834,25 @@ function Drawing({
|
|
|
11504
11834
|
}
|
|
11505
11835
|
|
|
11506
11836
|
// src/DashboardCanvas.tsx
|
|
11507
|
-
var
|
|
11508
|
-
var
|
|
11509
|
-
var
|
|
11510
|
-
var
|
|
11837
|
+
var import_react86 = require("react");
|
|
11838
|
+
var import_react87 = require("@ai-matrx/records/react");
|
|
11839
|
+
var import_design_system43 = require("@ai-matrx/design-system");
|
|
11840
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
11511
11841
|
function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
11512
|
-
const client = (0,
|
|
11842
|
+
const client = (0, import_react87.useRecordsClient)();
|
|
11513
11843
|
const host = useRecordsUi();
|
|
11514
|
-
const table = (0,
|
|
11844
|
+
const table = (0, import_react87.useTable)(tableId);
|
|
11515
11845
|
const rights = useTableRights(table.data);
|
|
11516
|
-
const fields = (0,
|
|
11517
|
-
const [boards, setBoards] = (0,
|
|
11518
|
-
const [error, setError] = (0,
|
|
11519
|
-
const [activeId, setActiveId] = (0,
|
|
11520
|
-
const [run, setRun] = (0,
|
|
11521
|
-
const [running, setRunning] = (0,
|
|
11522
|
-
const [question, setQuestion] = (0,
|
|
11523
|
-
const [asking, setAsking] = (0,
|
|
11524
|
-
const
|
|
11846
|
+
const fields = (0, import_react87.useFields)(tableId);
|
|
11847
|
+
const [boards, setBoards] = (0, import_react86.useState)(null);
|
|
11848
|
+
const [error, setError] = (0, import_react86.useState)(null);
|
|
11849
|
+
const [activeId, setActiveId] = (0, import_react86.useState)(activeDashboardId ?? null);
|
|
11850
|
+
const [run, setRun] = (0, import_react86.useState)(null);
|
|
11851
|
+
const [running, setRunning] = (0, import_react86.useState)(false);
|
|
11852
|
+
const [question, setQuestion] = (0, import_react86.useState)("");
|
|
11853
|
+
const [asking, setAsking] = (0, import_react86.useState)(false);
|
|
11854
|
+
const [scheduling, setScheduling] = (0, import_react86.useState)(false);
|
|
11855
|
+
const load = (0, import_react86.useCallback)(async () => {
|
|
11525
11856
|
const answered = await client.dashboards({ table_id: tableId });
|
|
11526
11857
|
if (!answered.ok) {
|
|
11527
11858
|
setError(answered.error);
|
|
@@ -11530,17 +11861,17 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11530
11861
|
setError(null);
|
|
11531
11862
|
setBoards(answered.data.map(dashboardFromSummary));
|
|
11532
11863
|
}, [client, tableId]);
|
|
11533
|
-
(0,
|
|
11864
|
+
(0, import_react86.useEffect)(() => {
|
|
11534
11865
|
void load();
|
|
11535
11866
|
}, [load]);
|
|
11536
|
-
(0,
|
|
11867
|
+
(0, import_react86.useEffect)(() => {
|
|
11537
11868
|
if (!boards || boards.length === 0) return;
|
|
11538
11869
|
const chosen = boards.find((d) => d.id === (activeDashboardId ?? activeId)) ?? boards[0];
|
|
11539
11870
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
11540
11871
|
}, [boards, activeDashboardId]);
|
|
11541
|
-
const board = (0,
|
|
11872
|
+
const board = (0, import_react86.useMemo)(() => boards?.find((d) => d.id === activeId) ?? null, [boards, activeId]);
|
|
11542
11873
|
const filterKey = JSON.stringify(filter ?? {});
|
|
11543
|
-
(0,
|
|
11874
|
+
(0, import_react86.useEffect)(() => {
|
|
11544
11875
|
if (!activeId) {
|
|
11545
11876
|
setRun(null);
|
|
11546
11877
|
return;
|
|
@@ -11558,7 +11889,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11558
11889
|
cancelled = true;
|
|
11559
11890
|
};
|
|
11560
11891
|
}, [client, activeId, filterKey]);
|
|
11561
|
-
const declare2 = (0,
|
|
11892
|
+
const declare2 = (0, import_react86.useCallback)(
|
|
11562
11893
|
async (next, blocks) => {
|
|
11563
11894
|
const written = await client.dashboardDeclare(
|
|
11564
11895
|
dashboardDeclareArgs({ ...next, blocks }, tableId)
|
|
@@ -11604,7 +11935,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11604
11935
|
]
|
|
11605
11936
|
);
|
|
11606
11937
|
}
|
|
11607
|
-
const refresh = (0,
|
|
11938
|
+
const refresh = (0, import_react86.useCallback)(async () => {
|
|
11608
11939
|
if (!activeId) return;
|
|
11609
11940
|
setRunning(true);
|
|
11610
11941
|
const again = await client.dashboardRun({
|
|
@@ -11645,20 +11976,20 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11645
11976
|
}
|
|
11646
11977
|
}
|
|
11647
11978
|
if (error) {
|
|
11648
|
-
return /* @__PURE__ */ (0,
|
|
11979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
11649
11980
|
RefusalNotice,
|
|
11650
11981
|
{
|
|
11651
11982
|
error,
|
|
11652
11983
|
className,
|
|
11653
|
-
actions: /* @__PURE__ */ (0,
|
|
11984
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Button, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
11654
11985
|
}
|
|
11655
11986
|
);
|
|
11656
11987
|
}
|
|
11657
|
-
if (boards === null) return /* @__PURE__ */ (0,
|
|
11658
|
-
return /* @__PURE__ */ (0,
|
|
11659
|
-
/* @__PURE__ */ (0,
|
|
11660
|
-
boards.map((d) => /* @__PURE__ */ (0,
|
|
11661
|
-
|
|
11988
|
+
if (boards === null) return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Skeleton, { className: (0, import_design_system43.cn)("h-64 w-full", className) });
|
|
11989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: (0, import_design_system43.cn)("flex min-h-0 flex-col gap-2", className), children: [
|
|
11990
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Dashboards", children: [
|
|
11991
|
+
boards.map((d) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
11992
|
+
import_design_system43.Button,
|
|
11662
11993
|
{
|
|
11663
11994
|
size: "sm",
|
|
11664
11995
|
variant: d.id === activeId ? "secondary" : "ghost",
|
|
@@ -11668,10 +11999,10 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11668
11999
|
},
|
|
11669
12000
|
d.id
|
|
11670
12001
|
)),
|
|
11671
|
-
rights.admin ? /* @__PURE__ */ (0,
|
|
11672
|
-
board ? /* @__PURE__ */ (0,
|
|
11673
|
-
/* @__PURE__ */ (0,
|
|
11674
|
-
|
|
12002
|
+
rights.admin ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Button, { size: "sm", variant: "ghost", onClick: () => void create(), children: "New dashboard" }) : null,
|
|
12003
|
+
board ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "ml-auto flex items-center gap-1", children: [
|
|
12004
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
12005
|
+
import_design_system43.Button,
|
|
11675
12006
|
{
|
|
11676
12007
|
size: "sm",
|
|
11677
12008
|
variant: "ghost",
|
|
@@ -11680,13 +12011,31 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11680
12011
|
children: running ? "Asking" : "Refresh"
|
|
11681
12012
|
}
|
|
11682
12013
|
),
|
|
11683
|
-
|
|
12014
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
12015
|
+
import_design_system43.Button,
|
|
12016
|
+
{
|
|
12017
|
+
size: "sm",
|
|
12018
|
+
variant: scheduling ? "secondary" : "ghost",
|
|
12019
|
+
onClick: () => setScheduling((v) => !v),
|
|
12020
|
+
children: scheduling ? "Done" : "Send on a schedule"
|
|
12021
|
+
}
|
|
12022
|
+
),
|
|
12023
|
+
rights.admin ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Button, { size: "sm", variant: "ghost", onClick: () => void remove(board), children: "Delete" }) : null
|
|
11684
12024
|
] }) : null
|
|
11685
12025
|
] }),
|
|
11686
|
-
board ? /* @__PURE__ */ (0,
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
12026
|
+
board && scheduling ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
12027
|
+
DigestScheduler,
|
|
12028
|
+
{
|
|
12029
|
+
tableId,
|
|
12030
|
+
subjectName: board.name,
|
|
12031
|
+
...filter ? { filters: filter } : {},
|
|
12032
|
+
onClose: () => setScheduling(false)
|
|
12033
|
+
}
|
|
12034
|
+
) : null,
|
|
12035
|
+
board ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
12036
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
12037
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
12038
|
+
import_design_system43.BasicInput,
|
|
11690
12039
|
{
|
|
11691
12040
|
value: question,
|
|
11692
12041
|
"aria-label": "Ask for a change to this dashboard",
|
|
@@ -11699,15 +12048,15 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11699
12048
|
className: "h-8 min-w-0 flex-1 text-xs"
|
|
11700
12049
|
}
|
|
11701
12050
|
),
|
|
11702
|
-
/* @__PURE__ */ (0,
|
|
12051
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Button, { size: "sm", disabled: !host.onReask || asking || question.trim() === "", onClick: () => void reask(), children: asking ? "Asking" : "Ask" })
|
|
11703
12052
|
] }),
|
|
11704
|
-
!host.onReask ? /* @__PURE__ */ (0,
|
|
12053
|
+
!host.onReask ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-xs text-muted-foreground", children: NO_REASK_REASON }) : null
|
|
11705
12054
|
] }) : null,
|
|
11706
|
-
!board ? /* @__PURE__ */ (0,
|
|
11707
|
-
/* @__PURE__ */ (0,
|
|
11708
|
-
/* @__PURE__ */ (0,
|
|
11709
|
-
rights.admin && board.blocks[index] ? /* @__PURE__ */ (0,
|
|
11710
|
-
/* @__PURE__ */ (0,
|
|
12055
|
+
!board ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-xs text-muted-foreground", children: rights.admin ? "No dashboard looks at this table yet. \u201CNew dashboard\u201D makes one, or ask an agent for the one you want and it writes the whole thing." : rights.why("structure") }) : run === null ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_design_system43.Skeleton, { className: "h-64 w-full" }) : run.blocks.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-xs text-muted-foreground", children: "This dashboard has no blocks yet. Each one is a single question the store answers \u2014 grouped, bucketed and measured inside the read door." }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
12056
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-3", children: run.blocks.map((block, index) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [
|
|
12057
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ChartBlock, { block, subject: tableId }),
|
|
12058
|
+
rights.admin && board.blocks[index] ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1 text-xs", children: [
|
|
12059
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
11711
12060
|
"select",
|
|
11712
12061
|
{
|
|
11713
12062
|
"aria-label": `Shape of ${block.title}`,
|
|
@@ -11719,11 +12068,11 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11719
12068
|
(b, i) => i === index ? { ...b, kind: e.target.value } : b
|
|
11720
12069
|
)
|
|
11721
12070
|
),
|
|
11722
|
-
children: CHART_KINDS.map((kind) => /* @__PURE__ */ (0,
|
|
12071
|
+
children: CHART_KINDS.map((kind) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("option", { value: kind, children: CHART_KIND_LABEL[kind] }, kind))
|
|
11723
12072
|
}
|
|
11724
12073
|
),
|
|
11725
|
-
/* @__PURE__ */ (0,
|
|
11726
|
-
|
|
12074
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
12075
|
+
import_design_system43.Button,
|
|
11727
12076
|
{
|
|
11728
12077
|
size: "sm",
|
|
11729
12078
|
variant: "ghost",
|
|
@@ -11736,17 +12085,17 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11736
12085
|
)
|
|
11737
12086
|
] }) : null
|
|
11738
12087
|
] }, `${block.title}-${index}`)) }),
|
|
11739
|
-
!host.openRecords ? /* @__PURE__ */ (0,
|
|
12088
|
+
!host.openRecords ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "text-xs text-muted-foreground", children: NO_OPEN_RECORDS_REASON }) : null
|
|
11740
12089
|
] })
|
|
11741
12090
|
] });
|
|
11742
12091
|
}
|
|
11743
12092
|
|
|
11744
12093
|
// src/FormsPanel.tsx
|
|
11745
|
-
var
|
|
11746
|
-
var
|
|
12094
|
+
var import_react88 = require("react");
|
|
12095
|
+
var import_react89 = require("@ai-matrx/records/react");
|
|
11747
12096
|
var import_records8 = require("@ai-matrx/records");
|
|
11748
|
-
var
|
|
11749
|
-
var
|
|
12097
|
+
var import_design_system44 = require("@ai-matrx/design-system");
|
|
12098
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
11750
12099
|
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.";
|
|
11751
12100
|
var NO_ADMIN = "This table has no forms. Making one needs the admin level on it, because a form decides what people with no account may add here.";
|
|
11752
12101
|
function formSuggestion(tableName2) {
|
|
@@ -11754,16 +12103,16 @@ function formSuggestion(tableName2) {
|
|
|
11754
12103
|
return `Make me a form that collects new ${subject} entries and tells me when somebody answers.`;
|
|
11755
12104
|
}
|
|
11756
12105
|
function FormsPanel({ tableId, className }) {
|
|
11757
|
-
const client = (0,
|
|
12106
|
+
const client = (0, import_react89.useRecordsClient)();
|
|
11758
12107
|
const host = useRecordsUi();
|
|
11759
|
-
const table = (0,
|
|
12108
|
+
const table = (0, import_react89.useTable)(tableId);
|
|
11760
12109
|
const rights = useTableRights(table.data);
|
|
11761
|
-
const [forms, setForms] = (0,
|
|
11762
|
-
const [error, setError] = (0,
|
|
11763
|
-
const [busy, setBusy] = (0,
|
|
11764
|
-
const [copied, setCopied] = (0,
|
|
11765
|
-
const [building, setBuilding] = (0,
|
|
11766
|
-
const load = (0,
|
|
12110
|
+
const [forms, setForms] = (0, import_react88.useState)(null);
|
|
12111
|
+
const [error, setError] = (0, import_react88.useState)(null);
|
|
12112
|
+
const [busy, setBusy] = (0, import_react88.useState)(null);
|
|
12113
|
+
const [copied, setCopied] = (0, import_react88.useState)(null);
|
|
12114
|
+
const [building, setBuilding] = (0, import_react88.useState)(false);
|
|
12115
|
+
const load = (0, import_react88.useCallback)(async () => {
|
|
11767
12116
|
const answered = await client.forms({ table_id: tableId });
|
|
11768
12117
|
if (!answered.ok) {
|
|
11769
12118
|
setError(answered.error);
|
|
@@ -11773,10 +12122,10 @@ function FormsPanel({ tableId, className }) {
|
|
|
11773
12122
|
setError(null);
|
|
11774
12123
|
setForms(answered.data);
|
|
11775
12124
|
}, [client, tableId]);
|
|
11776
|
-
(0,
|
|
12125
|
+
(0, import_react88.useEffect)(() => {
|
|
11777
12126
|
void load();
|
|
11778
12127
|
}, [load]);
|
|
11779
|
-
const toggle = (0,
|
|
12128
|
+
const toggle = (0, import_react88.useCallback)(
|
|
11780
12129
|
async (form) => {
|
|
11781
12130
|
setBusy(form.form_id);
|
|
11782
12131
|
const wanted = form.published_at === null || form.closed_at !== null;
|
|
@@ -11790,8 +12139,8 @@ function FormsPanel({ tableId, className }) {
|
|
|
11790
12139
|
},
|
|
11791
12140
|
[client, load]
|
|
11792
12141
|
);
|
|
11793
|
-
const [shown, setShown] = (0,
|
|
11794
|
-
const copy = (0,
|
|
12142
|
+
const [shown, setShown] = (0, import_react88.useState)(null);
|
|
12143
|
+
const copy = (0, import_react88.useCallback)(async (url, formId) => {
|
|
11795
12144
|
try {
|
|
11796
12145
|
await navigator.clipboard.writeText(url);
|
|
11797
12146
|
setCopied(formId);
|
|
@@ -11801,17 +12150,17 @@ function FormsPanel({ tableId, className }) {
|
|
|
11801
12150
|
setShown(url);
|
|
11802
12151
|
}
|
|
11803
12152
|
}, []);
|
|
11804
|
-
if (forms === null) return /* @__PURE__ */ (0,
|
|
12153
|
+
if (forms === null) return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_design_system44.Skeleton, { className: (0, import_design_system44.cn)("h-32 w-full", className) });
|
|
11805
12154
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
11806
|
-
return /* @__PURE__ */ (0,
|
|
11807
|
-
/* @__PURE__ */ (0,
|
|
11808
|
-
/* @__PURE__ */ (0,
|
|
11809
|
-
/* @__PURE__ */ (0,
|
|
11810
|
-
/* @__PURE__ */ (0,
|
|
11811
|
-
rights.structure && forms.length > 0 ? /* @__PURE__ */ (0,
|
|
12155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("section", { className: (0, import_design_system44.cn)("flex flex-col gap-3", className), children: [
|
|
12156
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
12157
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h3", { className: "text-sm font-medium", children: "Forms" }),
|
|
12158
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs text-muted-foreground", children: forms.length === 0 ? "none yet" : `${forms.length}` }),
|
|
12159
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex-1" }),
|
|
12160
|
+
rights.structure && forms.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_design_system44.Button, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a form" }) : null
|
|
11812
12161
|
] }),
|
|
11813
|
-
error ? /* @__PURE__ */ (0,
|
|
11814
|
-
building ? /* @__PURE__ */ (0,
|
|
12162
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(RefusalNotice, { error }) : null,
|
|
12163
|
+
building ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
11815
12164
|
FormBuilder,
|
|
11816
12165
|
{
|
|
11817
12166
|
tableId,
|
|
@@ -11820,7 +12169,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
11820
12169
|
}
|
|
11821
12170
|
}
|
|
11822
12171
|
) : null,
|
|
11823
|
-
forms.length === 0 && !building ? /* @__PURE__ */ (0,
|
|
12172
|
+
forms.length === 0 && !building ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
11824
12173
|
BuildOrAsk,
|
|
11825
12174
|
{
|
|
11826
12175
|
mayBuild: rights.structure,
|
|
@@ -11838,36 +12187,36 @@ function FormsPanel({ tableId, className }) {
|
|
|
11838
12187
|
children: WHAT_A_FORM_IS
|
|
11839
12188
|
}
|
|
11840
12189
|
) : null,
|
|
11841
|
-
/* @__PURE__ */ (0,
|
|
12190
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("ul", { className: "flex flex-col gap-2", children: forms.map((form) => {
|
|
11842
12191
|
const url = `${origin}${(0, import_records8.publicFormPath)(form.form_id)}`;
|
|
11843
|
-
return /* @__PURE__ */ (0,
|
|
11844
|
-
/* @__PURE__ */ (0,
|
|
11845
|
-
/* @__PURE__ */ (0,
|
|
11846
|
-
/* @__PURE__ */ (0,
|
|
12192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("li", { className: "rounded-md border p-2.5", children: [
|
|
12193
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12194
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: form.title ?? form.slug }),
|
|
12195
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_design_system44.Badge, { variant: form.state === "open" ? "default" : "secondary", children: form.state })
|
|
11847
12196
|
] }),
|
|
11848
|
-
/* @__PURE__ */ (0,
|
|
11849
|
-
/* @__PURE__ */ (0,
|
|
11850
|
-
/* @__PURE__ */ (0,
|
|
12197
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "mt-0.5 text-xs text-muted-foreground", children: FORM_STATE_WORDS[form.state] }),
|
|
12198
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("p", { className: "mt-1.5 text-xs", children: [
|
|
12199
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "font-medium", children: form.in_table }),
|
|
11851
12200
|
" in the table",
|
|
11852
|
-
form.held > 0 ? /* @__PURE__ */ (0,
|
|
12201
|
+
form.held > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
11853
12202
|
" \xB7 ",
|
|
11854
|
-
/* @__PURE__ */ (0,
|
|
12203
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "font-medium", children: form.held }),
|
|
11855
12204
|
" waiting for someone"
|
|
11856
12205
|
] }) : null,
|
|
11857
|
-
form.rejected > 0 ? /* @__PURE__ */ (0,
|
|
12206
|
+
form.rejected > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
11858
12207
|
" \xB7 ",
|
|
11859
|
-
/* @__PURE__ */ (0,
|
|
12208
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "font-medium", children: form.rejected }),
|
|
11860
12209
|
" turned away"
|
|
11861
12210
|
] }) : null,
|
|
11862
|
-
form.submission_cap !== null ? /* @__PURE__ */ (0,
|
|
12211
|
+
form.submission_cap !== null ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
11863
12212
|
" \xB7 stops at ",
|
|
11864
12213
|
form.submission_cap
|
|
11865
12214
|
] }) : null
|
|
11866
12215
|
] }),
|
|
11867
|
-
/* @__PURE__ */ (0,
|
|
11868
|
-
form.published_at ? /* @__PURE__ */ (0,
|
|
11869
|
-
rights.structure ? /* @__PURE__ */ (0,
|
|
11870
|
-
|
|
12216
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "mt-2 flex flex-wrap items-center gap-1.5", children: [
|
|
12217
|
+
form.published_at ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_design_system44.Button, { size: "sm", variant: "outline", onClick: () => void copy(url, form.form_id), children: copied === form.form_id ? "Copied" : "Copy link" }) : null,
|
|
12218
|
+
rights.structure ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
12219
|
+
import_design_system44.Button,
|
|
11871
12220
|
{
|
|
11872
12221
|
size: "sm",
|
|
11873
12222
|
variant: "ghost",
|
|
@@ -11877,23 +12226,23 @@ function FormsPanel({ tableId, className }) {
|
|
|
11877
12226
|
}
|
|
11878
12227
|
) : null
|
|
11879
12228
|
] }),
|
|
11880
|
-
shown && shown === url ? /* @__PURE__ */ (0,
|
|
12229
|
+
shown && shown === url ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("p", { className: "mt-1.5 break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
11881
12230
|
"This browser would not let the page copy for you, so here it is to copy by hand:",
|
|
11882
12231
|
" ",
|
|
11883
12232
|
url
|
|
11884
12233
|
] }) : null
|
|
11885
12234
|
] }, form.form_id);
|
|
11886
12235
|
}) }),
|
|
11887
|
-
!rights.known ? /* @__PURE__ */ (0,
|
|
12236
|
+
!rights.known ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-xs text-muted-foreground", children: "Still asking what you may do with this table \u2014 nothing is offered until it answers." }) : null
|
|
11888
12237
|
] });
|
|
11889
12238
|
}
|
|
11890
12239
|
|
|
11891
12240
|
// src/BookingBuilder.tsx
|
|
11892
|
-
var
|
|
11893
|
-
var
|
|
12241
|
+
var import_react90 = require("react");
|
|
12242
|
+
var import_react91 = require("@ai-matrx/records/react");
|
|
11894
12243
|
var import_records9 = require("@ai-matrx/records");
|
|
11895
|
-
var
|
|
11896
|
-
var
|
|
12244
|
+
var import_design_system45 = require("@ai-matrx/design-system");
|
|
12245
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
11897
12246
|
var STORE_ANSWERS_THESE = ["slot", "status", "booked_with"];
|
|
11898
12247
|
var DAYS = [
|
|
11899
12248
|
{ weekday: 1, label: "Mon" },
|
|
@@ -11917,36 +12266,36 @@ function draftWindows(availability) {
|
|
|
11917
12266
|
});
|
|
11918
12267
|
}
|
|
11919
12268
|
function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
11920
|
-
const client = (0,
|
|
12269
|
+
const client = (0, import_react91.useRecordsClient)();
|
|
11921
12270
|
const host = useRecordsUi();
|
|
11922
|
-
const table = (0,
|
|
12271
|
+
const table = (0, import_react91.useTable)(tableId);
|
|
11923
12272
|
const rights = useTableRights(table.data);
|
|
11924
|
-
const fields = (0,
|
|
11925
|
-
const [existing, setExisting] = (0,
|
|
11926
|
-
const [loaded, setLoaded] = (0,
|
|
11927
|
-
const [error, setError] = (0,
|
|
11928
|
-
const [saving, setSaving] = (0,
|
|
11929
|
-
const [publishing, setPublishing] = (0,
|
|
11930
|
-
const [copied, setCopied] = (0,
|
|
11931
|
-
const [title, setTitle] = (0,
|
|
11932
|
-
const [minutes, setMinutes] = (0,
|
|
11933
|
-
const [buffer, setBuffer] = (0,
|
|
11934
|
-
const [lead, setLead] = (0,
|
|
11935
|
-
const [perDay, setPerDay] = (0,
|
|
11936
|
-
const [days, setDays] = (0,
|
|
11937
|
-
const [windows, setWindows] = (0,
|
|
11938
|
-
const [asked, setAsked] = (0,
|
|
11939
|
-
const [confirmation, setConfirmation] = (0,
|
|
11940
|
-
const [offer, setOffer] = (0,
|
|
11941
|
-
const [formId, setFormId] = (0,
|
|
12273
|
+
const fields = (0, import_react91.useFields)(tableId);
|
|
12274
|
+
const [existing, setExisting] = (0, import_react90.useState)(null);
|
|
12275
|
+
const [loaded, setLoaded] = (0, import_react90.useState)(false);
|
|
12276
|
+
const [error, setError] = (0, import_react90.useState)(null);
|
|
12277
|
+
const [saving, setSaving] = (0, import_react90.useState)(false);
|
|
12278
|
+
const [publishing, setPublishing] = (0, import_react90.useState)(false);
|
|
12279
|
+
const [copied, setCopied] = (0, import_react90.useState)(false);
|
|
12280
|
+
const [title, setTitle] = (0, import_react90.useState)("");
|
|
12281
|
+
const [minutes, setMinutes] = (0, import_react90.useState)(30);
|
|
12282
|
+
const [buffer, setBuffer] = (0, import_react90.useState)(0);
|
|
12283
|
+
const [lead, setLead] = (0, import_react90.useState)(120);
|
|
12284
|
+
const [perDay, setPerDay] = (0, import_react90.useState)(8);
|
|
12285
|
+
const [days, setDays] = (0, import_react90.useState)(30);
|
|
12286
|
+
const [windows, setWindows] = (0, import_react90.useState)(() => draftWindows(null));
|
|
12287
|
+
const [asked, setAsked] = (0, import_react90.useState)([]);
|
|
12288
|
+
const [confirmation, setConfirmation] = (0, import_react90.useState)("");
|
|
12289
|
+
const [offer, setOffer] = (0, import_react90.useState)(null);
|
|
12290
|
+
const [formId, setFormId] = (0, import_react90.useState)(bookingId ?? null);
|
|
11942
12291
|
const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
11943
|
-
const askable = (0,
|
|
12292
|
+
const askable = (0, import_react90.useMemo)(
|
|
11944
12293
|
() => (fields.data ?? []).filter(
|
|
11945
12294
|
(f) => !STORE_ANSWERS_THESE.includes(f.key)
|
|
11946
12295
|
),
|
|
11947
12296
|
[fields.data]
|
|
11948
12297
|
);
|
|
11949
|
-
const load = (0,
|
|
12298
|
+
const load = (0, import_react90.useCallback)(async () => {
|
|
11950
12299
|
const answered = await client.bookings({ table_id: tableId });
|
|
11951
12300
|
if (!answered.ok) {
|
|
11952
12301
|
setError(answered.error);
|
|
@@ -11958,18 +12307,18 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
11958
12307
|
setLoaded(true);
|
|
11959
12308
|
if (mine) setFormId(mine.form_id);
|
|
11960
12309
|
}, [client, tableId, bookingId]);
|
|
11961
|
-
(0,
|
|
12310
|
+
(0, import_react90.useEffect)(() => {
|
|
11962
12311
|
void load();
|
|
11963
12312
|
}, [load]);
|
|
11964
|
-
(0,
|
|
12313
|
+
(0, import_react90.useEffect)(() => {
|
|
11965
12314
|
if (title !== "" || !table.data) return;
|
|
11966
12315
|
setTitle(existing?.title ?? `Book a ${minutes}-minute ${table.data.name} appointment`);
|
|
11967
12316
|
}, [table.data, existing]);
|
|
11968
|
-
(0,
|
|
12317
|
+
(0, import_react90.useEffect)(() => {
|
|
11969
12318
|
if (!existing) return;
|
|
11970
12319
|
setMinutes(existing.slot_minutes);
|
|
11971
12320
|
}, [existing]);
|
|
11972
|
-
const availability = (0,
|
|
12321
|
+
const availability = (0, import_react90.useCallback)(
|
|
11973
12322
|
() => ({
|
|
11974
12323
|
slot_minutes: minutes,
|
|
11975
12324
|
buffer_minutes: buffer,
|
|
@@ -12018,68 +12367,68 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12018
12367
|
await load();
|
|
12019
12368
|
onSaved?.({ form_id: formId });
|
|
12020
12369
|
}
|
|
12021
|
-
if (!loaded || fields.loading) return /* @__PURE__ */ (0,
|
|
12370
|
+
if (!loaded || fields.loading) return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Skeleton, { className: (0, import_design_system45.cn)("h-64 w-full", className) });
|
|
12022
12371
|
if (!rights.structure) {
|
|
12023
|
-
return /* @__PURE__ */ (0,
|
|
12372
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: (0, import_design_system45.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." });
|
|
12024
12373
|
}
|
|
12025
12374
|
const url = formId ? `${publicOrigin}${(0, import_records9.bookingPath)(formId)}` : null;
|
|
12026
12375
|
const shown = offer ?? null;
|
|
12027
|
-
return /* @__PURE__ */ (0,
|
|
12028
|
-
/* @__PURE__ */ (0,
|
|
12029
|
-
/* @__PURE__ */ (0,
|
|
12030
|
-
/* @__PURE__ */ (0,
|
|
12031
|
-
/* @__PURE__ */ (0,
|
|
12032
|
-
onClose ? /* @__PURE__ */ (0,
|
|
12376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: (0, import_design_system45.cn)("flex flex-col gap-3", className), children: [
|
|
12377
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
12378
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Booking page" : "New booking page" }),
|
|
12379
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex-1" }),
|
|
12380
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" }),
|
|
12381
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
|
|
12033
12382
|
] }),
|
|
12034
|
-
error ? /* @__PURE__ */ (0,
|
|
12035
|
-
/* @__PURE__ */ (0,
|
|
12036
|
-
/* @__PURE__ */ (0,
|
|
12037
|
-
/* @__PURE__ */ (0,
|
|
12383
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RefusalNotice, { error }) : null,
|
|
12384
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12385
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What it is called" }),
|
|
12386
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.BasicInput, { value: title, onChange: (e) => setTitle(e.target.value) })
|
|
12038
12387
|
] }),
|
|
12039
|
-
/* @__PURE__ */ (0,
|
|
12040
|
-
/* @__PURE__ */ (0,
|
|
12041
|
-
/* @__PURE__ */ (0,
|
|
12042
|
-
/* @__PURE__ */ (0,
|
|
12388
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
12389
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12390
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How long one appointment is" }),
|
|
12391
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12043
12392
|
"select",
|
|
12044
12393
|
{
|
|
12045
12394
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12046
12395
|
value: minutes,
|
|
12047
12396
|
onChange: (e) => setMinutes(Number(e.target.value)),
|
|
12048
|
-
children: LENGTHS.map((n) => /* @__PURE__ */ (0,
|
|
12397
|
+
children: LENGTHS.map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12049
12398
|
n,
|
|
12050
12399
|
" minutes"
|
|
12051
12400
|
] }, n))
|
|
12052
12401
|
}
|
|
12053
12402
|
)
|
|
12054
12403
|
] }),
|
|
12055
|
-
/* @__PURE__ */ (0,
|
|
12056
|
-
/* @__PURE__ */ (0,
|
|
12057
|
-
/* @__PURE__ */ (0,
|
|
12404
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12405
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Gap kept after each one" }),
|
|
12406
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12058
12407
|
"select",
|
|
12059
12408
|
{
|
|
12060
12409
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12061
12410
|
value: buffer,
|
|
12062
12411
|
onChange: (e) => setBuffer(Number(e.target.value)),
|
|
12063
|
-
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0,
|
|
12412
|
+
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
|
|
12064
12413
|
}
|
|
12065
12414
|
)
|
|
12066
12415
|
] }),
|
|
12067
|
-
/* @__PURE__ */ (0,
|
|
12068
|
-
/* @__PURE__ */ (0,
|
|
12069
|
-
/* @__PURE__ */ (0,
|
|
12416
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12417
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
|
|
12418
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12070
12419
|
"select",
|
|
12071
12420
|
{
|
|
12072
12421
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12073
12422
|
value: lead,
|
|
12074
12423
|
onChange: (e) => setLead(Number(e.target.value)),
|
|
12075
|
-
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0,
|
|
12424
|
+
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
|
|
12076
12425
|
}
|
|
12077
12426
|
)
|
|
12078
12427
|
] }),
|
|
12079
|
-
/* @__PURE__ */ (0,
|
|
12080
|
-
/* @__PURE__ */ (0,
|
|
12081
|
-
/* @__PURE__ */ (0,
|
|
12082
|
-
|
|
12428
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12429
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Most in one day" }),
|
|
12430
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12431
|
+
import_design_system45.BasicInput,
|
|
12083
12432
|
{
|
|
12084
12433
|
type: "number",
|
|
12085
12434
|
min: 1,
|
|
@@ -12088,15 +12437,15 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12088
12437
|
}
|
|
12089
12438
|
)
|
|
12090
12439
|
] }),
|
|
12091
|
-
/* @__PURE__ */ (0,
|
|
12092
|
-
/* @__PURE__ */ (0,
|
|
12093
|
-
/* @__PURE__ */ (0,
|
|
12440
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12441
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How far ahead the page offers" }),
|
|
12442
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12094
12443
|
"select",
|
|
12095
12444
|
{
|
|
12096
12445
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12097
12446
|
value: days,
|
|
12098
12447
|
onChange: (e) => setDays(Number(e.target.value)),
|
|
12099
|
-
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0,
|
|
12448
|
+
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12100
12449
|
n,
|
|
12101
12450
|
" days"
|
|
12102
12451
|
] }, n))
|
|
@@ -12104,12 +12453,12 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12104
12453
|
)
|
|
12105
12454
|
] })
|
|
12106
12455
|
] }),
|
|
12107
|
-
/* @__PURE__ */ (0,
|
|
12108
|
-
/* @__PURE__ */ (0,
|
|
12109
|
-
windows.map((w, i) => /* @__PURE__ */ (0,
|
|
12110
|
-
/* @__PURE__ */ (0,
|
|
12111
|
-
/* @__PURE__ */ (0,
|
|
12112
|
-
|
|
12456
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
12457
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Hours you are free" }),
|
|
12458
|
+
windows.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12459
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
|
|
12460
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12461
|
+
import_design_system45.Checkbox,
|
|
12113
12462
|
{
|
|
12114
12463
|
checked: w.on,
|
|
12115
12464
|
onCheckedChange: (on) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, on: Boolean(on) } : x))
|
|
@@ -12117,9 +12466,9 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12117
12466
|
),
|
|
12118
12467
|
DAYS[i]?.label
|
|
12119
12468
|
] }),
|
|
12120
|
-
w.on ? /* @__PURE__ */ (0,
|
|
12121
|
-
/* @__PURE__ */ (0,
|
|
12122
|
-
|
|
12469
|
+
w.on ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
12470
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12471
|
+
import_design_system45.BasicInput,
|
|
12123
12472
|
{
|
|
12124
12473
|
type: "time",
|
|
12125
12474
|
className: "h-8 w-28",
|
|
@@ -12127,9 +12476,9 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12127
12476
|
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, from: e.target.value } : x))
|
|
12128
12477
|
}
|
|
12129
12478
|
),
|
|
12130
|
-
/* @__PURE__ */ (0,
|
|
12131
|
-
/* @__PURE__ */ (0,
|
|
12132
|
-
|
|
12479
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
12480
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12481
|
+
import_design_system45.BasicInput,
|
|
12133
12482
|
{
|
|
12134
12483
|
type: "time",
|
|
12135
12484
|
className: "h-8 w-28",
|
|
@@ -12137,14 +12486,14 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12137
12486
|
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, to: e.target.value } : x))
|
|
12138
12487
|
}
|
|
12139
12488
|
)
|
|
12140
|
-
] }) : /* @__PURE__ */ (0,
|
|
12489
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "not taking bookings" })
|
|
12141
12490
|
] }, w.weekday))
|
|
12142
12491
|
] }),
|
|
12143
|
-
/* @__PURE__ */ (0,
|
|
12144
|
-
/* @__PURE__ */ (0,
|
|
12145
|
-
askable.length === 0 ? /* @__PURE__ */ (0,
|
|
12146
|
-
/* @__PURE__ */ (0,
|
|
12147
|
-
|
|
12492
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
12493
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What to ask the person booking" }),
|
|
12494
|
+
askable.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "This table has no fields yet, so there is nothing a booking page could ask for. Add a field first \u2014 every question is one of this table's own fields." }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: askable.map((f) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
12495
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12496
|
+
import_design_system45.Checkbox,
|
|
12148
12497
|
{
|
|
12149
12498
|
checked: asked.includes(f.key),
|
|
12150
12499
|
onCheckedChange: (on) => setAsked((prev) => on ? [...prev, f.key] : prev.filter((k) => k !== f.key))
|
|
@@ -12152,12 +12501,12 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12152
12501
|
),
|
|
12153
12502
|
fieldName(f)
|
|
12154
12503
|
] }, f.key)) }),
|
|
12155
|
-
/* @__PURE__ */ (0,
|
|
12504
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." })
|
|
12156
12505
|
] }),
|
|
12157
|
-
/* @__PURE__ */ (0,
|
|
12158
|
-
/* @__PURE__ */ (0,
|
|
12159
|
-
/* @__PURE__ */ (0,
|
|
12160
|
-
|
|
12506
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12507
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What they see after booking" }),
|
|
12508
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12509
|
+
import_design_system45.BasicTextarea,
|
|
12161
12510
|
{
|
|
12162
12511
|
rows: 2,
|
|
12163
12512
|
value: confirmation,
|
|
@@ -12166,7 +12515,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12166
12515
|
}
|
|
12167
12516
|
)
|
|
12168
12517
|
] }),
|
|
12169
|
-
shown ? /* @__PURE__ */ (0,
|
|
12518
|
+
shown ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
12170
12519
|
"Saved. The page offers ",
|
|
12171
12520
|
shown.slot_minutes,
|
|
12172
12521
|
"-minute appointments in ",
|
|
@@ -12185,10 +12534,10 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12185
12534
|
).join(", "),
|
|
12186
12535
|
"."
|
|
12187
12536
|
] }) : null,
|
|
12188
|
-
url ? /* @__PURE__ */ (0,
|
|
12189
|
-
/* @__PURE__ */ (0,
|
|
12190
|
-
/* @__PURE__ */ (0,
|
|
12191
|
-
|
|
12537
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
|
|
12538
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
|
|
12539
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12540
|
+
import_design_system45.Button,
|
|
12192
12541
|
{
|
|
12193
12542
|
size: "sm",
|
|
12194
12543
|
variant: "outline",
|
|
@@ -12201,8 +12550,8 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12201
12550
|
children: copied ? "Copied" : "Copy link"
|
|
12202
12551
|
}
|
|
12203
12552
|
),
|
|
12204
|
-
/* @__PURE__ */ (0,
|
|
12205
|
-
|
|
12553
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12554
|
+
import_design_system45.Button,
|
|
12206
12555
|
{
|
|
12207
12556
|
size: "sm",
|
|
12208
12557
|
disabled: publishing,
|
|
@@ -12210,17 +12559,17 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12210
12559
|
children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
|
|
12211
12560
|
}
|
|
12212
12561
|
),
|
|
12213
|
-
/* @__PURE__ */ (0,
|
|
12562
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: existing?.published_at && !existing.closed_at ? "Open. Anyone with this link can book a time." : "Not open yet \u2014 the link does not take bookings until you publish it." })
|
|
12214
12563
|
] }) : null
|
|
12215
12564
|
] });
|
|
12216
12565
|
}
|
|
12217
12566
|
|
|
12218
12567
|
// src/BookingSlots.tsx
|
|
12219
|
-
var
|
|
12220
|
-
var
|
|
12568
|
+
var import_react92 = require("react");
|
|
12569
|
+
var import_react93 = require("@ai-matrx/records/react");
|
|
12221
12570
|
var import_records10 = require("@ai-matrx/records");
|
|
12222
|
-
var
|
|
12223
|
-
var
|
|
12571
|
+
var import_design_system46 = require("@ai-matrx/design-system");
|
|
12572
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
12224
12573
|
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.";
|
|
12225
12574
|
function bookingSuggestion(tableName2) {
|
|
12226
12575
|
const subject = tableName2?.trim() ? tableName2.trim() : "appointments";
|
|
@@ -12234,15 +12583,15 @@ var STATE_WORDS = {
|
|
|
12234
12583
|
full: "Every time you offered is taken."
|
|
12235
12584
|
};
|
|
12236
12585
|
function BookingSlots({ tableId, className }) {
|
|
12237
|
-
const client = (0,
|
|
12586
|
+
const client = (0, import_react93.useRecordsClient)();
|
|
12238
12587
|
const host = useRecordsUi();
|
|
12239
|
-
const [pages, setPages] = (0,
|
|
12240
|
-
const [error, setError] = (0,
|
|
12241
|
-
const [busy, setBusy] = (0,
|
|
12242
|
-
const [copied, setCopied] = (0,
|
|
12243
|
-
const [shown, setShown] = (0,
|
|
12244
|
-
const [building, setBuilding] = (0,
|
|
12245
|
-
const load = (0,
|
|
12588
|
+
const [pages, setPages] = (0, import_react92.useState)(null);
|
|
12589
|
+
const [error, setError] = (0, import_react92.useState)(null);
|
|
12590
|
+
const [busy, setBusy] = (0, import_react92.useState)(null);
|
|
12591
|
+
const [copied, setCopied] = (0, import_react92.useState)(null);
|
|
12592
|
+
const [shown, setShown] = (0, import_react92.useState)(null);
|
|
12593
|
+
const [building, setBuilding] = (0, import_react92.useState)(false);
|
|
12594
|
+
const load = (0, import_react92.useCallback)(async () => {
|
|
12246
12595
|
const answered = await client.bookings(tableId ? { table_id: tableId } : {});
|
|
12247
12596
|
if (!answered.ok) {
|
|
12248
12597
|
setError(answered.error);
|
|
@@ -12252,15 +12601,15 @@ function BookingSlots({ tableId, className }) {
|
|
|
12252
12601
|
setError(null);
|
|
12253
12602
|
setPages(answered.data);
|
|
12254
12603
|
}, [client, tableId]);
|
|
12255
|
-
(0,
|
|
12604
|
+
(0, import_react92.useEffect)(() => {
|
|
12256
12605
|
void load();
|
|
12257
12606
|
}, [load]);
|
|
12258
|
-
const subjectIds = (0,
|
|
12607
|
+
const subjectIds = (0, import_react92.useMemo)(
|
|
12259
12608
|
() => Array.from(new Set((pages ?? []).map((p) => p.table_id))),
|
|
12260
12609
|
[pages]
|
|
12261
12610
|
);
|
|
12262
|
-
const levels = (0,
|
|
12263
|
-
const toggle = (0,
|
|
12611
|
+
const levels = (0, import_react93.useMyLevels)(subjectIds);
|
|
12612
|
+
const toggle = (0, import_react92.useCallback)(
|
|
12264
12613
|
async (page) => {
|
|
12265
12614
|
setBusy(page.form_id);
|
|
12266
12615
|
const wanted = page.published_at === null || page.closed_at !== null;
|
|
@@ -12274,7 +12623,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
12274
12623
|
},
|
|
12275
12624
|
[client, load]
|
|
12276
12625
|
);
|
|
12277
|
-
const copy = (0,
|
|
12626
|
+
const copy = (0, import_react92.useCallback)(async (url, formId) => {
|
|
12278
12627
|
try {
|
|
12279
12628
|
await navigator.clipboard.writeText(url);
|
|
12280
12629
|
setCopied(formId);
|
|
@@ -12284,18 +12633,18 @@ function BookingSlots({ tableId, className }) {
|
|
|
12284
12633
|
setShown(url);
|
|
12285
12634
|
}
|
|
12286
12635
|
}, []);
|
|
12287
|
-
if (pages === null) return /* @__PURE__ */ (0,
|
|
12636
|
+
if (pages === null) return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_design_system46.Skeleton, { className: (0, import_design_system46.cn)("h-32 w-full", className) });
|
|
12288
12637
|
if (pages.length === 0 && !tableId && !error && !building) return null;
|
|
12289
12638
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
12290
|
-
return /* @__PURE__ */ (0,
|
|
12291
|
-
/* @__PURE__ */ (0,
|
|
12292
|
-
/* @__PURE__ */ (0,
|
|
12293
|
-
/* @__PURE__ */ (0,
|
|
12294
|
-
/* @__PURE__ */ (0,
|
|
12295
|
-
tableId && pages.length > 0 ? /* @__PURE__ */ (0,
|
|
12639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("section", { className: (0, import_design_system46.cn)("flex flex-col gap-3", className), "data-testid": "booking-slots", children: [
|
|
12640
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
12641
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h3", { className: "text-sm font-medium", children: "Bookings" }),
|
|
12642
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs text-muted-foreground", children: pages.length === 0 ? "none yet" : `${pages.length}` }),
|
|
12643
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "flex-1" }),
|
|
12644
|
+
tableId && pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_design_system46.Button, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a booking page" }) : null
|
|
12296
12645
|
] }),
|
|
12297
|
-
error ? /* @__PURE__ */ (0,
|
|
12298
|
-
building && tableId ? /* @__PURE__ */ (0,
|
|
12646
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(RefusalNotice, { error }) : null,
|
|
12647
|
+
building && tableId ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
12299
12648
|
BookingBuilder,
|
|
12300
12649
|
{
|
|
12301
12650
|
tableId,
|
|
@@ -12305,7 +12654,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
12305
12654
|
onClose: () => setBuilding(false)
|
|
12306
12655
|
}
|
|
12307
12656
|
) : null,
|
|
12308
|
-
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ (0,
|
|
12657
|
+
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
12309
12658
|
BuildOrAsk,
|
|
12310
12659
|
{
|
|
12311
12660
|
mayBuild: true,
|
|
@@ -12321,47 +12670,47 @@ function BookingSlots({ tableId, className }) {
|
|
|
12321
12670
|
buildLabel: "Build the booking page",
|
|
12322
12671
|
children: WHAT_A_BOOKING_PAGE_IS
|
|
12323
12672
|
}
|
|
12324
|
-
) : /* @__PURE__ */ (0,
|
|
12673
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
|
|
12325
12674
|
WHAT_A_BOOKING_PAGE_IS,
|
|
12326
12675
|
" Open the table the appointments should land in to make one."
|
|
12327
12676
|
] }) : null,
|
|
12328
|
-
/* @__PURE__ */ (0,
|
|
12677
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "flex flex-col gap-2", children: pages.map((page) => {
|
|
12329
12678
|
const url = `${origin}${(0, import_records10.bookingPath)(page.form_id)}`;
|
|
12330
12679
|
const mayOpen = levels.data?.[page.table_id] === "admin";
|
|
12331
12680
|
const open = page.published_at !== null && page.closed_at === null;
|
|
12332
|
-
return /* @__PURE__ */ (0,
|
|
12333
|
-
/* @__PURE__ */ (0,
|
|
12334
|
-
/* @__PURE__ */ (0,
|
|
12335
|
-
/* @__PURE__ */ (0,
|
|
12681
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { className: "rounded-md border p-2.5", "data-testid": "booking-page", children: [
|
|
12682
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12683
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: page.title ?? page.slug }),
|
|
12684
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_design_system46.Badge, { variant: page.state === "open" ? "default" : "secondary", children: page.state })
|
|
12336
12685
|
] }),
|
|
12337
|
-
/* @__PURE__ */ (0,
|
|
12338
|
-
/* @__PURE__ */ (0,
|
|
12339
|
-
/* @__PURE__ */ (0,
|
|
12686
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mt-0.5 text-xs text-muted-foreground", children: STATE_WORDS[page.state] ?? page.state }),
|
|
12687
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("p", { className: "mt-1.5 text-xs", children: [
|
|
12688
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium", children: page.upcoming }),
|
|
12340
12689
|
" coming up",
|
|
12341
12690
|
" \xB7 ",
|
|
12342
|
-
/* @__PURE__ */ (0,
|
|
12691
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium", children: page.booked }),
|
|
12343
12692
|
" booked in all",
|
|
12344
|
-
page.held > 0 ? /* @__PURE__ */ (0,
|
|
12693
|
+
page.held > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
12345
12694
|
" \xB7 ",
|
|
12346
|
-
/* @__PURE__ */ (0,
|
|
12695
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium", children: page.held }),
|
|
12347
12696
|
" being held right now"
|
|
12348
12697
|
] }) : null,
|
|
12349
|
-
page.cancelled > 0 ? /* @__PURE__ */ (0,
|
|
12698
|
+
page.cancelled > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(import_jsx_runtime49.Fragment, { children: [
|
|
12350
12699
|
" \xB7 ",
|
|
12351
|
-
/* @__PURE__ */ (0,
|
|
12700
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "font-medium", children: page.cancelled }),
|
|
12352
12701
|
" cancelled"
|
|
12353
12702
|
] }) : null,
|
|
12354
|
-
/* @__PURE__ */ (0,
|
|
12703
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
12355
12704
|
" \xB7 ",
|
|
12356
12705
|
page.slot_minutes,
|
|
12357
12706
|
" minutes each"
|
|
12358
12707
|
] })
|
|
12359
12708
|
] }),
|
|
12360
|
-
/* @__PURE__ */ (0,
|
|
12361
|
-
/* @__PURE__ */ (0,
|
|
12362
|
-
/* @__PURE__ */ (0,
|
|
12363
|
-
mayOpen ? /* @__PURE__ */ (0,
|
|
12364
|
-
|
|
12709
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mt-1 text-xs text-muted-foreground", children: nextInWords(page) }),
|
|
12710
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "mt-2 flex flex-wrap items-center gap-1.5", children: [
|
|
12711
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_design_system46.Button, { size: "sm", variant: "outline", onClick: () => void copy(url, page.form_id), children: copied === page.form_id ? "Copied" : "Copy link" }),
|
|
12712
|
+
mayOpen ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
12713
|
+
import_design_system46.Button,
|
|
12365
12714
|
{
|
|
12366
12715
|
size: "sm",
|
|
12367
12716
|
variant: "ghost",
|
|
@@ -12371,13 +12720,13 @@ function BookingSlots({ tableId, className }) {
|
|
|
12371
12720
|
}
|
|
12372
12721
|
) : null
|
|
12373
12722
|
] }),
|
|
12374
|
-
shown && shown === url ? /* @__PURE__ */ (0,
|
|
12723
|
+
shown && shown === url ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("p", { className: "mt-1.5 break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
12375
12724
|
"This browser would not let the page copy for you, so here it is to copy by hand: ",
|
|
12376
12725
|
url
|
|
12377
12726
|
] }) : null
|
|
12378
12727
|
] }, page.form_id);
|
|
12379
12728
|
}) }),
|
|
12380
|
-
pages.length > 0 && !levels.loading && levels.data && subjectIds.every((id) => levels.data?.[id] !== "admin") ? /* @__PURE__ */ (0,
|
|
12729
|
+
pages.length > 0 && !levels.loading && levels.data && subjectIds.every((id) => levels.data?.[id] !== "admin") ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "text-xs text-muted-foreground", children: NO_ADMIN2 }) : null
|
|
12381
12730
|
] });
|
|
12382
12731
|
}
|
|
12383
12732
|
function nextInWords(page) {
|
|
@@ -12409,16 +12758,16 @@ function nextInWords(page) {
|
|
|
12409
12758
|
}
|
|
12410
12759
|
|
|
12411
12760
|
// src/CaptureSheet.tsx
|
|
12412
|
-
var
|
|
12413
|
-
var
|
|
12414
|
-
var
|
|
12761
|
+
var import_react96 = require("react");
|
|
12762
|
+
var import_react97 = require("@ai-matrx/records/react");
|
|
12763
|
+
var import_design_system48 = require("@ai-matrx/design-system");
|
|
12415
12764
|
|
|
12416
12765
|
// src/CaptureRun.tsx
|
|
12417
|
-
var
|
|
12766
|
+
var import_react94 = require("react");
|
|
12418
12767
|
var import_records11 = require("@ai-matrx/records");
|
|
12419
|
-
var
|
|
12420
|
-
var
|
|
12421
|
-
var
|
|
12768
|
+
var import_react95 = require("@ai-matrx/records/react");
|
|
12769
|
+
var import_design_system47 = require("@ai-matrx/design-system");
|
|
12770
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
12422
12771
|
function controlFor(field) {
|
|
12423
12772
|
if (!field) return "text";
|
|
12424
12773
|
const label = `${field.key} ${field.label ?? ""}`.toLowerCase();
|
|
@@ -12455,21 +12804,21 @@ function whereWeAre(timeoutMs = 4e3) {
|
|
|
12455
12804
|
});
|
|
12456
12805
|
}
|
|
12457
12806
|
function CaptureRun({ sheetId, face: given, className }) {
|
|
12458
|
-
const client = (0,
|
|
12807
|
+
const client = (0, import_react95.useRecordsClient)();
|
|
12459
12808
|
const host = useRecordsUi();
|
|
12460
|
-
const [face, setFace] = (0,
|
|
12461
|
-
const [loadFailed, setLoadFailed] = (0,
|
|
12462
|
-
const [at, setAt] = (0,
|
|
12463
|
-
const [answers, setAnswers] = (0,
|
|
12464
|
-
const [files, setFiles] = (0,
|
|
12465
|
-
const [missing, setMissing] = (0,
|
|
12466
|
-
const [done, setDone] = (0,
|
|
12467
|
-
const [counts, setCounts] = (0,
|
|
12468
|
-
const [items, setItems] = (0,
|
|
12469
|
-
const [lastSynced, setLastSynced] = (0,
|
|
12470
|
-
const [sending, setSending] = (0,
|
|
12471
|
-
const queueRef = (0,
|
|
12472
|
-
(0,
|
|
12809
|
+
const [face, setFace] = (0, import_react94.useState)(given);
|
|
12810
|
+
const [loadFailed, setLoadFailed] = (0, import_react94.useState)(null);
|
|
12811
|
+
const [at, setAt] = (0, import_react94.useState)(0);
|
|
12812
|
+
const [answers, setAnswers] = (0, import_react94.useState)({});
|
|
12813
|
+
const [files, setFiles] = (0, import_react94.useState)({});
|
|
12814
|
+
const [missing, setMissing] = (0, import_react94.useState)(null);
|
|
12815
|
+
const [done, setDone] = (0, import_react94.useState)(null);
|
|
12816
|
+
const [counts, setCounts] = (0, import_react94.useState)({ waiting: 0, sending: 0, refused: 0, landed: 0 });
|
|
12817
|
+
const [items, setItems] = (0, import_react94.useState)([]);
|
|
12818
|
+
const [lastSynced, setLastSynced] = (0, import_react94.useState)(null);
|
|
12819
|
+
const [sending, setSending] = (0, import_react94.useState)(false);
|
|
12820
|
+
const queueRef = (0, import_react94.useRef)(null);
|
|
12821
|
+
(0, import_react94.useEffect)(() => {
|
|
12473
12822
|
const q2 = (0, import_records11.openCaptureQueue)({
|
|
12474
12823
|
onChange: (c, all) => {
|
|
12475
12824
|
setCounts(c);
|
|
@@ -12507,7 +12856,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12507
12856
|
void q2.sync().then(() => void q2.lastSyncedAt().then(setLastSynced));
|
|
12508
12857
|
return () => q2.dispose();
|
|
12509
12858
|
}, [client, host]);
|
|
12510
|
-
(0,
|
|
12859
|
+
(0, import_react94.useEffect)(() => {
|
|
12511
12860
|
if (given !== void 0) return;
|
|
12512
12861
|
let cancelled = false;
|
|
12513
12862
|
void client.captureOpen({ sheet_id: sheetId }).then((res) => {
|
|
@@ -12519,7 +12868,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12519
12868
|
cancelled = true;
|
|
12520
12869
|
};
|
|
12521
12870
|
}, [client, given, sheetId]);
|
|
12522
|
-
const questions = (0,
|
|
12871
|
+
const questions = (0, import_react94.useMemo)(() => {
|
|
12523
12872
|
const asked = face?.presentation?.questions ?? [];
|
|
12524
12873
|
if (asked.length > 0) return asked;
|
|
12525
12874
|
return (face?.fields ?? []).map((f) => ({
|
|
@@ -12529,11 +12878,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12529
12878
|
required: f.required
|
|
12530
12879
|
}));
|
|
12531
12880
|
}, [face]);
|
|
12532
|
-
const fieldOf = (0,
|
|
12881
|
+
const fieldOf = (0, import_react94.useCallback)(
|
|
12533
12882
|
(key) => (face?.fields ?? []).find((f) => f.key === key),
|
|
12534
12883
|
[face]
|
|
12535
12884
|
);
|
|
12536
|
-
const sync = (0,
|
|
12885
|
+
const sync = (0, import_react94.useCallback)(async () => {
|
|
12537
12886
|
const q2 = queueRef.current;
|
|
12538
12887
|
if (!q2) return;
|
|
12539
12888
|
setSending(true);
|
|
@@ -12546,7 +12895,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12546
12895
|
setSending(false);
|
|
12547
12896
|
}
|
|
12548
12897
|
}, []);
|
|
12549
|
-
const answered = (0,
|
|
12898
|
+
const answered = (0, import_react94.useCallback)(
|
|
12550
12899
|
(key) => {
|
|
12551
12900
|
if (files[key]) return true;
|
|
12552
12901
|
const v = answers[key];
|
|
@@ -12591,24 +12940,24 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12591
12940
|
if (online) await sync();
|
|
12592
12941
|
}
|
|
12593
12942
|
if (loadFailed) {
|
|
12594
|
-
return /* @__PURE__ */ (0,
|
|
12943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("section", { className: (0, import_design_system47.cn)("mx-auto w-full max-w-sm p-4", className), children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-sm text-destructive", "data-testid": "capture-refusal", children: loadFailed }) });
|
|
12595
12944
|
}
|
|
12596
12945
|
if (face === void 0) {
|
|
12597
|
-
return /* @__PURE__ */ (0,
|
|
12946
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_design_system47.Skeleton, { className: (0, import_design_system47.cn)("mx-auto h-64 w-full max-w-sm", className) });
|
|
12598
12947
|
}
|
|
12599
12948
|
if (face === null) {
|
|
12600
|
-
return /* @__PURE__ */ (0,
|
|
12949
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("section", { className: (0, import_design_system47.cn)("mx-auto w-full max-w-sm p-4", className), children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-sm", "data-testid": "capture-refusal", children: "This capture sheet is not here, or it is not yours to open. If somebody sent you this link, ask them to check it." }) });
|
|
12601
12950
|
}
|
|
12602
12951
|
const waiting = counts.waiting + counts.sending;
|
|
12603
|
-
const queueLine = /* @__PURE__ */ (0,
|
|
12604
|
-
/* @__PURE__ */ (0,
|
|
12605
|
-
counts.refused > 0 ? /* @__PURE__ */ (0,
|
|
12952
|
+
const queueLine = /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", "data-testid": "capture-queue-line", children: [
|
|
12953
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "tabular-nums", "data-testid": "capture-waiting", children: waiting === 0 ? "Nothing waiting" : `${waiting} waiting` }),
|
|
12954
|
+
counts.refused > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "text-destructive tabular-nums", "data-testid": "capture-refused", children: [
|
|
12606
12955
|
counts.refused,
|
|
12607
12956
|
" to fix"
|
|
12608
12957
|
] }) : null,
|
|
12609
|
-
/* @__PURE__ */ (0,
|
|
12610
|
-
waiting > 0 || counts.refused > 0 ? /* @__PURE__ */ (0,
|
|
12611
|
-
|
|
12958
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ml-auto", "data-testid": "capture-last-synced", children: lastSynced ? `Last synced ${new Date(lastSynced).toLocaleTimeString()}` : "Not synced yet" }),
|
|
12959
|
+
waiting > 0 || counts.refused > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
12960
|
+
import_design_system47.Button,
|
|
12612
12961
|
{
|
|
12613
12962
|
size: "sm",
|
|
12614
12963
|
variant: "ghost",
|
|
@@ -12620,11 +12969,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12620
12969
|
}
|
|
12621
12970
|
) : null
|
|
12622
12971
|
] });
|
|
12623
|
-
const queuePanel = items.filter((i) => i.state !== "landed").length > 0 ? /* @__PURE__ */ (0,
|
|
12624
|
-
/* @__PURE__ */ (0,
|
|
12625
|
-
/* @__PURE__ */ (0,
|
|
12626
|
-
i.state === "refused" ? /* @__PURE__ */ (0,
|
|
12627
|
-
|
|
12972
|
+
const queuePanel = items.filter((i) => i.state !== "landed").length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("ul", { className: "flex flex-col gap-1 rounded border p-2", "data-testid": "capture-queue", children: items.filter((i) => i.state !== "landed").map((i) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("li", { className: "flex items-start gap-2 text-[11px]", children: [
|
|
12973
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "tabular-nums text-muted-foreground", children: new Date(i.captured_at).toLocaleTimeString() }),
|
|
12974
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: (0, import_design_system47.cn)("flex-1", i.state === "refused" && "text-destructive"), children: i.state === "refused" ? i.last_error ?? "This one was refused." : i.last_error ?? "Waiting for a signal." }),
|
|
12975
|
+
i.state === "refused" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
12976
|
+
import_design_system47.Button,
|
|
12628
12977
|
{
|
|
12629
12978
|
size: "sm",
|
|
12630
12979
|
variant: "ghost",
|
|
@@ -12635,19 +12984,19 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12635
12984
|
) : null
|
|
12636
12985
|
] }, i.client_key)) }) : null;
|
|
12637
12986
|
if (!face.may_capture) {
|
|
12638
|
-
return /* @__PURE__ */ (0,
|
|
12639
|
-
/* @__PURE__ */ (0,
|
|
12640
|
-
/* @__PURE__ */ (0,
|
|
12987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("section", { className: (0, import_design_system47.cn)("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
12988
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("h1", { className: "text-lg font-medium", children: face.title }),
|
|
12989
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-sm", "data-testid": "capture-refusal", children: face.message }),
|
|
12641
12990
|
queueLine,
|
|
12642
12991
|
queuePanel
|
|
12643
12992
|
] });
|
|
12644
12993
|
}
|
|
12645
12994
|
if (done) {
|
|
12646
12995
|
const thanks = face.presentation?.thank_you ?? {};
|
|
12647
|
-
return /* @__PURE__ */ (0,
|
|
12648
|
-
/* @__PURE__ */ (0,
|
|
12649
|
-
/* @__PURE__ */ (0,
|
|
12650
|
-
/* @__PURE__ */ (0,
|
|
12996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("section", { className: (0, import_design_system47.cn)("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
12997
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("h2", { className: "text-lg font-medium", "data-testid": "capture-thankyou", children: thanks.title ?? "Logged" }),
|
|
12998
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-sm text-muted-foreground", children: done.queued ? "There is no signal, so this one is on the phone and goes up the moment there is. Nothing is lost." : thanks.body ?? "Ready for the next one." }),
|
|
12999
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_design_system47.Button, { className: "h-12", onClick: () => setDone(null), "data-testid": "capture-next", children: "Next one" }),
|
|
12651
13000
|
queueLine,
|
|
12652
13001
|
queuePanel
|
|
12653
13002
|
] });
|
|
@@ -12656,14 +13005,14 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12656
13005
|
const field = fieldOf(q.field);
|
|
12657
13006
|
const control = controlFor(field);
|
|
12658
13007
|
const last = at >= questions.length - 1;
|
|
12659
|
-
return /* @__PURE__ */ (0,
|
|
12660
|
-
/* @__PURE__ */ (0,
|
|
12661
|
-
/* @__PURE__ */ (0,
|
|
13008
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("section", { className: (0, import_design_system47.cn)("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
13009
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", children: [
|
|
13010
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "tabular-nums", "data-testid": "capture-progress", children: [
|
|
12662
13011
|
at + 1,
|
|
12663
13012
|
" of ",
|
|
12664
13013
|
questions.length
|
|
12665
13014
|
] }),
|
|
12666
|
-
/* @__PURE__ */ (0,
|
|
13015
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "h-1 flex-1 overflow-hidden rounded bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
12667
13016
|
"div",
|
|
12668
13017
|
{
|
|
12669
13018
|
className: "h-full bg-primary transition-[width] duration-200",
|
|
@@ -12671,7 +13020,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12671
13020
|
}
|
|
12672
13021
|
) })
|
|
12673
13022
|
] }),
|
|
12674
|
-
/* @__PURE__ */ (0,
|
|
13023
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
12675
13024
|
"label",
|
|
12676
13025
|
{
|
|
12677
13026
|
className: "text-xl font-medium leading-snug",
|
|
@@ -12679,13 +13028,13 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12679
13028
|
"data-testid": "capture-ask",
|
|
12680
13029
|
children: [
|
|
12681
13030
|
q.ask ?? q.field,
|
|
12682
|
-
q.required ? /* @__PURE__ */ (0,
|
|
13031
|
+
q.required ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "text-muted-foreground", children: " *" }) : null
|
|
12683
13032
|
]
|
|
12684
13033
|
}
|
|
12685
13034
|
),
|
|
12686
|
-
q.help ? /* @__PURE__ */ (0,
|
|
12687
|
-
control === "photo" || control === "voice" ? !host.upload ? /* @__PURE__ */ (0,
|
|
12688
|
-
/* @__PURE__ */ (0,
|
|
13035
|
+
q.help ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "-mt-1 text-sm text-muted-foreground", children: q.help }) : null,
|
|
13036
|
+
control === "photo" || control === "voice" ? !host.upload ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "rounded border border-dashed px-2 py-2 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
13037
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
12689
13038
|
"input",
|
|
12690
13039
|
{
|
|
12691
13040
|
id: `capture-${q.field}`,
|
|
@@ -12703,12 +13052,12 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12703
13052
|
}
|
|
12704
13053
|
}
|
|
12705
13054
|
),
|
|
12706
|
-
files[q.field] ? /* @__PURE__ */ (0,
|
|
13055
|
+
files[q.field] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("p", { className: "text-[11px] text-muted-foreground", "data-testid": `capture-have-${q.field}`, children: [
|
|
12707
13056
|
files[q.field].name,
|
|
12708
13057
|
" is on the phone. It goes up with the capture."
|
|
12709
13058
|
] }) : null
|
|
12710
|
-
] }) : control === "number" ? /* @__PURE__ */ (0,
|
|
12711
|
-
|
|
13059
|
+
] }) : control === "number" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13060
|
+
import_design_system47.Input,
|
|
12712
13061
|
{
|
|
12713
13062
|
id: `capture-${q.field}`,
|
|
12714
13063
|
"data-testid": `capture-input-${q.field}`,
|
|
@@ -12723,8 +13072,8 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12723
13072
|
setMissing(null);
|
|
12724
13073
|
}
|
|
12725
13074
|
}
|
|
12726
|
-
) : /* @__PURE__ */ (0,
|
|
12727
|
-
|
|
13075
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13076
|
+
import_design_system47.Textarea,
|
|
12728
13077
|
{
|
|
12729
13078
|
id: `capture-${q.field}`,
|
|
12730
13079
|
"data-testid": `capture-input-${q.field}`,
|
|
@@ -12738,10 +13087,10 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12738
13087
|
}
|
|
12739
13088
|
}
|
|
12740
13089
|
),
|
|
12741
|
-
missing ? /* @__PURE__ */ (0,
|
|
12742
|
-
/* @__PURE__ */ (0,
|
|
12743
|
-
at > 0 ? /* @__PURE__ */ (0,
|
|
12744
|
-
|
|
13090
|
+
missing ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "text-sm text-destructive", "data-testid": "capture-missing", children: missing }) : null,
|
|
13091
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
13092
|
+
at > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13093
|
+
import_design_system47.Button,
|
|
12745
13094
|
{
|
|
12746
13095
|
variant: "ghost",
|
|
12747
13096
|
className: "h-12 px-3",
|
|
@@ -12750,16 +13099,16 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12750
13099
|
children: "Back"
|
|
12751
13100
|
}
|
|
12752
13101
|
) : null,
|
|
12753
|
-
last ? /* @__PURE__ */ (0,
|
|
12754
|
-
|
|
13102
|
+
last ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13103
|
+
import_design_system47.Button,
|
|
12755
13104
|
{
|
|
12756
13105
|
className: "h-12 flex-1 text-base",
|
|
12757
13106
|
onClick: () => void capture(),
|
|
12758
13107
|
"data-testid": "capture-submit",
|
|
12759
13108
|
children: "Capture"
|
|
12760
13109
|
}
|
|
12761
|
-
) : /* @__PURE__ */ (0,
|
|
12762
|
-
|
|
13110
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
13111
|
+
import_design_system47.Button,
|
|
12763
13112
|
{
|
|
12764
13113
|
className: "h-12 flex-1 text-base",
|
|
12765
13114
|
onClick: () => setAt(at + 1),
|
|
@@ -12774,7 +13123,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12774
13123
|
}
|
|
12775
13124
|
|
|
12776
13125
|
// src/CaptureSheet.tsx
|
|
12777
|
-
var
|
|
13126
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
12778
13127
|
var CAPTURE_MODES = ["reading", "photo", "voice"];
|
|
12779
13128
|
var IN_MEMORY_QUEUE_REASON = "No capture queue is bound, so anything that cannot be sent right now is held in this page's memory and is lost if the page closes. Bind `captureQueue` on <RecordsUiProvider> with your host's own durable store (IndexedDB in a browser) and a queued capture survives the tab, the reload and the flight. It is said here rather than discovered later.";
|
|
12780
13129
|
function mintClientKey() {
|
|
@@ -12794,8 +13143,8 @@ function CaptureSheet({
|
|
|
12794
13143
|
attachmentField,
|
|
12795
13144
|
className
|
|
12796
13145
|
}) {
|
|
12797
|
-
if (sheetId) return /* @__PURE__ */ (0,
|
|
12798
|
-
return /* @__PURE__ */ (0,
|
|
13146
|
+
if (sheetId) return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(CaptureRun, { sheetId, className });
|
|
13147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
12799
13148
|
AdHocCaptureSheet,
|
|
12800
13149
|
{
|
|
12801
13150
|
tableId,
|
|
@@ -12813,21 +13162,21 @@ function AdHocCaptureSheet({
|
|
|
12813
13162
|
attachmentField,
|
|
12814
13163
|
className
|
|
12815
13164
|
}) {
|
|
12816
|
-
const client = (0,
|
|
13165
|
+
const client = (0, import_react97.useRecordsClient)();
|
|
12817
13166
|
const host = useRecordsUi();
|
|
12818
|
-
const table = (0,
|
|
12819
|
-
const fields = (0,
|
|
12820
|
-
const [mode, setMode] = (0,
|
|
12821
|
-
const [reading, setReading] = (0,
|
|
12822
|
-
const [note, setNote] = (0,
|
|
12823
|
-
const [fileId, setFileId] = (0,
|
|
12824
|
-
const [pending, setPending] = (0,
|
|
12825
|
-
const [saved, setSaved] = (0,
|
|
12826
|
-
const [error, setError] = (0,
|
|
12827
|
-
const [uploadError, setUploadError] = (0,
|
|
12828
|
-
const [flushing, setFlushing] = (0,
|
|
12829
|
-
const queue = (0,
|
|
12830
|
-
const keep = (0,
|
|
13167
|
+
const table = (0, import_react97.useTable)(tableId);
|
|
13168
|
+
const fields = (0, import_react97.useFields)(tableId);
|
|
13169
|
+
const [mode, setMode] = (0, import_react96.useState)("reading");
|
|
13170
|
+
const [reading, setReading] = (0, import_react96.useState)("");
|
|
13171
|
+
const [note, setNote] = (0, import_react96.useState)("");
|
|
13172
|
+
const [fileId, setFileId] = (0, import_react96.useState)(null);
|
|
13173
|
+
const [pending, setPending] = (0, import_react96.useState)(null);
|
|
13174
|
+
const [saved, setSaved] = (0, import_react96.useState)([]);
|
|
13175
|
+
const [error, setError] = (0, import_react96.useState)(null);
|
|
13176
|
+
const [uploadError, setUploadError] = (0, import_react96.useState)(null);
|
|
13177
|
+
const [flushing, setFlushing] = (0, import_react96.useState)(false);
|
|
13178
|
+
const queue = (0, import_react96.useRef)([]);
|
|
13179
|
+
const keep = (0, import_react96.useCallback)(
|
|
12831
13180
|
async (next) => {
|
|
12832
13181
|
queue.current = next;
|
|
12833
13182
|
setPending(next);
|
|
@@ -12835,7 +13184,7 @@ function AdHocCaptureSheet({
|
|
|
12835
13184
|
},
|
|
12836
13185
|
[host]
|
|
12837
13186
|
);
|
|
12838
|
-
(0,
|
|
13187
|
+
(0, import_react96.useEffect)(() => {
|
|
12839
13188
|
let cancelled = false;
|
|
12840
13189
|
void (async () => {
|
|
12841
13190
|
const held = host.captureQueue ? await host.captureQueue.load() : [];
|
|
@@ -12847,7 +13196,7 @@ function AdHocCaptureSheet({
|
|
|
12847
13196
|
cancelled = true;
|
|
12848
13197
|
};
|
|
12849
13198
|
}, [host]);
|
|
12850
|
-
const resolved = (0,
|
|
13199
|
+
const resolved = (0, import_react96.useCallback)(() => {
|
|
12851
13200
|
const all = fields.data ?? [];
|
|
12852
13201
|
return {
|
|
12853
13202
|
reading: readingField ?? all.find((f) => f.type === "range")?.key ?? null,
|
|
@@ -12855,7 +13204,7 @@ function AdHocCaptureSheet({
|
|
|
12855
13204
|
attachment: attachmentField ?? all.find((f) => f.format === "file" || f.format === "image")?.key ?? null
|
|
12856
13205
|
};
|
|
12857
13206
|
}, [attachmentField, fields.data, noteField, readingField, table.data]);
|
|
12858
|
-
const flush = (0,
|
|
13207
|
+
const flush = (0, import_react96.useCallback)(async () => {
|
|
12859
13208
|
if (flushing || queue.current.length === 0) return;
|
|
12860
13209
|
setFlushing(true);
|
|
12861
13210
|
const left = [];
|
|
@@ -12907,14 +13256,14 @@ function AdHocCaptureSheet({
|
|
|
12907
13256
|
await keep([...queue.current, item]);
|
|
12908
13257
|
await flush();
|
|
12909
13258
|
}
|
|
12910
|
-
if (table.error) return /* @__PURE__ */ (0,
|
|
12911
|
-
if (fields.error) return /* @__PURE__ */ (0,
|
|
12912
|
-
if (fields.loading || pending === null) return /* @__PURE__ */ (0,
|
|
13259
|
+
if (table.error) return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RefusalNotice, { error: table.error, className });
|
|
13260
|
+
if (fields.error) return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RefusalNotice, { error: fields.error, className });
|
|
13261
|
+
if (fields.loading || pending === null) return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_design_system48.Skeleton, { className: (0, import_design_system48.cn)("h-64 w-full", className) });
|
|
12913
13262
|
const keys = resolved();
|
|
12914
|
-
return /* @__PURE__ */ (0,
|
|
12915
|
-
/* @__PURE__ */ (0,
|
|
12916
|
-
CAPTURE_MODES.map((m) => /* @__PURE__ */ (0,
|
|
12917
|
-
|
|
13263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("section", { className: (0, import_design_system48.cn)("mx-auto flex w-full max-w-sm flex-col gap-2", className), children: [
|
|
13264
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("header", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
13265
|
+
CAPTURE_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
13266
|
+
import_design_system48.Button,
|
|
12918
13267
|
{
|
|
12919
13268
|
size: "sm",
|
|
12920
13269
|
variant: m === mode ? "default" : "ghost",
|
|
@@ -12924,11 +13273,11 @@ function AdHocCaptureSheet({
|
|
|
12924
13273
|
},
|
|
12925
13274
|
m
|
|
12926
13275
|
)),
|
|
12927
|
-
/* @__PURE__ */ (0,
|
|
13276
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "ml-auto tabular-nums", children: pending.length > 0 ? `${pending.length} waiting` : `${saved.length} saved` })
|
|
12928
13277
|
] }),
|
|
12929
|
-
error ? /* @__PURE__ */ (0,
|
|
12930
|
-
mode === "reading" ? keys.reading ? /* @__PURE__ */ (0,
|
|
12931
|
-
|
|
13278
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(RefusalNotice, { error }) : null,
|
|
13279
|
+
mode === "reading" ? keys.reading ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
13280
|
+
import_design_system48.Input,
|
|
12932
13281
|
{
|
|
12933
13282
|
"aria-label": "Reading",
|
|
12934
13283
|
inputMode: "decimal",
|
|
@@ -12937,22 +13286,22 @@ function AdHocCaptureSheet({
|
|
|
12937
13286
|
value: reading,
|
|
12938
13287
|
onChange: (e) => setReading(e.target.value)
|
|
12939
13288
|
}
|
|
12940
|
-
) : /* @__PURE__ */ (0,
|
|
13289
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
12941
13290
|
table.data?.name ?? "This table",
|
|
12942
13291
|
" has no number Field for a reading to go in, so this mode would have nowhere to put what you typed. Add one, or name it with ",
|
|
12943
|
-
/* @__PURE__ */ (0,
|
|
13292
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("code", { children: "readingField" }),
|
|
12944
13293
|
"."
|
|
12945
13294
|
] }) : null,
|
|
12946
|
-
mode !== "reading" ? !host.upload ? /* @__PURE__ */ (0,
|
|
13295
|
+
mode !== "reading" ? !host.upload ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : !keys.attachment ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
12947
13296
|
table.data?.name ?? "This table",
|
|
12948
13297
|
" has no Field a file id can go in, so a ",
|
|
12949
13298
|
mode,
|
|
12950
13299
|
" capture would upload the bytes and then have nowhere to record them. Add one, or name it with",
|
|
12951
13300
|
" ",
|
|
12952
|
-
/* @__PURE__ */ (0,
|
|
13301
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("code", { children: "attachmentField" }),
|
|
12953
13302
|
"."
|
|
12954
|
-
] }) : /* @__PURE__ */ (0,
|
|
12955
|
-
/* @__PURE__ */ (0,
|
|
13303
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
13304
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
12956
13305
|
"input",
|
|
12957
13306
|
{
|
|
12958
13307
|
"aria-label": mode === "photo" ? "Take a photo" : "Record a voice note",
|
|
@@ -12971,11 +13320,11 @@ function AdHocCaptureSheet({
|
|
|
12971
13320
|
}
|
|
12972
13321
|
}
|
|
12973
13322
|
),
|
|
12974
|
-
fileId ? /* @__PURE__ */ (0,
|
|
12975
|
-
uploadError ? /* @__PURE__ */ (0,
|
|
13323
|
+
fileId ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "text-[11px] text-muted-foreground", children: "Attached." }) : null,
|
|
13324
|
+
uploadError ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "text-xs text-destructive", children: uploadError }) : null
|
|
12976
13325
|
] }) : null,
|
|
12977
|
-
/* @__PURE__ */ (0,
|
|
12978
|
-
|
|
13326
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
13327
|
+
import_design_system48.Textarea,
|
|
12979
13328
|
{
|
|
12980
13329
|
"aria-label": "Note",
|
|
12981
13330
|
rows: 2,
|
|
@@ -12985,12 +13334,12 @@ function AdHocCaptureSheet({
|
|
|
12985
13334
|
onChange: (e) => setNote(e.target.value)
|
|
12986
13335
|
}
|
|
12987
13336
|
),
|
|
12988
|
-
/* @__PURE__ */ (0,
|
|
12989
|
-
pending.length > 0 ? /* @__PURE__ */ (0,
|
|
12990
|
-
/* @__PURE__ */ (0,
|
|
12991
|
-
/* @__PURE__ */ (0,
|
|
12992
|
-
/* @__PURE__ */ (0,
|
|
12993
|
-
|
|
13337
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_design_system48.Button, { className: "h-12", onClick: () => void capture(), children: "Capture" }),
|
|
13338
|
+
pending.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex flex-col gap-1 rounded border p-2", children: [
|
|
13339
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
13340
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "font-medium", children: "Waiting to send" }),
|
|
13341
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
13342
|
+
import_design_system48.Button,
|
|
12994
13343
|
{
|
|
12995
13344
|
size: "sm",
|
|
12996
13345
|
variant: "ghost",
|
|
@@ -13001,7 +13350,7 @@ function AdHocCaptureSheet({
|
|
|
13001
13350
|
}
|
|
13002
13351
|
)
|
|
13003
13352
|
] }),
|
|
13004
|
-
/* @__PURE__ */ (0,
|
|
13353
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("ul", { className: "flex flex-col gap-0.5", children: pending.map((item) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("li", { className: "text-[11px] text-muted-foreground", children: [
|
|
13005
13354
|
new Date(item.capturedAt).toLocaleTimeString(),
|
|
13006
13355
|
" \xB7 ",
|
|
13007
13356
|
item.attempts,
|
|
@@ -13009,23 +13358,23 @@ function AdHocCaptureSheet({
|
|
|
13009
13358
|
item.lastRefusal ? ` \xB7 ${item.lastRefusal}` : ""
|
|
13010
13359
|
] }, item.clientKey)) })
|
|
13011
13360
|
] }) : null,
|
|
13012
|
-
!host.captureQueue ? /* @__PURE__ */ (0,
|
|
13361
|
+
!host.captureQueue ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("p", { className: "rounded border border-dashed px-2 py-1 text-[11px] text-muted-foreground", children: IN_MEMORY_QUEUE_REASON }) : null
|
|
13013
13362
|
] });
|
|
13014
13363
|
}
|
|
13015
13364
|
|
|
13016
13365
|
// src/PortalShell.tsx
|
|
13017
|
-
var
|
|
13018
|
-
var
|
|
13019
|
-
var
|
|
13020
|
-
var
|
|
13366
|
+
var import_react98 = require("react");
|
|
13367
|
+
var import_react99 = require("@ai-matrx/records/react");
|
|
13368
|
+
var import_design_system49 = require("@ai-matrx/design-system");
|
|
13369
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
13021
13370
|
function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
13022
|
-
const client = (0,
|
|
13023
|
-
const [card, setCard] = (0,
|
|
13024
|
-
const [reach, setReach] = (0,
|
|
13025
|
-
const [error, setError] = (0,
|
|
13026
|
-
const [open, setOpen] = (0,
|
|
13027
|
-
const [sending, setSending] = (0,
|
|
13028
|
-
const load = (0,
|
|
13371
|
+
const client = (0, import_react99.useRecordsClient)();
|
|
13372
|
+
const [card, setCard] = (0, import_react98.useState)(null);
|
|
13373
|
+
const [reach, setReach] = (0, import_react98.useState)(null);
|
|
13374
|
+
const [error, setError] = (0, import_react98.useState)(null);
|
|
13375
|
+
const [open, setOpen] = (0, import_react98.useState)(null);
|
|
13376
|
+
const [sending, setSending] = (0, import_react98.useState)(false);
|
|
13377
|
+
const load = (0, import_react98.useCallback)(async () => {
|
|
13029
13378
|
const who = await client.externalPrincipalCard();
|
|
13030
13379
|
if (!who.ok) {
|
|
13031
13380
|
setError(who.error);
|
|
@@ -13040,23 +13389,23 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
|
13040
13389
|
}
|
|
13041
13390
|
setReach(reached.data.map((row) => row.resource_id));
|
|
13042
13391
|
}, [client, resourceType]);
|
|
13043
|
-
(0,
|
|
13392
|
+
(0, import_react98.useEffect)(() => {
|
|
13044
13393
|
void load();
|
|
13045
13394
|
}, [load]);
|
|
13046
13395
|
if (error) {
|
|
13047
|
-
return /* @__PURE__ */ (0,
|
|
13396
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(RefusalNotice, { error, className });
|
|
13048
13397
|
}
|
|
13049
|
-
if (!card || reach === null) return /* @__PURE__ */ (0,
|
|
13398
|
+
if (!card || reach === null) return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_design_system49.Skeleton, { className: (0, import_design_system49.cn)("h-64 w-full", className) });
|
|
13050
13399
|
if (!card.external) {
|
|
13051
|
-
return /* @__PURE__ */ (0,
|
|
13400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("p", { className: (0, import_design_system49.cn)("rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", className), children: card.explanation || "You are a member of an organization here, so this portal is not yours \u2014 a portal is the scoped view an OUTSIDER gets. You have the full application instead." });
|
|
13052
13401
|
}
|
|
13053
13402
|
if (sending && form) {
|
|
13054
|
-
return /* @__PURE__ */ (0,
|
|
13055
|
-
/* @__PURE__ */ (0,
|
|
13056
|
-
/* @__PURE__ */ (0,
|
|
13057
|
-
/* @__PURE__ */ (0,
|
|
13403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("section", { className: (0, import_design_system49.cn)("flex min-h-0 flex-col gap-2", className), children: [
|
|
13404
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13405
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "font-medium text-foreground", children: form.name }),
|
|
13406
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_design_system49.Button, { size: "sm", variant: "ghost", className: "ml-auto h-6 px-2 text-[11px]", onClick: () => setSending(false), children: "Back" })
|
|
13058
13407
|
] }),
|
|
13059
|
-
/* @__PURE__ */ (0,
|
|
13408
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13060
13409
|
FormRunner,
|
|
13061
13410
|
{
|
|
13062
13411
|
form,
|
|
@@ -13069,38 +13418,38 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
|
13069
13418
|
] });
|
|
13070
13419
|
}
|
|
13071
13420
|
if (open) {
|
|
13072
|
-
return /* @__PURE__ */ (0,
|
|
13421
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("section", { className: (0, import_design_system49.cn)("flex min-h-0 flex-col gap-2", className), children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(Peek, { tableId, recordId: open, onClose: () => setOpen(null) }) });
|
|
13073
13422
|
}
|
|
13074
|
-
return /* @__PURE__ */ (0,
|
|
13075
|
-
/* @__PURE__ */ (0,
|
|
13076
|
-
/* @__PURE__ */ (0,
|
|
13077
|
-
/* @__PURE__ */ (0,
|
|
13078
|
-
form ? /* @__PURE__ */ (0,
|
|
13423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("section", { className: (0, import_design_system49.cn)("flex min-h-0 flex-col gap-2", className), children: [
|
|
13424
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13425
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "font-medium text-foreground", children: "Shared with you" }),
|
|
13426
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "tabular-nums", children: reach.length }),
|
|
13427
|
+
form ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_design_system49.Button, { size: "sm", className: "ml-auto h-7 px-2 text-[11px]", onClick: () => setSending(true), children: form.submitLabel ?? form.name }) : null
|
|
13079
13428
|
] }),
|
|
13080
13429
|
reach.length === 0 ? (
|
|
13081
13430
|
// EMPTY, AND IT SAYS WHICH EMPTY. "Nobody has shared anything with you"
|
|
13082
13431
|
// and "the store would not tell us" are different sentences, and a
|
|
13083
13432
|
// person acts on them differently.
|
|
13084
|
-
/* @__PURE__ */ (0,
|
|
13433
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
13085
13434
|
"Nothing has been shared with you yet. ",
|
|
13086
13435
|
card.explanation,
|
|
13087
13436
|
" When somebody shares a record with you it appears here \u2014 this list is exactly what Visibility gave you, one record at a time, never an organization's list."
|
|
13088
13437
|
] })
|
|
13089
|
-
) : /* @__PURE__ */ (0,
|
|
13438
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("ul", { className: "flex min-h-0 flex-col gap-1 overflow-y-auto", children: reach.map((id) => /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13090
13439
|
"button",
|
|
13091
13440
|
{
|
|
13092
13441
|
type: "button",
|
|
13093
13442
|
className: "w-full truncate rounded border px-2 py-1.5 text-left text-xs hover:bg-muted",
|
|
13094
13443
|
onClick: () => setOpen(id),
|
|
13095
|
-
children: /* @__PURE__ */ (0,
|
|
13444
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(PortalRow, { tableId, recordId: id })
|
|
13096
13445
|
}
|
|
13097
13446
|
) }, id)) })
|
|
13098
13447
|
] });
|
|
13099
13448
|
}
|
|
13100
13449
|
function PortalRow({ tableId, recordId }) {
|
|
13101
|
-
const client = (0,
|
|
13102
|
-
const [title, setTitle] = (0,
|
|
13103
|
-
(0,
|
|
13450
|
+
const client = (0, import_react99.useRecordsClient)();
|
|
13451
|
+
const [title, setTitle] = (0, import_react98.useState)(null);
|
|
13452
|
+
(0, import_react98.useEffect)(() => {
|
|
13104
13453
|
let cancelled = false;
|
|
13105
13454
|
void client.recordRead({ record_id: recordId }).then((answered) => {
|
|
13106
13455
|
if (cancelled) return;
|
|
@@ -13116,22 +13465,22 @@ function PortalRow({ tableId, recordId }) {
|
|
|
13116
13465
|
cancelled = true;
|
|
13117
13466
|
};
|
|
13118
13467
|
}, [client, recordId, tableId]);
|
|
13119
|
-
return /* @__PURE__ */ (0,
|
|
13468
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { children: title ?? "\u2026" });
|
|
13120
13469
|
}
|
|
13121
13470
|
|
|
13122
13471
|
// src/PublicViewPage.tsx
|
|
13123
|
-
var
|
|
13124
|
-
var
|
|
13125
|
-
var
|
|
13126
|
-
var
|
|
13472
|
+
var import_react100 = require("react");
|
|
13473
|
+
var import_react101 = require("@ai-matrx/records/react");
|
|
13474
|
+
var import_design_system50 = require("@ai-matrx/design-system");
|
|
13475
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
13127
13476
|
function PublicViewPage({ slug, className }) {
|
|
13128
|
-
const client = (0,
|
|
13129
|
-
const [binding, setBinding] = (0,
|
|
13130
|
-
const [rows, setRows] = (0,
|
|
13131
|
-
const [fields, setFields] = (0,
|
|
13132
|
-
const [error, setError] = (0,
|
|
13133
|
-
const [gap, setGap] = (0,
|
|
13134
|
-
const load = (0,
|
|
13477
|
+
const client = (0, import_react101.useRecordsClient)();
|
|
13478
|
+
const [binding, setBinding] = (0, import_react100.useState)(null);
|
|
13479
|
+
const [rows, setRows] = (0, import_react100.useState)(null);
|
|
13480
|
+
const [fields, setFields] = (0, import_react100.useState)(null);
|
|
13481
|
+
const [error, setError] = (0, import_react100.useState)(null);
|
|
13482
|
+
const [gap, setGap] = (0, import_react100.useState)(null);
|
|
13483
|
+
const load = (0, import_react100.useCallback)(async () => {
|
|
13135
13484
|
const notice = await client.worldPublishGapNotice();
|
|
13136
13485
|
if (notice.ok) setGap(notice.data);
|
|
13137
13486
|
const resolved = await client.resolvePublishBinding({ slug });
|
|
@@ -13164,48 +13513,48 @@ function PublicViewPage({ slug, className }) {
|
|
|
13164
13513
|
}
|
|
13165
13514
|
setRows([{ id: found.resource_id, document: read.data.document, level: "viewer", hidden: read.data.hidden }]);
|
|
13166
13515
|
}, [client, slug]);
|
|
13167
|
-
(0,
|
|
13516
|
+
(0, import_react100.useEffect)(() => {
|
|
13168
13517
|
void load();
|
|
13169
13518
|
}, [load]);
|
|
13170
|
-
if (error) return /* @__PURE__ */ (0,
|
|
13171
|
-
if (binding === null) return /* @__PURE__ */ (0,
|
|
13519
|
+
if (error) return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(RefusalNotice, { error, className });
|
|
13520
|
+
if (binding === null) return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_design_system50.Skeleton, { className: (0, import_design_system50.cn)("h-64 w-full", className) });
|
|
13172
13521
|
if (binding === "none") {
|
|
13173
|
-
return /* @__PURE__ */ (0,
|
|
13174
|
-
/* @__PURE__ */ (0,
|
|
13175
|
-
/* @__PURE__ */ (0,
|
|
13176
|
-
gap ? /* @__PURE__ */ (0,
|
|
13522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("main", { className: (0, import_design_system50.cn)("mx-auto max-w-2xl py-16 text-center", className), children: [
|
|
13523
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("h1", { className: "text-lg font-medium", children: "Nothing here" }),
|
|
13524
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: "There is no public page at this address." }),
|
|
13525
|
+
gap ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "mt-6 text-xs text-muted-foreground", children: gap }) : null
|
|
13177
13526
|
] });
|
|
13178
13527
|
}
|
|
13179
|
-
return /* @__PURE__ */ (0,
|
|
13180
|
-
/* @__PURE__ */ (0,
|
|
13181
|
-
/* @__PURE__ */ (0,
|
|
13182
|
-
/* @__PURE__ */ (0,
|
|
13528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("main", { className: (0, import_design_system50.cn)("mx-auto flex max-w-2xl flex-col gap-3 py-8", className), children: [
|
|
13529
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("header", { className: "flex items-baseline gap-2 text-xs text-muted-foreground", children: [
|
|
13530
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "font-medium text-foreground", children: binding.namespace ?? "Published" }),
|
|
13531
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { children: binding.render_mode === "list" ? `${rows?.length ?? 0} items` : "Shared publicly" })
|
|
13183
13532
|
] }),
|
|
13184
|
-
rows === null ? /* @__PURE__ */ (0,
|
|
13185
|
-
/* @__PURE__ */ (0,
|
|
13533
|
+
rows === null ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_design_system50.Skeleton, { className: "h-40 w-full" }) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "text-sm text-muted-foreground", children: "This page has nothing on it yet." }) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("ol", { className: "flex flex-col gap-2", children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("li", { className: "rounded border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(PublicRow, { row, fields }) }, row.id)) }),
|
|
13534
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("footer", { className: "mt-4 border-t pt-3 text-xs text-muted-foreground", children: binding.notice || gap || "Nothing was scanned before this was listed." })
|
|
13186
13535
|
] });
|
|
13187
13536
|
}
|
|
13188
13537
|
function PublicRow({ row, fields }) {
|
|
13189
13538
|
const document2 = row.document ?? {};
|
|
13190
13539
|
if (!fields) {
|
|
13191
13540
|
const first = Object.entries(document2).filter(([key]) => !key.startsWith("_"));
|
|
13192
|
-
return /* @__PURE__ */ (0,
|
|
13193
|
-
/* @__PURE__ */ (0,
|
|
13194
|
-
/* @__PURE__ */ (0,
|
|
13541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-sm", children: first.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "contents", children: [
|
|
13542
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dt", { className: "text-xs text-muted-foreground", children: key }),
|
|
13543
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dd", { className: "text-sm", children: String(value ?? "") })
|
|
13195
13544
|
] }, key)) });
|
|
13196
13545
|
}
|
|
13197
|
-
return /* @__PURE__ */ (0,
|
|
13198
|
-
/* @__PURE__ */ (0,
|
|
13199
|
-
/* @__PURE__ */ (0,
|
|
13546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "contents", children: [
|
|
13547
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dt", { className: "text-xs text-muted-foreground", children: field.label }),
|
|
13548
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("dd", { className: "text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(RecordValue, { field, value: document2[field.key], document: row.document }) })
|
|
13200
13549
|
] }, field.key)) });
|
|
13201
13550
|
}
|
|
13202
13551
|
|
|
13203
13552
|
// src/EmbedFrame.tsx
|
|
13204
|
-
var
|
|
13205
|
-
var
|
|
13206
|
-
var
|
|
13207
|
-
var
|
|
13208
|
-
var
|
|
13553
|
+
var import_react102 = require("react");
|
|
13554
|
+
var import_react103 = require("@ai-matrx/records/react");
|
|
13555
|
+
var import_design_system51 = require("@ai-matrx/design-system");
|
|
13556
|
+
var import_react104 = require("@ai-matrx/records/react");
|
|
13557
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
13209
13558
|
function EmbedFrame({
|
|
13210
13559
|
tableId,
|
|
13211
13560
|
formId,
|
|
@@ -13214,18 +13563,18 @@ function EmbedFrame({
|
|
|
13214
13563
|
embedUrl,
|
|
13215
13564
|
className
|
|
13216
13565
|
}) {
|
|
13217
|
-
const client = (0,
|
|
13566
|
+
const client = (0, import_react103.useRecordsClient)();
|
|
13218
13567
|
const host = useRecordsUi();
|
|
13219
|
-
const table = (0,
|
|
13568
|
+
const table = (0, import_react104.useTable)(tableId);
|
|
13220
13569
|
const rights = useTableRights(table.data);
|
|
13221
|
-
const [origins, setOrigins] = (0,
|
|
13222
|
-
const [secret, setSecret] = (0,
|
|
13223
|
-
const [tokenId, setTokenId] = (0,
|
|
13224
|
-
const [error, setError] = (0,
|
|
13225
|
-
const [busy, setBusy] = (0,
|
|
13570
|
+
const [origins, setOrigins] = (0, import_react102.useState)("");
|
|
13571
|
+
const [secret, setSecret] = (0, import_react102.useState)(null);
|
|
13572
|
+
const [tokenId, setTokenId] = (0, import_react102.useState)(null);
|
|
13573
|
+
const [error, setError] = (0, import_react102.useState)(null);
|
|
13574
|
+
const [busy, setBusy] = (0, import_react102.useState)(false);
|
|
13226
13575
|
const mode = formId ? "write" : "read";
|
|
13227
13576
|
const parsed = origins.split(/[\s,]+/).map((o) => o.trim()).filter((o) => o.length > 0);
|
|
13228
|
-
const issue = (0,
|
|
13577
|
+
const issue = (0, import_react102.useCallback)(async () => {
|
|
13229
13578
|
setBusy(true);
|
|
13230
13579
|
setError(null);
|
|
13231
13580
|
const minted = await client.anonTokenIssue({
|
|
@@ -13244,7 +13593,7 @@ function EmbedFrame({
|
|
|
13244
13593
|
setTokenId(minted.data.token_id);
|
|
13245
13594
|
host.notify?.success("Embed token issued. Copy it now \u2014 it is never shown again.");
|
|
13246
13595
|
}, [client, formId, host, mode, parsed, recordId, savedViewId]);
|
|
13247
|
-
const revoke = (0,
|
|
13596
|
+
const revoke = (0, import_react102.useCallback)(async () => {
|
|
13248
13597
|
if (!tokenId) return;
|
|
13249
13598
|
setBusy(true);
|
|
13250
13599
|
const done = await client.anonTokenRevoke({ token_id: tokenId });
|
|
@@ -13256,25 +13605,25 @@ function EmbedFrame({
|
|
|
13256
13605
|
setSecret(null);
|
|
13257
13606
|
setTokenId(null);
|
|
13258
13607
|
}, [client, tokenId]);
|
|
13259
|
-
if (table.error) return /* @__PURE__ */ (0,
|
|
13260
|
-
if (table.loading) return /* @__PURE__ */ (0,
|
|
13608
|
+
if (table.error) return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(RefusalNotice, { error: table.error, className });
|
|
13609
|
+
if (table.loading) return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_design_system51.Skeleton, { className: (0, import_design_system51.cn)("h-48 w-full", className) });
|
|
13261
13610
|
if (!rights.admin) {
|
|
13262
|
-
return /* @__PURE__ */ (0,
|
|
13611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("p", { className: (0, import_design_system51.cn)("rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", className), children: [
|
|
13263
13612
|
rights.why("structure"),
|
|
13264
13613
|
" Issuing an embed opens a way in from somebody else's website, so the store asks for the admin level on this table before it will mint one."
|
|
13265
13614
|
] });
|
|
13266
13615
|
}
|
|
13267
13616
|
const snippet = secret ? `<iframe src="${embedUrl}#t=${secret}" style="width:100%;height:640px;border:0" loading="lazy"></iframe>` : null;
|
|
13268
|
-
return /* @__PURE__ */ (0,
|
|
13269
|
-
/* @__PURE__ */ (0,
|
|
13270
|
-
/* @__PURE__ */ (0,
|
|
13271
|
-
/* @__PURE__ */ (0,
|
|
13617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("section", { className: (0, import_design_system51.cn)("flex min-h-0 flex-col gap-2", className), children: [
|
|
13618
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13619
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "font-medium text-foreground", children: "Embed" }),
|
|
13620
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { children: mode === "write" ? "a form people can send" : "a read-only view" })
|
|
13272
13621
|
] }),
|
|
13273
|
-
error ? /* @__PURE__ */ (0,
|
|
13274
|
-
/* @__PURE__ */ (0,
|
|
13275
|
-
/* @__PURE__ */ (0,
|
|
13276
|
-
/* @__PURE__ */ (0,
|
|
13277
|
-
|
|
13622
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(RefusalNotice, { error }) : null,
|
|
13623
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("label", { className: "flex flex-col gap-1 text-xs", children: [
|
|
13624
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "text-muted-foreground", children: "Sites this embed works on" }),
|
|
13625
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
13626
|
+
import_design_system51.Input,
|
|
13278
13627
|
{
|
|
13279
13628
|
"aria-label": "Allowed origins",
|
|
13280
13629
|
className: "h-8 text-xs",
|
|
@@ -13283,18 +13632,18 @@ function EmbedFrame({
|
|
|
13283
13632
|
onChange: (e) => setOrigins(e.target.value)
|
|
13284
13633
|
}
|
|
13285
13634
|
),
|
|
13286
|
-
/* @__PURE__ */ (0,
|
|
13635
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "text-[11px] text-muted-foreground", children: [
|
|
13287
13636
|
`Name every site, scheme and host and port. An empty list is refused rather than quietly meaning "anywhere": a token that works from any page on the internet includes an attacker's. The match is exact, so `,
|
|
13288
|
-
/* @__PURE__ */ (0,
|
|
13637
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("code", { children: "example.com.evil.test" }),
|
|
13289
13638
|
" will not pass."
|
|
13290
13639
|
] })
|
|
13291
13640
|
] }),
|
|
13292
|
-
!secret ? /* @__PURE__ */ (0,
|
|
13293
|
-
/* @__PURE__ */ (0,
|
|
13294
|
-
/* @__PURE__ */ (0,
|
|
13295
|
-
/* @__PURE__ */ (0,
|
|
13296
|
-
/* @__PURE__ */ (0,
|
|
13297
|
-
|
|
13641
|
+
!secret ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_design_system51.Button, { size: "sm", className: "self-start", disabled: busy || parsed.length === 0, onClick: () => void issue(), children: busy ? "Issuing\u2026" : "Issue embed" }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
|
|
13642
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: "rounded border px-2 py-1 text-xs text-muted-foreground", children: "Copy this now. Only its digest is stored, so nobody \u2014 including us \u2014 can show it to you again; if it is lost, issue a new one and replace the old." }),
|
|
13643
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_design_system51.Textarea, { "aria-label": "Embed snippet", readOnly: true, rows: 3, className: "font-mono text-[11px]", value: snippet ?? "" }),
|
|
13644
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "flex gap-2", children: [
|
|
13645
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
13646
|
+
import_design_system51.Button,
|
|
13298
13647
|
{
|
|
13299
13648
|
size: "sm",
|
|
13300
13649
|
variant: "outline",
|
|
@@ -13302,19 +13651,19 @@ function EmbedFrame({
|
|
|
13302
13651
|
children: "Copy"
|
|
13303
13652
|
}
|
|
13304
13653
|
),
|
|
13305
|
-
/* @__PURE__ */ (0,
|
|
13654
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_design_system51.Button, { size: "sm", variant: "ghost", disabled: busy, onClick: () => void revoke(), children: "Revoke" })
|
|
13306
13655
|
] })
|
|
13307
13656
|
] })
|
|
13308
13657
|
] });
|
|
13309
13658
|
}
|
|
13310
13659
|
function useEmbedHandshake(args) {
|
|
13311
|
-
const client = (0,
|
|
13312
|
-
const [binding, setBinding] = (0,
|
|
13313
|
-
const [error, setError] = (0,
|
|
13314
|
-
const [loading, setLoading] = (0,
|
|
13660
|
+
const client = (0, import_react103.useRecordsClient)();
|
|
13661
|
+
const [binding, setBinding] = (0, import_react102.useState)(null);
|
|
13662
|
+
const [error, setError] = (0, import_react102.useState)(null);
|
|
13663
|
+
const [loading, setLoading] = (0, import_react102.useState)(true);
|
|
13315
13664
|
const origin = args.origin ?? (typeof location === "undefined" ? "" : location.origin);
|
|
13316
13665
|
const { secret, requiredMode } = args;
|
|
13317
|
-
(0,
|
|
13666
|
+
(0, import_react102.useEffect)(() => {
|
|
13318
13667
|
let cancelled = false;
|
|
13319
13668
|
setLoading(true);
|
|
13320
13669
|
setError(null);
|
|
@@ -13336,8 +13685,8 @@ function useEmbedHandshake(args) {
|
|
|
13336
13685
|
}
|
|
13337
13686
|
|
|
13338
13687
|
// src/RecordsMount.tsx
|
|
13339
|
-
var
|
|
13340
|
-
var
|
|
13688
|
+
var import_react105 = require("@ai-matrx/records/react");
|
|
13689
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
13341
13690
|
var STORE_DECIDES_REASON = "This host offers exactly what the record store says this person may do: the level comes back with the table on the read door, so a control they cannot use is never drawn in the first place.";
|
|
13342
13691
|
function storeDecidesRights(_table) {
|
|
13343
13692
|
return NO_RIGHTS;
|
|
@@ -13350,7 +13699,7 @@ function RecordsMount({
|
|
|
13350
13699
|
}) {
|
|
13351
13700
|
const bound = { ...host ?? {} };
|
|
13352
13701
|
void letTheStoreDecideRights;
|
|
13353
|
-
return /* @__PURE__ */ (0,
|
|
13702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react105.RecordsProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(RecordsUiProvider, { value: bound, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(RecordLabelProvider, { children }) }) });
|
|
13354
13703
|
}
|
|
13355
13704
|
function personActor(userId) {
|
|
13356
13705
|
return userId ? { actor: "user", user_id: userId } : { actor: "user" };
|
|
@@ -13369,9 +13718,9 @@ function recordsDataSource(client, fallbackSchema = "custom") {
|
|
|
13369
13718
|
}
|
|
13370
13719
|
|
|
13371
13720
|
// src/TablesHome.tsx
|
|
13372
|
-
var
|
|
13373
|
-
var
|
|
13374
|
-
var
|
|
13721
|
+
var import_react106 = require("react");
|
|
13722
|
+
var import_react107 = require("@ai-matrx/records/react");
|
|
13723
|
+
var import_design_system52 = require("@ai-matrx/design-system");
|
|
13375
13724
|
|
|
13376
13725
|
// src/createTable.ts
|
|
13377
13726
|
function tokenFor(name) {
|
|
@@ -13481,7 +13830,7 @@ function declaredType(field) {
|
|
|
13481
13830
|
}
|
|
13482
13831
|
|
|
13483
13832
|
// src/TablesHome.tsx
|
|
13484
|
-
var
|
|
13833
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
13485
13834
|
var TABLE_LANES = ["mine", "organization", "system", "community", "app"];
|
|
13486
13835
|
var LANE_TITLE = {
|
|
13487
13836
|
mine: "Mine",
|
|
@@ -13506,15 +13855,15 @@ function laneFor(table) {
|
|
|
13506
13855
|
return "organization";
|
|
13507
13856
|
}
|
|
13508
13857
|
function TablesHome({ onOpenTable, className }) {
|
|
13509
|
-
const client = (0,
|
|
13510
|
-
const tables = (0,
|
|
13511
|
-
const [creating, setCreating] = (0,
|
|
13512
|
-
const [name, setName] = (0,
|
|
13513
|
-
const [busy, setBusy] = (0,
|
|
13514
|
-
const [error, setError] = (0,
|
|
13515
|
-
const [importInto, setImportInto] = (0,
|
|
13516
|
-
const [boards, setBoards] = (0,
|
|
13517
|
-
(0,
|
|
13858
|
+
const client = (0, import_react107.useRecordsClient)();
|
|
13859
|
+
const tables = (0, import_react107.useTables)();
|
|
13860
|
+
const [creating, setCreating] = (0, import_react106.useState)(false);
|
|
13861
|
+
const [name, setName] = (0, import_react106.useState)("");
|
|
13862
|
+
const [busy, setBusy] = (0, import_react106.useState)(false);
|
|
13863
|
+
const [error, setError] = (0, import_react106.useState)(null);
|
|
13864
|
+
const [importInto, setImportInto] = (0, import_react106.useState)(null);
|
|
13865
|
+
const [boards, setBoards] = (0, import_react106.useState)(null);
|
|
13866
|
+
(0, import_react106.useEffect)(() => {
|
|
13518
13867
|
let cancelled = false;
|
|
13519
13868
|
void client.dashboards({}).then((result) => {
|
|
13520
13869
|
if (cancelled) return;
|
|
@@ -13524,7 +13873,7 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13524
13873
|
cancelled = true;
|
|
13525
13874
|
};
|
|
13526
13875
|
}, [client]);
|
|
13527
|
-
const create = (0,
|
|
13876
|
+
const create = (0, import_react106.useCallback)(
|
|
13528
13877
|
async (mode) => {
|
|
13529
13878
|
const trimmed = name.trim();
|
|
13530
13879
|
if (!trimmed) return;
|
|
@@ -13544,10 +13893,10 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13544
13893
|
},
|
|
13545
13894
|
[client, name, onOpenTable, tables]
|
|
13546
13895
|
);
|
|
13547
|
-
return /* @__PURE__ */ (0,
|
|
13548
|
-
/* @__PURE__ */ (0,
|
|
13549
|
-
/* @__PURE__ */ (0,
|
|
13550
|
-
|
|
13896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: (0, import_design_system52.cn)("flex min-h-0 flex-col gap-4", className), children: [
|
|
13897
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "flex items-center gap-2", children: creating ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
13898
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
13899
|
+
import_design_system52.BasicInput,
|
|
13551
13900
|
{
|
|
13552
13901
|
autoFocus: true,
|
|
13553
13902
|
value: name,
|
|
@@ -13560,9 +13909,9 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13560
13909
|
className: "h-8 max-w-xs"
|
|
13561
13910
|
}
|
|
13562
13911
|
),
|
|
13563
|
-
/* @__PURE__ */ (0,
|
|
13564
|
-
/* @__PURE__ */ (0,
|
|
13565
|
-
|
|
13912
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Button, { size: "sm", disabled: busy || name.trim().length === 0, onClick: () => void create("open"), children: busy ? "Declaring\u2026" : "Create" }),
|
|
13913
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
13914
|
+
import_design_system52.Button,
|
|
13566
13915
|
{
|
|
13567
13916
|
size: "sm",
|
|
13568
13917
|
variant: "outline",
|
|
@@ -13571,37 +13920,37 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13571
13920
|
children: "Create and import a file"
|
|
13572
13921
|
}
|
|
13573
13922
|
),
|
|
13574
|
-
/* @__PURE__ */ (0,
|
|
13575
|
-
] }) : /* @__PURE__ */ (0,
|
|
13576
|
-
error ? /* @__PURE__ */ (0,
|
|
13577
|
-
importInto ? /* @__PURE__ */ (0,
|
|
13578
|
-
/* @__PURE__ */ (0,
|
|
13579
|
-
/* @__PURE__ */ (0,
|
|
13923
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Button, { size: "sm", variant: "ghost", onClick: () => setCreating(false), children: "Cancel" })
|
|
13924
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Button, { size: "sm", onClick: () => setCreating(true), children: "New table" }) }),
|
|
13925
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(RefusalNotice, { error }) : null,
|
|
13926
|
+
importInto ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "rounded-md border p-3", children: [
|
|
13927
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ImportWizard, { tableId: importInto, onDone: () => setImportInto(null) }),
|
|
13928
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Button, { size: "sm", variant: "ghost", className: "mt-2", onClick: () => onOpenTable?.(importInto), children: "Open the table" })
|
|
13580
13929
|
] }) : null,
|
|
13581
|
-
tables.error ? /* @__PURE__ */ (0,
|
|
13582
|
-
tables.loading && !tables.data ? /* @__PURE__ */ (0,
|
|
13583
|
-
/* @__PURE__ */ (0,
|
|
13584
|
-
/* @__PURE__ */ (0,
|
|
13930
|
+
tables.error ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(RefusalNotice, { error: tables.error }) : null,
|
|
13931
|
+
tables.loading && !tables.data ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "space-y-2", children: [
|
|
13932
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Skeleton, { className: "h-6 w-40" }),
|
|
13933
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_design_system52.Skeleton, { className: "h-16 w-full" })
|
|
13585
13934
|
] }) : null,
|
|
13586
|
-
/* @__PURE__ */ (0,
|
|
13587
|
-
boards && boards.length > 0 ? /* @__PURE__ */ (0,
|
|
13588
|
-
/* @__PURE__ */ (0,
|
|
13589
|
-
/* @__PURE__ */ (0,
|
|
13590
|
-
/* @__PURE__ */ (0,
|
|
13935
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(BookingSlots, {}),
|
|
13936
|
+
boards && boards.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("section", { className: "space-y-1.5", children: [
|
|
13937
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
13938
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("h2", { className: "text-sm font-medium", children: "Dashboards" }),
|
|
13939
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "text-xs opacity-60", children: boards.length })
|
|
13591
13940
|
] }),
|
|
13592
|
-
/* @__PURE__ */ (0,
|
|
13941
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("ul", { className: "grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3", children: boards.map((board) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
13593
13942
|
"button",
|
|
13594
13943
|
{
|
|
13595
13944
|
type: "button",
|
|
13596
13945
|
disabled: !board.table_id,
|
|
13597
13946
|
onClick: () => board.table_id ? onOpenTable?.(board.table_id, board.dashboard_id) : void 0,
|
|
13598
|
-
className: (0,
|
|
13947
|
+
className: (0, import_design_system52.cn)(
|
|
13599
13948
|
"w-full rounded-md border px-3 py-2 text-left transition-colors",
|
|
13600
13949
|
onOpenTable && board.table_id ? "hover:bg-accent" : "cursor-default"
|
|
13601
13950
|
),
|
|
13602
13951
|
children: [
|
|
13603
|
-
/* @__PURE__ */ (0,
|
|
13604
|
-
/* @__PURE__ */ (0,
|
|
13952
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "block truncate text-sm", children: board.name }),
|
|
13953
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "block truncate text-xs opacity-60", children: [
|
|
13605
13954
|
board.block_count,
|
|
13606
13955
|
" block",
|
|
13607
13956
|
board.block_count === 1 ? "" : "s",
|
|
@@ -13617,23 +13966,23 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13617
13966
|
] }) : null,
|
|
13618
13967
|
tables.data ? TABLE_LANES.map((lane) => {
|
|
13619
13968
|
const rows = tables.data.filter((t) => laneFor(t) === lane);
|
|
13620
|
-
return /* @__PURE__ */ (0,
|
|
13621
|
-
/* @__PURE__ */ (0,
|
|
13622
|
-
/* @__PURE__ */ (0,
|
|
13623
|
-
/* @__PURE__ */ (0,
|
|
13969
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("section", { className: "space-y-1.5", children: [
|
|
13970
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
13971
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("h2", { className: "text-sm font-medium", children: LANE_TITLE[lane] }),
|
|
13972
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "text-xs opacity-60", children: rows.length })
|
|
13624
13973
|
] }),
|
|
13625
|
-
rows.length === 0 ? /* @__PURE__ */ (0,
|
|
13974
|
+
rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("p", { className: "text-xs opacity-70", children: LANE_EMPTY[lane] }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("ul", { className: "grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3", children: rows.map((table) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
13626
13975
|
"button",
|
|
13627
13976
|
{
|
|
13628
13977
|
type: "button",
|
|
13629
13978
|
onClick: () => onOpenTable?.(table.id),
|
|
13630
|
-
className: (0,
|
|
13979
|
+
className: (0, import_design_system52.cn)(
|
|
13631
13980
|
"w-full rounded-md border px-3 py-2 text-left transition-colors",
|
|
13632
13981
|
onOpenTable ? "hover:bg-accent" : "cursor-default"
|
|
13633
13982
|
),
|
|
13634
13983
|
children: [
|
|
13635
|
-
/* @__PURE__ */ (0,
|
|
13636
|
-
/* @__PURE__ */ (0,
|
|
13984
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "block truncate text-sm", children: tableName(table) }),
|
|
13985
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "block truncate text-xs opacity-60", children: [
|
|
13637
13986
|
table.fields.length,
|
|
13638
13987
|
" field",
|
|
13639
13988
|
table.fields.length === 1 ? "" : "s",
|
|
@@ -13648,10 +13997,10 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13648
13997
|
}
|
|
13649
13998
|
|
|
13650
13999
|
// src/TablePage.tsx
|
|
13651
|
-
var
|
|
13652
|
-
var
|
|
13653
|
-
var
|
|
13654
|
-
var
|
|
14000
|
+
var import_react108 = require("react");
|
|
14001
|
+
var import_react109 = require("@ai-matrx/records/react");
|
|
14002
|
+
var import_design_system53 = require("@ai-matrx/design-system");
|
|
14003
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
13655
14004
|
var TABLE_NOT_REACHABLE = "This table is not in the organization you are working in, so there is nothing here to show. Switch to the organization that owns it and open it again \u2014 or it may have been deleted.";
|
|
13656
14005
|
var DEFAULT_VIEW_NAME = "All records";
|
|
13657
14006
|
var VIEW_NOT_SAVED_YET = "This table has no saved view yet, so the layout you pick here is not being kept. Save one from the bar above and it is remembered.";
|
|
@@ -13682,29 +14031,29 @@ function TablePage({
|
|
|
13682
14031
|
activeRecordId,
|
|
13683
14032
|
className
|
|
13684
14033
|
}) {
|
|
13685
|
-
const client = (0,
|
|
13686
|
-
const table = (0,
|
|
14034
|
+
const client = (0, import_react109.useRecordsClient)();
|
|
14035
|
+
const table = (0, import_react109.useTable)(tableId);
|
|
13687
14036
|
const rights = useTableRights(table.data);
|
|
13688
|
-
const organizationId = (0,
|
|
13689
|
-
const [view, setView] = (0,
|
|
14037
|
+
const organizationId = (0, import_react109.useRecordsClient)().config.organizationId;
|
|
14038
|
+
const [view, setView] = (0, import_react108.useState)(null);
|
|
13690
14039
|
const opening = openingRail(activeRecordId);
|
|
13691
|
-
const [asking, setAsking] = (0,
|
|
13692
|
-
const [surface, setSurface] = (0,
|
|
14040
|
+
const [asking, setAsking] = (0, import_react108.useState)(null);
|
|
14041
|
+
const [surface, setSurface] = (0, import_react108.useState)({
|
|
13693
14042
|
main: activeDashboardId ? "dashboards" : "records",
|
|
13694
14043
|
rail: opening.rail
|
|
13695
14044
|
});
|
|
13696
14045
|
const { main, rail } = surface;
|
|
13697
14046
|
const setRail = (next) => setSurface((now) => ({ ...now, rail: next }));
|
|
13698
|
-
const [openRecord, setOpenRecord] = (0,
|
|
14047
|
+
const [openRecord, setOpenRecord] = (0, import_react108.useState)(opening.record);
|
|
13699
14048
|
const viewVersion = useRecordVersion(view?.id ?? null);
|
|
13700
14049
|
const press = (pressed) => setSurface((now) => chooseSurface(now, pressed));
|
|
13701
14050
|
const show = (next) => press({ rail: next });
|
|
13702
|
-
(0,
|
|
14051
|
+
(0, import_react108.useEffect)(() => {
|
|
13703
14052
|
if (!activeRecordId) return;
|
|
13704
14053
|
setOpenRecord(activeRecordId);
|
|
13705
14054
|
setSurface((now) => ({ ...now, rail: "record" }));
|
|
13706
14055
|
}, [activeRecordId]);
|
|
13707
|
-
const patchView = (0,
|
|
14056
|
+
const patchView = (0, import_react108.useCallback)(
|
|
13708
14057
|
async (patch) => {
|
|
13709
14058
|
const current = view;
|
|
13710
14059
|
if (!current) return;
|
|
@@ -13720,19 +14069,19 @@ function TablePage({
|
|
|
13720
14069
|
},
|
|
13721
14070
|
[client, view, viewVersion]
|
|
13722
14071
|
);
|
|
13723
|
-
if (table.error) return /* @__PURE__ */ (0,
|
|
13724
|
-
if (table.loading) return /* @__PURE__ */ (0,
|
|
14072
|
+
if (table.error) return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(RefusalNotice, { error: table.error });
|
|
14073
|
+
if (table.loading) return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Skeleton, { className: "h-40 w-full" });
|
|
13725
14074
|
if (!table.data) {
|
|
13726
|
-
return /* @__PURE__ */ (0,
|
|
13727
|
-
/* @__PURE__ */ (0,
|
|
13728
|
-
/* @__PURE__ */ (0,
|
|
13729
|
-
onLeave ? /* @__PURE__ */ (0,
|
|
14075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: (0, import_design_system53.cn)("flex flex-col items-start gap-2 rounded-md border border-dashed p-6", className), children: [
|
|
14076
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "text-sm font-medium", children: "This table is not here" }),
|
|
14077
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "max-w-prose text-xs text-muted-foreground", children: TABLE_NOT_REACHABLE }),
|
|
14078
|
+
onLeave ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Button, { size: "sm", variant: "outline", onClick: onLeave, children: leaveLabel }) : null
|
|
13730
14079
|
] });
|
|
13731
14080
|
}
|
|
13732
|
-
return /* @__PURE__ */ (0,
|
|
13733
|
-
/* @__PURE__ */ (0,
|
|
13734
|
-
/* @__PURE__ */ (0,
|
|
13735
|
-
/* @__PURE__ */ (0,
|
|
14081
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: (0, import_design_system53.cn)("flex min-h-0 gap-4", className), children: [
|
|
14082
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
|
|
14083
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
14084
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13736
14085
|
ViewBar,
|
|
13737
14086
|
{
|
|
13738
14087
|
tableId,
|
|
@@ -13741,10 +14090,10 @@ function TablePage({
|
|
|
13741
14090
|
className: "min-w-0 flex-1"
|
|
13742
14091
|
}
|
|
13743
14092
|
),
|
|
13744
|
-
rights.write && view && view.layout !== "grid" ? /* @__PURE__ */ (0,
|
|
13745
|
-
rights.structure ? /* @__PURE__ */ (0,
|
|
13746
|
-
/* @__PURE__ */ (0,
|
|
13747
|
-
|
|
14093
|
+
rights.write && view && view.layout !== "grid" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Button, { size: "sm", onClick: () => show("new-record"), children: "New record" }) : null,
|
|
14094
|
+
rights.structure ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14095
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14096
|
+
import_design_system53.Button,
|
|
13748
14097
|
{
|
|
13749
14098
|
size: "sm",
|
|
13750
14099
|
variant: surfaceChosen(surface, { rail: "field" }) ? "secondary" : "outline",
|
|
@@ -13753,8 +14102,8 @@ function TablePage({
|
|
|
13753
14102
|
children: "Add field"
|
|
13754
14103
|
}
|
|
13755
14104
|
),
|
|
13756
|
-
/* @__PURE__ */ (0,
|
|
13757
|
-
|
|
14105
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14106
|
+
import_design_system53.Button,
|
|
13758
14107
|
{
|
|
13759
14108
|
size: "sm",
|
|
13760
14109
|
variant: surfaceChosen(surface, { rail: "settings" }) ? "secondary" : "ghost",
|
|
@@ -13763,8 +14112,8 @@ function TablePage({
|
|
|
13763
14112
|
children: "Settings"
|
|
13764
14113
|
}
|
|
13765
14114
|
),
|
|
13766
|
-
/* @__PURE__ */ (0,
|
|
13767
|
-
|
|
14115
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14116
|
+
import_design_system53.Button,
|
|
13768
14117
|
{
|
|
13769
14118
|
size: "sm",
|
|
13770
14119
|
variant: surfaceChosen(surface, { rail: "import" }) ? "secondary" : "ghost",
|
|
@@ -13774,8 +14123,8 @@ function TablePage({
|
|
|
13774
14123
|
}
|
|
13775
14124
|
)
|
|
13776
14125
|
] }) : null,
|
|
13777
|
-
/* @__PURE__ */ (0,
|
|
13778
|
-
|
|
14126
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14127
|
+
import_design_system53.Button,
|
|
13779
14128
|
{
|
|
13780
14129
|
size: "sm",
|
|
13781
14130
|
variant: surfaceChosen(surface, { main: "dashboards" }) ? "secondary" : "ghost",
|
|
@@ -13784,8 +14133,8 @@ function TablePage({
|
|
|
13784
14133
|
children: "Dashboards"
|
|
13785
14134
|
}
|
|
13786
14135
|
),
|
|
13787
|
-
/* @__PURE__ */ (0,
|
|
13788
|
-
|
|
14136
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14137
|
+
import_design_system53.Button,
|
|
13789
14138
|
{
|
|
13790
14139
|
size: "sm",
|
|
13791
14140
|
variant: surfaceChosen(surface, { rail: "forms" }) ? "secondary" : "ghost",
|
|
@@ -13794,8 +14143,8 @@ function TablePage({
|
|
|
13794
14143
|
children: "Forms"
|
|
13795
14144
|
}
|
|
13796
14145
|
),
|
|
13797
|
-
/* @__PURE__ */ (0,
|
|
13798
|
-
|
|
14146
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14147
|
+
import_design_system53.Button,
|
|
13799
14148
|
{
|
|
13800
14149
|
size: "sm",
|
|
13801
14150
|
variant: surfaceChosen(surface, { rail: "bookings" }) ? "secondary" : "ghost",
|
|
@@ -13804,8 +14153,8 @@ function TablePage({
|
|
|
13804
14153
|
children: "Bookings"
|
|
13805
14154
|
}
|
|
13806
14155
|
),
|
|
13807
|
-
/* @__PURE__ */ (0,
|
|
13808
|
-
|
|
14156
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14157
|
+
import_design_system53.Button,
|
|
13809
14158
|
{
|
|
13810
14159
|
size: "sm",
|
|
13811
14160
|
variant: surfaceChosen(surface, { rail: "checklists" }) ? "secondary" : "ghost",
|
|
@@ -13814,8 +14163,8 @@ function TablePage({
|
|
|
13814
14163
|
children: "Checklists"
|
|
13815
14164
|
}
|
|
13816
14165
|
),
|
|
13817
|
-
/* @__PURE__ */ (0,
|
|
13818
|
-
|
|
14166
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14167
|
+
import_design_system53.Button,
|
|
13819
14168
|
{
|
|
13820
14169
|
size: "sm",
|
|
13821
14170
|
variant: surfaceChosen(surface, { rail: "notifications" }) ? "secondary" : "ghost",
|
|
@@ -13824,8 +14173,8 @@ function TablePage({
|
|
|
13824
14173
|
children: "Notifications"
|
|
13825
14174
|
}
|
|
13826
14175
|
),
|
|
13827
|
-
/* @__PURE__ */ (0,
|
|
13828
|
-
|
|
14176
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14177
|
+
import_design_system53.Button,
|
|
13829
14178
|
{
|
|
13830
14179
|
size: "sm",
|
|
13831
14180
|
variant: surfaceChosen(surface, { rail: "portals" }) ? "secondary" : "ghost",
|
|
@@ -13834,8 +14183,8 @@ function TablePage({
|
|
|
13834
14183
|
children: "Portals"
|
|
13835
14184
|
}
|
|
13836
14185
|
),
|
|
13837
|
-
/* @__PURE__ */ (0,
|
|
13838
|
-
|
|
14186
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14187
|
+
import_design_system53.Button,
|
|
13839
14188
|
{
|
|
13840
14189
|
size: "sm",
|
|
13841
14190
|
variant: surfaceChosen(surface, { rail: "inbox" }) ? "secondary" : "ghost",
|
|
@@ -13844,7 +14193,7 @@ function TablePage({
|
|
|
13844
14193
|
children: "Inbox"
|
|
13845
14194
|
}
|
|
13846
14195
|
),
|
|
13847
|
-
/* @__PURE__ */ (0,
|
|
14196
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13848
14197
|
ShareControl,
|
|
13849
14198
|
{
|
|
13850
14199
|
kind: "table",
|
|
@@ -13854,10 +14203,10 @@ function TablePage({
|
|
|
13854
14203
|
may: rights.share
|
|
13855
14204
|
}
|
|
13856
14205
|
),
|
|
13857
|
-
/* @__PURE__ */ (0,
|
|
14206
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ExportMenu, { tableId })
|
|
13858
14207
|
] }),
|
|
13859
|
-
main === "dashboards" ? /* @__PURE__ */ (0,
|
|
13860
|
-
/* @__PURE__ */ (0,
|
|
14208
|
+
main === "dashboards" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DashboardCanvas, { tableId, activeDashboardId: activeDashboardId ?? null }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14209
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13861
14210
|
ViewSwitcher,
|
|
13862
14211
|
{
|
|
13863
14212
|
view: view ?? defaultView(tableId),
|
|
@@ -13874,18 +14223,18 @@ function TablePage({
|
|
|
13874
14223
|
}
|
|
13875
14224
|
}
|
|
13876
14225
|
),
|
|
13877
|
-
view ? null : /* @__PURE__ */ (0,
|
|
14226
|
+
view ? null : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "text-xs text-muted-foreground", children: VIEW_NOT_SAVED_YET })
|
|
13878
14227
|
] })
|
|
13879
14228
|
] }),
|
|
13880
|
-
rail === "none" ? null : /* @__PURE__ */ (0,
|
|
13881
|
-
rail === "settings" ? /* @__PURE__ */ (0,
|
|
14229
|
+
rail === "none" ? null : /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("aside", { className: "w-[26rem] shrink-0 overflow-y-auto rounded-md border p-3", children: [
|
|
14230
|
+
rail === "settings" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13882
14231
|
TableSettings,
|
|
13883
14232
|
{
|
|
13884
14233
|
tableId,
|
|
13885
14234
|
...onLeave ? { onDeleted: onLeave } : {}
|
|
13886
14235
|
}
|
|
13887
14236
|
) : null,
|
|
13888
|
-
rail === "inbox" ? /* @__PURE__ */ (0,
|
|
14237
|
+
rail === "inbox" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13889
14238
|
ActionInbox,
|
|
13890
14239
|
{
|
|
13891
14240
|
tableId,
|
|
@@ -13895,9 +14244,9 @@ function TablePage({
|
|
|
13895
14244
|
}
|
|
13896
14245
|
}
|
|
13897
14246
|
) : null,
|
|
13898
|
-
rail === "forms" ? /* @__PURE__ */ (0,
|
|
13899
|
-
rail === "bookings" ? /* @__PURE__ */ (0,
|
|
13900
|
-
rail === "checklists" ? /* @__PURE__ */ (0,
|
|
14247
|
+
rail === "forms" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FormsPanel, { tableId }) : null,
|
|
14248
|
+
rail === "bookings" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(BookingSlots, { tableId }) : null,
|
|
14249
|
+
rail === "checklists" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13901
14250
|
ChecklistsPanel,
|
|
13902
14251
|
{
|
|
13903
14252
|
tableId,
|
|
@@ -13907,11 +14256,11 @@ function TablePage({
|
|
|
13907
14256
|
}
|
|
13908
14257
|
}
|
|
13909
14258
|
) : null,
|
|
13910
|
-
rail === "notifications" ? /* @__PURE__ */ (0,
|
|
13911
|
-
rail === "portals" ? /* @__PURE__ */ (0,
|
|
13912
|
-
rail === "import" ? /* @__PURE__ */ (0,
|
|
13913
|
-
rail === "field" ? /* @__PURE__ */ (0,
|
|
13914
|
-
rail === "new-record" ? /* @__PURE__ */ (0,
|
|
14259
|
+
rail === "notifications" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(SubscriptionsPanel, { tableId }) : null,
|
|
14260
|
+
rail === "portals" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(PortalsPanel, { tableId }) : null,
|
|
14261
|
+
rail === "import" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ImportWizard, { tableId, onDone: () => setRail("none") }) : null,
|
|
14262
|
+
rail === "field" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(FieldEditor, { tableId, onSaved: () => setRail("none"), onCancel: () => setRail("none") }) : null,
|
|
14263
|
+
rail === "new-record" ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13915
14264
|
RecordForm,
|
|
13916
14265
|
{
|
|
13917
14266
|
tableId,
|
|
@@ -13922,7 +14271,7 @@ function TablePage({
|
|
|
13922
14271
|
onCancel: () => setRail("none")
|
|
13923
14272
|
}
|
|
13924
14273
|
) : null,
|
|
13925
|
-
rail === "who-changed" && asking ? /* @__PURE__ */ (0,
|
|
14274
|
+
rail === "who-changed" && asking ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13926
14275
|
FieldHistoryPanel,
|
|
13927
14276
|
{
|
|
13928
14277
|
tableId,
|
|
@@ -13935,10 +14284,10 @@ function TablePage({
|
|
|
13935
14284
|
}
|
|
13936
14285
|
}
|
|
13937
14286
|
) : null,
|
|
13938
|
-
rail === "record" && openRecord ? /* @__PURE__ */ (0,
|
|
13939
|
-
/* @__PURE__ */ (0,
|
|
13940
|
-
/* @__PURE__ */ (0,
|
|
13941
|
-
/* @__PURE__ */ (0,
|
|
14287
|
+
rail === "record" && openRecord ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "space-y-3", children: [
|
|
14288
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Peek, { tableId, recordId: openRecord, onClose: () => setRail("none") }),
|
|
14289
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Separator, {}),
|
|
14290
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
13942
14291
|
HistoryPanel,
|
|
13943
14292
|
{
|
|
13944
14293
|
tableId,
|
|
@@ -13949,10 +14298,10 @@ function TablePage({
|
|
|
13949
14298
|
}
|
|
13950
14299
|
}
|
|
13951
14300
|
),
|
|
13952
|
-
/* @__PURE__ */ (0,
|
|
13953
|
-
/* @__PURE__ */ (0,
|
|
13954
|
-
/* @__PURE__ */ (0,
|
|
13955
|
-
/* @__PURE__ */ (0,
|
|
14301
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Separator, {}),
|
|
14302
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ChecklistRunner, { tableId, recordId: openRecord }),
|
|
14303
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_design_system53.Separator, {}),
|
|
14304
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(CommentThread, { tableId, recordId: openRecord })
|
|
13956
14305
|
] }) : null
|
|
13957
14306
|
] })
|
|
13958
14307
|
] });
|