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