@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.js
CHANGED
|
@@ -6250,6 +6250,7 @@ function Card({
|
|
|
6250
6250
|
|
|
6251
6251
|
// src/ViewSwitcher.tsx
|
|
6252
6252
|
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
6253
|
+
var NO_FIELDS = [];
|
|
6253
6254
|
function useViewRecords(view, pageSize = 200) {
|
|
6254
6255
|
const client = useRecordsClient16();
|
|
6255
6256
|
const table = useRecords4(view.ruleId ? null : view.subject, { pageSize });
|
|
@@ -6619,7 +6620,12 @@ function Card2({
|
|
|
6619
6620
|
onOpenRecord
|
|
6620
6621
|
}) {
|
|
6621
6622
|
const host = useRecordsUi();
|
|
6622
|
-
const
|
|
6623
|
+
const wanted = useMemo17(
|
|
6624
|
+
() => field && pointsAtRecords(field) ? [field] : NO_FIELDS,
|
|
6625
|
+
[field]
|
|
6626
|
+
);
|
|
6627
|
+
const labels = useRecordLabels(wanted);
|
|
6628
|
+
const label = field ? scalarText(field, (record.document ?? {})[field.key], labels) : rowName(record, null, "Untitled");
|
|
6623
6629
|
return /* @__PURE__ */ jsx25(
|
|
6624
6630
|
"button",
|
|
6625
6631
|
{
|
|
@@ -9398,28 +9404,325 @@ function Invite({ card, onInvited }) {
|
|
|
9398
9404
|
] });
|
|
9399
9405
|
}
|
|
9400
9406
|
|
|
9401
|
-
// src/
|
|
9402
|
-
import { useCallback as useCallback19, useEffect as useEffect22, useState as useState32 } from "react";
|
|
9407
|
+
// src/DigestScheduler.tsx
|
|
9408
|
+
import { useCallback as useCallback19, useEffect as useEffect22, useMemo as useMemo23, useState as useState32 } from "react";
|
|
9403
9409
|
import { useRecordsClient as useRecordsClient26 } from "@ai-matrx/records/react";
|
|
9404
|
-
import {
|
|
9405
|
-
import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
9410
|
+
import { BasicInput as BasicInput10, Button as Button29, Checkbox as Checkbox5, Label as Label5, Separator as Separator11, Skeleton as Skeleton16, cn as cn30 } from "@ai-matrx/design-system";
|
|
9411
|
+
import { Fragment as Fragment16, jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
9412
|
+
var WEEKDAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
|
9413
|
+
var CADENCE_WORDS = {
|
|
9414
|
+
instant: "the moment something arrives",
|
|
9415
|
+
hourly: "every hour",
|
|
9416
|
+
daily: "every day",
|
|
9417
|
+
weekly: "every week"
|
|
9418
|
+
};
|
|
9419
|
+
var CHANNEL_WORDS = {
|
|
9420
|
+
in_app: "in the app",
|
|
9421
|
+
email: "by email \u2014 only if an address is on their account",
|
|
9422
|
+
sms: "by text \u2014 only if a number is on their account"
|
|
9423
|
+
};
|
|
9424
|
+
function DigestScheduler({
|
|
9425
|
+
tableId,
|
|
9426
|
+
savedViewId,
|
|
9427
|
+
subjectName,
|
|
9428
|
+
filters,
|
|
9429
|
+
onScheduled,
|
|
9430
|
+
onClose,
|
|
9431
|
+
className
|
|
9432
|
+
}) {
|
|
9433
|
+
const client = useRecordsClient26();
|
|
9434
|
+
const host = useRecordsUi();
|
|
9435
|
+
const [views, setViews] = useState32(null);
|
|
9436
|
+
const [cadences, setCadences] = useState32([]);
|
|
9437
|
+
const [members, setMembers] = useState32(null);
|
|
9438
|
+
const [error, setError] = useState32(null);
|
|
9439
|
+
const [viewId, setViewId] = useState32(savedViewId ?? "");
|
|
9440
|
+
const [name, setName] = useState32(subjectName?.trim() ? `${subjectName.trim()} summary` : "");
|
|
9441
|
+
const [cadence, setCadence] = useState32("weekly");
|
|
9442
|
+
const [weekday, setWeekday] = useState32("monday");
|
|
9443
|
+
const [time, setTime] = useState32("08:00");
|
|
9444
|
+
const [channel, setChannel] = useState32("in_app");
|
|
9445
|
+
const [quiet, setQuiet] = useState32(false);
|
|
9446
|
+
const [quietFrom, setQuietFrom] = useState32("22:00");
|
|
9447
|
+
const [quietTo, setQuietTo] = useState32("07:00");
|
|
9448
|
+
const [recipients, setRecipients] = useState32([]);
|
|
9449
|
+
const [saving, setSaving] = useState32(false);
|
|
9450
|
+
const [outcomes, setOutcomes] = useState32(null);
|
|
9451
|
+
const [preview, setPreview] = useState32(null);
|
|
9452
|
+
const [previewing, setPreviewing] = useState32(false);
|
|
9453
|
+
const load = useCallback19(async () => {
|
|
9454
|
+
const [saved, offered] = await Promise.all([
|
|
9455
|
+
// The store's own door onto `platform.saved_view`, narrowed in SQL to
|
|
9456
|
+
// Tables this person can already open — never a grant on the table behind it.
|
|
9457
|
+
client.views({ table_id: tableId }),
|
|
9458
|
+
// The cadences are ASKED, never typed into this file, so a picker can
|
|
9459
|
+
// never offer a cadence the digest runner does not honour.
|
|
9460
|
+
client.subscriptionCadences()
|
|
9461
|
+
]);
|
|
9462
|
+
if (!saved.ok) setError(saved.error);
|
|
9463
|
+
else setViews(saved.data);
|
|
9464
|
+
if (offered.ok) setCadences(offered.data.filter((c) => c !== "instant"));
|
|
9465
|
+
if (host.members) {
|
|
9466
|
+
const who = await host.members();
|
|
9467
|
+
setMembers(who.map((m) => ({ userId: m.userId, name: m.name ?? m.email ?? m.userId })));
|
|
9468
|
+
} else {
|
|
9469
|
+
setMembers([]);
|
|
9470
|
+
}
|
|
9471
|
+
}, [client, tableId, host]);
|
|
9472
|
+
useEffect22(() => {
|
|
9473
|
+
void load();
|
|
9474
|
+
}, [load]);
|
|
9475
|
+
const schedule = useMemo23(() => {
|
|
9476
|
+
if (cadence === "weekly") return `${weekday} ${time}`;
|
|
9477
|
+
if (cadence === "daily") return time;
|
|
9478
|
+
return null;
|
|
9479
|
+
}, [cadence, weekday, time]);
|
|
9480
|
+
const quietHours = useMemo23(
|
|
9481
|
+
() => quiet ? { start: quietFrom, end: quietTo } : null,
|
|
9482
|
+
[quiet, quietFrom, quietTo]
|
|
9483
|
+
);
|
|
9484
|
+
async function scheduleIt() {
|
|
9485
|
+
setSaving(true);
|
|
9486
|
+
setError(null);
|
|
9487
|
+
setOutcomes(null);
|
|
9488
|
+
let subject = viewId;
|
|
9489
|
+
if (subject === "" || subject === "new") {
|
|
9490
|
+
const declared = await client.viewDeclare({
|
|
9491
|
+
table_id: tableId,
|
|
9492
|
+
spec: {
|
|
9493
|
+
name: subjectName?.trim() ? subjectName.trim() : name.trim() || "Weekly summary",
|
|
9494
|
+
filters: filters ?? {}
|
|
9495
|
+
}
|
|
9496
|
+
});
|
|
9497
|
+
if (!declared.ok) {
|
|
9498
|
+
setSaving(false);
|
|
9499
|
+
setError(declared.error);
|
|
9500
|
+
return;
|
|
9501
|
+
}
|
|
9502
|
+
subject = declared.data;
|
|
9503
|
+
setViewId(declared.data);
|
|
9504
|
+
}
|
|
9505
|
+
const who = recipients.length > 0 ? recipients : [""];
|
|
9506
|
+
const done = [];
|
|
9507
|
+
for (const userId of who) {
|
|
9508
|
+
const label = members?.find((m) => m.userId === userId)?.name ?? (userId === "" ? "you" : userId);
|
|
9509
|
+
const written = await client.subscriptionDeclare({
|
|
9510
|
+
table_id: tableId,
|
|
9511
|
+
spec: {
|
|
9512
|
+
name: name.trim() === "" ? "Weekly summary" : name.trim(),
|
|
9513
|
+
saved_view_id: subject,
|
|
9514
|
+
cadence,
|
|
9515
|
+
schedule,
|
|
9516
|
+
channel,
|
|
9517
|
+
quiet_hours: quietHours,
|
|
9518
|
+
...userId === "" ? {} : { recipient_user_id: userId }
|
|
9519
|
+
}
|
|
9520
|
+
});
|
|
9521
|
+
if (written.ok) done.push({ userId, who: label, ruleId: written.data });
|
|
9522
|
+
else done.push({ userId, who: label, refused: written.error });
|
|
9523
|
+
}
|
|
9524
|
+
setSaving(false);
|
|
9525
|
+
setOutcomes(done);
|
|
9526
|
+
if (done.some((d) => d.ruleId)) onScheduled?.();
|
|
9527
|
+
}
|
|
9528
|
+
async function showOne(ruleId) {
|
|
9529
|
+
setPreviewing(true);
|
|
9530
|
+
const answered = await client.subscriptionPreview({ rule_id: ruleId });
|
|
9531
|
+
setPreviewing(false);
|
|
9532
|
+
if (!answered.ok) {
|
|
9533
|
+
setError(answered.error);
|
|
9534
|
+
return;
|
|
9535
|
+
}
|
|
9536
|
+
setPreview(answered.data);
|
|
9537
|
+
}
|
|
9538
|
+
if (views === null && !error) return /* @__PURE__ */ jsx36(Skeleton16, { className: cn30("h-56 w-full", className) });
|
|
9539
|
+
return /* @__PURE__ */ jsxs32("section", { className: cn30("flex flex-col gap-3", className), children: [
|
|
9540
|
+
/* @__PURE__ */ jsxs32("header", { className: "flex items-center gap-2", children: [
|
|
9541
|
+
/* @__PURE__ */ jsx36("h3", { className: "text-sm font-medium", children: "Send this on a schedule" }),
|
|
9542
|
+
/* @__PURE__ */ jsx36("div", { className: "flex-1" }),
|
|
9543
|
+
/* @__PURE__ */ jsx36(Button29, { size: "sm", disabled: saving, onClick: () => void scheduleIt(), children: saving ? "Scheduling\u2026" : "Schedule it" }),
|
|
9544
|
+
onClose ? /* @__PURE__ */ jsx36(Button29, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
|
|
9545
|
+
] }),
|
|
9546
|
+
error ? /* @__PURE__ */ jsx36(RefusalNotice, { error }) : null,
|
|
9547
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9548
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "What to call it" }),
|
|
9549
|
+
/* @__PURE__ */ jsx36(
|
|
9550
|
+
BasicInput10,
|
|
9551
|
+
{
|
|
9552
|
+
value: name,
|
|
9553
|
+
placeholder: "Monday donor summary",
|
|
9554
|
+
onChange: (e) => setName(e.target.value)
|
|
9555
|
+
}
|
|
9556
|
+
)
|
|
9557
|
+
] }),
|
|
9558
|
+
savedViewId ? null : /* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9559
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "What it summarises" }),
|
|
9560
|
+
/* @__PURE__ */ jsxs32(
|
|
9561
|
+
"select",
|
|
9562
|
+
{
|
|
9563
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9564
|
+
value: viewId,
|
|
9565
|
+
onChange: (e) => setViewId(e.target.value),
|
|
9566
|
+
children: [
|
|
9567
|
+
/* @__PURE__ */ jsx36("option", { value: "new", children: subjectName?.trim() ? `What I am looking at now (${subjectName.trim()})` : "What I am looking at now" }),
|
|
9568
|
+
(views ?? []).map((v) => /* @__PURE__ */ jsx36("option", { value: v.view_id, children: v.name }, v.view_id))
|
|
9569
|
+
]
|
|
9570
|
+
}
|
|
9571
|
+
),
|
|
9572
|
+
/* @__PURE__ */ jsx36("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." })
|
|
9573
|
+
] }),
|
|
9574
|
+
/* @__PURE__ */ jsxs32("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
9575
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9576
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "How often" }),
|
|
9577
|
+
/* @__PURE__ */ jsx36(
|
|
9578
|
+
"select",
|
|
9579
|
+
{
|
|
9580
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9581
|
+
value: cadence,
|
|
9582
|
+
onChange: (e) => setCadence(e.target.value),
|
|
9583
|
+
children: (cadences.length > 0 ? cadences : ["hourly", "daily", "weekly"]).map((c) => /* @__PURE__ */ jsx36("option", { value: c, children: CADENCE_WORDS[c] ?? c }, c))
|
|
9584
|
+
}
|
|
9585
|
+
)
|
|
9586
|
+
] }),
|
|
9587
|
+
cadence === "weekly" ? /* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9588
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "Which day" }),
|
|
9589
|
+
/* @__PURE__ */ jsx36(
|
|
9590
|
+
"select",
|
|
9591
|
+
{
|
|
9592
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9593
|
+
value: weekday,
|
|
9594
|
+
onChange: (e) => setWeekday(e.target.value),
|
|
9595
|
+
children: WEEKDAYS.map((d) => /* @__PURE__ */ jsx36("option", { value: d, children: d[0].toUpperCase() + d.slice(1) }, d))
|
|
9596
|
+
}
|
|
9597
|
+
)
|
|
9598
|
+
] }) : null,
|
|
9599
|
+
cadence === "weekly" || cadence === "daily" ? /* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9600
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "At" }),
|
|
9601
|
+
/* @__PURE__ */ jsx36(BasicInput10, { type: "time", value: time, onChange: (e) => setTime(e.target.value) })
|
|
9602
|
+
] }) : null,
|
|
9603
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex flex-col gap-1", children: [
|
|
9604
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "Where it arrives" }),
|
|
9605
|
+
/* @__PURE__ */ jsx36(
|
|
9606
|
+
"select",
|
|
9607
|
+
{
|
|
9608
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
9609
|
+
value: channel,
|
|
9610
|
+
onChange: (e) => setChannel(e.target.value),
|
|
9611
|
+
children: Object.entries(CHANNEL_WORDS).map(([key, words]) => /* @__PURE__ */ jsx36("option", { value: key, children: words }, key))
|
|
9612
|
+
}
|
|
9613
|
+
)
|
|
9614
|
+
] })
|
|
9615
|
+
] }),
|
|
9616
|
+
/* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1.5", children: [
|
|
9617
|
+
/* @__PURE__ */ jsx36(Label5, { className: "text-xs font-medium", children: "Who to send it to" }),
|
|
9618
|
+
members === null ? /* @__PURE__ */ jsx36(Skeleton16, { className: "h-8 w-full" }) : members.length === 0 ? /* @__PURE__ */ jsx36("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__ */ jsxs32(Fragment16, { children: [
|
|
9619
|
+
/* @__PURE__ */ jsx36("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: members.map((m) => /* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
9620
|
+
/* @__PURE__ */ jsx36(
|
|
9621
|
+
Checkbox5,
|
|
9622
|
+
{
|
|
9623
|
+
checked: recipients.includes(m.userId),
|
|
9624
|
+
onCheckedChange: (on) => setRecipients(
|
|
9625
|
+
(prev) => on ? [...prev, m.userId] : prev.filter((u) => u !== m.userId)
|
|
9626
|
+
)
|
|
9627
|
+
}
|
|
9628
|
+
),
|
|
9629
|
+
m.name
|
|
9630
|
+
] }, m.userId)) }),
|
|
9631
|
+
/* @__PURE__ */ jsx36("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.` })
|
|
9632
|
+
] })
|
|
9633
|
+
] }),
|
|
9634
|
+
/* @__PURE__ */ jsxs32("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
9635
|
+
/* @__PURE__ */ jsx36(Checkbox5, { checked: quiet, onCheckedChange: (on) => setQuiet(Boolean(on)) }),
|
|
9636
|
+
"Not between certain hours"
|
|
9637
|
+
] }),
|
|
9638
|
+
quiet ? /* @__PURE__ */ jsxs32("div", { className: "flex items-center gap-2", children: [
|
|
9639
|
+
/* @__PURE__ */ jsx36(
|
|
9640
|
+
BasicInput10,
|
|
9641
|
+
{
|
|
9642
|
+
type: "time",
|
|
9643
|
+
className: "h-8 w-28",
|
|
9644
|
+
value: quietFrom,
|
|
9645
|
+
onChange: (e) => setQuietFrom(e.target.value)
|
|
9646
|
+
}
|
|
9647
|
+
),
|
|
9648
|
+
/* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children: "and" }),
|
|
9649
|
+
/* @__PURE__ */ jsx36(
|
|
9650
|
+
BasicInput10,
|
|
9651
|
+
{
|
|
9652
|
+
type: "time",
|
|
9653
|
+
className: "h-8 w-28",
|
|
9654
|
+
value: quietTo,
|
|
9655
|
+
onChange: (e) => setQuietTo(e.target.value)
|
|
9656
|
+
}
|
|
9657
|
+
),
|
|
9658
|
+
/* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground", children: "A send inside these hours waits until they end \u2014 it is never dropped." })
|
|
9659
|
+
] }) : null,
|
|
9660
|
+
outcomes ? /* @__PURE__ */ jsxs32(Fragment16, { children: [
|
|
9661
|
+
/* @__PURE__ */ jsx36(Separator11, {}),
|
|
9662
|
+
/* @__PURE__ */ jsx36("div", { className: "flex flex-col gap-1.5", children: outcomes.map((o) => /* @__PURE__ */ jsx36("div", { className: "text-xs", children: o.ruleId ? /* @__PURE__ */ jsxs32("span", { children: [
|
|
9663
|
+
o.who,
|
|
9664
|
+
" will get it ",
|
|
9665
|
+
CADENCE_WORDS[cadence] ?? cadence,
|
|
9666
|
+
schedule ? `, ${schedule}` : "",
|
|
9667
|
+
".",
|
|
9668
|
+
" ",
|
|
9669
|
+
/* @__PURE__ */ jsx36(
|
|
9670
|
+
Button29,
|
|
9671
|
+
{
|
|
9672
|
+
size: "sm",
|
|
9673
|
+
variant: "ghost",
|
|
9674
|
+
disabled: previewing,
|
|
9675
|
+
onClick: () => void showOne(o.ruleId),
|
|
9676
|
+
children: "Send me one now"
|
|
9677
|
+
}
|
|
9678
|
+
)
|
|
9679
|
+
] }) : o.refused ? /* @__PURE__ */ jsx36(RefusalNotice, { error: o.refused }) : null }, o.userId || "me")) })
|
|
9680
|
+
] }) : null,
|
|
9681
|
+
preview ? /* @__PURE__ */ jsxs32("div", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
9682
|
+
/* @__PURE__ */ jsx36("p", { className: "font-medium", children: preview.subject }),
|
|
9683
|
+
/* @__PURE__ */ jsx36("p", { className: "mt-1 text-muted-foreground", children: preview.body }),
|
|
9684
|
+
preview.incomplete ? /* @__PURE__ */ jsx36("p", { className: "mt-1 text-destructive", children: preview.incomplete }) : null,
|
|
9685
|
+
preview.entered.length > 0 ? /* @__PURE__ */ jsxs32("p", { className: "mt-1", children: [
|
|
9686
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium", children: "Arrived:" }),
|
|
9687
|
+
" ",
|
|
9688
|
+
preview.entered.map((e) => e.name).join(", ")
|
|
9689
|
+
] }) : null,
|
|
9690
|
+
preview.changed.length > 0 ? /* @__PURE__ */ jsxs32("p", { className: "mt-1", children: [
|
|
9691
|
+
/* @__PURE__ */ jsx36("span", { className: "font-medium", children: "Changed:" }),
|
|
9692
|
+
" ",
|
|
9693
|
+
preview.changed.map((e) => e.name).join(", ")
|
|
9694
|
+
] }) : null,
|
|
9695
|
+
/* @__PURE__ */ jsx36("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." }),
|
|
9696
|
+
/* @__PURE__ */ jsx36(Button29, { size: "sm", variant: "ghost", className: "mt-1", onClick: () => setPreview(null), children: "Close" })
|
|
9697
|
+
] }) : null
|
|
9698
|
+
] });
|
|
9699
|
+
}
|
|
9700
|
+
|
|
9701
|
+
// src/SubscriptionsPanel.tsx
|
|
9702
|
+
import { useCallback as useCallback20, useEffect as useEffect23, useState as useState33 } from "react";
|
|
9703
|
+
import { useRecordsClient as useRecordsClient27 } from "@ai-matrx/records/react";
|
|
9704
|
+
import { Badge as Badge14, Button as Button30, Skeleton as Skeleton17, Switch as Switch2, cn as cn31 } from "@ai-matrx/design-system";
|
|
9705
|
+
import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
9406
9706
|
function whenItFires(subscription) {
|
|
9407
9707
|
if (subscription.cadence === "instant") return "as it happens";
|
|
9408
9708
|
const every = subscription.cadence === "hourly" ? "an hourly summary" : subscription.cadence === "weekly" ? "a weekly summary" : "a daily summary";
|
|
9409
9709
|
return subscription.schedule ? `${every}, ${subscription.schedule}` : every;
|
|
9410
9710
|
}
|
|
9411
|
-
var
|
|
9711
|
+
var CHANNEL_WORDS2 = {
|
|
9412
9712
|
in_app: "in the app",
|
|
9413
9713
|
email: "by email \u2014 only if an address is on the account",
|
|
9414
9714
|
sms: "by text \u2014 only if a number is on the account"
|
|
9415
9715
|
};
|
|
9716
|
+
var DIGEST_SUGGESTION = "Email me a summary of this every Monday at 8 in the morning.";
|
|
9416
9717
|
function SubscriptionsPanel({ tableId, className }) {
|
|
9417
|
-
const client =
|
|
9418
|
-
const [rows, setRows] =
|
|
9419
|
-
const [error, setError] =
|
|
9420
|
-
const [busy, setBusy] =
|
|
9421
|
-
const [preview, setPreview] =
|
|
9422
|
-
const
|
|
9718
|
+
const client = useRecordsClient27();
|
|
9719
|
+
const [rows, setRows] = useState33(null);
|
|
9720
|
+
const [error, setError] = useState33(null);
|
|
9721
|
+
const [busy, setBusy] = useState33(null);
|
|
9722
|
+
const [preview, setPreview] = useState33(null);
|
|
9723
|
+
const [scheduling, setScheduling] = useState33(false);
|
|
9724
|
+
const host = useRecordsUi();
|
|
9725
|
+
const load = useCallback20(async () => {
|
|
9423
9726
|
const answered = await client.subscriptions({ table_id: tableId });
|
|
9424
9727
|
if (!answered.ok) {
|
|
9425
9728
|
setError(answered.error);
|
|
@@ -9429,10 +9732,10 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9429
9732
|
setError(null);
|
|
9430
9733
|
setRows(answered.data);
|
|
9431
9734
|
}, [client, tableId]);
|
|
9432
|
-
|
|
9735
|
+
useEffect23(() => {
|
|
9433
9736
|
void load();
|
|
9434
9737
|
}, [load]);
|
|
9435
|
-
const flip =
|
|
9738
|
+
const flip = useCallback20(
|
|
9436
9739
|
async (subscription, on) => {
|
|
9437
9740
|
setBusy(subscription.rule_id);
|
|
9438
9741
|
const answered = await client.subscriptionMute({
|
|
@@ -9448,7 +9751,7 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9448
9751
|
},
|
|
9449
9752
|
[client, load]
|
|
9450
9753
|
);
|
|
9451
|
-
const showOne =
|
|
9754
|
+
const showOne = useCallback20(
|
|
9452
9755
|
async (subscription) => {
|
|
9453
9756
|
setBusy(subscription.rule_id);
|
|
9454
9757
|
const answered = await client.subscriptionPreview({ rule_id: subscription.rule_id });
|
|
@@ -9462,25 +9765,57 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9462
9765
|
},
|
|
9463
9766
|
[client]
|
|
9464
9767
|
);
|
|
9465
|
-
if (rows === null) return /* @__PURE__ */
|
|
9466
|
-
return /* @__PURE__ */
|
|
9467
|
-
/* @__PURE__ */
|
|
9468
|
-
/* @__PURE__ */
|
|
9469
|
-
/* @__PURE__ */
|
|
9768
|
+
if (rows === null) return /* @__PURE__ */ jsx37(Skeleton17, { className: cn31("h-32 w-full", className) });
|
|
9769
|
+
return /* @__PURE__ */ jsxs33("section", { className: cn31("flex flex-col gap-3", className), children: [
|
|
9770
|
+
/* @__PURE__ */ jsxs33("header", { className: "flex items-center gap-2", children: [
|
|
9771
|
+
/* @__PURE__ */ jsx37("h3", { className: "text-sm font-medium", children: "Notifications" }),
|
|
9772
|
+
/* @__PURE__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: rows.length === 0 ? "none" : `${rows.filter((r) => !r.muted).length} on` }),
|
|
9773
|
+
/* @__PURE__ */ jsx37("div", { className: "flex-1" }),
|
|
9774
|
+
rows.length > 0 ? /* @__PURE__ */ jsx37(
|
|
9775
|
+
Button30,
|
|
9776
|
+
{
|
|
9777
|
+
size: "sm",
|
|
9778
|
+
variant: scheduling ? "secondary" : "ghost",
|
|
9779
|
+
onClick: () => setScheduling((s) => !s),
|
|
9780
|
+
children: scheduling ? "Done" : "Schedule a summary"
|
|
9781
|
+
}
|
|
9782
|
+
) : null
|
|
9470
9783
|
] }),
|
|
9471
|
-
error ? /* @__PURE__ */
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9784
|
+
error ? /* @__PURE__ */ jsx37(RefusalNotice, { error }) : null,
|
|
9785
|
+
scheduling ? /* @__PURE__ */ jsx37(
|
|
9786
|
+
DigestScheduler,
|
|
9787
|
+
{
|
|
9788
|
+
tableId,
|
|
9789
|
+
onScheduled: () => {
|
|
9790
|
+
void load();
|
|
9791
|
+
},
|
|
9792
|
+
onClose: () => setScheduling(false)
|
|
9793
|
+
}
|
|
9794
|
+
) : null,
|
|
9795
|
+
rows.length === 0 && !scheduling ? /* @__PURE__ */ jsx37(
|
|
9796
|
+
BuildOrAsk,
|
|
9797
|
+
{
|
|
9798
|
+
mayBuild: true,
|
|
9799
|
+
onBuild: () => setScheduling(true),
|
|
9800
|
+
...host.onAskForOne ? {
|
|
9801
|
+
onAsk: () => host.onAskForOne?.({ kind: "digest", tableId, suggestion: DIGEST_SUGGESTION })
|
|
9802
|
+
} : {},
|
|
9803
|
+
suggestion: DIGEST_SUGGESTION,
|
|
9804
|
+
buildLabel: "Schedule a summary",
|
|
9805
|
+
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."
|
|
9806
|
+
}
|
|
9807
|
+
) : null,
|
|
9808
|
+
/* @__PURE__ */ jsx37("ul", { className: "flex flex-col gap-2", children: rows.map((subscription) => /* @__PURE__ */ jsxs33("li", { className: "rounded-md border p-2.5", children: [
|
|
9809
|
+
/* @__PURE__ */ jsxs33("div", { className: "flex items-start gap-2", children: [
|
|
9810
|
+
/* @__PURE__ */ jsxs33("div", { className: "min-w-0 flex-1", children: [
|
|
9811
|
+
/* @__PURE__ */ jsx37("p", { className: "truncate text-sm font-medium", children: subscription.name }),
|
|
9812
|
+
/* @__PURE__ */ jsxs33("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
9813
|
+
CHANNEL_WORDS2[subscription.channel] ?? `on the ${subscription.channel} channel`,
|
|
9479
9814
|
" \xB7 ",
|
|
9480
9815
|
whenItFires(subscription)
|
|
9481
9816
|
] })
|
|
9482
9817
|
] }),
|
|
9483
|
-
subscription.i_may_mute ? /* @__PURE__ */
|
|
9818
|
+
subscription.i_may_mute ? /* @__PURE__ */ jsx37(
|
|
9484
9819
|
Switch2,
|
|
9485
9820
|
{
|
|
9486
9821
|
checked: !subscription.muted,
|
|
@@ -9488,27 +9823,27 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9488
9823
|
"aria-label": `Tell me about ${subscription.name}`,
|
|
9489
9824
|
onCheckedChange: (on) => void flip(subscription, on)
|
|
9490
9825
|
}
|
|
9491
|
-
) : /* @__PURE__ */
|
|
9826
|
+
) : /* @__PURE__ */ jsx37(Badge14, { variant: "secondary", children: "someone else's" })
|
|
9492
9827
|
] }),
|
|
9493
|
-
/* @__PURE__ */
|
|
9494
|
-
/* @__PURE__ */
|
|
9495
|
-
subscription.next_digest_at ? /* @__PURE__ */
|
|
9828
|
+
/* @__PURE__ */ jsx37("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." }),
|
|
9829
|
+
/* @__PURE__ */ jsxs33("div", { className: "mt-1.5 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
|
|
9830
|
+
subscription.next_digest_at ? /* @__PURE__ */ jsxs33("span", { children: [
|
|
9496
9831
|
"Next summary ",
|
|
9497
9832
|
new Date(subscription.next_digest_at).toLocaleString()
|
|
9498
|
-
] }) : subscription.cadence === "instant" ? null : subscription.muted ? /* @__PURE__ */
|
|
9499
|
-
subscription.last_sent_at ? /* @__PURE__ */
|
|
9833
|
+
] }) : subscription.cadence === "instant" ? null : subscription.muted ? /* @__PURE__ */ jsx37("span", { children: "No next summary while it is off." }) : null,
|
|
9834
|
+
subscription.last_sent_at ? /* @__PURE__ */ jsxs33("span", { children: [
|
|
9500
9835
|
"Last told you ",
|
|
9501
9836
|
new Date(subscription.last_sent_at).toLocaleString()
|
|
9502
|
-
] }) : /* @__PURE__ */
|
|
9503
|
-
subscription.quiet_hours ? /* @__PURE__ */
|
|
9837
|
+
] }) : /* @__PURE__ */ jsx37("span", { children: "It has not told you anything yet." }),
|
|
9838
|
+
subscription.quiet_hours ? /* @__PURE__ */ jsxs33("span", { children: [
|
|
9504
9839
|
"Not between ",
|
|
9505
9840
|
subscription.quiet_hours.start,
|
|
9506
9841
|
" and ",
|
|
9507
9842
|
subscription.quiet_hours.end,
|
|
9508
9843
|
" \u2014 a send inside those hours waits until they end."
|
|
9509
9844
|
] }) : null,
|
|
9510
|
-
subscription.cadence === "instant" ? null : /* @__PURE__ */
|
|
9511
|
-
|
|
9845
|
+
subscription.cadence === "instant" ? null : /* @__PURE__ */ jsx37(
|
|
9846
|
+
Button30,
|
|
9512
9847
|
{
|
|
9513
9848
|
size: "sm",
|
|
9514
9849
|
variant: "ghost",
|
|
@@ -9518,66 +9853,66 @@ function SubscriptionsPanel({ tableId, className }) {
|
|
|
9518
9853
|
}
|
|
9519
9854
|
)
|
|
9520
9855
|
] }),
|
|
9521
|
-
preview && preview.rule_id === subscription.rule_id ? /* @__PURE__ */
|
|
9522
|
-
/* @__PURE__ */
|
|
9523
|
-
/* @__PURE__ */
|
|
9856
|
+
preview && preview.rule_id === subscription.rule_id ? /* @__PURE__ */ jsxs33("div", { className: "mt-2 rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
9857
|
+
/* @__PURE__ */ jsx37("p", { className: "font-medium", children: preview.subject }),
|
|
9858
|
+
/* @__PURE__ */ jsx37("p", { className: "mt-1 text-muted-foreground", children: preview.body }),
|
|
9524
9859
|
preview.incomplete ? (
|
|
9525
9860
|
// Absent or honest: a subscription that cannot produce a summary
|
|
9526
9861
|
// says which piece is missing instead of showing an empty one.
|
|
9527
|
-
/* @__PURE__ */
|
|
9862
|
+
/* @__PURE__ */ jsx37("p", { className: "mt-1 text-destructive", children: preview.incomplete })
|
|
9528
9863
|
) : null,
|
|
9529
|
-
preview.entered.length > 0 ? /* @__PURE__ */
|
|
9530
|
-
/* @__PURE__ */
|
|
9864
|
+
preview.entered.length > 0 ? /* @__PURE__ */ jsxs33("p", { className: "mt-1", children: [
|
|
9865
|
+
/* @__PURE__ */ jsx37("span", { className: "font-medium", children: "Arrived:" }),
|
|
9531
9866
|
" ",
|
|
9532
9867
|
preview.entered.map((e) => e.name).join(", ")
|
|
9533
9868
|
] }) : null,
|
|
9534
|
-
preview.left.length > 0 ? /* @__PURE__ */
|
|
9535
|
-
/* @__PURE__ */
|
|
9869
|
+
preview.left.length > 0 ? /* @__PURE__ */ jsxs33("p", { className: "mt-1", children: [
|
|
9870
|
+
/* @__PURE__ */ jsx37("span", { className: "font-medium", children: "Left:" }),
|
|
9536
9871
|
" ",
|
|
9537
9872
|
preview.left.map((e) => e.name).join(", ")
|
|
9538
9873
|
] }) : null,
|
|
9539
|
-
preview.changed.length > 0 ? /* @__PURE__ */
|
|
9540
|
-
/* @__PURE__ */
|
|
9874
|
+
preview.changed.length > 0 ? /* @__PURE__ */ jsxs33("p", { className: "mt-1", children: [
|
|
9875
|
+
/* @__PURE__ */ jsx37("span", { className: "font-medium", children: "Changed:" }),
|
|
9541
9876
|
" ",
|
|
9542
9877
|
preview.changed.map((e) => e.name).join(", ")
|
|
9543
9878
|
] }) : null,
|
|
9544
|
-
/* @__PURE__ */
|
|
9545
|
-
/* @__PURE__ */
|
|
9879
|
+
/* @__PURE__ */ jsx37("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." }),
|
|
9880
|
+
/* @__PURE__ */ jsx37(Button30, { size: "sm", variant: "ghost", className: "mt-1", onClick: () => setPreview(null), children: "Close" })
|
|
9546
9881
|
] }) : null
|
|
9547
9882
|
] }, subscription.rule_id)) })
|
|
9548
9883
|
] });
|
|
9549
9884
|
}
|
|
9550
9885
|
|
|
9551
9886
|
// src/FormBuilder.tsx
|
|
9552
|
-
import { useCallback as
|
|
9553
|
-
import { useFields as useFields16, useRecordsClient as
|
|
9887
|
+
import { useCallback as useCallback22, useEffect as useEffect25, useMemo as useMemo25, useState as useState35 } from "react";
|
|
9888
|
+
import { useFields as useFields16, useRecordsClient as useRecordsClient28, useTable as useTable13 } from "@ai-matrx/records/react";
|
|
9554
9889
|
import { publicFormPath } from "@ai-matrx/records";
|
|
9555
9890
|
import {
|
|
9556
|
-
BasicInput as
|
|
9891
|
+
BasicInput as BasicInput11,
|
|
9557
9892
|
BasicTextarea as BasicTextarea5,
|
|
9558
|
-
Button as
|
|
9559
|
-
Checkbox as
|
|
9560
|
-
Label as
|
|
9561
|
-
Skeleton as
|
|
9562
|
-
cn as
|
|
9893
|
+
Button as Button32,
|
|
9894
|
+
Checkbox as Checkbox6,
|
|
9895
|
+
Label as Label6,
|
|
9896
|
+
Skeleton as Skeleton19,
|
|
9897
|
+
cn as cn33
|
|
9563
9898
|
} from "@ai-matrx/design-system";
|
|
9564
9899
|
|
|
9565
9900
|
// src/FormRunner.tsx
|
|
9566
|
-
import { useCallback as
|
|
9901
|
+
import { useCallback as useCallback21, useEffect as useEffect24, useMemo as useMemo24, useRef as useRef9, useState as useState34 } from "react";
|
|
9567
9902
|
import { useFields as useFields15, useOptionalRecordsClient } from "@ai-matrx/records/react";
|
|
9568
|
-
import { Button as
|
|
9569
|
-
import { Fragment as
|
|
9903
|
+
import { Button as Button31, Progress, Skeleton as Skeleton18, cn as cn32 } from "@ai-matrx/design-system";
|
|
9904
|
+
import { Fragment as Fragment17, jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
9570
9905
|
function FormRunner(props) {
|
|
9571
9906
|
if (props.fields && props.onSubmit) {
|
|
9572
|
-
return /* @__PURE__ */
|
|
9907
|
+
return /* @__PURE__ */ jsx38(FormStage, { ...props, fields: props.fields, onSubmit: props.onSubmit });
|
|
9573
9908
|
}
|
|
9574
|
-
return /* @__PURE__ */
|
|
9909
|
+
return /* @__PURE__ */ jsx38(ConnectedFormRunner, { ...props });
|
|
9575
9910
|
}
|
|
9576
9911
|
function ConnectedFormRunner(props) {
|
|
9577
9912
|
const client = useOptionalRecordsClient();
|
|
9578
9913
|
const fields = useFields15(props.form.subject);
|
|
9579
9914
|
const { form, className } = props;
|
|
9580
|
-
const submit =
|
|
9915
|
+
const submit = useCallback21(
|
|
9581
9916
|
async (values) => {
|
|
9582
9917
|
if (!client) {
|
|
9583
9918
|
return {
|
|
@@ -9600,7 +9935,7 @@ function ConnectedFormRunner(props) {
|
|
|
9600
9935
|
},
|
|
9601
9936
|
[client, form]
|
|
9602
9937
|
);
|
|
9603
|
-
const evaluate =
|
|
9938
|
+
const evaluate = useCallback21(
|
|
9604
9939
|
async (expr, values) => {
|
|
9605
9940
|
if (!client) return null;
|
|
9606
9941
|
const answered = await client.ruleEval({ expr, values });
|
|
@@ -9609,9 +9944,9 @@ function ConnectedFormRunner(props) {
|
|
|
9609
9944
|
},
|
|
9610
9945
|
[client]
|
|
9611
9946
|
);
|
|
9612
|
-
if (fields.error) return /* @__PURE__ */
|
|
9613
|
-
if (fields.loading) return /* @__PURE__ */
|
|
9614
|
-
return /* @__PURE__ */
|
|
9947
|
+
if (fields.error) return /* @__PURE__ */ jsx38(RefusalNotice, { error: fields.error, className });
|
|
9948
|
+
if (fields.loading) return /* @__PURE__ */ jsx38(Skeleton18, { className: cn32("h-40 w-full", className) });
|
|
9949
|
+
return /* @__PURE__ */ jsx38(
|
|
9615
9950
|
FormStage,
|
|
9616
9951
|
{
|
|
9617
9952
|
...props,
|
|
@@ -9634,16 +9969,16 @@ function FormStage({
|
|
|
9634
9969
|
connected = false
|
|
9635
9970
|
}) {
|
|
9636
9971
|
const host = useRecordsUi();
|
|
9637
|
-
const [answers, setAnswers] =
|
|
9638
|
-
const [at, setAt] =
|
|
9639
|
-
const [error, setError] =
|
|
9640
|
-
const [refusal, setRefusal] =
|
|
9641
|
-
const [writing, setWriting] =
|
|
9642
|
-
const [done, setDone] =
|
|
9643
|
-
const [hidden, setHidden] =
|
|
9972
|
+
const [answers, setAnswers] = useState34({});
|
|
9973
|
+
const [at, setAt] = useState34(0);
|
|
9974
|
+
const [error, setError] = useState34(null);
|
|
9975
|
+
const [refusal, setRefusal] = useState34(null);
|
|
9976
|
+
const [writing, setWriting] = useState34(false);
|
|
9977
|
+
const [done, setDone] = useState34(null);
|
|
9978
|
+
const [hidden, setHidden] = useState34({});
|
|
9644
9979
|
const decoy = useRef9("");
|
|
9645
9980
|
const stage = useRef9(null);
|
|
9646
|
-
const questions =
|
|
9981
|
+
const questions = useMemo24(() => {
|
|
9647
9982
|
const byKey = new Map((fields ?? []).map((f) => [f.key, f]));
|
|
9648
9983
|
return (form.questions ?? []).map((q) => {
|
|
9649
9984
|
const field = byKey.get(q.field) ?? null;
|
|
@@ -9657,7 +9992,7 @@ function FormStage({
|
|
|
9657
9992
|
};
|
|
9658
9993
|
});
|
|
9659
9994
|
}, [fields, form.questions]);
|
|
9660
|
-
|
|
9995
|
+
useEffect24(() => {
|
|
9661
9996
|
let cancelled = false;
|
|
9662
9997
|
const conditional = questions.filter((q) => q.showIf);
|
|
9663
9998
|
if (conditional.length === 0 || !evaluate) return;
|
|
@@ -9691,7 +10026,7 @@ function FormStage({
|
|
|
9691
10026
|
const v = answers[q.key];
|
|
9692
10027
|
return q.required && (v === void 0 || v === null || v === "");
|
|
9693
10028
|
});
|
|
9694
|
-
const submit =
|
|
10029
|
+
const submit = useCallback21(async () => {
|
|
9695
10030
|
if (preview) {
|
|
9696
10031
|
setDone("preview");
|
|
9697
10032
|
return;
|
|
@@ -9728,51 +10063,51 @@ function FormStage({
|
|
|
9728
10063
|
if (event.shiftKey) retreat();
|
|
9729
10064
|
else advance();
|
|
9730
10065
|
}
|
|
9731
|
-
|
|
10066
|
+
useEffect24(() => {
|
|
9732
10067
|
const input = stage.current?.querySelector(
|
|
9733
10068
|
"input:not([tabindex='-1']), textarea, select, [role='combobox']"
|
|
9734
10069
|
);
|
|
9735
10070
|
input?.focus();
|
|
9736
10071
|
}, [index, done]);
|
|
9737
10072
|
if (done) {
|
|
9738
|
-
return /* @__PURE__ */
|
|
9739
|
-
/* @__PURE__ */
|
|
9740
|
-
form.thankYou?.body ? /* @__PURE__ */
|
|
9741
|
-
/* @__PURE__ */
|
|
10073
|
+
return /* @__PURE__ */ jsxs34("section", { className: cn32("mx-auto max-w-xl py-10", centred && "text-center", className), children: [
|
|
10074
|
+
/* @__PURE__ */ jsx38("h2", { className: "text-lg font-medium", children: form.thankYou?.title ?? "Thank you" }),
|
|
10075
|
+
form.thankYou?.body ? /* @__PURE__ */ jsx38("p", { className: "mt-1 text-sm text-muted-foreground", children: form.thankYou.body }) : null,
|
|
10076
|
+
/* @__PURE__ */ jsx38("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 })
|
|
9742
10077
|
] });
|
|
9743
10078
|
}
|
|
9744
10079
|
const unresolved = questions.filter((q) => !q.field);
|
|
9745
10080
|
const unanswerable = !evaluate && questions.some((q) => q.showIf);
|
|
9746
10081
|
const signedInPublic = connected && form.isPublic === true;
|
|
9747
|
-
return /* @__PURE__ */
|
|
10082
|
+
return /* @__PURE__ */ jsxs34(
|
|
9748
10083
|
"section",
|
|
9749
10084
|
{
|
|
9750
|
-
className:
|
|
10085
|
+
className: cn32("mx-auto flex max-w-xl flex-col gap-3 py-4", centred && "text-center", className),
|
|
9751
10086
|
onKeyDown,
|
|
9752
10087
|
children: [
|
|
9753
|
-
/* @__PURE__ */
|
|
9754
|
-
/* @__PURE__ */
|
|
10088
|
+
/* @__PURE__ */ jsxs34("header", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
|
|
10089
|
+
/* @__PURE__ */ jsx38(
|
|
9755
10090
|
Progress,
|
|
9756
10091
|
{
|
|
9757
10092
|
value: live.length === 0 ? 0 : (oneAtATime ? index + 1 : answered) / live.length * 100,
|
|
9758
10093
|
className: "h-1 flex-1"
|
|
9759
10094
|
}
|
|
9760
10095
|
),
|
|
9761
|
-
/* @__PURE__ */
|
|
10096
|
+
/* @__PURE__ */ jsx38("span", { className: "tabular-nums", children: oneAtATime ? `${index + 1} of ${live.length}` : `${answered} of ${live.length}` })
|
|
9762
10097
|
] }),
|
|
9763
|
-
signedInPublic ? /* @__PURE__ */
|
|
9764
|
-
unanswerable ? /* @__PURE__ */
|
|
9765
|
-
unresolved.length > 0 ? /* @__PURE__ */
|
|
10098
|
+
signedInPublic ? /* @__PURE__ */ jsx38("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,
|
|
10099
|
+
unanswerable ? /* @__PURE__ */ jsx38("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,
|
|
10100
|
+
unresolved.length > 0 ? /* @__PURE__ */ jsxs34("p", { className: "rounded border border-dashed px-2 py-1 text-left text-xs text-destructive", children: [
|
|
9766
10101
|
unresolved.map((q) => q.key).join(", "),
|
|
9767
10102
|
" ",
|
|
9768
10103
|
unresolved.length === 1 ? "is a question" : "are questions",
|
|
9769
10104
|
" 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."
|
|
9770
10105
|
] }) : null,
|
|
9771
|
-
form.intro && index === 0 ? /* @__PURE__ */
|
|
9772
|
-
error ? /* @__PURE__ */
|
|
9773
|
-
refusal ? /* @__PURE__ */
|
|
9774
|
-
/* @__PURE__ */
|
|
9775
|
-
(oneAtATime ? current ? [current] : [] : live).map((q) => /* @__PURE__ */
|
|
10106
|
+
form.intro && index === 0 ? /* @__PURE__ */ jsx38("p", { className: "text-sm text-muted-foreground", children: form.intro }) : null,
|
|
10107
|
+
error ? /* @__PURE__ */ jsx38(RefusalNotice, { error, className: "text-left" }) : null,
|
|
10108
|
+
refusal ? /* @__PURE__ */ jsx38("p", { role: "alert", className: "rounded border border-destructive/40 px-2 py-1 text-left text-xs text-destructive", children: refusal }) : null,
|
|
10109
|
+
/* @__PURE__ */ jsxs34("div", { ref: stage, className: "flex flex-col gap-4 text-left", children: [
|
|
10110
|
+
(oneAtATime ? current ? [current] : [] : live).map((q) => /* @__PURE__ */ jsx38(
|
|
9776
10111
|
Question,
|
|
9777
10112
|
{
|
|
9778
10113
|
question: q,
|
|
@@ -9782,11 +10117,11 @@ function FormStage({
|
|
|
9782
10117
|
},
|
|
9783
10118
|
q.key
|
|
9784
10119
|
)),
|
|
9785
|
-
live.length === 0 ? /* @__PURE__ */
|
|
10120
|
+
live.length === 0 ? /* @__PURE__ */ jsx38("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
|
|
9786
10121
|
] }),
|
|
9787
|
-
honeypotKey ? /* @__PURE__ */
|
|
9788
|
-
/* @__PURE__ */
|
|
9789
|
-
/* @__PURE__ */
|
|
10122
|
+
honeypotKey ? /* @__PURE__ */ jsxs34("div", { "aria-hidden": true, className: "pointer-events-none absolute left-[-9999px] h-px w-px overflow-hidden", children: [
|
|
10123
|
+
/* @__PURE__ */ jsx38("label", { htmlFor: `hp-${honeypotKey}`, children: "Leave this field empty" }),
|
|
10124
|
+
/* @__PURE__ */ jsx38(
|
|
9790
10125
|
"input",
|
|
9791
10126
|
{
|
|
9792
10127
|
id: `hp-${honeypotKey}`,
|
|
@@ -9801,16 +10136,16 @@ function FormStage({
|
|
|
9801
10136
|
}
|
|
9802
10137
|
)
|
|
9803
10138
|
] }) : null,
|
|
9804
|
-
/* @__PURE__ */
|
|
9805
|
-
oneAtATime && index > 0 ? /* @__PURE__ */
|
|
9806
|
-
oneAtATime && index < live.length - 1 ? /* @__PURE__ */
|
|
9807
|
-
missing.length > 0 && (!oneAtATime || index === live.length - 1) ? /* @__PURE__ */
|
|
10139
|
+
/* @__PURE__ */ jsxs34("footer", { className: cn32("flex flex-wrap items-center gap-2", centred && "justify-center"), children: [
|
|
10140
|
+
oneAtATime && index > 0 ? /* @__PURE__ */ jsx38(Button31, { size: "sm", variant: "ghost", onClick: retreat, children: "Back" }) : null,
|
|
10141
|
+
oneAtATime && index < live.length - 1 ? /* @__PURE__ */ jsx38(Button31, { size: "sm", onClick: advance, children: "Next" }) : /* @__PURE__ */ jsx38(Button31, { size: "sm", disabled: writing || missing.length > 0, onClick: () => void submit(), children: writing ? "Sending\u2026" : form.submitLabel ?? "Submit" }),
|
|
10142
|
+
missing.length > 0 && (!oneAtATime || index === live.length - 1) ? /* @__PURE__ */ jsxs34("span", { className: "text-xs text-muted-foreground", children: [
|
|
9808
10143
|
missing.map((q) => q.ask).join(", "),
|
|
9809
10144
|
" still ",
|
|
9810
10145
|
missing.length === 1 ? "needs" : "need",
|
|
9811
10146
|
" an answer."
|
|
9812
10147
|
] }) : null,
|
|
9813
|
-
preview ? /* @__PURE__ */
|
|
10148
|
+
preview ? /* @__PURE__ */ jsx38("span", { className: "text-xs text-muted-foreground", children: "Preview \u2014 nothing is written." }) : null
|
|
9814
10149
|
] })
|
|
9815
10150
|
]
|
|
9816
10151
|
}
|
|
@@ -9822,16 +10157,16 @@ function Question({
|
|
|
9822
10157
|
onChange,
|
|
9823
10158
|
upload
|
|
9824
10159
|
}) {
|
|
9825
|
-
const [uploadError, setUploadError] =
|
|
10160
|
+
const [uploadError, setUploadError] = useState34(null);
|
|
9826
10161
|
const field = question.field;
|
|
9827
10162
|
if (!field) return null;
|
|
9828
10163
|
const id = `form-${field.key}`;
|
|
9829
10164
|
const isAttachment = editorKindFor(field) === "attachment";
|
|
9830
|
-
return /* @__PURE__ */
|
|
9831
|
-
/* @__PURE__ */
|
|
9832
|
-
question.help ? /* @__PURE__ */
|
|
9833
|
-
isAttachment && !upload ? /* @__PURE__ */
|
|
9834
|
-
/* @__PURE__ */
|
|
10165
|
+
return /* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1.5", children: [
|
|
10166
|
+
/* @__PURE__ */ jsx38(FieldLabel, { field: { ...field, label: question.ask, required: question.required }, htmlFor: id }),
|
|
10167
|
+
question.help ? /* @__PURE__ */ jsx38("p", { className: "text-xs text-muted-foreground", children: question.help }) : null,
|
|
10168
|
+
isAttachment && !upload ? /* @__PURE__ */ jsx38("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : isAttachment ? /* @__PURE__ */ jsxs34(Fragment17, { children: [
|
|
10169
|
+
/* @__PURE__ */ jsx38(
|
|
9835
10170
|
"input",
|
|
9836
10171
|
{
|
|
9837
10172
|
id,
|
|
@@ -9849,31 +10184,31 @@ function Question({
|
|
|
9849
10184
|
}
|
|
9850
10185
|
}
|
|
9851
10186
|
),
|
|
9852
|
-
uploadError ? /* @__PURE__ */
|
|
9853
|
-
] }) : /* @__PURE__ */
|
|
10187
|
+
uploadError ? /* @__PURE__ */ jsx38("p", { className: "text-xs text-destructive", children: uploadError }) : null
|
|
10188
|
+
] }) : /* @__PURE__ */ jsx38(FieldControl, { field, value, onChange, id })
|
|
9854
10189
|
] });
|
|
9855
10190
|
}
|
|
9856
10191
|
|
|
9857
10192
|
// src/FormBuilder.tsx
|
|
9858
|
-
import { Fragment as
|
|
10193
|
+
import { Fragment as Fragment18, jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
9859
10194
|
function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
9860
|
-
const client =
|
|
10195
|
+
const client = useRecordsClient28();
|
|
9861
10196
|
const host = useRecordsUi();
|
|
9862
10197
|
const claimSeed = useSeedGuard();
|
|
9863
10198
|
const table = useTable13(tableId);
|
|
9864
10199
|
const rights = useTableRights(table.data);
|
|
9865
10200
|
const fields = useFields16(tableId);
|
|
9866
|
-
const [forms, setForms] =
|
|
9867
|
-
const [error, setError] =
|
|
9868
|
-
const [activeId, setActiveId] =
|
|
9869
|
-
const [draft, setDraft] =
|
|
9870
|
-
const [saving, setSaving] =
|
|
9871
|
-
const [saved, setSaved] =
|
|
9872
|
-
const [publishing, setPublishing] =
|
|
9873
|
-
const [copied, setCopied] =
|
|
9874
|
-
const [shownUrl, setShownUrl] =
|
|
10201
|
+
const [forms, setForms] = useState35(null);
|
|
10202
|
+
const [error, setError] = useState35(null);
|
|
10203
|
+
const [activeId, setActiveId] = useState35(activeFormId ?? null);
|
|
10204
|
+
const [draft, setDraft] = useState35(null);
|
|
10205
|
+
const [saving, setSaving] = useState35(false);
|
|
10206
|
+
const [saved, setSaved] = useState35(null);
|
|
10207
|
+
const [publishing, setPublishing] = useState35(false);
|
|
10208
|
+
const [copied, setCopied] = useState35(false);
|
|
10209
|
+
const [shownUrl, setShownUrl] = useState35(null);
|
|
9875
10210
|
const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
9876
|
-
const load =
|
|
10211
|
+
const load = useCallback22(async () => {
|
|
9877
10212
|
const answered = await client.forms({ table_id: tableId });
|
|
9878
10213
|
if (!answered.ok) {
|
|
9879
10214
|
setError(answered.error);
|
|
@@ -9900,17 +10235,17 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
9900
10235
|
setError(null);
|
|
9901
10236
|
setForms(mine);
|
|
9902
10237
|
}, [client, tableId, seed, claimSeed]);
|
|
9903
|
-
|
|
10238
|
+
useEffect25(() => {
|
|
9904
10239
|
void load();
|
|
9905
10240
|
}, [load]);
|
|
9906
|
-
|
|
10241
|
+
useEffect25(() => {
|
|
9907
10242
|
if (!forms || forms.length === 0) return;
|
|
9908
10243
|
const chosen = forms.find((f) => f.id === (activeFormId ?? activeId)) ?? forms[0];
|
|
9909
10244
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
9910
10245
|
setDraft(chosen);
|
|
9911
10246
|
onActiveForm?.(chosen);
|
|
9912
10247
|
}, [forms, activeFormId]);
|
|
9913
|
-
const byKey =
|
|
10248
|
+
const byKey = useMemo25(() => new Map((fields.data ?? []).map((f) => [f.key, f])), [fields.data]);
|
|
9914
10249
|
function patch(change) {
|
|
9915
10250
|
setDraft((prev) => prev ? { ...prev, ...change } : prev);
|
|
9916
10251
|
setSaved(null);
|
|
@@ -9970,26 +10305,26 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
9970
10305
|
setActiveId(written.data);
|
|
9971
10306
|
await load();
|
|
9972
10307
|
}
|
|
9973
|
-
if (fields.error) return /* @__PURE__ */
|
|
10308
|
+
if (fields.error) return /* @__PURE__ */ jsx39(RefusalNotice, { error: fields.error, className });
|
|
9974
10309
|
if (error) {
|
|
9975
|
-
return /* @__PURE__ */
|
|
10310
|
+
return /* @__PURE__ */ jsx39(
|
|
9976
10311
|
RefusalNotice,
|
|
9977
10312
|
{
|
|
9978
10313
|
error,
|
|
9979
10314
|
className,
|
|
9980
|
-
actions: /* @__PURE__ */
|
|
10315
|
+
actions: /* @__PURE__ */ jsx39(Button32, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
9981
10316
|
}
|
|
9982
10317
|
);
|
|
9983
10318
|
}
|
|
9984
|
-
if (fields.loading || forms === null) return /* @__PURE__ */
|
|
10319
|
+
if (fields.loading || forms === null) return /* @__PURE__ */ jsx39(Skeleton19, { className: cn33("h-64 w-full", className) });
|
|
9985
10320
|
if (!rights.admin) {
|
|
9986
|
-
return /* @__PURE__ */
|
|
10321
|
+
return /* @__PURE__ */ jsx39("p", { className: cn33("text-xs text-muted-foreground", className), children: rights.why("structure") });
|
|
9987
10322
|
}
|
|
9988
|
-
return /* @__PURE__ */
|
|
9989
|
-
/* @__PURE__ */
|
|
9990
|
-
/* @__PURE__ */
|
|
9991
|
-
forms.map((form) => /* @__PURE__ */
|
|
9992
|
-
|
|
10323
|
+
return /* @__PURE__ */ jsxs35("div", { className: cn33("flex min-h-0 gap-3", className), children: [
|
|
10324
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex min-w-0 flex-1 flex-col gap-2 overflow-auto", children: [
|
|
10325
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Forms", children: [
|
|
10326
|
+
forms.map((form) => /* @__PURE__ */ jsx39(
|
|
10327
|
+
Button32,
|
|
9993
10328
|
{
|
|
9994
10329
|
size: "sm",
|
|
9995
10330
|
variant: form.id === activeId ? "secondary" : "ghost",
|
|
@@ -10002,14 +10337,14 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10002
10337
|
},
|
|
10003
10338
|
form.id
|
|
10004
10339
|
)),
|
|
10005
|
-
(fields.data ?? []).length > 0 ? /* @__PURE__ */
|
|
10006
|
-
/* @__PURE__ */
|
|
10007
|
-
saved ? /* @__PURE__ */
|
|
10008
|
-
/* @__PURE__ */
|
|
10340
|
+
(fields.data ?? []).length > 0 ? /* @__PURE__ */ jsx39(Button32, { size: "sm", variant: "ghost", onClick: () => void create(`Form ${forms.length + 1}`), children: "New form" }) : null,
|
|
10341
|
+
/* @__PURE__ */ jsxs35("span", { className: "ml-auto flex items-center gap-2", children: [
|
|
10342
|
+
saved ? /* @__PURE__ */ jsx39("span", { className: "text-xs text-muted-foreground", children: saved }) : null,
|
|
10343
|
+
/* @__PURE__ */ jsx39(Button32, { size: "sm", disabled: saving || !draft, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" })
|
|
10009
10344
|
] })
|
|
10010
10345
|
] }),
|
|
10011
|
-
!draft ? /* @__PURE__ */
|
|
10012
|
-
/* @__PURE__ */
|
|
10346
|
+
!draft ? /* @__PURE__ */ jsx39("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__ */ jsxs35(Fragment18, { children: [
|
|
10347
|
+
/* @__PURE__ */ jsx39(
|
|
10013
10348
|
PublishRow,
|
|
10014
10349
|
{
|
|
10015
10350
|
url: `${publicOrigin}${publicFormPath(draft.id)}`,
|
|
@@ -10023,26 +10358,26 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10023
10358
|
onCopy: (url) => void copyLink(url)
|
|
10024
10359
|
}
|
|
10025
10360
|
),
|
|
10026
|
-
/* @__PURE__ */
|
|
10027
|
-
/* @__PURE__ */
|
|
10028
|
-
/* @__PURE__ */
|
|
10029
|
-
/* @__PURE__ */
|
|
10361
|
+
/* @__PURE__ */ jsxs35("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
10362
|
+
/* @__PURE__ */ jsxs35("label", { className: "flex flex-col gap-1", children: [
|
|
10363
|
+
/* @__PURE__ */ jsx39(Label6, { className: "text-xs font-medium", children: "Name" }),
|
|
10364
|
+
/* @__PURE__ */ jsx39(BasicInput11, { value: draft.name, onChange: (e) => patch({ name: e.target.value }) })
|
|
10030
10365
|
] }),
|
|
10031
|
-
/* @__PURE__ */
|
|
10032
|
-
/* @__PURE__ */
|
|
10033
|
-
/* @__PURE__ */
|
|
10366
|
+
/* @__PURE__ */ jsxs35("label", { className: "flex flex-col gap-1", children: [
|
|
10367
|
+
/* @__PURE__ */ jsx39(Label6, { className: "text-xs font-medium", children: "Flow" }),
|
|
10368
|
+
/* @__PURE__ */ jsx39(
|
|
10034
10369
|
"select",
|
|
10035
10370
|
{
|
|
10036
10371
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
10037
10372
|
value: draft.flow ?? "one-at-a-time",
|
|
10038
10373
|
onChange: (e) => patch({ flow: e.target.value }),
|
|
10039
|
-
children: FORM_FLOWS.map((flow) => /* @__PURE__ */
|
|
10374
|
+
children: FORM_FLOWS.map((flow) => /* @__PURE__ */ jsx39("option", { value: flow, children: flow === "one-at-a-time" ? "One question at a time" : "All on one page" }, flow))
|
|
10040
10375
|
}
|
|
10041
10376
|
)
|
|
10042
10377
|
] }),
|
|
10043
|
-
/* @__PURE__ */
|
|
10044
|
-
/* @__PURE__ */
|
|
10045
|
-
/* @__PURE__ */
|
|
10378
|
+
/* @__PURE__ */ jsxs35("label", { className: "col-span-2 flex flex-col gap-1", children: [
|
|
10379
|
+
/* @__PURE__ */ jsx39(Label6, { className: "text-xs font-medium", children: "Intro" }),
|
|
10380
|
+
/* @__PURE__ */ jsx39(
|
|
10046
10381
|
BasicTextarea5,
|
|
10047
10382
|
{
|
|
10048
10383
|
rows: 2,
|
|
@@ -10051,10 +10386,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10051
10386
|
}
|
|
10052
10387
|
)
|
|
10053
10388
|
] }),
|
|
10054
|
-
/* @__PURE__ */
|
|
10055
|
-
/* @__PURE__ */
|
|
10056
|
-
/* @__PURE__ */
|
|
10057
|
-
|
|
10389
|
+
/* @__PURE__ */ jsxs35("label", { className: "flex flex-col gap-1", children: [
|
|
10390
|
+
/* @__PURE__ */ jsx39(Label6, { className: "text-xs font-medium", children: "Submit button" }),
|
|
10391
|
+
/* @__PURE__ */ jsx39(
|
|
10392
|
+
BasicInput11,
|
|
10058
10393
|
{
|
|
10059
10394
|
value: draft.submitLabel ?? "",
|
|
10060
10395
|
placeholder: "Submit",
|
|
@@ -10062,10 +10397,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10062
10397
|
}
|
|
10063
10398
|
)
|
|
10064
10399
|
] }),
|
|
10065
|
-
/* @__PURE__ */
|
|
10066
|
-
/* @__PURE__ */
|
|
10067
|
-
/* @__PURE__ */
|
|
10068
|
-
|
|
10400
|
+
/* @__PURE__ */ jsxs35("label", { className: "flex flex-col gap-1", children: [
|
|
10401
|
+
/* @__PURE__ */ jsx39(Label6, { className: "text-xs font-medium", children: "Thank-you title" }),
|
|
10402
|
+
/* @__PURE__ */ jsx39(
|
|
10403
|
+
BasicInput11,
|
|
10069
10404
|
{
|
|
10070
10405
|
value: draft.thankYou?.title ?? "",
|
|
10071
10406
|
placeholder: "Thank you",
|
|
@@ -10076,10 +10411,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10076
10411
|
)
|
|
10077
10412
|
] })
|
|
10078
10413
|
] }),
|
|
10079
|
-
/* @__PURE__ */
|
|
10080
|
-
/* @__PURE__ */
|
|
10081
|
-
/* @__PURE__ */
|
|
10082
|
-
/* @__PURE__ */
|
|
10414
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-1", children: [
|
|
10415
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
10416
|
+
/* @__PURE__ */ jsx39("span", { className: "font-medium text-foreground", children: "Questions" }),
|
|
10417
|
+
/* @__PURE__ */ jsxs35("span", { children: [
|
|
10083
10418
|
draft.questions.length,
|
|
10084
10419
|
" of this table's ",
|
|
10085
10420
|
fields.data?.length ?? 0,
|
|
@@ -10090,10 +10425,10 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10090
10425
|
const index = draft.questions.findIndex((q) => q.field === field.key);
|
|
10091
10426
|
const asked = index >= 0;
|
|
10092
10427
|
const question = asked ? draft.questions[index] : null;
|
|
10093
|
-
return /* @__PURE__ */
|
|
10094
|
-
/* @__PURE__ */
|
|
10095
|
-
/* @__PURE__ */
|
|
10096
|
-
|
|
10428
|
+
return /* @__PURE__ */ jsxs35("div", { className: "rounded border px-2 py-1.5", children: [
|
|
10429
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
10430
|
+
/* @__PURE__ */ jsx39(
|
|
10431
|
+
Checkbox6,
|
|
10097
10432
|
{
|
|
10098
10433
|
checked: asked,
|
|
10099
10434
|
"aria-label": `Ask for ${fieldName(field)}`,
|
|
@@ -10102,13 +10437,13 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10102
10437
|
})
|
|
10103
10438
|
}
|
|
10104
10439
|
),
|
|
10105
|
-
/* @__PURE__ */
|
|
10106
|
-
/* @__PURE__ */
|
|
10107
|
-
field.required ? /* @__PURE__ */
|
|
10440
|
+
/* @__PURE__ */ jsx39("span", { className: "text-xs font-medium", children: fieldName(field) }),
|
|
10441
|
+
/* @__PURE__ */ jsx39("span", { className: "text-xs text-muted-foreground", children: field.key }),
|
|
10442
|
+
field.required ? /* @__PURE__ */ jsx39("span", { className: "text-xs text-destructive", children: "required" }) : null
|
|
10108
10443
|
] }),
|
|
10109
|
-
asked && question ? /* @__PURE__ */
|
|
10110
|
-
/* @__PURE__ */
|
|
10111
|
-
|
|
10444
|
+
asked && question ? /* @__PURE__ */ jsxs35("div", { className: "mt-1.5 grid grid-cols-2 gap-2 pl-6", children: [
|
|
10445
|
+
/* @__PURE__ */ jsx39(
|
|
10446
|
+
BasicInput11,
|
|
10112
10447
|
{
|
|
10113
10448
|
className: "h-8 text-xs",
|
|
10114
10449
|
placeholder: fieldName(field),
|
|
@@ -10117,8 +10452,8 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10117
10452
|
onChange: (e) => patchQuestion(index, { ask: e.target.value || null })
|
|
10118
10453
|
}
|
|
10119
10454
|
),
|
|
10120
|
-
/* @__PURE__ */
|
|
10121
|
-
|
|
10455
|
+
/* @__PURE__ */ jsx39(
|
|
10456
|
+
BasicInput11,
|
|
10122
10457
|
{
|
|
10123
10458
|
className: "h-8 text-xs",
|
|
10124
10459
|
placeholder: "Help text",
|
|
@@ -10127,7 +10462,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10127
10462
|
onChange: (e) => patchQuestion(index, { help: e.target.value || null })
|
|
10128
10463
|
}
|
|
10129
10464
|
),
|
|
10130
|
-
/* @__PURE__ */
|
|
10465
|
+
/* @__PURE__ */ jsx39(
|
|
10131
10466
|
Condition,
|
|
10132
10467
|
{
|
|
10133
10468
|
question,
|
|
@@ -10138,7 +10473,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10138
10473
|
] }) : null
|
|
10139
10474
|
] }, field.id);
|
|
10140
10475
|
}),
|
|
10141
|
-
draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */
|
|
10476
|
+
draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */ jsxs35("p", { className: "text-xs text-destructive", children: [
|
|
10142
10477
|
'This form asks for "',
|
|
10143
10478
|
q.field,
|
|
10144
10479
|
'" and this table has no such Field. It is shown here rather than quietly dropped.'
|
|
@@ -10146,9 +10481,9 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10146
10481
|
] })
|
|
10147
10482
|
] })
|
|
10148
10483
|
] }),
|
|
10149
|
-
draft ? /* @__PURE__ */
|
|
10150
|
-
/* @__PURE__ */
|
|
10151
|
-
/* @__PURE__ */
|
|
10484
|
+
draft ? /* @__PURE__ */ jsxs35("aside", { className: "w-96 shrink-0 overflow-auto rounded border p-2", children: [
|
|
10485
|
+
/* @__PURE__ */ jsx39("h4", { className: "px-1 text-sm font-medium", children: draft.name }),
|
|
10486
|
+
/* @__PURE__ */ jsx39(FormRunner, { form: draft, preview: true })
|
|
10152
10487
|
] }) : null
|
|
10153
10488
|
] });
|
|
10154
10489
|
}
|
|
@@ -10164,10 +10499,10 @@ function PublishRow({
|
|
|
10164
10499
|
onCopy
|
|
10165
10500
|
}) {
|
|
10166
10501
|
const open = state === "open";
|
|
10167
|
-
return /* @__PURE__ */
|
|
10168
|
-
/* @__PURE__ */
|
|
10169
|
-
mayPublish ? /* @__PURE__ */
|
|
10170
|
-
|
|
10502
|
+
return /* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-1.5 rounded border px-2.5 py-2", children: [
|
|
10503
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
10504
|
+
mayPublish ? /* @__PURE__ */ jsx39(
|
|
10505
|
+
Button32,
|
|
10171
10506
|
{
|
|
10172
10507
|
size: "sm",
|
|
10173
10508
|
variant: open ? "ghost" : "default",
|
|
@@ -10176,8 +10511,8 @@ function PublishRow({
|
|
|
10176
10511
|
children: busy ? "\u2026" : open ? "Unpublish" : "Publish"
|
|
10177
10512
|
}
|
|
10178
10513
|
) : null,
|
|
10179
|
-
state !== "draft" ? /* @__PURE__ */
|
|
10180
|
-
/* @__PURE__ */
|
|
10514
|
+
state !== "draft" ? /* @__PURE__ */ jsxs35(Fragment18, { children: [
|
|
10515
|
+
/* @__PURE__ */ jsx39(
|
|
10181
10516
|
"a",
|
|
10182
10517
|
{
|
|
10183
10518
|
href: url,
|
|
@@ -10187,12 +10522,12 @@ function PublishRow({
|
|
|
10187
10522
|
children: url
|
|
10188
10523
|
}
|
|
10189
10524
|
),
|
|
10190
|
-
/* @__PURE__ */
|
|
10525
|
+
/* @__PURE__ */ jsx39(Button32, { size: "sm", variant: "outline", onClick: () => onCopy(url), children: copied ? "Copied" : "Copy link" })
|
|
10191
10526
|
] }) : null
|
|
10192
10527
|
] }),
|
|
10193
|
-
/* @__PURE__ */
|
|
10194
|
-
!mayPublish ? /* @__PURE__ */
|
|
10195
|
-
shownUrl ? /* @__PURE__ */
|
|
10528
|
+
/* @__PURE__ */ jsx39("p", { className: "text-xs text-muted-foreground", children: FORM_STATE_WORDS[state] }),
|
|
10529
|
+
!mayPublish ? /* @__PURE__ */ jsx39("p", { className: "text-xs text-muted-foreground", children: why }) : null,
|
|
10530
|
+
shownUrl ? /* @__PURE__ */ jsxs35("p", { className: "break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
10196
10531
|
"This browser would not let the page copy for you, so here it is to copy by hand: ",
|
|
10197
10532
|
shownUrl
|
|
10198
10533
|
] }) : null
|
|
@@ -10203,7 +10538,7 @@ function Condition({
|
|
|
10203
10538
|
fieldKeys,
|
|
10204
10539
|
onChange
|
|
10205
10540
|
}) {
|
|
10206
|
-
return /* @__PURE__ */
|
|
10541
|
+
return /* @__PURE__ */ jsx39(
|
|
10207
10542
|
ConditionRow,
|
|
10208
10543
|
{
|
|
10209
10544
|
lead: "Ask only when",
|
|
@@ -10301,17 +10636,17 @@ function groupLabel(groups) {
|
|
|
10301
10636
|
|
|
10302
10637
|
// src/chartFrame.tsx
|
|
10303
10638
|
import {
|
|
10304
|
-
useEffect as
|
|
10639
|
+
useEffect as useEffect26,
|
|
10305
10640
|
useId,
|
|
10306
10641
|
useRef as useRef10,
|
|
10307
|
-
useState as
|
|
10642
|
+
useState as useState36
|
|
10308
10643
|
} from "react";
|
|
10309
|
-
import { cn as
|
|
10310
|
-
import { jsx as
|
|
10644
|
+
import { cn as cn34 } from "@ai-matrx/design-system";
|
|
10645
|
+
import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
10311
10646
|
function useMeasuredWidth(fallback = 480) {
|
|
10312
10647
|
const ref = useRef10(null);
|
|
10313
|
-
const [width, setWidth] =
|
|
10314
|
-
|
|
10648
|
+
const [width, setWidth] = useState36(fallback);
|
|
10649
|
+
useEffect26(() => {
|
|
10315
10650
|
const node = ref.current;
|
|
10316
10651
|
if (!node) return;
|
|
10317
10652
|
const apply = () => {
|
|
@@ -10342,13 +10677,13 @@ function ChartFrame({
|
|
|
10342
10677
|
}) {
|
|
10343
10678
|
const [ref, width] = useMeasuredWidth();
|
|
10344
10679
|
const chartId = `records-chart-${useId().replace(/:/g, "")}`;
|
|
10345
|
-
return /* @__PURE__ */
|
|
10680
|
+
return /* @__PURE__ */ jsx40(
|
|
10346
10681
|
"div",
|
|
10347
10682
|
{
|
|
10348
10683
|
ref,
|
|
10349
10684
|
"data-chart": chartId,
|
|
10350
10685
|
style: { height, ...chartVariables(config) },
|
|
10351
|
-
className:
|
|
10686
|
+
className: cn34(
|
|
10352
10687
|
"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",
|
|
10353
10688
|
className
|
|
10354
10689
|
),
|
|
@@ -10364,27 +10699,27 @@ function ChartTooltipContent({
|
|
|
10364
10699
|
className
|
|
10365
10700
|
}) {
|
|
10366
10701
|
if (!active || !payload || payload.length === 0) return null;
|
|
10367
|
-
return /* @__PURE__ */
|
|
10702
|
+
return /* @__PURE__ */ jsxs36(
|
|
10368
10703
|
"div",
|
|
10369
10704
|
{
|
|
10370
|
-
className:
|
|
10705
|
+
className: cn34(
|
|
10371
10706
|
"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",
|
|
10372
10707
|
className
|
|
10373
10708
|
),
|
|
10374
10709
|
children: [
|
|
10375
|
-
label ? /* @__PURE__ */
|
|
10376
|
-
/* @__PURE__ */
|
|
10710
|
+
label ? /* @__PURE__ */ jsx40("div", { className: "font-medium", children: label }) : null,
|
|
10711
|
+
/* @__PURE__ */ jsx40("div", { className: "grid gap-1.5", children: payload.map((entry, index) => {
|
|
10377
10712
|
const key = String(entry.dataKey ?? entry.name ?? index);
|
|
10378
|
-
return /* @__PURE__ */
|
|
10379
|
-
/* @__PURE__ */
|
|
10713
|
+
return /* @__PURE__ */ jsxs36("div", { className: "flex w-full items-center gap-2", children: [
|
|
10714
|
+
/* @__PURE__ */ jsx40(
|
|
10380
10715
|
"span",
|
|
10381
10716
|
{
|
|
10382
10717
|
className: "h-2.5 w-2.5 shrink-0 rounded-[2px] bg-[--color-swatch]",
|
|
10383
10718
|
style: { "--color-swatch": entry.color }
|
|
10384
10719
|
}
|
|
10385
10720
|
),
|
|
10386
|
-
/* @__PURE__ */
|
|
10387
|
-
/* @__PURE__ */
|
|
10721
|
+
/* @__PURE__ */ jsx40("span", { className: "text-muted-foreground", children: config[key]?.label ?? key }),
|
|
10722
|
+
/* @__PURE__ */ jsx40("span", { className: "ml-auto font-mono font-medium tabular-nums text-foreground", children: typeof entry.value === "number" ? entry.value.toLocaleString() : entry.value })
|
|
10388
10723
|
] }, key);
|
|
10389
10724
|
}) })
|
|
10390
10725
|
]
|
|
@@ -10397,10 +10732,10 @@ function ChartLegendContent({
|
|
|
10397
10732
|
className
|
|
10398
10733
|
}) {
|
|
10399
10734
|
if (!payload || payload.length === 0) return null;
|
|
10400
|
-
return /* @__PURE__ */
|
|
10735
|
+
return /* @__PURE__ */ jsx40("div", { className: cn34("flex flex-wrap items-center justify-center gap-3 pt-2", className), children: payload.map((entry, index) => {
|
|
10401
10736
|
const key = String(entry.dataKey ?? entry.value ?? index);
|
|
10402
|
-
return /* @__PURE__ */
|
|
10403
|
-
/* @__PURE__ */
|
|
10737
|
+
return /* @__PURE__ */ jsxs36("span", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
10738
|
+
/* @__PURE__ */ jsx40(
|
|
10404
10739
|
"span",
|
|
10405
10740
|
{
|
|
10406
10741
|
className: "h-2 w-2 shrink-0 rounded-[2px] bg-[--color-swatch]",
|
|
@@ -10435,24 +10770,24 @@ function isSignatureField(field) {
|
|
|
10435
10770
|
}
|
|
10436
10771
|
|
|
10437
10772
|
// src/DocTemplate.tsx
|
|
10438
|
-
import { useCallback as
|
|
10439
|
-
import { useFields as useFields17, useRecordsClient as
|
|
10440
|
-
import { BasicInput as
|
|
10441
|
-
import { jsx as
|
|
10773
|
+
import { useCallback as useCallback23, useEffect as useEffect27, useState as useState37 } from "react";
|
|
10774
|
+
import { useFields as useFields17, useRecordsClient as useRecordsClient29, useTable as useTable14 } from "@ai-matrx/records/react";
|
|
10775
|
+
import { BasicInput as BasicInput12, BasicTextarea as BasicTextarea6, Button as Button33, Label as Label7, Skeleton as Skeleton20, cn as cn35 } from "@ai-matrx/design-system";
|
|
10776
|
+
import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
10442
10777
|
function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, className }) {
|
|
10443
|
-
const client =
|
|
10778
|
+
const client = useRecordsClient29();
|
|
10444
10779
|
const claimSeed = useSeedGuard();
|
|
10445
10780
|
const table = useTable14(tableId);
|
|
10446
10781
|
const rights = useTableRights(table.data);
|
|
10447
10782
|
const fields = useFields17(tableId);
|
|
10448
|
-
const [templates, setTemplates] =
|
|
10449
|
-
const [error, setError] =
|
|
10450
|
-
const [activeId, setActiveId] =
|
|
10451
|
-
const [draftName, setDraftName] =
|
|
10452
|
-
const [draftBody, setDraftBody] =
|
|
10453
|
-
const [unresolved, setUnresolved] =
|
|
10454
|
-
const [saving, setSaving] =
|
|
10455
|
-
const load =
|
|
10783
|
+
const [templates, setTemplates] = useState37(null);
|
|
10784
|
+
const [error, setError] = useState37(null);
|
|
10785
|
+
const [activeId, setActiveId] = useState37(activeTemplateId ?? null);
|
|
10786
|
+
const [draftName, setDraftName] = useState37("");
|
|
10787
|
+
const [draftBody, setDraftBody] = useState37("");
|
|
10788
|
+
const [unresolved, setUnresolved] = useState37([]);
|
|
10789
|
+
const [saving, setSaving] = useState37(false);
|
|
10790
|
+
const load = useCallback23(async () => {
|
|
10456
10791
|
const held = await client.docTemplates({ table_id: tableId });
|
|
10457
10792
|
if (!held.ok) {
|
|
10458
10793
|
setError(held.error);
|
|
@@ -10483,10 +10818,10 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10483
10818
|
setError(null);
|
|
10484
10819
|
setTemplates(rows);
|
|
10485
10820
|
}, [client, tableId, seed, fields.data]);
|
|
10486
|
-
|
|
10821
|
+
useEffect27(() => {
|
|
10487
10822
|
void load();
|
|
10488
10823
|
}, [load]);
|
|
10489
|
-
|
|
10824
|
+
useEffect27(() => {
|
|
10490
10825
|
if (!templates || templates.length === 0) return;
|
|
10491
10826
|
const chosen = templates.find((t) => t.id === (activeTemplateId ?? activeId)) ?? templates[0];
|
|
10492
10827
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
@@ -10494,7 +10829,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10494
10829
|
setDraftBody(chosen.body);
|
|
10495
10830
|
onActiveTemplate?.(chosen);
|
|
10496
10831
|
}, [templates, activeTemplateId]);
|
|
10497
|
-
|
|
10832
|
+
useEffect27(() => {
|
|
10498
10833
|
let cancelled = false;
|
|
10499
10834
|
if (draftBody.trim() === "") {
|
|
10500
10835
|
setUnresolved([]);
|
|
@@ -10524,25 +10859,25 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10524
10859
|
setActiveId(saved.data);
|
|
10525
10860
|
await load();
|
|
10526
10861
|
}
|
|
10527
|
-
if (fields.error) return /* @__PURE__ */
|
|
10862
|
+
if (fields.error) return /* @__PURE__ */ jsx41(RefusalNotice, { error: fields.error, className });
|
|
10528
10863
|
if (error) {
|
|
10529
|
-
return /* @__PURE__ */
|
|
10864
|
+
return /* @__PURE__ */ jsx41(
|
|
10530
10865
|
RefusalNotice,
|
|
10531
10866
|
{
|
|
10532
10867
|
error,
|
|
10533
10868
|
className,
|
|
10534
|
-
actions: /* @__PURE__ */
|
|
10869
|
+
actions: /* @__PURE__ */ jsx41(Button33, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10535
10870
|
}
|
|
10536
10871
|
);
|
|
10537
10872
|
}
|
|
10538
|
-
if (templates === null || fields.loading) return /* @__PURE__ */
|
|
10873
|
+
if (templates === null || fields.loading) return /* @__PURE__ */ jsx41(Skeleton20, { className: cn35("h-64 w-full", className) });
|
|
10539
10874
|
if (!rights.admin) {
|
|
10540
|
-
return /* @__PURE__ */
|
|
10875
|
+
return /* @__PURE__ */ jsx41("p", { className: cn35("text-xs text-muted-foreground", className), children: rights.why("structure") });
|
|
10541
10876
|
}
|
|
10542
|
-
return /* @__PURE__ */
|
|
10543
|
-
/* @__PURE__ */
|
|
10544
|
-
templates.map((t) => /* @__PURE__ */
|
|
10545
|
-
|
|
10877
|
+
return /* @__PURE__ */ jsxs37("div", { className: cn35("flex flex-col gap-2", className), children: [
|
|
10878
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Templates", children: [
|
|
10879
|
+
templates.map((t) => /* @__PURE__ */ jsxs37(
|
|
10880
|
+
Button33,
|
|
10546
10881
|
{
|
|
10547
10882
|
size: "sm",
|
|
10548
10883
|
variant: t.id === activeId ? "secondary" : "ghost",
|
|
@@ -10554,7 +10889,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10554
10889
|
},
|
|
10555
10890
|
children: [
|
|
10556
10891
|
t.name,
|
|
10557
|
-
/* @__PURE__ */
|
|
10892
|
+
/* @__PURE__ */ jsxs37("span", { className: "ml-1 text-[10px] text-muted-foreground", children: [
|
|
10558
10893
|
"v",
|
|
10559
10894
|
t.template_version
|
|
10560
10895
|
] })
|
|
@@ -10562,8 +10897,8 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10562
10897
|
},
|
|
10563
10898
|
t.id
|
|
10564
10899
|
)),
|
|
10565
|
-
/* @__PURE__ */
|
|
10566
|
-
|
|
10900
|
+
/* @__PURE__ */ jsx41(
|
|
10901
|
+
Button33,
|
|
10567
10902
|
{
|
|
10568
10903
|
size: "sm",
|
|
10569
10904
|
variant: "ghost",
|
|
@@ -10575,16 +10910,16 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10575
10910
|
children: "New template"
|
|
10576
10911
|
}
|
|
10577
10912
|
),
|
|
10578
|
-
/* @__PURE__ */
|
|
10913
|
+
/* @__PURE__ */ jsx41(Button33, { size: "sm", className: "ml-auto", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" })
|
|
10579
10914
|
] }),
|
|
10580
|
-
/* @__PURE__ */
|
|
10581
|
-
/* @__PURE__ */
|
|
10582
|
-
/* @__PURE__ */
|
|
10915
|
+
/* @__PURE__ */ jsxs37("label", { className: "flex flex-col gap-1", children: [
|
|
10916
|
+
/* @__PURE__ */ jsx41(Label7, { className: "text-xs font-medium", children: "Name" }),
|
|
10917
|
+
/* @__PURE__ */ jsx41(BasicInput12, { value: draftName, onChange: (e) => setDraftName(e.target.value), placeholder: "Agreement" })
|
|
10583
10918
|
] }),
|
|
10584
|
-
/* @__PURE__ */
|
|
10585
|
-
/* @__PURE__ */
|
|
10586
|
-
(fields.data ?? []).map((field) => /* @__PURE__ */
|
|
10587
|
-
|
|
10919
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex flex-wrap items-center gap-1", children: [
|
|
10920
|
+
/* @__PURE__ */ jsx41("span", { className: "text-xs text-muted-foreground", children: "Insert" }),
|
|
10921
|
+
(fields.data ?? []).map((field) => /* @__PURE__ */ jsx41(
|
|
10922
|
+
Button33,
|
|
10588
10923
|
{
|
|
10589
10924
|
size: "sm",
|
|
10590
10925
|
variant: "ghost",
|
|
@@ -10595,7 +10930,7 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10595
10930
|
field.id
|
|
10596
10931
|
))
|
|
10597
10932
|
] }),
|
|
10598
|
-
/* @__PURE__ */
|
|
10933
|
+
/* @__PURE__ */ jsx41(
|
|
10599
10934
|
BasicTextarea6,
|
|
10600
10935
|
{
|
|
10601
10936
|
rows: 10,
|
|
@@ -10605,28 +10940,28 @@ function DocTemplate({ tableId, seed, activeTemplateId, onActiveTemplate, classN
|
|
|
10605
10940
|
onChange: (e) => setDraftBody(e.target.value)
|
|
10606
10941
|
}
|
|
10607
10942
|
),
|
|
10608
|
-
unresolved.length > 0 ? /* @__PURE__ */
|
|
10609
|
-
/* @__PURE__ */
|
|
10943
|
+
unresolved.length > 0 ? /* @__PURE__ */ jsx41("ul", { className: "flex flex-col gap-0.5 rounded border border-dashed px-2 py-1 text-xs", children: unresolved.map((token) => /* @__PURE__ */ jsxs37("li", { className: "text-destructive", children: [
|
|
10944
|
+
/* @__PURE__ */ jsx41("code", { children: token.raw }),
|
|
10610
10945
|
" \u2014 ",
|
|
10611
10946
|
token.why
|
|
10612
|
-
] }, token.raw)) }) : draftBody.trim() !== "" ? /* @__PURE__ */
|
|
10947
|
+
] }, token.raw)) }) : draftBody.trim() !== "" ? /* @__PURE__ */ jsx41("p", { className: "text-xs text-muted-foreground", children: "Every token in this body points at a Field this table can answer." }) : null
|
|
10613
10948
|
] });
|
|
10614
10949
|
}
|
|
10615
10950
|
|
|
10616
10951
|
// src/DocRender.tsx
|
|
10617
|
-
import { useCallback as
|
|
10618
|
-
import { useRecordsClient as
|
|
10619
|
-
import { Button as
|
|
10620
|
-
import { jsx as
|
|
10952
|
+
import { useCallback as useCallback24, useEffect as useEffect28, useRef as useRef11, useState as useState38 } from "react";
|
|
10953
|
+
import { useRecordsClient as useRecordsClient30 } from "@ai-matrx/records/react";
|
|
10954
|
+
import { Button as Button34, Skeleton as Skeleton21, cn as cn36 } from "@ai-matrx/design-system";
|
|
10955
|
+
import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
10621
10956
|
function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
10622
|
-
const client =
|
|
10623
|
-
const [preview, setPreview] =
|
|
10624
|
-
const [renders, setRenders] =
|
|
10625
|
-
const [showing, setShowing] =
|
|
10626
|
-
const [error, setError] =
|
|
10627
|
-
const [busy, setBusy] =
|
|
10957
|
+
const client = useRecordsClient30();
|
|
10958
|
+
const [preview, setPreview] = useState38(null);
|
|
10959
|
+
const [renders, setRenders] = useState38(null);
|
|
10960
|
+
const [showing, setShowing] = useState38(null);
|
|
10961
|
+
const [error, setError] = useState38(null);
|
|
10962
|
+
const [busy, setBusy] = useState38(null);
|
|
10628
10963
|
const paper = useRef11(null);
|
|
10629
|
-
const load =
|
|
10964
|
+
const load = useCallback24(async () => {
|
|
10630
10965
|
const [body, held] = await Promise.all([
|
|
10631
10966
|
client.docRenderBody({ template_id: templateId, record_id: recordId }),
|
|
10632
10967
|
client.docRenders({ record_id: recordId })
|
|
@@ -10643,7 +10978,7 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10643
10978
|
setPreview(body.data);
|
|
10644
10979
|
setRenders(held.data.filter((r) => r.template_id === templateId));
|
|
10645
10980
|
}, [client, templateId, recordId]);
|
|
10646
|
-
|
|
10981
|
+
useEffect28(() => {
|
|
10647
10982
|
void load();
|
|
10648
10983
|
}, [load]);
|
|
10649
10984
|
async function freeze() {
|
|
@@ -10680,22 +11015,22 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10680
11015
|
}
|
|
10681
11016
|
}
|
|
10682
11017
|
if (error) {
|
|
10683
|
-
return /* @__PURE__ */
|
|
11018
|
+
return /* @__PURE__ */ jsx42(
|
|
10684
11019
|
RefusalNotice,
|
|
10685
11020
|
{
|
|
10686
11021
|
error,
|
|
10687
11022
|
className,
|
|
10688
|
-
actions: /* @__PURE__ */
|
|
11023
|
+
actions: /* @__PURE__ */ jsx42(Button34, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10689
11024
|
}
|
|
10690
11025
|
);
|
|
10691
11026
|
}
|
|
10692
|
-
if (preview === null || renders === null) return /* @__PURE__ */
|
|
11027
|
+
if (preview === null || renders === null) return /* @__PURE__ */ jsx42(Skeleton21, { className: cn36("h-64 w-full", className) });
|
|
10693
11028
|
const frozen = showing ? renders.find((r) => r.id === showing) ?? null : null;
|
|
10694
11029
|
const text = frozen ? frozen.body : preview;
|
|
10695
|
-
return /* @__PURE__ */
|
|
10696
|
-
/* @__PURE__ */
|
|
10697
|
-
/* @__PURE__ */
|
|
10698
|
-
|
|
11030
|
+
return /* @__PURE__ */ jsxs38("div", { className: cn36("flex flex-col gap-2", className), children: [
|
|
11031
|
+
/* @__PURE__ */ jsxs38("div", { className: "flex items-center gap-1 text-xs", children: [
|
|
11032
|
+
/* @__PURE__ */ jsx42(
|
|
11033
|
+
Button34,
|
|
10699
11034
|
{
|
|
10700
11035
|
size: "sm",
|
|
10701
11036
|
variant: frozen ? "ghost" : "secondary",
|
|
@@ -10704,8 +11039,8 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10704
11039
|
children: "As it reads now"
|
|
10705
11040
|
}
|
|
10706
11041
|
),
|
|
10707
|
-
renders.map((render) => /* @__PURE__ */
|
|
10708
|
-
|
|
11042
|
+
renders.map((render) => /* @__PURE__ */ jsx42(
|
|
11043
|
+
Button34,
|
|
10709
11044
|
{
|
|
10710
11045
|
size: "sm",
|
|
10711
11046
|
variant: render.id === showing ? "secondary" : "ghost",
|
|
@@ -10716,33 +11051,33 @@ function DocRender({ templateId, recordId, filename, onRendered, className }) {
|
|
|
10716
11051
|
},
|
|
10717
11052
|
render.id
|
|
10718
11053
|
)),
|
|
10719
|
-
/* @__PURE__ */
|
|
10720
|
-
/* @__PURE__ */
|
|
10721
|
-
/* @__PURE__ */
|
|
11054
|
+
/* @__PURE__ */ jsxs38("span", { className: "ml-auto flex items-center gap-1", children: [
|
|
11055
|
+
/* @__PURE__ */ jsx42(Button34, { size: "sm", disabled: busy !== null, onClick: () => void freeze(), children: busy === "freeze" ? "Freezing\u2026" : "Freeze this version" }),
|
|
11056
|
+
/* @__PURE__ */ jsx42(Button34, { size: "sm", variant: "ghost", disabled: busy !== null, onClick: () => void toPdf(), children: busy === "pdf" ? "Making the PDF\u2026" : "PDF" })
|
|
10722
11057
|
] })
|
|
10723
11058
|
] }),
|
|
10724
|
-
/* @__PURE__ */
|
|
10725
|
-
/* @__PURE__ */
|
|
11059
|
+
/* @__PURE__ */ jsx42("div", { ref: paper, className: "whitespace-pre-wrap rounded border bg-background p-4 text-sm text-foreground", children: text }),
|
|
11060
|
+
/* @__PURE__ */ jsx42("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." })
|
|
10726
11061
|
] });
|
|
10727
11062
|
}
|
|
10728
11063
|
|
|
10729
11064
|
// src/SignBlock.tsx
|
|
10730
|
-
import { useCallback as
|
|
10731
|
-
import { useFields as useFields18, useRecordsClient as
|
|
10732
|
-
import { BasicInput as
|
|
11065
|
+
import { useCallback as useCallback25, useEffect as useEffect29, useState as useState39 } from "react";
|
|
11066
|
+
import { useFields as useFields18, useRecordsClient as useRecordsClient31 } from "@ai-matrx/records/react";
|
|
11067
|
+
import { BasicInput as BasicInput13, Button as Button35, Skeleton as Skeleton22, cn as cn37 } from "@ai-matrx/design-system";
|
|
10733
11068
|
import { useTable as useTable15 } from "@ai-matrx/records/react";
|
|
10734
|
-
import { jsx as
|
|
11069
|
+
import { jsx as jsx43, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
10735
11070
|
function SignBlock({ tableId, recordId, render, className }) {
|
|
10736
|
-
const client =
|
|
11071
|
+
const client = useRecordsClient31();
|
|
10737
11072
|
const table = useTable15(tableId);
|
|
10738
11073
|
const rights = useTableRights(table.data);
|
|
10739
11074
|
const fields = useFields18(tableId);
|
|
10740
|
-
const [signatures, setSignatures] =
|
|
10741
|
-
const [verdicts, setVerdicts] =
|
|
10742
|
-
const [error, setError] =
|
|
10743
|
-
const [name, setName] =
|
|
10744
|
-
const [busy, setBusy] =
|
|
10745
|
-
const load =
|
|
11075
|
+
const [signatures, setSignatures] = useState39(null);
|
|
11076
|
+
const [verdicts, setVerdicts] = useState39({});
|
|
11077
|
+
const [error, setError] = useState39(null);
|
|
11078
|
+
const [name, setName] = useState39("");
|
|
11079
|
+
const [busy, setBusy] = useState39(false);
|
|
11080
|
+
const load = useCallback25(async () => {
|
|
10746
11081
|
const held = await client.docSignatures({ record_id: recordId });
|
|
10747
11082
|
if (!held.ok) {
|
|
10748
11083
|
setError(held.error);
|
|
@@ -10757,7 +11092,7 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10757
11092
|
}
|
|
10758
11093
|
setVerdicts(answers);
|
|
10759
11094
|
}, [client, recordId]);
|
|
10760
|
-
|
|
11095
|
+
useEffect29(() => {
|
|
10761
11096
|
void load();
|
|
10762
11097
|
}, [load]);
|
|
10763
11098
|
async function sign(field) {
|
|
@@ -10777,58 +11112,58 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10777
11112
|
setName("");
|
|
10778
11113
|
await load();
|
|
10779
11114
|
}
|
|
10780
|
-
if (fields.error) return /* @__PURE__ */
|
|
11115
|
+
if (fields.error) return /* @__PURE__ */ jsx43(RefusalNotice, { error: fields.error, className });
|
|
10781
11116
|
if (error) {
|
|
10782
|
-
return /* @__PURE__ */
|
|
11117
|
+
return /* @__PURE__ */ jsx43(
|
|
10783
11118
|
RefusalNotice,
|
|
10784
11119
|
{
|
|
10785
11120
|
error,
|
|
10786
11121
|
className,
|
|
10787
|
-
actions: /* @__PURE__ */
|
|
11122
|
+
actions: /* @__PURE__ */ jsx43(Button35, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10788
11123
|
}
|
|
10789
11124
|
);
|
|
10790
11125
|
}
|
|
10791
|
-
if (fields.loading || signatures === null) return /* @__PURE__ */
|
|
11126
|
+
if (fields.loading || signatures === null) return /* @__PURE__ */ jsx43(Skeleton22, { className: cn37("h-32 w-full", className) });
|
|
10792
11127
|
const signable = (fields.data ?? []).filter(isSignatureField);
|
|
10793
|
-
return /* @__PURE__ */
|
|
10794
|
-
/* @__PURE__ */
|
|
10795
|
-
/* @__PURE__ */
|
|
10796
|
-
/* @__PURE__ */
|
|
11128
|
+
return /* @__PURE__ */ jsxs39("div", { className: cn37("flex flex-col gap-2", className), children: [
|
|
11129
|
+
/* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
11130
|
+
/* @__PURE__ */ jsx43("span", { className: "font-medium text-foreground", children: "Signatures" }),
|
|
11131
|
+
/* @__PURE__ */ jsxs39("span", { children: [
|
|
10797
11132
|
signatures.length,
|
|
10798
11133
|
" on this record"
|
|
10799
11134
|
] })
|
|
10800
11135
|
] }),
|
|
10801
|
-
signatures.length > 0 ? /* @__PURE__ */
|
|
11136
|
+
signatures.length > 0 ? /* @__PURE__ */ jsx43("ul", { className: "flex flex-col gap-1", children: signatures.map((signature) => {
|
|
10802
11137
|
const verdict = verdicts[signature.id];
|
|
10803
11138
|
const intact = typeof verdict === "object" && verdict !== null ? verdict.intact : void 0;
|
|
10804
|
-
return /* @__PURE__ */
|
|
10805
|
-
/* @__PURE__ */
|
|
10806
|
-
/* @__PURE__ */
|
|
10807
|
-
/* @__PURE__ */
|
|
10808
|
-
/* @__PURE__ */
|
|
10809
|
-
/* @__PURE__ */
|
|
11139
|
+
return /* @__PURE__ */ jsxs39("li", { className: "rounded border px-2 py-1.5 text-xs", children: [
|
|
11140
|
+
/* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-2", children: [
|
|
11141
|
+
/* @__PURE__ */ jsx43("span", { className: "font-medium", children: signature.signer_name }),
|
|
11142
|
+
/* @__PURE__ */ jsx43("span", { className: "text-muted-foreground", children: signature.field_key }),
|
|
11143
|
+
/* @__PURE__ */ jsx43("span", { className: "text-muted-foreground", children: new Date(signature.signed_at).toLocaleString() }),
|
|
11144
|
+
/* @__PURE__ */ jsxs39("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground", children: [
|
|
10810
11145
|
"v",
|
|
10811
11146
|
signature.document_version,
|
|
10812
11147
|
" \xB7 ",
|
|
10813
11148
|
signature.document_hash.slice(0, 12)
|
|
10814
11149
|
] })
|
|
10815
11150
|
] }),
|
|
10816
|
-
/* @__PURE__ */
|
|
11151
|
+
/* @__PURE__ */ jsx43("p", { className: cn37("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 ?? "") })
|
|
10817
11152
|
] }, signature.id);
|
|
10818
11153
|
}) }) : null,
|
|
10819
|
-
!render ? /* @__PURE__ */
|
|
11154
|
+
!render ? /* @__PURE__ */ jsx43("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__ */ jsxs39("p", { className: "text-xs text-muted-foreground", children: [
|
|
10820
11155
|
"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 ",
|
|
10821
|
-
/* @__PURE__ */
|
|
11156
|
+
/* @__PURE__ */ jsx43("code", { children: "signature" }),
|
|
10822
11157
|
" \u2014 add one and the signing appears."
|
|
10823
|
-
] }) : !rights.write ? /* @__PURE__ */
|
|
11158
|
+
] }) : !rights.write ? /* @__PURE__ */ jsx43("p", { className: "text-xs text-muted-foreground", children: rights.why("write") }) : /* @__PURE__ */ jsx43("div", { className: "flex flex-col gap-1", children: signable.map((field) => {
|
|
10824
11159
|
const already = signatures.find((s) => s.field_key === field.key);
|
|
10825
11160
|
if (already) {
|
|
10826
|
-
return /* @__PURE__ */
|
|
11161
|
+
return /* @__PURE__ */ jsxs39("p", { className: "text-xs text-muted-foreground", children: [
|
|
10827
11162
|
fieldName(field),
|
|
10828
11163
|
" 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."
|
|
10829
11164
|
] }, field.id);
|
|
10830
11165
|
}
|
|
10831
|
-
return /* @__PURE__ */
|
|
11166
|
+
return /* @__PURE__ */ jsxs39(
|
|
10832
11167
|
"form",
|
|
10833
11168
|
{
|
|
10834
11169
|
className: "flex items-center gap-1",
|
|
@@ -10837,8 +11172,8 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10837
11172
|
if (name.trim() !== "") void sign(field);
|
|
10838
11173
|
},
|
|
10839
11174
|
children: [
|
|
10840
|
-
/* @__PURE__ */
|
|
10841
|
-
|
|
11175
|
+
/* @__PURE__ */ jsx43(
|
|
11176
|
+
BasicInput13,
|
|
10842
11177
|
{
|
|
10843
11178
|
className: "h-8 w-56 text-xs",
|
|
10844
11179
|
"aria-label": `Sign ${fieldName(field)}`,
|
|
@@ -10847,8 +11182,8 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10847
11182
|
onChange: (e) => setName(e.target.value)
|
|
10848
11183
|
}
|
|
10849
11184
|
),
|
|
10850
|
-
/* @__PURE__ */
|
|
10851
|
-
/* @__PURE__ */
|
|
11185
|
+
/* @__PURE__ */ jsx43(Button35, { size: "sm", type: "submit", disabled: busy || name.trim() === "", children: "Sign" }),
|
|
11186
|
+
/* @__PURE__ */ jsxs39("span", { className: "text-xs text-muted-foreground", children: [
|
|
10852
11187
|
"seals version ",
|
|
10853
11188
|
render.template_version,
|
|
10854
11189
|
" \xB7 ",
|
|
@@ -10864,32 +11199,32 @@ function SignBlock({ tableId, recordId, render, className }) {
|
|
|
10864
11199
|
}
|
|
10865
11200
|
|
|
10866
11201
|
// src/NotifyRuleEditor.tsx
|
|
10867
|
-
import { useCallback as
|
|
10868
|
-
import { useRecordsClient as
|
|
10869
|
-
import { Button as
|
|
10870
|
-
import { jsx as
|
|
10871
|
-
var
|
|
11202
|
+
import { useCallback as useCallback26, useEffect as useEffect30, useState as useState40 } from "react";
|
|
11203
|
+
import { useRecordsClient as useRecordsClient32, useTable as useTable16 } from "@ai-matrx/records/react";
|
|
11204
|
+
import { Button as Button36, Skeleton as Skeleton23, cn as cn38 } from "@ai-matrx/design-system";
|
|
11205
|
+
import { jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
11206
|
+
var CADENCE_WORDS2 = {
|
|
10872
11207
|
instant: "as it happens",
|
|
10873
11208
|
hourly: "hourly summary",
|
|
10874
11209
|
daily: "daily summary",
|
|
10875
11210
|
weekly: "weekly summary"
|
|
10876
11211
|
};
|
|
10877
|
-
var
|
|
11212
|
+
var CHANNEL_WORDS3 = {
|
|
10878
11213
|
in_app: "in the app",
|
|
10879
11214
|
email: "by email",
|
|
10880
11215
|
sms: "by text"
|
|
10881
11216
|
};
|
|
10882
11217
|
function NotifyRuleEditor({ tableId, seed, className }) {
|
|
10883
|
-
const client =
|
|
11218
|
+
const client = useRecordsClient32();
|
|
10884
11219
|
const host = useRecordsUi();
|
|
10885
11220
|
const table = useTable16(tableId);
|
|
10886
11221
|
const rights = useTableRights(table.data);
|
|
10887
|
-
const [subscriptions, setSubscriptions] =
|
|
10888
|
-
const [cadences, setCadences] =
|
|
10889
|
-
const [views, setViews] =
|
|
10890
|
-
const [error, setError] =
|
|
10891
|
-
const [busy, setBusy] =
|
|
10892
|
-
const load =
|
|
11222
|
+
const [subscriptions, setSubscriptions] = useState40(null);
|
|
11223
|
+
const [cadences, setCadences] = useState40([]);
|
|
11224
|
+
const [views, setViews] = useState40(null);
|
|
11225
|
+
const [error, setError] = useState40(null);
|
|
11226
|
+
const [busy, setBusy] = useState40(false);
|
|
11227
|
+
const load = useCallback26(async () => {
|
|
10893
11228
|
const [held, offered] = await Promise.all([
|
|
10894
11229
|
// THE PERSON'S OWN DOOR, not the notifier's. It answers what is addressed
|
|
10895
11230
|
// to them plus — only where they hold admin on this Table — anyone's over
|
|
@@ -10909,10 +11244,10 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
10909
11244
|
if (host.savedViews) setViews(await host.savedViews());
|
|
10910
11245
|
else setViews(null);
|
|
10911
11246
|
}, [client, host, tableId]);
|
|
10912
|
-
|
|
11247
|
+
useEffect30(() => {
|
|
10913
11248
|
void load();
|
|
10914
11249
|
}, [load]);
|
|
10915
|
-
const write =
|
|
11250
|
+
const write = useCallback26(
|
|
10916
11251
|
async (spec) => {
|
|
10917
11252
|
const declared = await client.subscriptionDeclare({
|
|
10918
11253
|
table_id: tableId,
|
|
@@ -10937,7 +11272,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
10937
11272
|
},
|
|
10938
11273
|
[client, tableId]
|
|
10939
11274
|
);
|
|
10940
|
-
|
|
11275
|
+
useEffect30(() => {
|
|
10941
11276
|
if (!subscriptions || !seed || seed.length === 0) return;
|
|
10942
11277
|
const missing = seed.filter((s) => !subscriptions.some((held) => held.name === s.name));
|
|
10943
11278
|
if (missing.length === 0) return;
|
|
@@ -10951,7 +11286,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
10951
11286
|
async function subscribe(viewId, viewName, cadence, channel, schedule, quiet) {
|
|
10952
11287
|
setBusy(true);
|
|
10953
11288
|
const ok = await write({
|
|
10954
|
-
name: `${viewName} \u2014 ${
|
|
11289
|
+
name: `${viewName} \u2014 ${CADENCE_WORDS2[cadence] ?? cadence}`,
|
|
10955
11290
|
savedViewId: viewId,
|
|
10956
11291
|
cadence,
|
|
10957
11292
|
channel,
|
|
@@ -10972,45 +11307,45 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
10972
11307
|
await load();
|
|
10973
11308
|
}
|
|
10974
11309
|
if (error) {
|
|
10975
|
-
return /* @__PURE__ */
|
|
11310
|
+
return /* @__PURE__ */ jsx44(
|
|
10976
11311
|
RefusalNotice,
|
|
10977
11312
|
{
|
|
10978
11313
|
error,
|
|
10979
11314
|
className,
|
|
10980
|
-
actions: /* @__PURE__ */
|
|
11315
|
+
actions: /* @__PURE__ */ jsx44(Button36, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
10981
11316
|
}
|
|
10982
11317
|
);
|
|
10983
11318
|
}
|
|
10984
|
-
if (subscriptions === null) return /* @__PURE__ */
|
|
10985
|
-
return /* @__PURE__ */
|
|
10986
|
-
/* @__PURE__ */
|
|
10987
|
-
/* @__PURE__ */
|
|
10988
|
-
/* @__PURE__ */
|
|
11319
|
+
if (subscriptions === null) return /* @__PURE__ */ jsx44(Skeleton23, { className: cn38("h-40 w-full", className) });
|
|
11320
|
+
return /* @__PURE__ */ jsxs40("div", { className: cn38("flex flex-col gap-2", className), children: [
|
|
11321
|
+
/* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
11322
|
+
/* @__PURE__ */ jsx44("span", { className: "font-medium text-foreground", children: "Tell me when" }),
|
|
11323
|
+
/* @__PURE__ */ jsxs40("span", { children: [
|
|
10989
11324
|
subscriptions.length,
|
|
10990
11325
|
" subscription",
|
|
10991
11326
|
subscriptions.length === 1 ? "" : "s"
|
|
10992
11327
|
] })
|
|
10993
11328
|
] }),
|
|
10994
|
-
subscriptions.length === 0 ? /* @__PURE__ */
|
|
10995
|
-
/* @__PURE__ */
|
|
10996
|
-
/* @__PURE__ */
|
|
10997
|
-
/* @__PURE__ */
|
|
10998
|
-
held.schedule ? /* @__PURE__ */
|
|
10999
|
-
held.next_digest_at ? /* @__PURE__ */
|
|
11329
|
+
subscriptions.length === 0 ? /* @__PURE__ */ jsx44("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__ */ jsx44("ul", { className: "flex flex-col gap-1", children: subscriptions.map((held) => /* @__PURE__ */ jsxs40("li", { className: "flex items-center gap-2 rounded border px-2 py-1.5 text-xs", children: [
|
|
11330
|
+
/* @__PURE__ */ jsx44("span", { className: "truncate font-medium", children: held.name }),
|
|
11331
|
+
/* @__PURE__ */ jsx44("span", { className: "text-muted-foreground", children: CADENCE_WORDS2[held.cadence] ?? held.cadence }),
|
|
11332
|
+
/* @__PURE__ */ jsx44("span", { className: "text-muted-foreground", children: CHANNEL_WORDS3[held.channel] ?? held.channel }),
|
|
11333
|
+
held.schedule ? /* @__PURE__ */ jsx44("span", { className: "text-muted-foreground", children: held.schedule }) : null,
|
|
11334
|
+
held.next_digest_at ? /* @__PURE__ */ jsxs40("span", { className: "text-muted-foreground", children: [
|
|
11000
11335
|
"next ",
|
|
11001
11336
|
new Date(held.next_digest_at).toLocaleString()
|
|
11002
11337
|
] }) : null,
|
|
11003
|
-
held.quiet_hours ? /* @__PURE__ */
|
|
11338
|
+
held.quiet_hours ? /* @__PURE__ */ jsxs40("span", { className: "text-muted-foreground", children: [
|
|
11004
11339
|
"quiet ",
|
|
11005
11340
|
held.quiet_hours.start,
|
|
11006
11341
|
"\u2013",
|
|
11007
11342
|
held.quiet_hours.end
|
|
11008
11343
|
] }) : null,
|
|
11009
|
-
held.recipient_user_id === null ? /* @__PURE__ */
|
|
11010
|
-
held.saved_view_id === null ? /* @__PURE__ */
|
|
11011
|
-
held.muted ? /* @__PURE__ */
|
|
11012
|
-
rights.write ? /* @__PURE__ */
|
|
11013
|
-
|
|
11344
|
+
held.recipient_user_id === null ? /* @__PURE__ */ jsx44("span", { className: "text-destructive", children: "This one has nobody to tell, so it fires at nobody." }) : null,
|
|
11345
|
+
held.saved_view_id === null ? /* @__PURE__ */ jsx44("span", { className: "text-destructive", children: "This one names no view, so the store never admits a record to it." }) : null,
|
|
11346
|
+
held.muted ? /* @__PURE__ */ jsx44("span", { className: "text-muted-foreground", children: "Switched off \u2014 it tells nobody until somebody switches it back on." }) : null,
|
|
11347
|
+
rights.write ? /* @__PURE__ */ jsx44(
|
|
11348
|
+
Button36,
|
|
11014
11349
|
{
|
|
11015
11350
|
size: "sm",
|
|
11016
11351
|
variant: "ghost",
|
|
@@ -11021,7 +11356,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11021
11356
|
}
|
|
11022
11357
|
) : null
|
|
11023
11358
|
] }, held.rule_id)) }),
|
|
11024
|
-
views === null ? /* @__PURE__ */
|
|
11359
|
+
views === null ? /* @__PURE__ */ jsx44("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_SAVED_VIEWS_REASON }) : views.length === 0 ? /* @__PURE__ */ jsx44("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__ */ jsxs40(
|
|
11025
11360
|
"form",
|
|
11026
11361
|
{
|
|
11027
11362
|
className: "flex flex-wrap items-center gap-1",
|
|
@@ -11039,10 +11374,10 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11039
11374
|
if (view) void subscribe(view, name, cadence, channel, schedule, quiet);
|
|
11040
11375
|
},
|
|
11041
11376
|
children: [
|
|
11042
|
-
/* @__PURE__ */
|
|
11043
|
-
/* @__PURE__ */
|
|
11044
|
-
/* @__PURE__ */
|
|
11045
|
-
/* @__PURE__ */
|
|
11377
|
+
/* @__PURE__ */ jsx44("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__ */ jsx44("option", { value: view.id, children: view.name }, view.id)) }),
|
|
11378
|
+
/* @__PURE__ */ jsx44("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__ */ jsx44("option", { value: cadence, children: CADENCE_WORDS2[cadence] ?? cadence }, cadence)) }),
|
|
11379
|
+
/* @__PURE__ */ jsx44("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__ */ jsx44("option", { value: channel, children: CHANNEL_WORDS3[channel] }, channel)) }),
|
|
11380
|
+
/* @__PURE__ */ jsx44(
|
|
11046
11381
|
"input",
|
|
11047
11382
|
{
|
|
11048
11383
|
name: "schedule",
|
|
@@ -11051,8 +11386,8 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11051
11386
|
className: "h-7 w-28 rounded border bg-background px-1 text-xs"
|
|
11052
11387
|
}
|
|
11053
11388
|
),
|
|
11054
|
-
/* @__PURE__ */
|
|
11055
|
-
/* @__PURE__ */
|
|
11389
|
+
/* @__PURE__ */ jsx44("span", { className: "text-xs text-muted-foreground", children: "not between" }),
|
|
11390
|
+
/* @__PURE__ */ jsx44(
|
|
11056
11391
|
"input",
|
|
11057
11392
|
{
|
|
11058
11393
|
name: "quiet_start",
|
|
@@ -11061,8 +11396,8 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11061
11396
|
className: "h-7 rounded border bg-background px-1 text-xs"
|
|
11062
11397
|
}
|
|
11063
11398
|
),
|
|
11064
|
-
/* @__PURE__ */
|
|
11065
|
-
/* @__PURE__ */
|
|
11399
|
+
/* @__PURE__ */ jsx44("span", { className: "text-xs text-muted-foreground", children: "and" }),
|
|
11400
|
+
/* @__PURE__ */ jsx44(
|
|
11066
11401
|
"input",
|
|
11067
11402
|
{
|
|
11068
11403
|
name: "quiet_end",
|
|
@@ -11071,16 +11406,16 @@ function NotifyRuleEditor({ tableId, seed, className }) {
|
|
|
11071
11406
|
className: "h-7 rounded border bg-background px-1 text-xs"
|
|
11072
11407
|
}
|
|
11073
11408
|
),
|
|
11074
|
-
/* @__PURE__ */
|
|
11075
|
-
/* @__PURE__ */
|
|
11409
|
+
/* @__PURE__ */ jsx44(Button36, { size: "sm", type: "submit", disabled: busy, children: "Tell me" }),
|
|
11410
|
+
/* @__PURE__ */ jsx44("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." })
|
|
11076
11411
|
]
|
|
11077
11412
|
}
|
|
11078
|
-
) : /* @__PURE__ */
|
|
11413
|
+
) : /* @__PURE__ */ jsx44("p", { className: "text-xs text-muted-foreground", children: rights.why("write") })
|
|
11079
11414
|
] });
|
|
11080
11415
|
}
|
|
11081
11416
|
|
|
11082
11417
|
// src/ChartBlock.tsx
|
|
11083
|
-
import { useMemo as
|
|
11418
|
+
import { useMemo as useMemo26 } from "react";
|
|
11084
11419
|
import {
|
|
11085
11420
|
Bar,
|
|
11086
11421
|
BarChart,
|
|
@@ -11099,8 +11434,8 @@ import {
|
|
|
11099
11434
|
measureKey
|
|
11100
11435
|
} from "@ai-matrx/records";
|
|
11101
11436
|
import { mapPgError } from "@ai-matrx/records/core";
|
|
11102
|
-
import { cn as
|
|
11103
|
-
import { Fragment as
|
|
11437
|
+
import { cn as cn39 } from "@ai-matrx/design-system";
|
|
11438
|
+
import { Fragment as Fragment19, jsx as jsx45, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
11104
11439
|
function pretty(n) {
|
|
11105
11440
|
return Number.isInteger(n) ? n.toLocaleString() : n.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
11106
11441
|
}
|
|
@@ -11120,7 +11455,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11120
11455
|
const measures = block.measures && block.measures.length > 0 ? block.measures : [{ op: "count" }];
|
|
11121
11456
|
const primary = measureKey(measures[0]);
|
|
11122
11457
|
const series = [primary];
|
|
11123
|
-
const points =
|
|
11458
|
+
const points = useMemo26(() => {
|
|
11124
11459
|
if (kind === "stuck") return [];
|
|
11125
11460
|
const rows = block.rows ?? [];
|
|
11126
11461
|
return rows.map((row) => ({
|
|
@@ -11132,7 +11467,7 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11132
11467
|
n: row.row_count
|
|
11133
11468
|
}));
|
|
11134
11469
|
}, [block.rows, kind, series.join("|")]);
|
|
11135
|
-
const config =
|
|
11470
|
+
const config = useMemo26(() => {
|
|
11136
11471
|
const out = {};
|
|
11137
11472
|
series.forEach((key, index) => {
|
|
11138
11473
|
out[key] = {
|
|
@@ -11156,18 +11491,18 @@ function ChartBlock({ block, subject, className }) {
|
|
|
11156
11491
|
label: point.label === "All records" ? block.title : `${block.title} \xB7 ${point.label}`
|
|
11157
11492
|
});
|
|
11158
11493
|
} : null;
|
|
11159
|
-
return /* @__PURE__ */
|
|
11160
|
-
/* @__PURE__ */
|
|
11161
|
-
/* @__PURE__ */
|
|
11162
|
-
/* @__PURE__ */
|
|
11163
|
-
typeof block.ms === "number" ? /* @__PURE__ */
|
|
11494
|
+
return /* @__PURE__ */ jsxs41("figure", { className: cn39("flex min-w-0 flex-col gap-1.5 rounded border p-2", className), children: [
|
|
11495
|
+
/* @__PURE__ */ jsxs41("figcaption", { className: "flex items-baseline gap-2 text-xs", children: [
|
|
11496
|
+
/* @__PURE__ */ jsx45("span", { className: "truncate font-medium", children: block.title || CHART_KIND_LABEL[kind] }),
|
|
11497
|
+
/* @__PURE__ */ jsx45("span", { className: "ml-auto shrink-0 text-muted-foreground", children: kind === "stuck" ? `${block.days ?? 14} days` : primary.replace("_", " of ") }),
|
|
11498
|
+
typeof block.ms === "number" ? /* @__PURE__ */ jsxs41("span", { className: "shrink-0 tabular-nums text-muted-foreground/70", title: "how long the store took", children: [
|
|
11164
11499
|
pretty(block.ms),
|
|
11165
11500
|
" ms"
|
|
11166
11501
|
] }) : null
|
|
11167
11502
|
] }),
|
|
11168
|
-
block.refused ? /* @__PURE__ */
|
|
11169
|
-
/* @__PURE__ */
|
|
11170
|
-
/* @__PURE__ */
|
|
11503
|
+
block.refused ? /* @__PURE__ */ jsx45(RefusalNotice, { error: asRefusal(block) }) : needs ? /* @__PURE__ */ jsx45("p", { className: "px-1 py-3 text-xs text-muted-foreground", children: needs }) : kind === "stuck" ? /* @__PURE__ */ jsx45(StuckList, { rows: block.rows ?? [] }) : points.length === 0 ? /* @__PURE__ */ jsx45("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__ */ jsx45(Fragment19, { children: kind === "number" ? /* @__PURE__ */ jsx45(BigNumber, { points, measure: primary, onDrill: drill }) : kind === "table" ? /* @__PURE__ */ jsx45(GroupTable, { points, series, onDrill: drill }) : /* @__PURE__ */ jsxs41(Fragment19, { children: [
|
|
11504
|
+
/* @__PURE__ */ jsx45(Drawing, { kind, points, series, config, onDrill: drill }),
|
|
11505
|
+
/* @__PURE__ */ jsx45(Values, { points, measure: primary, config, onDrill: drill })
|
|
11171
11506
|
] }) })
|
|
11172
11507
|
] });
|
|
11173
11508
|
}
|
|
@@ -11178,16 +11513,16 @@ function BigNumber({
|
|
|
11178
11513
|
}) {
|
|
11179
11514
|
const total = points.reduce((sum, p) => sum + (p.values[measure] ?? 0), 0);
|
|
11180
11515
|
const records = points.reduce((sum, p) => sum + p.n, 0);
|
|
11181
|
-
const body = /* @__PURE__ */
|
|
11182
|
-
/* @__PURE__ */
|
|
11183
|
-
/* @__PURE__ */
|
|
11516
|
+
const body = /* @__PURE__ */ jsxs41(Fragment19, { children: [
|
|
11517
|
+
/* @__PURE__ */ jsx45("span", { className: "text-2xl font-semibold tabular-nums", children: pretty(total) }),
|
|
11518
|
+
/* @__PURE__ */ jsxs41("span", { className: "text-xs text-muted-foreground", children: [
|
|
11184
11519
|
"from ",
|
|
11185
11520
|
records.toLocaleString(),
|
|
11186
11521
|
" records"
|
|
11187
11522
|
] })
|
|
11188
11523
|
] });
|
|
11189
|
-
if (!onDrill || !points[0]) return /* @__PURE__ */
|
|
11190
|
-
return /* @__PURE__ */
|
|
11524
|
+
if (!onDrill || !points[0]) return /* @__PURE__ */ jsx45("div", { className: "flex items-baseline gap-2 px-1 py-2", children: body });
|
|
11525
|
+
return /* @__PURE__ */ jsx45(
|
|
11191
11526
|
"button",
|
|
11192
11527
|
{
|
|
11193
11528
|
type: "button",
|
|
@@ -11203,19 +11538,19 @@ function Values({
|
|
|
11203
11538
|
config,
|
|
11204
11539
|
onDrill
|
|
11205
11540
|
}) {
|
|
11206
|
-
return /* @__PURE__ */
|
|
11207
|
-
const text = /* @__PURE__ */
|
|
11208
|
-
/* @__PURE__ */
|
|
11541
|
+
return /* @__PURE__ */ jsx45("ul", { className: "flex flex-wrap gap-x-2 gap-y-0.5", children: points.map((point) => {
|
|
11542
|
+
const text = /* @__PURE__ */ jsxs41(Fragment19, { children: [
|
|
11543
|
+
/* @__PURE__ */ jsx45(
|
|
11209
11544
|
"span",
|
|
11210
11545
|
{
|
|
11211
11546
|
className: "h-2 w-2 shrink-0 rounded-[2px]",
|
|
11212
11547
|
style: { background: String(config[point.label]?.color ?? SERIES_COLORS[0]) }
|
|
11213
11548
|
}
|
|
11214
11549
|
),
|
|
11215
|
-
/* @__PURE__ */
|
|
11216
|
-
/* @__PURE__ */
|
|
11550
|
+
/* @__PURE__ */ jsx45("span", { className: "truncate", children: point.label }),
|
|
11551
|
+
/* @__PURE__ */ jsx45("span", { className: "tabular-nums text-muted-foreground", children: pretty(point.values[measure] ?? 0) })
|
|
11217
11552
|
] });
|
|
11218
|
-
return /* @__PURE__ */
|
|
11553
|
+
return /* @__PURE__ */ jsx45("li", { className: "min-w-0", children: onDrill ? /* @__PURE__ */ jsx45(
|
|
11219
11554
|
"button",
|
|
11220
11555
|
{
|
|
11221
11556
|
type: "button",
|
|
@@ -11223,7 +11558,7 @@ function Values({
|
|
|
11223
11558
|
onClick: () => onDrill(point),
|
|
11224
11559
|
children: text
|
|
11225
11560
|
}
|
|
11226
|
-
) : /* @__PURE__ */
|
|
11561
|
+
) : /* @__PURE__ */ jsx45("span", { className: "flex min-w-0 items-center gap-1.5 px-1 py-0.5 text-xs", children: text }) }, point.label);
|
|
11227
11562
|
}) });
|
|
11228
11563
|
}
|
|
11229
11564
|
function GroupTable({
|
|
@@ -11231,8 +11566,8 @@ function GroupTable({
|
|
|
11231
11566
|
series,
|
|
11232
11567
|
onDrill
|
|
11233
11568
|
}) {
|
|
11234
|
-
return /* @__PURE__ */
|
|
11235
|
-
/* @__PURE__ */
|
|
11569
|
+
return /* @__PURE__ */ jsx45("table", { className: "w-full text-xs", children: /* @__PURE__ */ jsx45("tbody", { children: points.map((point) => /* @__PURE__ */ jsxs41("tr", { className: "border-t first:border-t-0", children: [
|
|
11570
|
+
/* @__PURE__ */ jsx45("td", { className: "min-w-0 truncate py-0.5 pr-2", children: onDrill ? /* @__PURE__ */ jsx45(
|
|
11236
11571
|
"button",
|
|
11237
11572
|
{
|
|
11238
11573
|
type: "button",
|
|
@@ -11241,29 +11576,29 @@ function GroupTable({
|
|
|
11241
11576
|
children: point.label
|
|
11242
11577
|
}
|
|
11243
11578
|
) : point.label }),
|
|
11244
|
-
series.map((key) => /* @__PURE__ */
|
|
11245
|
-
/* @__PURE__ */
|
|
11579
|
+
series.map((key) => /* @__PURE__ */ jsx45("td", { className: "py-0.5 pl-2 text-right tabular-nums", children: pretty(point.values[key] ?? 0) }, key)),
|
|
11580
|
+
/* @__PURE__ */ jsx45("td", { className: "py-0.5 pl-2 text-right tabular-nums text-muted-foreground", children: point.n })
|
|
11246
11581
|
] }, point.label)) }) });
|
|
11247
11582
|
}
|
|
11248
11583
|
function StuckList({ rows }) {
|
|
11249
11584
|
if (rows.length === 0) {
|
|
11250
|
-
return /* @__PURE__ */
|
|
11585
|
+
return /* @__PURE__ */ jsx45("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." });
|
|
11251
11586
|
}
|
|
11252
|
-
return /* @__PURE__ */
|
|
11253
|
-
/* @__PURE__ */
|
|
11254
|
-
/* @__PURE__ */
|
|
11255
|
-
/* @__PURE__ */
|
|
11256
|
-
/* @__PURE__ */
|
|
11587
|
+
return /* @__PURE__ */ jsxs41("table", { className: "w-full table-fixed text-xs", children: [
|
|
11588
|
+
/* @__PURE__ */ jsxs41("colgroup", { children: [
|
|
11589
|
+
/* @__PURE__ */ jsx45("col", { className: "w-[45%]" }),
|
|
11590
|
+
/* @__PURE__ */ jsx45("col", { className: "w-[33%]" }),
|
|
11591
|
+
/* @__PURE__ */ jsx45("col", { className: "w-[22%]" })
|
|
11257
11592
|
] }),
|
|
11258
|
-
/* @__PURE__ */
|
|
11259
|
-
/* @__PURE__ */
|
|
11260
|
-
/* @__PURE__ */
|
|
11261
|
-
/* @__PURE__ */
|
|
11593
|
+
/* @__PURE__ */ jsx45("thead", { className: "sr-only", children: /* @__PURE__ */ jsxs41("tr", { children: [
|
|
11594
|
+
/* @__PURE__ */ jsx45("th", { children: "Record" }),
|
|
11595
|
+
/* @__PURE__ */ jsx45("th", { children: "Where it is" }),
|
|
11596
|
+
/* @__PURE__ */ jsx45("th", { children: "Days unchanged" })
|
|
11262
11597
|
] }) }),
|
|
11263
|
-
/* @__PURE__ */
|
|
11264
|
-
/* @__PURE__ */
|
|
11265
|
-
/* @__PURE__ */
|
|
11266
|
-
/* @__PURE__ */
|
|
11598
|
+
/* @__PURE__ */ jsx45("tbody", { children: rows.map((row) => /* @__PURE__ */ jsxs41("tr", { className: "border-t first:border-t-0", children: [
|
|
11599
|
+
/* @__PURE__ */ jsx45("td", { className: "truncate py-0.5 pr-2", title: row.title ?? void 0, children: row.title ?? row.record_id.slice(0, 8) }),
|
|
11600
|
+
/* @__PURE__ */ jsx45("td", { className: "truncate py-0.5 pr-2 text-muted-foreground", title: row.state ?? void 0, children: row.state ?? "\u2014" }),
|
|
11601
|
+
/* @__PURE__ */ jsxs41(
|
|
11267
11602
|
"td",
|
|
11268
11603
|
{
|
|
11269
11604
|
className: "whitespace-nowrap py-0.5 text-right tabular-nums",
|
|
@@ -11313,12 +11648,12 @@ function Drawing({
|
|
|
11313
11648
|
axisLine: false,
|
|
11314
11649
|
tickFormatter: compactTick
|
|
11315
11650
|
};
|
|
11316
|
-
const tooltip = /* @__PURE__ */
|
|
11317
|
-
const legend = series.length > 1 ? /* @__PURE__ */
|
|
11651
|
+
const tooltip = /* @__PURE__ */ jsx45(Tooltip, { content: /* @__PURE__ */ jsx45(ChartTooltipContent, { config }), cursor: false });
|
|
11652
|
+
const legend = series.length > 1 ? /* @__PURE__ */ jsx45(Legend, { content: /* @__PURE__ */ jsx45(ChartLegendContent, { config }) }) : null;
|
|
11318
11653
|
if (kind === "donut") {
|
|
11319
|
-
return /* @__PURE__ */
|
|
11654
|
+
return /* @__PURE__ */ jsx45(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ jsxs41(PieChart, { width, height: HEIGHT, children: [
|
|
11320
11655
|
tooltip,
|
|
11321
|
-
/* @__PURE__ */
|
|
11656
|
+
/* @__PURE__ */ jsx45(
|
|
11322
11657
|
Pie,
|
|
11323
11658
|
{
|
|
11324
11659
|
data,
|
|
@@ -11328,19 +11663,19 @@ function Drawing({
|
|
|
11328
11663
|
outerRadius: 58,
|
|
11329
11664
|
isAnimationActive: false,
|
|
11330
11665
|
...click ? { onClick: click, className: "cursor-pointer" } : {},
|
|
11331
|
-
children: points.map((point) => /* @__PURE__ */
|
|
11666
|
+
children: points.map((point) => /* @__PURE__ */ jsx45(Cell, { fill: String(config[point.label]?.color ?? SERIES_COLORS[0]) }, point.label))
|
|
11332
11667
|
}
|
|
11333
11668
|
)
|
|
11334
11669
|
] }) });
|
|
11335
11670
|
}
|
|
11336
11671
|
if (kind === "line") {
|
|
11337
|
-
return /* @__PURE__ */
|
|
11338
|
-
/* @__PURE__ */
|
|
11339
|
-
/* @__PURE__ */
|
|
11340
|
-
/* @__PURE__ */
|
|
11672
|
+
return /* @__PURE__ */ jsx45(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ jsxs41(LineChart, { width, height: HEIGHT, data, margin: { top: 6, right: 6, bottom: 0, left: 0 }, children: [
|
|
11673
|
+
/* @__PURE__ */ jsx45(CartesianGrid, { vertical: false }),
|
|
11674
|
+
/* @__PURE__ */ jsx45(XAxis, { dataKey: "label", ...axis }),
|
|
11675
|
+
/* @__PURE__ */ jsx45(YAxis, { width: 44, ...axis }),
|
|
11341
11676
|
tooltip,
|
|
11342
11677
|
legend,
|
|
11343
|
-
series.map((key) => /* @__PURE__ */
|
|
11678
|
+
series.map((key) => /* @__PURE__ */ jsx45(
|
|
11344
11679
|
Line2,
|
|
11345
11680
|
{
|
|
11346
11681
|
type: "monotone",
|
|
@@ -11356,7 +11691,7 @@ function Drawing({
|
|
|
11356
11691
|
] }) });
|
|
11357
11692
|
}
|
|
11358
11693
|
const horizontal = kind === "bar";
|
|
11359
|
-
return /* @__PURE__ */
|
|
11694
|
+
return /* @__PURE__ */ jsx45(ChartFrame, { config, height: HEIGHT, children: (width) => /* @__PURE__ */ jsxs41(
|
|
11360
11695
|
BarChart,
|
|
11361
11696
|
{
|
|
11362
11697
|
width,
|
|
@@ -11365,17 +11700,17 @@ function Drawing({
|
|
|
11365
11700
|
layout: horizontal ? "vertical" : "horizontal",
|
|
11366
11701
|
margin: { top: 6, right: 6, bottom: 0, left: 0 },
|
|
11367
11702
|
children: [
|
|
11368
|
-
/* @__PURE__ */
|
|
11369
|
-
horizontal ? /* @__PURE__ */
|
|
11370
|
-
/* @__PURE__ */
|
|
11371
|
-
/* @__PURE__ */
|
|
11372
|
-
] }) : /* @__PURE__ */
|
|
11373
|
-
/* @__PURE__ */
|
|
11374
|
-
/* @__PURE__ */
|
|
11703
|
+
/* @__PURE__ */ jsx45(CartesianGrid, { vertical: horizontal, horizontal: !horizontal }),
|
|
11704
|
+
horizontal ? /* @__PURE__ */ jsxs41(Fragment19, { children: [
|
|
11705
|
+
/* @__PURE__ */ jsx45(XAxis, { type: "number", ...axis }),
|
|
11706
|
+
/* @__PURE__ */ jsx45(YAxis, { type: "category", dataKey: "label", width: 88, ...axis })
|
|
11707
|
+
] }) : /* @__PURE__ */ jsxs41(Fragment19, { children: [
|
|
11708
|
+
/* @__PURE__ */ jsx45(XAxis, { dataKey: "label", ...axis }),
|
|
11709
|
+
/* @__PURE__ */ jsx45(YAxis, { width: 44, ...axis })
|
|
11375
11710
|
] }),
|
|
11376
11711
|
tooltip,
|
|
11377
11712
|
legend,
|
|
11378
|
-
series.map((key, index) => /* @__PURE__ */
|
|
11713
|
+
series.map((key, index) => /* @__PURE__ */ jsx45(
|
|
11379
11714
|
Bar,
|
|
11380
11715
|
{
|
|
11381
11716
|
dataKey: key,
|
|
@@ -11383,7 +11718,7 @@ function Drawing({
|
|
|
11383
11718
|
isAnimationActive: false,
|
|
11384
11719
|
fill: `var(--color-${key})`,
|
|
11385
11720
|
...click ? { onClick: click, className: "cursor-pointer" } : {},
|
|
11386
|
-
children: series.length === 1 ? points.map((point) => /* @__PURE__ */
|
|
11721
|
+
children: series.length === 1 ? points.map((point) => /* @__PURE__ */ jsx45(Cell, { fill: String(config[point.label]?.color ?? SERIES_COLORS[index]) }, point.label)) : null
|
|
11387
11722
|
},
|
|
11388
11723
|
key
|
|
11389
11724
|
))
|
|
@@ -11393,24 +11728,25 @@ function Drawing({
|
|
|
11393
11728
|
}
|
|
11394
11729
|
|
|
11395
11730
|
// src/DashboardCanvas.tsx
|
|
11396
|
-
import { useCallback as
|
|
11397
|
-
import { useFields as useFields19, useRecordsClient as
|
|
11398
|
-
import { BasicInput as
|
|
11399
|
-
import { Fragment as
|
|
11731
|
+
import { useCallback as useCallback27, useEffect as useEffect31, useMemo as useMemo27, useState as useState41 } from "react";
|
|
11732
|
+
import { useFields as useFields19, useRecordsClient as useRecordsClient33, useTable as useTable17 } from "@ai-matrx/records/react";
|
|
11733
|
+
import { BasicInput as BasicInput14, Button as Button37, Skeleton as Skeleton24, cn as cn40 } from "@ai-matrx/design-system";
|
|
11734
|
+
import { Fragment as Fragment20, jsx as jsx46, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
11400
11735
|
function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
11401
|
-
const client =
|
|
11736
|
+
const client = useRecordsClient33();
|
|
11402
11737
|
const host = useRecordsUi();
|
|
11403
11738
|
const table = useTable17(tableId);
|
|
11404
11739
|
const rights = useTableRights(table.data);
|
|
11405
11740
|
const fields = useFields19(tableId);
|
|
11406
|
-
const [boards, setBoards] =
|
|
11407
|
-
const [error, setError] =
|
|
11408
|
-
const [activeId, setActiveId] =
|
|
11409
|
-
const [run, setRun] =
|
|
11410
|
-
const [running, setRunning] =
|
|
11411
|
-
const [question, setQuestion] =
|
|
11412
|
-
const [asking, setAsking] =
|
|
11413
|
-
const
|
|
11741
|
+
const [boards, setBoards] = useState41(null);
|
|
11742
|
+
const [error, setError] = useState41(null);
|
|
11743
|
+
const [activeId, setActiveId] = useState41(activeDashboardId ?? null);
|
|
11744
|
+
const [run, setRun] = useState41(null);
|
|
11745
|
+
const [running, setRunning] = useState41(false);
|
|
11746
|
+
const [question, setQuestion] = useState41("");
|
|
11747
|
+
const [asking, setAsking] = useState41(false);
|
|
11748
|
+
const [scheduling, setScheduling] = useState41(false);
|
|
11749
|
+
const load = useCallback27(async () => {
|
|
11414
11750
|
const answered = await client.dashboards({ table_id: tableId });
|
|
11415
11751
|
if (!answered.ok) {
|
|
11416
11752
|
setError(answered.error);
|
|
@@ -11419,17 +11755,17 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11419
11755
|
setError(null);
|
|
11420
11756
|
setBoards(answered.data.map(dashboardFromSummary));
|
|
11421
11757
|
}, [client, tableId]);
|
|
11422
|
-
|
|
11758
|
+
useEffect31(() => {
|
|
11423
11759
|
void load();
|
|
11424
11760
|
}, [load]);
|
|
11425
|
-
|
|
11761
|
+
useEffect31(() => {
|
|
11426
11762
|
if (!boards || boards.length === 0) return;
|
|
11427
11763
|
const chosen = boards.find((d) => d.id === (activeDashboardId ?? activeId)) ?? boards[0];
|
|
11428
11764
|
if (chosen.id !== activeId) setActiveId(chosen.id);
|
|
11429
11765
|
}, [boards, activeDashboardId]);
|
|
11430
|
-
const board =
|
|
11766
|
+
const board = useMemo27(() => boards?.find((d) => d.id === activeId) ?? null, [boards, activeId]);
|
|
11431
11767
|
const filterKey = JSON.stringify(filter ?? {});
|
|
11432
|
-
|
|
11768
|
+
useEffect31(() => {
|
|
11433
11769
|
if (!activeId) {
|
|
11434
11770
|
setRun(null);
|
|
11435
11771
|
return;
|
|
@@ -11447,7 +11783,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11447
11783
|
cancelled = true;
|
|
11448
11784
|
};
|
|
11449
11785
|
}, [client, activeId, filterKey]);
|
|
11450
|
-
const declare2 =
|
|
11786
|
+
const declare2 = useCallback27(
|
|
11451
11787
|
async (next, blocks) => {
|
|
11452
11788
|
const written = await client.dashboardDeclare(
|
|
11453
11789
|
dashboardDeclareArgs({ ...next, blocks }, tableId)
|
|
@@ -11493,7 +11829,7 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11493
11829
|
]
|
|
11494
11830
|
);
|
|
11495
11831
|
}
|
|
11496
|
-
const refresh =
|
|
11832
|
+
const refresh = useCallback27(async () => {
|
|
11497
11833
|
if (!activeId) return;
|
|
11498
11834
|
setRunning(true);
|
|
11499
11835
|
const again = await client.dashboardRun({
|
|
@@ -11534,20 +11870,20 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11534
11870
|
}
|
|
11535
11871
|
}
|
|
11536
11872
|
if (error) {
|
|
11537
|
-
return /* @__PURE__ */
|
|
11873
|
+
return /* @__PURE__ */ jsx46(
|
|
11538
11874
|
RefusalNotice,
|
|
11539
11875
|
{
|
|
11540
11876
|
error,
|
|
11541
11877
|
className,
|
|
11542
|
-
actions: /* @__PURE__ */
|
|
11878
|
+
actions: /* @__PURE__ */ jsx46(Button37, { size: "sm", variant: "ghost", onClick: () => void load(), children: "Try again" })
|
|
11543
11879
|
}
|
|
11544
11880
|
);
|
|
11545
11881
|
}
|
|
11546
|
-
if (boards === null) return /* @__PURE__ */
|
|
11547
|
-
return /* @__PURE__ */
|
|
11548
|
-
/* @__PURE__ */
|
|
11549
|
-
boards.map((d) => /* @__PURE__ */
|
|
11550
|
-
|
|
11882
|
+
if (boards === null) return /* @__PURE__ */ jsx46(Skeleton24, { className: cn40("h-64 w-full", className) });
|
|
11883
|
+
return /* @__PURE__ */ jsxs42("div", { className: cn40("flex min-h-0 flex-col gap-2", className), children: [
|
|
11884
|
+
/* @__PURE__ */ jsxs42("div", { className: "flex flex-wrap items-center gap-1", role: "group", "aria-label": "Dashboards", children: [
|
|
11885
|
+
boards.map((d) => /* @__PURE__ */ jsx46(
|
|
11886
|
+
Button37,
|
|
11551
11887
|
{
|
|
11552
11888
|
size: "sm",
|
|
11553
11889
|
variant: d.id === activeId ? "secondary" : "ghost",
|
|
@@ -11557,10 +11893,10 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11557
11893
|
},
|
|
11558
11894
|
d.id
|
|
11559
11895
|
)),
|
|
11560
|
-
rights.admin ? /* @__PURE__ */
|
|
11561
|
-
board ? /* @__PURE__ */
|
|
11562
|
-
/* @__PURE__ */
|
|
11563
|
-
|
|
11896
|
+
rights.admin ? /* @__PURE__ */ jsx46(Button37, { size: "sm", variant: "ghost", onClick: () => void create(), children: "New dashboard" }) : null,
|
|
11897
|
+
board ? /* @__PURE__ */ jsxs42("span", { className: "ml-auto flex items-center gap-1", children: [
|
|
11898
|
+
/* @__PURE__ */ jsx46(
|
|
11899
|
+
Button37,
|
|
11564
11900
|
{
|
|
11565
11901
|
size: "sm",
|
|
11566
11902
|
variant: "ghost",
|
|
@@ -11569,13 +11905,31 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11569
11905
|
children: running ? "Asking" : "Refresh"
|
|
11570
11906
|
}
|
|
11571
11907
|
),
|
|
11572
|
-
|
|
11908
|
+
/* @__PURE__ */ jsx46(
|
|
11909
|
+
Button37,
|
|
11910
|
+
{
|
|
11911
|
+
size: "sm",
|
|
11912
|
+
variant: scheduling ? "secondary" : "ghost",
|
|
11913
|
+
onClick: () => setScheduling((v) => !v),
|
|
11914
|
+
children: scheduling ? "Done" : "Send on a schedule"
|
|
11915
|
+
}
|
|
11916
|
+
),
|
|
11917
|
+
rights.admin ? /* @__PURE__ */ jsx46(Button37, { size: "sm", variant: "ghost", onClick: () => void remove(board), children: "Delete" }) : null
|
|
11573
11918
|
] }) : null
|
|
11574
11919
|
] }),
|
|
11575
|
-
board ? /* @__PURE__ */
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11920
|
+
board && scheduling ? /* @__PURE__ */ jsx46(
|
|
11921
|
+
DigestScheduler,
|
|
11922
|
+
{
|
|
11923
|
+
tableId,
|
|
11924
|
+
subjectName: board.name,
|
|
11925
|
+
...filter ? { filters: filter } : {},
|
|
11926
|
+
onClose: () => setScheduling(false)
|
|
11927
|
+
}
|
|
11928
|
+
) : null,
|
|
11929
|
+
board ? /* @__PURE__ */ jsxs42("div", { className: "flex flex-col gap-1", children: [
|
|
11930
|
+
/* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-1", children: [
|
|
11931
|
+
/* @__PURE__ */ jsx46(
|
|
11932
|
+
BasicInput14,
|
|
11579
11933
|
{
|
|
11580
11934
|
value: question,
|
|
11581
11935
|
"aria-label": "Ask for a change to this dashboard",
|
|
@@ -11588,15 +11942,15 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11588
11942
|
className: "h-8 min-w-0 flex-1 text-xs"
|
|
11589
11943
|
}
|
|
11590
11944
|
),
|
|
11591
|
-
/* @__PURE__ */
|
|
11945
|
+
/* @__PURE__ */ jsx46(Button37, { size: "sm", disabled: !host.onReask || asking || question.trim() === "", onClick: () => void reask(), children: asking ? "Asking" : "Ask" })
|
|
11592
11946
|
] }),
|
|
11593
|
-
!host.onReask ? /* @__PURE__ */
|
|
11947
|
+
!host.onReask ? /* @__PURE__ */ jsx46("p", { className: "text-xs text-muted-foreground", children: NO_REASK_REASON }) : null
|
|
11594
11948
|
] }) : null,
|
|
11595
|
-
!board ? /* @__PURE__ */
|
|
11596
|
-
/* @__PURE__ */
|
|
11597
|
-
/* @__PURE__ */
|
|
11598
|
-
rights.admin && board.blocks[index] ? /* @__PURE__ */
|
|
11599
|
-
/* @__PURE__ */
|
|
11949
|
+
!board ? /* @__PURE__ */ jsx46("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__ */ jsx46(Skeleton24, { className: "h-64 w-full" }) : run.blocks.length === 0 ? /* @__PURE__ */ jsx46("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__ */ jsxs42(Fragment20, { children: [
|
|
11950
|
+
/* @__PURE__ */ jsx46("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-3", children: run.blocks.map((block, index) => /* @__PURE__ */ jsxs42("div", { className: "flex min-w-0 flex-col gap-1", children: [
|
|
11951
|
+
/* @__PURE__ */ jsx46(ChartBlock, { block, subject: tableId }),
|
|
11952
|
+
rights.admin && board.blocks[index] ? /* @__PURE__ */ jsxs42("div", { className: "flex items-center gap-1 text-xs", children: [
|
|
11953
|
+
/* @__PURE__ */ jsx46(
|
|
11600
11954
|
"select",
|
|
11601
11955
|
{
|
|
11602
11956
|
"aria-label": `Shape of ${block.title}`,
|
|
@@ -11608,11 +11962,11 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11608
11962
|
(b, i) => i === index ? { ...b, kind: e.target.value } : b
|
|
11609
11963
|
)
|
|
11610
11964
|
),
|
|
11611
|
-
children: CHART_KINDS.map((kind) => /* @__PURE__ */
|
|
11965
|
+
children: CHART_KINDS.map((kind) => /* @__PURE__ */ jsx46("option", { value: kind, children: CHART_KIND_LABEL[kind] }, kind))
|
|
11612
11966
|
}
|
|
11613
11967
|
),
|
|
11614
|
-
/* @__PURE__ */
|
|
11615
|
-
|
|
11968
|
+
/* @__PURE__ */ jsx46(
|
|
11969
|
+
Button37,
|
|
11616
11970
|
{
|
|
11617
11971
|
size: "sm",
|
|
11618
11972
|
variant: "ghost",
|
|
@@ -11625,17 +11979,17 @@ function DashboardCanvas({ tableId, activeDashboardId, filter, className }) {
|
|
|
11625
11979
|
)
|
|
11626
11980
|
] }) : null
|
|
11627
11981
|
] }, `${block.title}-${index}`)) }),
|
|
11628
|
-
!host.openRecords ? /* @__PURE__ */
|
|
11982
|
+
!host.openRecords ? /* @__PURE__ */ jsx46("p", { className: "text-xs text-muted-foreground", children: NO_OPEN_RECORDS_REASON }) : null
|
|
11629
11983
|
] })
|
|
11630
11984
|
] });
|
|
11631
11985
|
}
|
|
11632
11986
|
|
|
11633
11987
|
// src/FormsPanel.tsx
|
|
11634
|
-
import { useCallback as
|
|
11635
|
-
import { useRecordsClient as
|
|
11988
|
+
import { useCallback as useCallback28, useEffect as useEffect32, useState as useState42 } from "react";
|
|
11989
|
+
import { useRecordsClient as useRecordsClient34, useTable as useTable18 } from "@ai-matrx/records/react";
|
|
11636
11990
|
import { publicFormPath as publicFormPath2 } from "@ai-matrx/records";
|
|
11637
|
-
import { Badge as Badge15, Button as
|
|
11638
|
-
import { Fragment as
|
|
11991
|
+
import { Badge as Badge15, Button as Button38, Skeleton as Skeleton25, cn as cn41 } from "@ai-matrx/design-system";
|
|
11992
|
+
import { Fragment as Fragment21, jsx as jsx47, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
11639
11993
|
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.";
|
|
11640
11994
|
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.";
|
|
11641
11995
|
function formSuggestion(tableName2) {
|
|
@@ -11643,16 +11997,16 @@ function formSuggestion(tableName2) {
|
|
|
11643
11997
|
return `Make me a form that collects new ${subject} entries and tells me when somebody answers.`;
|
|
11644
11998
|
}
|
|
11645
11999
|
function FormsPanel({ tableId, className }) {
|
|
11646
|
-
const client =
|
|
12000
|
+
const client = useRecordsClient34();
|
|
11647
12001
|
const host = useRecordsUi();
|
|
11648
12002
|
const table = useTable18(tableId);
|
|
11649
12003
|
const rights = useTableRights(table.data);
|
|
11650
|
-
const [forms, setForms] =
|
|
11651
|
-
const [error, setError] =
|
|
11652
|
-
const [busy, setBusy] =
|
|
11653
|
-
const [copied, setCopied] =
|
|
11654
|
-
const [building, setBuilding] =
|
|
11655
|
-
const load =
|
|
12004
|
+
const [forms, setForms] = useState42(null);
|
|
12005
|
+
const [error, setError] = useState42(null);
|
|
12006
|
+
const [busy, setBusy] = useState42(null);
|
|
12007
|
+
const [copied, setCopied] = useState42(null);
|
|
12008
|
+
const [building, setBuilding] = useState42(false);
|
|
12009
|
+
const load = useCallback28(async () => {
|
|
11656
12010
|
const answered = await client.forms({ table_id: tableId });
|
|
11657
12011
|
if (!answered.ok) {
|
|
11658
12012
|
setError(answered.error);
|
|
@@ -11662,10 +12016,10 @@ function FormsPanel({ tableId, className }) {
|
|
|
11662
12016
|
setError(null);
|
|
11663
12017
|
setForms(answered.data);
|
|
11664
12018
|
}, [client, tableId]);
|
|
11665
|
-
|
|
12019
|
+
useEffect32(() => {
|
|
11666
12020
|
void load();
|
|
11667
12021
|
}, [load]);
|
|
11668
|
-
const toggle =
|
|
12022
|
+
const toggle = useCallback28(
|
|
11669
12023
|
async (form) => {
|
|
11670
12024
|
setBusy(form.form_id);
|
|
11671
12025
|
const wanted = form.published_at === null || form.closed_at !== null;
|
|
@@ -11679,8 +12033,8 @@ function FormsPanel({ tableId, className }) {
|
|
|
11679
12033
|
},
|
|
11680
12034
|
[client, load]
|
|
11681
12035
|
);
|
|
11682
|
-
const [shown, setShown] =
|
|
11683
|
-
const copy =
|
|
12036
|
+
const [shown, setShown] = useState42(null);
|
|
12037
|
+
const copy = useCallback28(async (url, formId) => {
|
|
11684
12038
|
try {
|
|
11685
12039
|
await navigator.clipboard.writeText(url);
|
|
11686
12040
|
setCopied(formId);
|
|
@@ -11690,17 +12044,17 @@ function FormsPanel({ tableId, className }) {
|
|
|
11690
12044
|
setShown(url);
|
|
11691
12045
|
}
|
|
11692
12046
|
}, []);
|
|
11693
|
-
if (forms === null) return /* @__PURE__ */
|
|
12047
|
+
if (forms === null) return /* @__PURE__ */ jsx47(Skeleton25, { className: cn41("h-32 w-full", className) });
|
|
11694
12048
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
11695
|
-
return /* @__PURE__ */
|
|
11696
|
-
/* @__PURE__ */
|
|
11697
|
-
/* @__PURE__ */
|
|
11698
|
-
/* @__PURE__ */
|
|
11699
|
-
/* @__PURE__ */
|
|
11700
|
-
rights.structure && forms.length > 0 ? /* @__PURE__ */
|
|
12049
|
+
return /* @__PURE__ */ jsxs43("section", { className: cn41("flex flex-col gap-3", className), children: [
|
|
12050
|
+
/* @__PURE__ */ jsxs43("header", { className: "flex items-center gap-2", children: [
|
|
12051
|
+
/* @__PURE__ */ jsx47("h3", { className: "text-sm font-medium", children: "Forms" }),
|
|
12052
|
+
/* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground", children: forms.length === 0 ? "none yet" : `${forms.length}` }),
|
|
12053
|
+
/* @__PURE__ */ jsx47("div", { className: "flex-1" }),
|
|
12054
|
+
rights.structure && forms.length > 0 ? /* @__PURE__ */ jsx47(Button38, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a form" }) : null
|
|
11701
12055
|
] }),
|
|
11702
|
-
error ? /* @__PURE__ */
|
|
11703
|
-
building ? /* @__PURE__ */
|
|
12056
|
+
error ? /* @__PURE__ */ jsx47(RefusalNotice, { error }) : null,
|
|
12057
|
+
building ? /* @__PURE__ */ jsx47(
|
|
11704
12058
|
FormBuilder,
|
|
11705
12059
|
{
|
|
11706
12060
|
tableId,
|
|
@@ -11709,7 +12063,7 @@ function FormsPanel({ tableId, className }) {
|
|
|
11709
12063
|
}
|
|
11710
12064
|
}
|
|
11711
12065
|
) : null,
|
|
11712
|
-
forms.length === 0 && !building ? /* @__PURE__ */
|
|
12066
|
+
forms.length === 0 && !building ? /* @__PURE__ */ jsx47(
|
|
11713
12067
|
BuildOrAsk,
|
|
11714
12068
|
{
|
|
11715
12069
|
mayBuild: rights.structure,
|
|
@@ -11727,36 +12081,36 @@ function FormsPanel({ tableId, className }) {
|
|
|
11727
12081
|
children: WHAT_A_FORM_IS
|
|
11728
12082
|
}
|
|
11729
12083
|
) : null,
|
|
11730
|
-
/* @__PURE__ */
|
|
12084
|
+
/* @__PURE__ */ jsx47("ul", { className: "flex flex-col gap-2", children: forms.map((form) => {
|
|
11731
12085
|
const url = `${origin}${publicFormPath2(form.form_id)}`;
|
|
11732
|
-
return /* @__PURE__ */
|
|
11733
|
-
/* @__PURE__ */
|
|
11734
|
-
/* @__PURE__ */
|
|
11735
|
-
/* @__PURE__ */
|
|
12086
|
+
return /* @__PURE__ */ jsxs43("li", { className: "rounded-md border p-2.5", children: [
|
|
12087
|
+
/* @__PURE__ */ jsxs43("div", { className: "flex items-center gap-2", children: [
|
|
12088
|
+
/* @__PURE__ */ jsx47("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: form.title ?? form.slug }),
|
|
12089
|
+
/* @__PURE__ */ jsx47(Badge15, { variant: form.state === "open" ? "default" : "secondary", children: form.state })
|
|
11736
12090
|
] }),
|
|
11737
|
-
/* @__PURE__ */
|
|
11738
|
-
/* @__PURE__ */
|
|
11739
|
-
/* @__PURE__ */
|
|
12091
|
+
/* @__PURE__ */ jsx47("p", { className: "mt-0.5 text-xs text-muted-foreground", children: FORM_STATE_WORDS[form.state] }),
|
|
12092
|
+
/* @__PURE__ */ jsxs43("p", { className: "mt-1.5 text-xs", children: [
|
|
12093
|
+
/* @__PURE__ */ jsx47("span", { className: "font-medium", children: form.in_table }),
|
|
11740
12094
|
" in the table",
|
|
11741
|
-
form.held > 0 ? /* @__PURE__ */
|
|
12095
|
+
form.held > 0 ? /* @__PURE__ */ jsxs43(Fragment21, { children: [
|
|
11742
12096
|
" \xB7 ",
|
|
11743
|
-
/* @__PURE__ */
|
|
12097
|
+
/* @__PURE__ */ jsx47("span", { className: "font-medium", children: form.held }),
|
|
11744
12098
|
" waiting for someone"
|
|
11745
12099
|
] }) : null,
|
|
11746
|
-
form.rejected > 0 ? /* @__PURE__ */
|
|
12100
|
+
form.rejected > 0 ? /* @__PURE__ */ jsxs43(Fragment21, { children: [
|
|
11747
12101
|
" \xB7 ",
|
|
11748
|
-
/* @__PURE__ */
|
|
12102
|
+
/* @__PURE__ */ jsx47("span", { className: "font-medium", children: form.rejected }),
|
|
11749
12103
|
" turned away"
|
|
11750
12104
|
] }) : null,
|
|
11751
|
-
form.submission_cap !== null ? /* @__PURE__ */
|
|
12105
|
+
form.submission_cap !== null ? /* @__PURE__ */ jsxs43("span", { className: "text-muted-foreground", children: [
|
|
11752
12106
|
" \xB7 stops at ",
|
|
11753
12107
|
form.submission_cap
|
|
11754
12108
|
] }) : null
|
|
11755
12109
|
] }),
|
|
11756
|
-
/* @__PURE__ */
|
|
11757
|
-
form.published_at ? /* @__PURE__ */
|
|
11758
|
-
rights.structure ? /* @__PURE__ */
|
|
11759
|
-
|
|
12110
|
+
/* @__PURE__ */ jsxs43("div", { className: "mt-2 flex flex-wrap items-center gap-1.5", children: [
|
|
12111
|
+
form.published_at ? /* @__PURE__ */ jsx47(Button38, { size: "sm", variant: "outline", onClick: () => void copy(url, form.form_id), children: copied === form.form_id ? "Copied" : "Copy link" }) : null,
|
|
12112
|
+
rights.structure ? /* @__PURE__ */ jsx47(
|
|
12113
|
+
Button38,
|
|
11760
12114
|
{
|
|
11761
12115
|
size: "sm",
|
|
11762
12116
|
variant: "ghost",
|
|
@@ -11766,25 +12120,25 @@ function FormsPanel({ tableId, className }) {
|
|
|
11766
12120
|
}
|
|
11767
12121
|
) : null
|
|
11768
12122
|
] }),
|
|
11769
|
-
shown && shown === url ? /* @__PURE__ */
|
|
12123
|
+
shown && shown === url ? /* @__PURE__ */ jsxs43("p", { className: "mt-1.5 break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
11770
12124
|
"This browser would not let the page copy for you, so here it is to copy by hand:",
|
|
11771
12125
|
" ",
|
|
11772
12126
|
url
|
|
11773
12127
|
] }) : null
|
|
11774
12128
|
] }, form.form_id);
|
|
11775
12129
|
}) }),
|
|
11776
|
-
!rights.known ? /* @__PURE__ */
|
|
12130
|
+
!rights.known ? /* @__PURE__ */ jsx47("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
|
|
11777
12131
|
] });
|
|
11778
12132
|
}
|
|
11779
12133
|
|
|
11780
12134
|
// src/BookingBuilder.tsx
|
|
11781
|
-
import { useCallback as
|
|
11782
|
-
import { useFields as useFields20, useRecordsClient as
|
|
12135
|
+
import { useCallback as useCallback29, useEffect as useEffect33, useMemo as useMemo28, useState as useState43 } from "react";
|
|
12136
|
+
import { useFields as useFields20, useRecordsClient as useRecordsClient35, useTable as useTable19 } from "@ai-matrx/records/react";
|
|
11783
12137
|
import {
|
|
11784
12138
|
bookingPath
|
|
11785
12139
|
} from "@ai-matrx/records";
|
|
11786
|
-
import { BasicInput as
|
|
11787
|
-
import { Fragment as
|
|
12140
|
+
import { BasicInput as BasicInput15, BasicTextarea as BasicTextarea7, Button as Button39, Checkbox as Checkbox7, Label as Label8, Skeleton as Skeleton26, cn as cn42 } from "@ai-matrx/design-system";
|
|
12141
|
+
import { Fragment as Fragment22, jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
11788
12142
|
var STORE_ANSWERS_THESE = ["slot", "status", "booked_with"];
|
|
11789
12143
|
var DAYS = [
|
|
11790
12144
|
{ weekday: 1, label: "Mon" },
|
|
@@ -11808,36 +12162,36 @@ function draftWindows(availability) {
|
|
|
11808
12162
|
});
|
|
11809
12163
|
}
|
|
11810
12164
|
function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
11811
|
-
const client =
|
|
12165
|
+
const client = useRecordsClient35();
|
|
11812
12166
|
const host = useRecordsUi();
|
|
11813
12167
|
const table = useTable19(tableId);
|
|
11814
12168
|
const rights = useTableRights(table.data);
|
|
11815
12169
|
const fields = useFields20(tableId);
|
|
11816
|
-
const [existing, setExisting] =
|
|
11817
|
-
const [loaded, setLoaded] =
|
|
11818
|
-
const [error, setError] =
|
|
11819
|
-
const [saving, setSaving] =
|
|
11820
|
-
const [publishing, setPublishing] =
|
|
11821
|
-
const [copied, setCopied] =
|
|
11822
|
-
const [title, setTitle] =
|
|
11823
|
-
const [minutes, setMinutes] =
|
|
11824
|
-
const [buffer, setBuffer] =
|
|
11825
|
-
const [lead, setLead] =
|
|
11826
|
-
const [perDay, setPerDay] =
|
|
11827
|
-
const [days, setDays] =
|
|
11828
|
-
const [windows, setWindows] =
|
|
11829
|
-
const [asked, setAsked] =
|
|
11830
|
-
const [confirmation, setConfirmation] =
|
|
11831
|
-
const [offer, setOffer] =
|
|
11832
|
-
const [formId, setFormId] =
|
|
12170
|
+
const [existing, setExisting] = useState43(null);
|
|
12171
|
+
const [loaded, setLoaded] = useState43(false);
|
|
12172
|
+
const [error, setError] = useState43(null);
|
|
12173
|
+
const [saving, setSaving] = useState43(false);
|
|
12174
|
+
const [publishing, setPublishing] = useState43(false);
|
|
12175
|
+
const [copied, setCopied] = useState43(false);
|
|
12176
|
+
const [title, setTitle] = useState43("");
|
|
12177
|
+
const [minutes, setMinutes] = useState43(30);
|
|
12178
|
+
const [buffer, setBuffer] = useState43(0);
|
|
12179
|
+
const [lead, setLead] = useState43(120);
|
|
12180
|
+
const [perDay, setPerDay] = useState43(8);
|
|
12181
|
+
const [days, setDays] = useState43(30);
|
|
12182
|
+
const [windows, setWindows] = useState43(() => draftWindows(null));
|
|
12183
|
+
const [asked, setAsked] = useState43([]);
|
|
12184
|
+
const [confirmation, setConfirmation] = useState43("");
|
|
12185
|
+
const [offer, setOffer] = useState43(null);
|
|
12186
|
+
const [formId, setFormId] = useState43(bookingId ?? null);
|
|
11833
12187
|
const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
11834
|
-
const askable =
|
|
12188
|
+
const askable = useMemo28(
|
|
11835
12189
|
() => (fields.data ?? []).filter(
|
|
11836
12190
|
(f) => !STORE_ANSWERS_THESE.includes(f.key)
|
|
11837
12191
|
),
|
|
11838
12192
|
[fields.data]
|
|
11839
12193
|
);
|
|
11840
|
-
const load =
|
|
12194
|
+
const load = useCallback29(async () => {
|
|
11841
12195
|
const answered = await client.bookings({ table_id: tableId });
|
|
11842
12196
|
if (!answered.ok) {
|
|
11843
12197
|
setError(answered.error);
|
|
@@ -11849,18 +12203,18 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
11849
12203
|
setLoaded(true);
|
|
11850
12204
|
if (mine) setFormId(mine.form_id);
|
|
11851
12205
|
}, [client, tableId, bookingId]);
|
|
11852
|
-
|
|
12206
|
+
useEffect33(() => {
|
|
11853
12207
|
void load();
|
|
11854
12208
|
}, [load]);
|
|
11855
|
-
|
|
12209
|
+
useEffect33(() => {
|
|
11856
12210
|
if (title !== "" || !table.data) return;
|
|
11857
12211
|
setTitle(existing?.title ?? `Book a ${minutes}-minute ${table.data.name} appointment`);
|
|
11858
12212
|
}, [table.data, existing]);
|
|
11859
|
-
|
|
12213
|
+
useEffect33(() => {
|
|
11860
12214
|
if (!existing) return;
|
|
11861
12215
|
setMinutes(existing.slot_minutes);
|
|
11862
12216
|
}, [existing]);
|
|
11863
|
-
const availability =
|
|
12217
|
+
const availability = useCallback29(
|
|
11864
12218
|
() => ({
|
|
11865
12219
|
slot_minutes: minutes,
|
|
11866
12220
|
buffer_minutes: buffer,
|
|
@@ -11909,68 +12263,68 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
11909
12263
|
await load();
|
|
11910
12264
|
onSaved?.({ form_id: formId });
|
|
11911
12265
|
}
|
|
11912
|
-
if (!loaded || fields.loading) return /* @__PURE__ */
|
|
12266
|
+
if (!loaded || fields.loading) return /* @__PURE__ */ jsx48(Skeleton26, { className: cn42("h-64 w-full", className) });
|
|
11913
12267
|
if (!rights.structure) {
|
|
11914
|
-
return /* @__PURE__ */
|
|
12268
|
+
return /* @__PURE__ */ jsx48("p", { className: cn42("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." });
|
|
11915
12269
|
}
|
|
11916
12270
|
const url = formId ? `${publicOrigin}${bookingPath(formId)}` : null;
|
|
11917
12271
|
const shown = offer ?? null;
|
|
11918
|
-
return /* @__PURE__ */
|
|
11919
|
-
/* @__PURE__ */
|
|
11920
|
-
/* @__PURE__ */
|
|
11921
|
-
/* @__PURE__ */
|
|
11922
|
-
/* @__PURE__ */
|
|
11923
|
-
onClose ? /* @__PURE__ */
|
|
12272
|
+
return /* @__PURE__ */ jsxs44("section", { className: cn42("flex flex-col gap-3", className), children: [
|
|
12273
|
+
/* @__PURE__ */ jsxs44("header", { className: "flex items-center gap-2", children: [
|
|
12274
|
+
/* @__PURE__ */ jsx48("h3", { className: "text-sm font-medium", children: existing ? "Booking page" : "New booking page" }),
|
|
12275
|
+
/* @__PURE__ */ jsx48("div", { className: "flex-1" }),
|
|
12276
|
+
/* @__PURE__ */ jsx48(Button39, { size: "sm", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" }),
|
|
12277
|
+
onClose ? /* @__PURE__ */ jsx48(Button39, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
|
|
11924
12278
|
] }),
|
|
11925
|
-
error ? /* @__PURE__ */
|
|
11926
|
-
/* @__PURE__ */
|
|
11927
|
-
/* @__PURE__ */
|
|
11928
|
-
/* @__PURE__ */
|
|
12279
|
+
error ? /* @__PURE__ */ jsx48(RefusalNotice, { error }) : null,
|
|
12280
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12281
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "What it is called" }),
|
|
12282
|
+
/* @__PURE__ */ jsx48(BasicInput15, { value: title, onChange: (e) => setTitle(e.target.value) })
|
|
11929
12283
|
] }),
|
|
11930
|
-
/* @__PURE__ */
|
|
11931
|
-
/* @__PURE__ */
|
|
11932
|
-
/* @__PURE__ */
|
|
11933
|
-
/* @__PURE__ */
|
|
12284
|
+
/* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
12285
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12286
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "How long one appointment is" }),
|
|
12287
|
+
/* @__PURE__ */ jsx48(
|
|
11934
12288
|
"select",
|
|
11935
12289
|
{
|
|
11936
12290
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
11937
12291
|
value: minutes,
|
|
11938
12292
|
onChange: (e) => setMinutes(Number(e.target.value)),
|
|
11939
|
-
children: LENGTHS.map((n) => /* @__PURE__ */
|
|
12293
|
+
children: LENGTHS.map((n) => /* @__PURE__ */ jsxs44("option", { value: n, children: [
|
|
11940
12294
|
n,
|
|
11941
12295
|
" minutes"
|
|
11942
12296
|
] }, n))
|
|
11943
12297
|
}
|
|
11944
12298
|
)
|
|
11945
12299
|
] }),
|
|
11946
|
-
/* @__PURE__ */
|
|
11947
|
-
/* @__PURE__ */
|
|
11948
|
-
/* @__PURE__ */
|
|
12300
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12301
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "Gap kept after each one" }),
|
|
12302
|
+
/* @__PURE__ */ jsx48(
|
|
11949
12303
|
"select",
|
|
11950
12304
|
{
|
|
11951
12305
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
11952
12306
|
value: buffer,
|
|
11953
12307
|
onChange: (e) => setBuffer(Number(e.target.value)),
|
|
11954
|
-
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */
|
|
12308
|
+
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ jsx48("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
|
|
11955
12309
|
}
|
|
11956
12310
|
)
|
|
11957
12311
|
] }),
|
|
11958
|
-
/* @__PURE__ */
|
|
11959
|
-
/* @__PURE__ */
|
|
11960
|
-
/* @__PURE__ */
|
|
12312
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12313
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
|
|
12314
|
+
/* @__PURE__ */ jsx48(
|
|
11961
12315
|
"select",
|
|
11962
12316
|
{
|
|
11963
12317
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
11964
12318
|
value: lead,
|
|
11965
12319
|
onChange: (e) => setLead(Number(e.target.value)),
|
|
11966
|
-
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */
|
|
12320
|
+
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ jsx48("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
|
|
11967
12321
|
}
|
|
11968
12322
|
)
|
|
11969
12323
|
] }),
|
|
11970
|
-
/* @__PURE__ */
|
|
11971
|
-
/* @__PURE__ */
|
|
11972
|
-
/* @__PURE__ */
|
|
11973
|
-
|
|
12324
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12325
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "Most in one day" }),
|
|
12326
|
+
/* @__PURE__ */ jsx48(
|
|
12327
|
+
BasicInput15,
|
|
11974
12328
|
{
|
|
11975
12329
|
type: "number",
|
|
11976
12330
|
min: 1,
|
|
@@ -11979,15 +12333,15 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
11979
12333
|
}
|
|
11980
12334
|
)
|
|
11981
12335
|
] }),
|
|
11982
|
-
/* @__PURE__ */
|
|
11983
|
-
/* @__PURE__ */
|
|
11984
|
-
/* @__PURE__ */
|
|
12336
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12337
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "How far ahead the page offers" }),
|
|
12338
|
+
/* @__PURE__ */ jsx48(
|
|
11985
12339
|
"select",
|
|
11986
12340
|
{
|
|
11987
12341
|
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
11988
12342
|
value: days,
|
|
11989
12343
|
onChange: (e) => setDays(Number(e.target.value)),
|
|
11990
|
-
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */
|
|
12344
|
+
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ jsxs44("option", { value: n, children: [
|
|
11991
12345
|
n,
|
|
11992
12346
|
" days"
|
|
11993
12347
|
] }, n))
|
|
@@ -11995,12 +12349,12 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
11995
12349
|
)
|
|
11996
12350
|
] })
|
|
11997
12351
|
] }),
|
|
11998
|
-
/* @__PURE__ */
|
|
11999
|
-
/* @__PURE__ */
|
|
12000
|
-
windows.map((w, i) => /* @__PURE__ */
|
|
12001
|
-
/* @__PURE__ */
|
|
12002
|
-
/* @__PURE__ */
|
|
12003
|
-
|
|
12352
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex flex-col gap-1.5", children: [
|
|
12353
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "Hours you are free" }),
|
|
12354
|
+
windows.map((w, i) => /* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
|
|
12355
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
|
|
12356
|
+
/* @__PURE__ */ jsx48(
|
|
12357
|
+
Checkbox7,
|
|
12004
12358
|
{
|
|
12005
12359
|
checked: w.on,
|
|
12006
12360
|
onCheckedChange: (on) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, on: Boolean(on) } : x))
|
|
@@ -12008,9 +12362,9 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12008
12362
|
),
|
|
12009
12363
|
DAYS[i]?.label
|
|
12010
12364
|
] }),
|
|
12011
|
-
w.on ? /* @__PURE__ */
|
|
12012
|
-
/* @__PURE__ */
|
|
12013
|
-
|
|
12365
|
+
w.on ? /* @__PURE__ */ jsxs44(Fragment22, { children: [
|
|
12366
|
+
/* @__PURE__ */ jsx48(
|
|
12367
|
+
BasicInput15,
|
|
12014
12368
|
{
|
|
12015
12369
|
type: "time",
|
|
12016
12370
|
className: "h-8 w-28",
|
|
@@ -12018,9 +12372,9 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12018
12372
|
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, from: e.target.value } : x))
|
|
12019
12373
|
}
|
|
12020
12374
|
),
|
|
12021
|
-
/* @__PURE__ */
|
|
12022
|
-
/* @__PURE__ */
|
|
12023
|
-
|
|
12375
|
+
/* @__PURE__ */ jsx48("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
12376
|
+
/* @__PURE__ */ jsx48(
|
|
12377
|
+
BasicInput15,
|
|
12024
12378
|
{
|
|
12025
12379
|
type: "time",
|
|
12026
12380
|
className: "h-8 w-28",
|
|
@@ -12028,14 +12382,14 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12028
12382
|
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, to: e.target.value } : x))
|
|
12029
12383
|
}
|
|
12030
12384
|
)
|
|
12031
|
-
] }) : /* @__PURE__ */
|
|
12385
|
+
] }) : /* @__PURE__ */ jsx48("span", { className: "text-xs text-muted-foreground", children: "not taking bookings" })
|
|
12032
12386
|
] }, w.weekday))
|
|
12033
12387
|
] }),
|
|
12034
|
-
/* @__PURE__ */
|
|
12035
|
-
/* @__PURE__ */
|
|
12036
|
-
askable.length === 0 ? /* @__PURE__ */
|
|
12037
|
-
/* @__PURE__ */
|
|
12038
|
-
|
|
12388
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex flex-col gap-1.5", children: [
|
|
12389
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "What to ask the person booking" }),
|
|
12390
|
+
askable.length === 0 ? /* @__PURE__ */ jsx48("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__ */ jsx48("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: askable.map((f) => /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
12391
|
+
/* @__PURE__ */ jsx48(
|
|
12392
|
+
Checkbox7,
|
|
12039
12393
|
{
|
|
12040
12394
|
checked: asked.includes(f.key),
|
|
12041
12395
|
onCheckedChange: (on) => setAsked((prev) => on ? [...prev, f.key] : prev.filter((k) => k !== f.key))
|
|
@@ -12043,11 +12397,11 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12043
12397
|
),
|
|
12044
12398
|
fieldName(f)
|
|
12045
12399
|
] }, f.key)) }),
|
|
12046
|
-
/* @__PURE__ */
|
|
12400
|
+
/* @__PURE__ */ jsx48("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." })
|
|
12047
12401
|
] }),
|
|
12048
|
-
/* @__PURE__ */
|
|
12049
|
-
/* @__PURE__ */
|
|
12050
|
-
/* @__PURE__ */
|
|
12402
|
+
/* @__PURE__ */ jsxs44("label", { className: "flex flex-col gap-1", children: [
|
|
12403
|
+
/* @__PURE__ */ jsx48(Label8, { className: "text-xs font-medium", children: "What they see after booking" }),
|
|
12404
|
+
/* @__PURE__ */ jsx48(
|
|
12051
12405
|
BasicTextarea7,
|
|
12052
12406
|
{
|
|
12053
12407
|
rows: 2,
|
|
@@ -12057,7 +12411,7 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12057
12411
|
}
|
|
12058
12412
|
)
|
|
12059
12413
|
] }),
|
|
12060
|
-
shown ? /* @__PURE__ */
|
|
12414
|
+
shown ? /* @__PURE__ */ jsxs44("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
12061
12415
|
"Saved. The page offers ",
|
|
12062
12416
|
shown.slot_minutes,
|
|
12063
12417
|
"-minute appointments in ",
|
|
@@ -12076,10 +12430,10 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12076
12430
|
).join(", "),
|
|
12077
12431
|
"."
|
|
12078
12432
|
] }) : null,
|
|
12079
|
-
url ? /* @__PURE__ */
|
|
12080
|
-
/* @__PURE__ */
|
|
12081
|
-
/* @__PURE__ */
|
|
12082
|
-
|
|
12433
|
+
url ? /* @__PURE__ */ jsxs44("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
|
|
12434
|
+
/* @__PURE__ */ jsx48("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
|
|
12435
|
+
/* @__PURE__ */ jsx48(
|
|
12436
|
+
Button39,
|
|
12083
12437
|
{
|
|
12084
12438
|
size: "sm",
|
|
12085
12439
|
variant: "outline",
|
|
@@ -12092,8 +12446,8 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12092
12446
|
children: copied ? "Copied" : "Copy link"
|
|
12093
12447
|
}
|
|
12094
12448
|
),
|
|
12095
|
-
/* @__PURE__ */
|
|
12096
|
-
|
|
12449
|
+
/* @__PURE__ */ jsx48(
|
|
12450
|
+
Button39,
|
|
12097
12451
|
{
|
|
12098
12452
|
size: "sm",
|
|
12099
12453
|
disabled: publishing,
|
|
@@ -12101,17 +12455,17 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12101
12455
|
children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
|
|
12102
12456
|
}
|
|
12103
12457
|
),
|
|
12104
|
-
/* @__PURE__ */
|
|
12458
|
+
/* @__PURE__ */ jsx48("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." })
|
|
12105
12459
|
] }) : null
|
|
12106
12460
|
] });
|
|
12107
12461
|
}
|
|
12108
12462
|
|
|
12109
12463
|
// src/BookingSlots.tsx
|
|
12110
|
-
import { useCallback as
|
|
12111
|
-
import { useRecordsClient as
|
|
12464
|
+
import { useCallback as useCallback30, useEffect as useEffect34, useMemo as useMemo29, useState as useState44 } from "react";
|
|
12465
|
+
import { useRecordsClient as useRecordsClient36, useMyLevels as useMyLevels2 } from "@ai-matrx/records/react";
|
|
12112
12466
|
import { bookingPath as bookingPath2 } from "@ai-matrx/records";
|
|
12113
|
-
import { Badge as Badge16, Button as
|
|
12114
|
-
import { Fragment as
|
|
12467
|
+
import { Badge as Badge16, Button as Button40, Skeleton as Skeleton27, cn as cn43 } from "@ai-matrx/design-system";
|
|
12468
|
+
import { Fragment as Fragment23, jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
12115
12469
|
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.";
|
|
12116
12470
|
function bookingSuggestion(tableName2) {
|
|
12117
12471
|
const subject = tableName2?.trim() ? tableName2.trim() : "appointments";
|
|
@@ -12125,15 +12479,15 @@ var STATE_WORDS = {
|
|
|
12125
12479
|
full: "Every time you offered is taken."
|
|
12126
12480
|
};
|
|
12127
12481
|
function BookingSlots({ tableId, className }) {
|
|
12128
|
-
const client =
|
|
12482
|
+
const client = useRecordsClient36();
|
|
12129
12483
|
const host = useRecordsUi();
|
|
12130
|
-
const [pages, setPages] =
|
|
12131
|
-
const [error, setError] =
|
|
12132
|
-
const [busy, setBusy] =
|
|
12133
|
-
const [copied, setCopied] =
|
|
12134
|
-
const [shown, setShown] =
|
|
12135
|
-
const [building, setBuilding] =
|
|
12136
|
-
const load =
|
|
12484
|
+
const [pages, setPages] = useState44(null);
|
|
12485
|
+
const [error, setError] = useState44(null);
|
|
12486
|
+
const [busy, setBusy] = useState44(null);
|
|
12487
|
+
const [copied, setCopied] = useState44(null);
|
|
12488
|
+
const [shown, setShown] = useState44(null);
|
|
12489
|
+
const [building, setBuilding] = useState44(false);
|
|
12490
|
+
const load = useCallback30(async () => {
|
|
12137
12491
|
const answered = await client.bookings(tableId ? { table_id: tableId } : {});
|
|
12138
12492
|
if (!answered.ok) {
|
|
12139
12493
|
setError(answered.error);
|
|
@@ -12143,15 +12497,15 @@ function BookingSlots({ tableId, className }) {
|
|
|
12143
12497
|
setError(null);
|
|
12144
12498
|
setPages(answered.data);
|
|
12145
12499
|
}, [client, tableId]);
|
|
12146
|
-
|
|
12500
|
+
useEffect34(() => {
|
|
12147
12501
|
void load();
|
|
12148
12502
|
}, [load]);
|
|
12149
|
-
const subjectIds =
|
|
12503
|
+
const subjectIds = useMemo29(
|
|
12150
12504
|
() => Array.from(new Set((pages ?? []).map((p) => p.table_id))),
|
|
12151
12505
|
[pages]
|
|
12152
12506
|
);
|
|
12153
12507
|
const levels = useMyLevels2(subjectIds);
|
|
12154
|
-
const toggle =
|
|
12508
|
+
const toggle = useCallback30(
|
|
12155
12509
|
async (page) => {
|
|
12156
12510
|
setBusy(page.form_id);
|
|
12157
12511
|
const wanted = page.published_at === null || page.closed_at !== null;
|
|
@@ -12165,7 +12519,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
12165
12519
|
},
|
|
12166
12520
|
[client, load]
|
|
12167
12521
|
);
|
|
12168
|
-
const copy =
|
|
12522
|
+
const copy = useCallback30(async (url, formId) => {
|
|
12169
12523
|
try {
|
|
12170
12524
|
await navigator.clipboard.writeText(url);
|
|
12171
12525
|
setCopied(formId);
|
|
@@ -12175,18 +12529,18 @@ function BookingSlots({ tableId, className }) {
|
|
|
12175
12529
|
setShown(url);
|
|
12176
12530
|
}
|
|
12177
12531
|
}, []);
|
|
12178
|
-
if (pages === null) return /* @__PURE__ */
|
|
12532
|
+
if (pages === null) return /* @__PURE__ */ jsx49(Skeleton27, { className: cn43("h-32 w-full", className) });
|
|
12179
12533
|
if (pages.length === 0 && !tableId && !error && !building) return null;
|
|
12180
12534
|
const origin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
|
|
12181
|
-
return /* @__PURE__ */
|
|
12182
|
-
/* @__PURE__ */
|
|
12183
|
-
/* @__PURE__ */
|
|
12184
|
-
/* @__PURE__ */
|
|
12185
|
-
/* @__PURE__ */
|
|
12186
|
-
tableId && pages.length > 0 ? /* @__PURE__ */
|
|
12535
|
+
return /* @__PURE__ */ jsxs45("section", { className: cn43("flex flex-col gap-3", className), "data-testid": "booking-slots", children: [
|
|
12536
|
+
/* @__PURE__ */ jsxs45("header", { className: "flex items-center gap-2", children: [
|
|
12537
|
+
/* @__PURE__ */ jsx49("h3", { className: "text-sm font-medium", children: "Bookings" }),
|
|
12538
|
+
/* @__PURE__ */ jsx49("span", { className: "text-xs text-muted-foreground", children: pages.length === 0 ? "none yet" : `${pages.length}` }),
|
|
12539
|
+
/* @__PURE__ */ jsx49("div", { className: "flex-1" }),
|
|
12540
|
+
tableId && pages.length > 0 ? /* @__PURE__ */ jsx49(Button40, { size: "sm", variant: building ? "secondary" : "ghost", onClick: () => setBuilding((b) => !b), children: building ? "Done building" : "Build a booking page" }) : null
|
|
12187
12541
|
] }),
|
|
12188
|
-
error ? /* @__PURE__ */
|
|
12189
|
-
building && tableId ? /* @__PURE__ */
|
|
12542
|
+
error ? /* @__PURE__ */ jsx49(RefusalNotice, { error }) : null,
|
|
12543
|
+
building && tableId ? /* @__PURE__ */ jsx49(
|
|
12190
12544
|
BookingBuilder,
|
|
12191
12545
|
{
|
|
12192
12546
|
tableId,
|
|
@@ -12196,7 +12550,7 @@ function BookingSlots({ tableId, className }) {
|
|
|
12196
12550
|
onClose: () => setBuilding(false)
|
|
12197
12551
|
}
|
|
12198
12552
|
) : null,
|
|
12199
|
-
pages.length === 0 && !building ? tableId ? /* @__PURE__ */
|
|
12553
|
+
pages.length === 0 && !building ? tableId ? /* @__PURE__ */ jsx49(
|
|
12200
12554
|
BuildOrAsk,
|
|
12201
12555
|
{
|
|
12202
12556
|
mayBuild: true,
|
|
@@ -12212,47 +12566,47 @@ function BookingSlots({ tableId, className }) {
|
|
|
12212
12566
|
buildLabel: "Build the booking page",
|
|
12213
12567
|
children: WHAT_A_BOOKING_PAGE_IS
|
|
12214
12568
|
}
|
|
12215
|
-
) : /* @__PURE__ */
|
|
12569
|
+
) : /* @__PURE__ */ jsxs45("p", { className: "text-xs text-muted-foreground", children: [
|
|
12216
12570
|
WHAT_A_BOOKING_PAGE_IS,
|
|
12217
12571
|
" Open the table the appointments should land in to make one."
|
|
12218
12572
|
] }) : null,
|
|
12219
|
-
/* @__PURE__ */
|
|
12573
|
+
/* @__PURE__ */ jsx49("ul", { className: "flex flex-col gap-2", children: pages.map((page) => {
|
|
12220
12574
|
const url = `${origin}${bookingPath2(page.form_id)}`;
|
|
12221
12575
|
const mayOpen = levels.data?.[page.table_id] === "admin";
|
|
12222
12576
|
const open = page.published_at !== null && page.closed_at === null;
|
|
12223
|
-
return /* @__PURE__ */
|
|
12224
|
-
/* @__PURE__ */
|
|
12225
|
-
/* @__PURE__ */
|
|
12226
|
-
/* @__PURE__ */
|
|
12577
|
+
return /* @__PURE__ */ jsxs45("li", { className: "rounded-md border p-2.5", "data-testid": "booking-page", children: [
|
|
12578
|
+
/* @__PURE__ */ jsxs45("div", { className: "flex items-center gap-2", children: [
|
|
12579
|
+
/* @__PURE__ */ jsx49("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: page.title ?? page.slug }),
|
|
12580
|
+
/* @__PURE__ */ jsx49(Badge16, { variant: page.state === "open" ? "default" : "secondary", children: page.state })
|
|
12227
12581
|
] }),
|
|
12228
|
-
/* @__PURE__ */
|
|
12229
|
-
/* @__PURE__ */
|
|
12230
|
-
/* @__PURE__ */
|
|
12582
|
+
/* @__PURE__ */ jsx49("p", { className: "mt-0.5 text-xs text-muted-foreground", children: STATE_WORDS[page.state] ?? page.state }),
|
|
12583
|
+
/* @__PURE__ */ jsxs45("p", { className: "mt-1.5 text-xs", children: [
|
|
12584
|
+
/* @__PURE__ */ jsx49("span", { className: "font-medium", children: page.upcoming }),
|
|
12231
12585
|
" coming up",
|
|
12232
12586
|
" \xB7 ",
|
|
12233
|
-
/* @__PURE__ */
|
|
12587
|
+
/* @__PURE__ */ jsx49("span", { className: "font-medium", children: page.booked }),
|
|
12234
12588
|
" booked in all",
|
|
12235
|
-
page.held > 0 ? /* @__PURE__ */
|
|
12589
|
+
page.held > 0 ? /* @__PURE__ */ jsxs45(Fragment23, { children: [
|
|
12236
12590
|
" \xB7 ",
|
|
12237
|
-
/* @__PURE__ */
|
|
12591
|
+
/* @__PURE__ */ jsx49("span", { className: "font-medium", children: page.held }),
|
|
12238
12592
|
" being held right now"
|
|
12239
12593
|
] }) : null,
|
|
12240
|
-
page.cancelled > 0 ? /* @__PURE__ */
|
|
12594
|
+
page.cancelled > 0 ? /* @__PURE__ */ jsxs45(Fragment23, { children: [
|
|
12241
12595
|
" \xB7 ",
|
|
12242
|
-
/* @__PURE__ */
|
|
12596
|
+
/* @__PURE__ */ jsx49("span", { className: "font-medium", children: page.cancelled }),
|
|
12243
12597
|
" cancelled"
|
|
12244
12598
|
] }) : null,
|
|
12245
|
-
/* @__PURE__ */
|
|
12599
|
+
/* @__PURE__ */ jsxs45("span", { className: "text-muted-foreground", children: [
|
|
12246
12600
|
" \xB7 ",
|
|
12247
12601
|
page.slot_minutes,
|
|
12248
12602
|
" minutes each"
|
|
12249
12603
|
] })
|
|
12250
12604
|
] }),
|
|
12251
|
-
/* @__PURE__ */
|
|
12252
|
-
/* @__PURE__ */
|
|
12253
|
-
/* @__PURE__ */
|
|
12254
|
-
mayOpen ? /* @__PURE__ */
|
|
12255
|
-
|
|
12605
|
+
/* @__PURE__ */ jsx49("p", { className: "mt-1 text-xs text-muted-foreground", children: nextInWords(page) }),
|
|
12606
|
+
/* @__PURE__ */ jsxs45("div", { className: "mt-2 flex flex-wrap items-center gap-1.5", children: [
|
|
12607
|
+
/* @__PURE__ */ jsx49(Button40, { size: "sm", variant: "outline", onClick: () => void copy(url, page.form_id), children: copied === page.form_id ? "Copied" : "Copy link" }),
|
|
12608
|
+
mayOpen ? /* @__PURE__ */ jsx49(
|
|
12609
|
+
Button40,
|
|
12256
12610
|
{
|
|
12257
12611
|
size: "sm",
|
|
12258
12612
|
variant: "ghost",
|
|
@@ -12262,13 +12616,13 @@ function BookingSlots({ tableId, className }) {
|
|
|
12262
12616
|
}
|
|
12263
12617
|
) : null
|
|
12264
12618
|
] }),
|
|
12265
|
-
shown && shown === url ? /* @__PURE__ */
|
|
12619
|
+
shown && shown === url ? /* @__PURE__ */ jsxs45("p", { className: "mt-1.5 break-all rounded border border-dashed px-2 py-1 text-xs", children: [
|
|
12266
12620
|
"This browser would not let the page copy for you, so here it is to copy by hand: ",
|
|
12267
12621
|
url
|
|
12268
12622
|
] }) : null
|
|
12269
12623
|
] }, page.form_id);
|
|
12270
12624
|
}) }),
|
|
12271
|
-
pages.length > 0 && !levels.loading && levels.data && subjectIds.every((id) => levels.data?.[id] !== "admin") ? /* @__PURE__ */
|
|
12625
|
+
pages.length > 0 && !levels.loading && levels.data && subjectIds.every((id) => levels.data?.[id] !== "admin") ? /* @__PURE__ */ jsx49("p", { className: "text-xs text-muted-foreground", children: NO_ADMIN2 }) : null
|
|
12272
12626
|
] });
|
|
12273
12627
|
}
|
|
12274
12628
|
function nextInWords(page) {
|
|
@@ -12300,18 +12654,18 @@ function nextInWords(page) {
|
|
|
12300
12654
|
}
|
|
12301
12655
|
|
|
12302
12656
|
// src/CaptureSheet.tsx
|
|
12303
|
-
import { useCallback as
|
|
12304
|
-
import { useFields as useFields21, useRecordsClient as
|
|
12305
|
-
import { Button as
|
|
12657
|
+
import { useCallback as useCallback32, useEffect as useEffect36, useRef as useRef13, useState as useState46 } from "react";
|
|
12658
|
+
import { useFields as useFields21, useRecordsClient as useRecordsClient38, useTable as useTable20 } from "@ai-matrx/records/react";
|
|
12659
|
+
import { Button as Button42, Input as Input4, Skeleton as Skeleton29, Textarea as Textarea3, cn as cn45 } from "@ai-matrx/design-system";
|
|
12306
12660
|
|
|
12307
12661
|
// src/CaptureRun.tsx
|
|
12308
|
-
import { useCallback as
|
|
12662
|
+
import { useCallback as useCallback31, useEffect as useEffect35, useMemo as useMemo30, useRef as useRef12, useState as useState45 } from "react";
|
|
12309
12663
|
import {
|
|
12310
12664
|
openCaptureQueue
|
|
12311
12665
|
} from "@ai-matrx/records";
|
|
12312
|
-
import { useRecordsClient as
|
|
12313
|
-
import { Button as
|
|
12314
|
-
import { jsx as
|
|
12666
|
+
import { useRecordsClient as useRecordsClient37 } from "@ai-matrx/records/react";
|
|
12667
|
+
import { Button as Button41, Input as Input3, Skeleton as Skeleton28, Textarea as Textarea2, cn as cn44 } from "@ai-matrx/design-system";
|
|
12668
|
+
import { jsx as jsx50, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
12315
12669
|
function controlFor(field) {
|
|
12316
12670
|
if (!field) return "text";
|
|
12317
12671
|
const label = `${field.key} ${field.label ?? ""}`.toLowerCase();
|
|
@@ -12348,21 +12702,21 @@ function whereWeAre(timeoutMs = 4e3) {
|
|
|
12348
12702
|
});
|
|
12349
12703
|
}
|
|
12350
12704
|
function CaptureRun({ sheetId, face: given, className }) {
|
|
12351
|
-
const client =
|
|
12705
|
+
const client = useRecordsClient37();
|
|
12352
12706
|
const host = useRecordsUi();
|
|
12353
|
-
const [face, setFace] =
|
|
12354
|
-
const [loadFailed, setLoadFailed] =
|
|
12355
|
-
const [at, setAt] =
|
|
12356
|
-
const [answers, setAnswers] =
|
|
12357
|
-
const [files, setFiles] =
|
|
12358
|
-
const [missing, setMissing] =
|
|
12359
|
-
const [done, setDone] =
|
|
12360
|
-
const [counts, setCounts] =
|
|
12361
|
-
const [items, setItems] =
|
|
12362
|
-
const [lastSynced, setLastSynced] =
|
|
12363
|
-
const [sending, setSending] =
|
|
12707
|
+
const [face, setFace] = useState45(given);
|
|
12708
|
+
const [loadFailed, setLoadFailed] = useState45(null);
|
|
12709
|
+
const [at, setAt] = useState45(0);
|
|
12710
|
+
const [answers, setAnswers] = useState45({});
|
|
12711
|
+
const [files, setFiles] = useState45({});
|
|
12712
|
+
const [missing, setMissing] = useState45(null);
|
|
12713
|
+
const [done, setDone] = useState45(null);
|
|
12714
|
+
const [counts, setCounts] = useState45({ waiting: 0, sending: 0, refused: 0, landed: 0 });
|
|
12715
|
+
const [items, setItems] = useState45([]);
|
|
12716
|
+
const [lastSynced, setLastSynced] = useState45(null);
|
|
12717
|
+
const [sending, setSending] = useState45(false);
|
|
12364
12718
|
const queueRef = useRef12(null);
|
|
12365
|
-
|
|
12719
|
+
useEffect35(() => {
|
|
12366
12720
|
const q2 = openCaptureQueue({
|
|
12367
12721
|
onChange: (c, all) => {
|
|
12368
12722
|
setCounts(c);
|
|
@@ -12400,7 +12754,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12400
12754
|
void q2.sync().then(() => void q2.lastSyncedAt().then(setLastSynced));
|
|
12401
12755
|
return () => q2.dispose();
|
|
12402
12756
|
}, [client, host]);
|
|
12403
|
-
|
|
12757
|
+
useEffect35(() => {
|
|
12404
12758
|
if (given !== void 0) return;
|
|
12405
12759
|
let cancelled = false;
|
|
12406
12760
|
void client.captureOpen({ sheet_id: sheetId }).then((res) => {
|
|
@@ -12412,7 +12766,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12412
12766
|
cancelled = true;
|
|
12413
12767
|
};
|
|
12414
12768
|
}, [client, given, sheetId]);
|
|
12415
|
-
const questions =
|
|
12769
|
+
const questions = useMemo30(() => {
|
|
12416
12770
|
const asked = face?.presentation?.questions ?? [];
|
|
12417
12771
|
if (asked.length > 0) return asked;
|
|
12418
12772
|
return (face?.fields ?? []).map((f) => ({
|
|
@@ -12422,11 +12776,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12422
12776
|
required: f.required
|
|
12423
12777
|
}));
|
|
12424
12778
|
}, [face]);
|
|
12425
|
-
const fieldOf =
|
|
12779
|
+
const fieldOf = useCallback31(
|
|
12426
12780
|
(key) => (face?.fields ?? []).find((f) => f.key === key),
|
|
12427
12781
|
[face]
|
|
12428
12782
|
);
|
|
12429
|
-
const sync =
|
|
12783
|
+
const sync = useCallback31(async () => {
|
|
12430
12784
|
const q2 = queueRef.current;
|
|
12431
12785
|
if (!q2) return;
|
|
12432
12786
|
setSending(true);
|
|
@@ -12439,7 +12793,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12439
12793
|
setSending(false);
|
|
12440
12794
|
}
|
|
12441
12795
|
}, []);
|
|
12442
|
-
const answered =
|
|
12796
|
+
const answered = useCallback31(
|
|
12443
12797
|
(key) => {
|
|
12444
12798
|
if (files[key]) return true;
|
|
12445
12799
|
const v = answers[key];
|
|
@@ -12484,24 +12838,24 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12484
12838
|
if (online) await sync();
|
|
12485
12839
|
}
|
|
12486
12840
|
if (loadFailed) {
|
|
12487
|
-
return /* @__PURE__ */
|
|
12841
|
+
return /* @__PURE__ */ jsx50("section", { className: cn44("mx-auto w-full max-w-sm p-4", className), children: /* @__PURE__ */ jsx50("p", { className: "text-sm text-destructive", "data-testid": "capture-refusal", children: loadFailed }) });
|
|
12488
12842
|
}
|
|
12489
12843
|
if (face === void 0) {
|
|
12490
|
-
return /* @__PURE__ */
|
|
12844
|
+
return /* @__PURE__ */ jsx50(Skeleton28, { className: cn44("mx-auto h-64 w-full max-w-sm", className) });
|
|
12491
12845
|
}
|
|
12492
12846
|
if (face === null) {
|
|
12493
|
-
return /* @__PURE__ */
|
|
12847
|
+
return /* @__PURE__ */ jsx50("section", { className: cn44("mx-auto w-full max-w-sm p-4", className), children: /* @__PURE__ */ jsx50("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." }) });
|
|
12494
12848
|
}
|
|
12495
12849
|
const waiting = counts.waiting + counts.sending;
|
|
12496
|
-
const queueLine = /* @__PURE__ */
|
|
12497
|
-
/* @__PURE__ */
|
|
12498
|
-
counts.refused > 0 ? /* @__PURE__ */
|
|
12850
|
+
const queueLine = /* @__PURE__ */ jsxs46("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", "data-testid": "capture-queue-line", children: [
|
|
12851
|
+
/* @__PURE__ */ jsx50("span", { className: "tabular-nums", "data-testid": "capture-waiting", children: waiting === 0 ? "Nothing waiting" : `${waiting} waiting` }),
|
|
12852
|
+
counts.refused > 0 ? /* @__PURE__ */ jsxs46("span", { className: "text-destructive tabular-nums", "data-testid": "capture-refused", children: [
|
|
12499
12853
|
counts.refused,
|
|
12500
12854
|
" to fix"
|
|
12501
12855
|
] }) : null,
|
|
12502
|
-
/* @__PURE__ */
|
|
12503
|
-
waiting > 0 || counts.refused > 0 ? /* @__PURE__ */
|
|
12504
|
-
|
|
12856
|
+
/* @__PURE__ */ jsx50("span", { className: "ml-auto", "data-testid": "capture-last-synced", children: lastSynced ? `Last synced ${new Date(lastSynced).toLocaleTimeString()}` : "Not synced yet" }),
|
|
12857
|
+
waiting > 0 || counts.refused > 0 ? /* @__PURE__ */ jsx50(
|
|
12858
|
+
Button41,
|
|
12505
12859
|
{
|
|
12506
12860
|
size: "sm",
|
|
12507
12861
|
variant: "ghost",
|
|
@@ -12513,11 +12867,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12513
12867
|
}
|
|
12514
12868
|
) : null
|
|
12515
12869
|
] });
|
|
12516
|
-
const queuePanel = items.filter((i) => i.state !== "landed").length > 0 ? /* @__PURE__ */
|
|
12517
|
-
/* @__PURE__ */
|
|
12518
|
-
/* @__PURE__ */
|
|
12519
|
-
i.state === "refused" ? /* @__PURE__ */
|
|
12520
|
-
|
|
12870
|
+
const queuePanel = items.filter((i) => i.state !== "landed").length > 0 ? /* @__PURE__ */ jsx50("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__ */ jsxs46("li", { className: "flex items-start gap-2 text-[11px]", children: [
|
|
12871
|
+
/* @__PURE__ */ jsx50("span", { className: "tabular-nums text-muted-foreground", children: new Date(i.captured_at).toLocaleTimeString() }),
|
|
12872
|
+
/* @__PURE__ */ jsx50("span", { className: cn44("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." }),
|
|
12873
|
+
i.state === "refused" ? /* @__PURE__ */ jsx50(
|
|
12874
|
+
Button41,
|
|
12521
12875
|
{
|
|
12522
12876
|
size: "sm",
|
|
12523
12877
|
variant: "ghost",
|
|
@@ -12528,19 +12882,19 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12528
12882
|
) : null
|
|
12529
12883
|
] }, i.client_key)) }) : null;
|
|
12530
12884
|
if (!face.may_capture) {
|
|
12531
|
-
return /* @__PURE__ */
|
|
12532
|
-
/* @__PURE__ */
|
|
12533
|
-
/* @__PURE__ */
|
|
12885
|
+
return /* @__PURE__ */ jsxs46("section", { className: cn44("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
12886
|
+
/* @__PURE__ */ jsx50("h1", { className: "text-lg font-medium", children: face.title }),
|
|
12887
|
+
/* @__PURE__ */ jsx50("p", { className: "text-sm", "data-testid": "capture-refusal", children: face.message }),
|
|
12534
12888
|
queueLine,
|
|
12535
12889
|
queuePanel
|
|
12536
12890
|
] });
|
|
12537
12891
|
}
|
|
12538
12892
|
if (done) {
|
|
12539
12893
|
const thanks = face.presentation?.thank_you ?? {};
|
|
12540
|
-
return /* @__PURE__ */
|
|
12541
|
-
/* @__PURE__ */
|
|
12542
|
-
/* @__PURE__ */
|
|
12543
|
-
/* @__PURE__ */
|
|
12894
|
+
return /* @__PURE__ */ jsxs46("section", { className: cn44("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
12895
|
+
/* @__PURE__ */ jsx50("h2", { className: "text-lg font-medium", "data-testid": "capture-thankyou", children: thanks.title ?? "Logged" }),
|
|
12896
|
+
/* @__PURE__ */ jsx50("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." }),
|
|
12897
|
+
/* @__PURE__ */ jsx50(Button41, { className: "h-12", onClick: () => setDone(null), "data-testid": "capture-next", children: "Next one" }),
|
|
12544
12898
|
queueLine,
|
|
12545
12899
|
queuePanel
|
|
12546
12900
|
] });
|
|
@@ -12549,14 +12903,14 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12549
12903
|
const field = fieldOf(q.field);
|
|
12550
12904
|
const control = controlFor(field);
|
|
12551
12905
|
const last = at >= questions.length - 1;
|
|
12552
|
-
return /* @__PURE__ */
|
|
12553
|
-
/* @__PURE__ */
|
|
12554
|
-
/* @__PURE__ */
|
|
12906
|
+
return /* @__PURE__ */ jsxs46("section", { className: cn44("mx-auto flex w-full max-w-sm flex-col gap-3 p-4", className), children: [
|
|
12907
|
+
/* @__PURE__ */ jsxs46("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", children: [
|
|
12908
|
+
/* @__PURE__ */ jsxs46("span", { className: "tabular-nums", "data-testid": "capture-progress", children: [
|
|
12555
12909
|
at + 1,
|
|
12556
12910
|
" of ",
|
|
12557
12911
|
questions.length
|
|
12558
12912
|
] }),
|
|
12559
|
-
/* @__PURE__ */
|
|
12913
|
+
/* @__PURE__ */ jsx50("div", { className: "h-1 flex-1 overflow-hidden rounded bg-muted", children: /* @__PURE__ */ jsx50(
|
|
12560
12914
|
"div",
|
|
12561
12915
|
{
|
|
12562
12916
|
className: "h-full bg-primary transition-[width] duration-200",
|
|
@@ -12564,7 +12918,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12564
12918
|
}
|
|
12565
12919
|
) })
|
|
12566
12920
|
] }),
|
|
12567
|
-
/* @__PURE__ */
|
|
12921
|
+
/* @__PURE__ */ jsxs46(
|
|
12568
12922
|
"label",
|
|
12569
12923
|
{
|
|
12570
12924
|
className: "text-xl font-medium leading-snug",
|
|
@@ -12572,13 +12926,13 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12572
12926
|
"data-testid": "capture-ask",
|
|
12573
12927
|
children: [
|
|
12574
12928
|
q.ask ?? q.field,
|
|
12575
|
-
q.required ? /* @__PURE__ */
|
|
12929
|
+
q.required ? /* @__PURE__ */ jsx50("span", { className: "text-muted-foreground", children: " *" }) : null
|
|
12576
12930
|
]
|
|
12577
12931
|
}
|
|
12578
12932
|
),
|
|
12579
|
-
q.help ? /* @__PURE__ */
|
|
12580
|
-
control === "photo" || control === "voice" ? !host.upload ? /* @__PURE__ */
|
|
12581
|
-
/* @__PURE__ */
|
|
12933
|
+
q.help ? /* @__PURE__ */ jsx50("p", { className: "-mt-1 text-sm text-muted-foreground", children: q.help }) : null,
|
|
12934
|
+
control === "photo" || control === "voice" ? !host.upload ? /* @__PURE__ */ jsx50("p", { className: "rounded border border-dashed px-2 py-2 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : /* @__PURE__ */ jsxs46("div", { className: "flex flex-col gap-1", children: [
|
|
12935
|
+
/* @__PURE__ */ jsx50(
|
|
12582
12936
|
"input",
|
|
12583
12937
|
{
|
|
12584
12938
|
id: `capture-${q.field}`,
|
|
@@ -12596,11 +12950,11 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12596
12950
|
}
|
|
12597
12951
|
}
|
|
12598
12952
|
),
|
|
12599
|
-
files[q.field] ? /* @__PURE__ */
|
|
12953
|
+
files[q.field] ? /* @__PURE__ */ jsxs46("p", { className: "text-[11px] text-muted-foreground", "data-testid": `capture-have-${q.field}`, children: [
|
|
12600
12954
|
files[q.field].name,
|
|
12601
12955
|
" is on the phone. It goes up with the capture."
|
|
12602
12956
|
] }) : null
|
|
12603
|
-
] }) : control === "number" ? /* @__PURE__ */
|
|
12957
|
+
] }) : control === "number" ? /* @__PURE__ */ jsx50(
|
|
12604
12958
|
Input3,
|
|
12605
12959
|
{
|
|
12606
12960
|
id: `capture-${q.field}`,
|
|
@@ -12616,7 +12970,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12616
12970
|
setMissing(null);
|
|
12617
12971
|
}
|
|
12618
12972
|
}
|
|
12619
|
-
) : /* @__PURE__ */
|
|
12973
|
+
) : /* @__PURE__ */ jsx50(
|
|
12620
12974
|
Textarea2,
|
|
12621
12975
|
{
|
|
12622
12976
|
id: `capture-${q.field}`,
|
|
@@ -12631,10 +12985,10 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12631
12985
|
}
|
|
12632
12986
|
}
|
|
12633
12987
|
),
|
|
12634
|
-
missing ? /* @__PURE__ */
|
|
12635
|
-
/* @__PURE__ */
|
|
12636
|
-
at > 0 ? /* @__PURE__ */
|
|
12637
|
-
|
|
12988
|
+
missing ? /* @__PURE__ */ jsx50("p", { className: "text-sm text-destructive", "data-testid": "capture-missing", children: missing }) : null,
|
|
12989
|
+
/* @__PURE__ */ jsxs46("div", { className: "flex items-center gap-2", children: [
|
|
12990
|
+
at > 0 ? /* @__PURE__ */ jsx50(
|
|
12991
|
+
Button41,
|
|
12638
12992
|
{
|
|
12639
12993
|
variant: "ghost",
|
|
12640
12994
|
className: "h-12 px-3",
|
|
@@ -12643,16 +12997,16 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12643
12997
|
children: "Back"
|
|
12644
12998
|
}
|
|
12645
12999
|
) : null,
|
|
12646
|
-
last ? /* @__PURE__ */
|
|
12647
|
-
|
|
13000
|
+
last ? /* @__PURE__ */ jsx50(
|
|
13001
|
+
Button41,
|
|
12648
13002
|
{
|
|
12649
13003
|
className: "h-12 flex-1 text-base",
|
|
12650
13004
|
onClick: () => void capture(),
|
|
12651
13005
|
"data-testid": "capture-submit",
|
|
12652
13006
|
children: "Capture"
|
|
12653
13007
|
}
|
|
12654
|
-
) : /* @__PURE__ */
|
|
12655
|
-
|
|
13008
|
+
) : /* @__PURE__ */ jsx50(
|
|
13009
|
+
Button41,
|
|
12656
13010
|
{
|
|
12657
13011
|
className: "h-12 flex-1 text-base",
|
|
12658
13012
|
onClick: () => setAt(at + 1),
|
|
@@ -12667,7 +13021,7 @@ function CaptureRun({ sheetId, face: given, className }) {
|
|
|
12667
13021
|
}
|
|
12668
13022
|
|
|
12669
13023
|
// src/CaptureSheet.tsx
|
|
12670
|
-
import { Fragment as
|
|
13024
|
+
import { Fragment as Fragment24, jsx as jsx51, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
12671
13025
|
var CAPTURE_MODES = ["reading", "photo", "voice"];
|
|
12672
13026
|
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.";
|
|
12673
13027
|
function mintClientKey() {
|
|
@@ -12687,8 +13041,8 @@ function CaptureSheet({
|
|
|
12687
13041
|
attachmentField,
|
|
12688
13042
|
className
|
|
12689
13043
|
}) {
|
|
12690
|
-
if (sheetId) return /* @__PURE__ */
|
|
12691
|
-
return /* @__PURE__ */
|
|
13044
|
+
if (sheetId) return /* @__PURE__ */ jsx51(CaptureRun, { sheetId, className });
|
|
13045
|
+
return /* @__PURE__ */ jsx51(
|
|
12692
13046
|
AdHocCaptureSheet,
|
|
12693
13047
|
{
|
|
12694
13048
|
tableId,
|
|
@@ -12706,21 +13060,21 @@ function AdHocCaptureSheet({
|
|
|
12706
13060
|
attachmentField,
|
|
12707
13061
|
className
|
|
12708
13062
|
}) {
|
|
12709
|
-
const client =
|
|
13063
|
+
const client = useRecordsClient38();
|
|
12710
13064
|
const host = useRecordsUi();
|
|
12711
13065
|
const table = useTable20(tableId);
|
|
12712
13066
|
const fields = useFields21(tableId);
|
|
12713
|
-
const [mode, setMode] =
|
|
12714
|
-
const [reading, setReading] =
|
|
12715
|
-
const [note, setNote] =
|
|
12716
|
-
const [fileId, setFileId] =
|
|
12717
|
-
const [pending, setPending] =
|
|
12718
|
-
const [saved, setSaved] =
|
|
12719
|
-
const [error, setError] =
|
|
12720
|
-
const [uploadError, setUploadError] =
|
|
12721
|
-
const [flushing, setFlushing] =
|
|
13067
|
+
const [mode, setMode] = useState46("reading");
|
|
13068
|
+
const [reading, setReading] = useState46("");
|
|
13069
|
+
const [note, setNote] = useState46("");
|
|
13070
|
+
const [fileId, setFileId] = useState46(null);
|
|
13071
|
+
const [pending, setPending] = useState46(null);
|
|
13072
|
+
const [saved, setSaved] = useState46([]);
|
|
13073
|
+
const [error, setError] = useState46(null);
|
|
13074
|
+
const [uploadError, setUploadError] = useState46(null);
|
|
13075
|
+
const [flushing, setFlushing] = useState46(false);
|
|
12722
13076
|
const queue = useRef13([]);
|
|
12723
|
-
const keep =
|
|
13077
|
+
const keep = useCallback32(
|
|
12724
13078
|
async (next) => {
|
|
12725
13079
|
queue.current = next;
|
|
12726
13080
|
setPending(next);
|
|
@@ -12728,7 +13082,7 @@ function AdHocCaptureSheet({
|
|
|
12728
13082
|
},
|
|
12729
13083
|
[host]
|
|
12730
13084
|
);
|
|
12731
|
-
|
|
13085
|
+
useEffect36(() => {
|
|
12732
13086
|
let cancelled = false;
|
|
12733
13087
|
void (async () => {
|
|
12734
13088
|
const held = host.captureQueue ? await host.captureQueue.load() : [];
|
|
@@ -12740,7 +13094,7 @@ function AdHocCaptureSheet({
|
|
|
12740
13094
|
cancelled = true;
|
|
12741
13095
|
};
|
|
12742
13096
|
}, [host]);
|
|
12743
|
-
const resolved =
|
|
13097
|
+
const resolved = useCallback32(() => {
|
|
12744
13098
|
const all = fields.data ?? [];
|
|
12745
13099
|
return {
|
|
12746
13100
|
reading: readingField ?? all.find((f) => f.type === "range")?.key ?? null,
|
|
@@ -12748,7 +13102,7 @@ function AdHocCaptureSheet({
|
|
|
12748
13102
|
attachment: attachmentField ?? all.find((f) => f.format === "file" || f.format === "image")?.key ?? null
|
|
12749
13103
|
};
|
|
12750
13104
|
}, [attachmentField, fields.data, noteField, readingField, table.data]);
|
|
12751
|
-
const flush =
|
|
13105
|
+
const flush = useCallback32(async () => {
|
|
12752
13106
|
if (flushing || queue.current.length === 0) return;
|
|
12753
13107
|
setFlushing(true);
|
|
12754
13108
|
const left = [];
|
|
@@ -12800,14 +13154,14 @@ function AdHocCaptureSheet({
|
|
|
12800
13154
|
await keep([...queue.current, item]);
|
|
12801
13155
|
await flush();
|
|
12802
13156
|
}
|
|
12803
|
-
if (table.error) return /* @__PURE__ */
|
|
12804
|
-
if (fields.error) return /* @__PURE__ */
|
|
12805
|
-
if (fields.loading || pending === null) return /* @__PURE__ */
|
|
13157
|
+
if (table.error) return /* @__PURE__ */ jsx51(RefusalNotice, { error: table.error, className });
|
|
13158
|
+
if (fields.error) return /* @__PURE__ */ jsx51(RefusalNotice, { error: fields.error, className });
|
|
13159
|
+
if (fields.loading || pending === null) return /* @__PURE__ */ jsx51(Skeleton29, { className: cn45("h-64 w-full", className) });
|
|
12806
13160
|
const keys = resolved();
|
|
12807
|
-
return /* @__PURE__ */
|
|
12808
|
-
/* @__PURE__ */
|
|
12809
|
-
CAPTURE_MODES.map((m) => /* @__PURE__ */
|
|
12810
|
-
|
|
13161
|
+
return /* @__PURE__ */ jsxs47("section", { className: cn45("mx-auto flex w-full max-w-sm flex-col gap-2", className), children: [
|
|
13162
|
+
/* @__PURE__ */ jsxs47("header", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
13163
|
+
CAPTURE_MODES.map((m) => /* @__PURE__ */ jsx51(
|
|
13164
|
+
Button42,
|
|
12811
13165
|
{
|
|
12812
13166
|
size: "sm",
|
|
12813
13167
|
variant: m === mode ? "default" : "ghost",
|
|
@@ -12817,10 +13171,10 @@ function AdHocCaptureSheet({
|
|
|
12817
13171
|
},
|
|
12818
13172
|
m
|
|
12819
13173
|
)),
|
|
12820
|
-
/* @__PURE__ */
|
|
13174
|
+
/* @__PURE__ */ jsx51("span", { className: "ml-auto tabular-nums", children: pending.length > 0 ? `${pending.length} waiting` : `${saved.length} saved` })
|
|
12821
13175
|
] }),
|
|
12822
|
-
error ? /* @__PURE__ */
|
|
12823
|
-
mode === "reading" ? keys.reading ? /* @__PURE__ */
|
|
13176
|
+
error ? /* @__PURE__ */ jsx51(RefusalNotice, { error }) : null,
|
|
13177
|
+
mode === "reading" ? keys.reading ? /* @__PURE__ */ jsx51(
|
|
12824
13178
|
Input4,
|
|
12825
13179
|
{
|
|
12826
13180
|
"aria-label": "Reading",
|
|
@@ -12830,22 +13184,22 @@ function AdHocCaptureSheet({
|
|
|
12830
13184
|
value: reading,
|
|
12831
13185
|
onChange: (e) => setReading(e.target.value)
|
|
12832
13186
|
}
|
|
12833
|
-
) : /* @__PURE__ */
|
|
13187
|
+
) : /* @__PURE__ */ jsxs47("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
12834
13188
|
table.data?.name ?? "This table",
|
|
12835
13189
|
" 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 ",
|
|
12836
|
-
/* @__PURE__ */
|
|
13190
|
+
/* @__PURE__ */ jsx51("code", { children: "readingField" }),
|
|
12837
13191
|
"."
|
|
12838
13192
|
] }) : null,
|
|
12839
|
-
mode !== "reading" ? !host.upload ? /* @__PURE__ */
|
|
13193
|
+
mode !== "reading" ? !host.upload ? /* @__PURE__ */ jsx51("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: NO_UPLOAD_REASON }) : !keys.attachment ? /* @__PURE__ */ jsxs47("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
12840
13194
|
table.data?.name ?? "This table",
|
|
12841
13195
|
" has no Field a file id can go in, so a ",
|
|
12842
13196
|
mode,
|
|
12843
13197
|
" capture would upload the bytes and then have nowhere to record them. Add one, or name it with",
|
|
12844
13198
|
" ",
|
|
12845
|
-
/* @__PURE__ */
|
|
13199
|
+
/* @__PURE__ */ jsx51("code", { children: "attachmentField" }),
|
|
12846
13200
|
"."
|
|
12847
|
-
] }) : /* @__PURE__ */
|
|
12848
|
-
/* @__PURE__ */
|
|
13201
|
+
] }) : /* @__PURE__ */ jsxs47(Fragment24, { children: [
|
|
13202
|
+
/* @__PURE__ */ jsx51(
|
|
12849
13203
|
"input",
|
|
12850
13204
|
{
|
|
12851
13205
|
"aria-label": mode === "photo" ? "Take a photo" : "Record a voice note",
|
|
@@ -12864,10 +13218,10 @@ function AdHocCaptureSheet({
|
|
|
12864
13218
|
}
|
|
12865
13219
|
}
|
|
12866
13220
|
),
|
|
12867
|
-
fileId ? /* @__PURE__ */
|
|
12868
|
-
uploadError ? /* @__PURE__ */
|
|
13221
|
+
fileId ? /* @__PURE__ */ jsx51("p", { className: "text-[11px] text-muted-foreground", children: "Attached." }) : null,
|
|
13222
|
+
uploadError ? /* @__PURE__ */ jsx51("p", { className: "text-xs text-destructive", children: uploadError }) : null
|
|
12869
13223
|
] }) : null,
|
|
12870
|
-
/* @__PURE__ */
|
|
13224
|
+
/* @__PURE__ */ jsx51(
|
|
12871
13225
|
Textarea3,
|
|
12872
13226
|
{
|
|
12873
13227
|
"aria-label": "Note",
|
|
@@ -12878,12 +13232,12 @@ function AdHocCaptureSheet({
|
|
|
12878
13232
|
onChange: (e) => setNote(e.target.value)
|
|
12879
13233
|
}
|
|
12880
13234
|
),
|
|
12881
|
-
/* @__PURE__ */
|
|
12882
|
-
pending.length > 0 ? /* @__PURE__ */
|
|
12883
|
-
/* @__PURE__ */
|
|
12884
|
-
/* @__PURE__ */
|
|
12885
|
-
/* @__PURE__ */
|
|
12886
|
-
|
|
13235
|
+
/* @__PURE__ */ jsx51(Button42, { className: "h-12", onClick: () => void capture(), children: "Capture" }),
|
|
13236
|
+
pending.length > 0 ? /* @__PURE__ */ jsxs47("div", { className: "flex flex-col gap-1 rounded border p-2", children: [
|
|
13237
|
+
/* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
13238
|
+
/* @__PURE__ */ jsx51("span", { className: "font-medium", children: "Waiting to send" }),
|
|
13239
|
+
/* @__PURE__ */ jsx51(
|
|
13240
|
+
Button42,
|
|
12887
13241
|
{
|
|
12888
13242
|
size: "sm",
|
|
12889
13243
|
variant: "ghost",
|
|
@@ -12894,7 +13248,7 @@ function AdHocCaptureSheet({
|
|
|
12894
13248
|
}
|
|
12895
13249
|
)
|
|
12896
13250
|
] }),
|
|
12897
|
-
/* @__PURE__ */
|
|
13251
|
+
/* @__PURE__ */ jsx51("ul", { className: "flex flex-col gap-0.5", children: pending.map((item) => /* @__PURE__ */ jsxs47("li", { className: "text-[11px] text-muted-foreground", children: [
|
|
12898
13252
|
new Date(item.capturedAt).toLocaleTimeString(),
|
|
12899
13253
|
" \xB7 ",
|
|
12900
13254
|
item.attempts,
|
|
@@ -12902,23 +13256,23 @@ function AdHocCaptureSheet({
|
|
|
12902
13256
|
item.lastRefusal ? ` \xB7 ${item.lastRefusal}` : ""
|
|
12903
13257
|
] }, item.clientKey)) })
|
|
12904
13258
|
] }) : null,
|
|
12905
|
-
!host.captureQueue ? /* @__PURE__ */
|
|
13259
|
+
!host.captureQueue ? /* @__PURE__ */ jsx51("p", { className: "rounded border border-dashed px-2 py-1 text-[11px] text-muted-foreground", children: IN_MEMORY_QUEUE_REASON }) : null
|
|
12906
13260
|
] });
|
|
12907
13261
|
}
|
|
12908
13262
|
|
|
12909
13263
|
// src/PortalShell.tsx
|
|
12910
|
-
import { useCallback as
|
|
12911
|
-
import { useRecordsClient as
|
|
12912
|
-
import { Button as
|
|
12913
|
-
import { jsx as
|
|
13264
|
+
import { useCallback as useCallback33, useEffect as useEffect37, useState as useState47 } from "react";
|
|
13265
|
+
import { useRecordsClient as useRecordsClient39 } from "@ai-matrx/records/react";
|
|
13266
|
+
import { Button as Button43, Skeleton as Skeleton30, cn as cn46 } from "@ai-matrx/design-system";
|
|
13267
|
+
import { jsx as jsx52, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
12914
13268
|
function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
12915
|
-
const client =
|
|
12916
|
-
const [card, setCard] =
|
|
12917
|
-
const [reach, setReach] =
|
|
12918
|
-
const [error, setError] =
|
|
12919
|
-
const [open, setOpen] =
|
|
12920
|
-
const [sending, setSending] =
|
|
12921
|
-
const load =
|
|
13269
|
+
const client = useRecordsClient39();
|
|
13270
|
+
const [card, setCard] = useState47(null);
|
|
13271
|
+
const [reach, setReach] = useState47(null);
|
|
13272
|
+
const [error, setError] = useState47(null);
|
|
13273
|
+
const [open, setOpen] = useState47(null);
|
|
13274
|
+
const [sending, setSending] = useState47(false);
|
|
13275
|
+
const load = useCallback33(async () => {
|
|
12922
13276
|
const who = await client.externalPrincipalCard();
|
|
12923
13277
|
if (!who.ok) {
|
|
12924
13278
|
setError(who.error);
|
|
@@ -12933,23 +13287,23 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
|
12933
13287
|
}
|
|
12934
13288
|
setReach(reached.data.map((row) => row.resource_id));
|
|
12935
13289
|
}, [client, resourceType]);
|
|
12936
|
-
|
|
13290
|
+
useEffect37(() => {
|
|
12937
13291
|
void load();
|
|
12938
13292
|
}, [load]);
|
|
12939
13293
|
if (error) {
|
|
12940
|
-
return /* @__PURE__ */
|
|
13294
|
+
return /* @__PURE__ */ jsx52(RefusalNotice, { error, className });
|
|
12941
13295
|
}
|
|
12942
|
-
if (!card || reach === null) return /* @__PURE__ */
|
|
13296
|
+
if (!card || reach === null) return /* @__PURE__ */ jsx52(Skeleton30, { className: cn46("h-64 w-full", className) });
|
|
12943
13297
|
if (!card.external) {
|
|
12944
|
-
return /* @__PURE__ */
|
|
13298
|
+
return /* @__PURE__ */ jsx52("p", { className: cn46("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." });
|
|
12945
13299
|
}
|
|
12946
13300
|
if (sending && form) {
|
|
12947
|
-
return /* @__PURE__ */
|
|
12948
|
-
/* @__PURE__ */
|
|
12949
|
-
/* @__PURE__ */
|
|
12950
|
-
/* @__PURE__ */
|
|
13301
|
+
return /* @__PURE__ */ jsxs48("section", { className: cn46("flex min-h-0 flex-col gap-2", className), children: [
|
|
13302
|
+
/* @__PURE__ */ jsxs48("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13303
|
+
/* @__PURE__ */ jsx52("span", { className: "font-medium text-foreground", children: form.name }),
|
|
13304
|
+
/* @__PURE__ */ jsx52(Button43, { size: "sm", variant: "ghost", className: "ml-auto h-6 px-2 text-[11px]", onClick: () => setSending(false), children: "Back" })
|
|
12951
13305
|
] }),
|
|
12952
|
-
/* @__PURE__ */
|
|
13306
|
+
/* @__PURE__ */ jsx52(
|
|
12953
13307
|
FormRunner,
|
|
12954
13308
|
{
|
|
12955
13309
|
form,
|
|
@@ -12962,38 +13316,38 @@ function PortalShell({ tableId, form, resourceType = "record", className }) {
|
|
|
12962
13316
|
] });
|
|
12963
13317
|
}
|
|
12964
13318
|
if (open) {
|
|
12965
|
-
return /* @__PURE__ */
|
|
13319
|
+
return /* @__PURE__ */ jsx52("section", { className: cn46("flex min-h-0 flex-col gap-2", className), children: /* @__PURE__ */ jsx52(Peek, { tableId, recordId: open, onClose: () => setOpen(null) }) });
|
|
12966
13320
|
}
|
|
12967
|
-
return /* @__PURE__ */
|
|
12968
|
-
/* @__PURE__ */
|
|
12969
|
-
/* @__PURE__ */
|
|
12970
|
-
/* @__PURE__ */
|
|
12971
|
-
form ? /* @__PURE__ */
|
|
13321
|
+
return /* @__PURE__ */ jsxs48("section", { className: cn46("flex min-h-0 flex-col gap-2", className), children: [
|
|
13322
|
+
/* @__PURE__ */ jsxs48("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13323
|
+
/* @__PURE__ */ jsx52("span", { className: "font-medium text-foreground", children: "Shared with you" }),
|
|
13324
|
+
/* @__PURE__ */ jsx52("span", { className: "tabular-nums", children: reach.length }),
|
|
13325
|
+
form ? /* @__PURE__ */ jsx52(Button43, { size: "sm", className: "ml-auto h-7 px-2 text-[11px]", onClick: () => setSending(true), children: form.submitLabel ?? form.name }) : null
|
|
12972
13326
|
] }),
|
|
12973
13327
|
reach.length === 0 ? (
|
|
12974
13328
|
// EMPTY, AND IT SAYS WHICH EMPTY. "Nobody has shared anything with you"
|
|
12975
13329
|
// and "the store would not tell us" are different sentences, and a
|
|
12976
13330
|
// person acts on them differently.
|
|
12977
|
-
/* @__PURE__ */
|
|
13331
|
+
/* @__PURE__ */ jsxs48("p", { className: "rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", children: [
|
|
12978
13332
|
"Nothing has been shared with you yet. ",
|
|
12979
13333
|
card.explanation,
|
|
12980
13334
|
" 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."
|
|
12981
13335
|
] })
|
|
12982
|
-
) : /* @__PURE__ */
|
|
13336
|
+
) : /* @__PURE__ */ jsx52("ul", { className: "flex min-h-0 flex-col gap-1 overflow-y-auto", children: reach.map((id) => /* @__PURE__ */ jsx52("li", { children: /* @__PURE__ */ jsx52(
|
|
12983
13337
|
"button",
|
|
12984
13338
|
{
|
|
12985
13339
|
type: "button",
|
|
12986
13340
|
className: "w-full truncate rounded border px-2 py-1.5 text-left text-xs hover:bg-muted",
|
|
12987
13341
|
onClick: () => setOpen(id),
|
|
12988
|
-
children: /* @__PURE__ */
|
|
13342
|
+
children: /* @__PURE__ */ jsx52(PortalRow, { tableId, recordId: id })
|
|
12989
13343
|
}
|
|
12990
13344
|
) }, id)) })
|
|
12991
13345
|
] });
|
|
12992
13346
|
}
|
|
12993
13347
|
function PortalRow({ tableId, recordId }) {
|
|
12994
|
-
const client =
|
|
12995
|
-
const [title, setTitle] =
|
|
12996
|
-
|
|
13348
|
+
const client = useRecordsClient39();
|
|
13349
|
+
const [title, setTitle] = useState47(null);
|
|
13350
|
+
useEffect37(() => {
|
|
12997
13351
|
let cancelled = false;
|
|
12998
13352
|
void client.recordRead({ record_id: recordId }).then((answered) => {
|
|
12999
13353
|
if (cancelled) return;
|
|
@@ -13009,22 +13363,22 @@ function PortalRow({ tableId, recordId }) {
|
|
|
13009
13363
|
cancelled = true;
|
|
13010
13364
|
};
|
|
13011
13365
|
}, [client, recordId, tableId]);
|
|
13012
|
-
return /* @__PURE__ */
|
|
13366
|
+
return /* @__PURE__ */ jsx52("span", { children: title ?? "\u2026" });
|
|
13013
13367
|
}
|
|
13014
13368
|
|
|
13015
13369
|
// src/PublicViewPage.tsx
|
|
13016
|
-
import { useCallback as
|
|
13017
|
-
import { useRecordsClient as
|
|
13018
|
-
import { Skeleton as
|
|
13019
|
-
import { jsx as
|
|
13370
|
+
import { useCallback as useCallback34, useEffect as useEffect38, useState as useState48 } from "react";
|
|
13371
|
+
import { useRecordsClient as useRecordsClient40 } from "@ai-matrx/records/react";
|
|
13372
|
+
import { Skeleton as Skeleton31, cn as cn47 } from "@ai-matrx/design-system";
|
|
13373
|
+
import { jsx as jsx53, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
13020
13374
|
function PublicViewPage({ slug, className }) {
|
|
13021
|
-
const client =
|
|
13022
|
-
const [binding, setBinding] =
|
|
13023
|
-
const [rows, setRows] =
|
|
13024
|
-
const [fields, setFields] =
|
|
13025
|
-
const [error, setError] =
|
|
13026
|
-
const [gap, setGap] =
|
|
13027
|
-
const load =
|
|
13375
|
+
const client = useRecordsClient40();
|
|
13376
|
+
const [binding, setBinding] = useState48(null);
|
|
13377
|
+
const [rows, setRows] = useState48(null);
|
|
13378
|
+
const [fields, setFields] = useState48(null);
|
|
13379
|
+
const [error, setError] = useState48(null);
|
|
13380
|
+
const [gap, setGap] = useState48(null);
|
|
13381
|
+
const load = useCallback34(async () => {
|
|
13028
13382
|
const notice = await client.worldPublishGapNotice();
|
|
13029
13383
|
if (notice.ok) setGap(notice.data);
|
|
13030
13384
|
const resolved = await client.resolvePublishBinding({ slug });
|
|
@@ -13057,48 +13411,48 @@ function PublicViewPage({ slug, className }) {
|
|
|
13057
13411
|
}
|
|
13058
13412
|
setRows([{ id: found.resource_id, document: read.data.document, level: "viewer", hidden: read.data.hidden }]);
|
|
13059
13413
|
}, [client, slug]);
|
|
13060
|
-
|
|
13414
|
+
useEffect38(() => {
|
|
13061
13415
|
void load();
|
|
13062
13416
|
}, [load]);
|
|
13063
|
-
if (error) return /* @__PURE__ */
|
|
13064
|
-
if (binding === null) return /* @__PURE__ */
|
|
13417
|
+
if (error) return /* @__PURE__ */ jsx53(RefusalNotice, { error, className });
|
|
13418
|
+
if (binding === null) return /* @__PURE__ */ jsx53(Skeleton31, { className: cn47("h-64 w-full", className) });
|
|
13065
13419
|
if (binding === "none") {
|
|
13066
|
-
return /* @__PURE__ */
|
|
13067
|
-
/* @__PURE__ */
|
|
13068
|
-
/* @__PURE__ */
|
|
13069
|
-
gap ? /* @__PURE__ */
|
|
13420
|
+
return /* @__PURE__ */ jsxs49("main", { className: cn47("mx-auto max-w-2xl py-16 text-center", className), children: [
|
|
13421
|
+
/* @__PURE__ */ jsx53("h1", { className: "text-lg font-medium", children: "Nothing here" }),
|
|
13422
|
+
/* @__PURE__ */ jsx53("p", { className: "mt-1 text-sm text-muted-foreground", children: "There is no public page at this address." }),
|
|
13423
|
+
gap ? /* @__PURE__ */ jsx53("p", { className: "mt-6 text-xs text-muted-foreground", children: gap }) : null
|
|
13070
13424
|
] });
|
|
13071
13425
|
}
|
|
13072
|
-
return /* @__PURE__ */
|
|
13073
|
-
/* @__PURE__ */
|
|
13074
|
-
/* @__PURE__ */
|
|
13075
|
-
/* @__PURE__ */
|
|
13426
|
+
return /* @__PURE__ */ jsxs49("main", { className: cn47("mx-auto flex max-w-2xl flex-col gap-3 py-8", className), children: [
|
|
13427
|
+
/* @__PURE__ */ jsxs49("header", { className: "flex items-baseline gap-2 text-xs text-muted-foreground", children: [
|
|
13428
|
+
/* @__PURE__ */ jsx53("span", { className: "font-medium text-foreground", children: binding.namespace ?? "Published" }),
|
|
13429
|
+
/* @__PURE__ */ jsx53("span", { children: binding.render_mode === "list" ? `${rows?.length ?? 0} items` : "Shared publicly" })
|
|
13076
13430
|
] }),
|
|
13077
|
-
rows === null ? /* @__PURE__ */
|
|
13078
|
-
/* @__PURE__ */
|
|
13431
|
+
rows === null ? /* @__PURE__ */ jsx53(Skeleton31, { className: "h-40 w-full" }) : rows.length === 0 ? /* @__PURE__ */ jsx53("p", { className: "text-sm text-muted-foreground", children: "This page has nothing on it yet." }) : /* @__PURE__ */ jsx53("ol", { className: "flex flex-col gap-2", children: rows.map((row) => /* @__PURE__ */ jsx53("li", { className: "rounded border p-3", children: /* @__PURE__ */ jsx53(PublicRow, { row, fields }) }, row.id)) }),
|
|
13432
|
+
/* @__PURE__ */ jsx53("footer", { className: "mt-4 border-t pt-3 text-xs text-muted-foreground", children: binding.notice || gap || "Nothing was scanned before this was listed." })
|
|
13079
13433
|
] });
|
|
13080
13434
|
}
|
|
13081
13435
|
function PublicRow({ row, fields }) {
|
|
13082
13436
|
const document2 = row.document ?? {};
|
|
13083
13437
|
if (!fields) {
|
|
13084
13438
|
const first = Object.entries(document2).filter(([key]) => !key.startsWith("_"));
|
|
13085
|
-
return /* @__PURE__ */
|
|
13086
|
-
/* @__PURE__ */
|
|
13087
|
-
/* @__PURE__ */
|
|
13439
|
+
return /* @__PURE__ */ jsx53("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-sm", children: first.map(([key, value]) => /* @__PURE__ */ jsxs49("div", { className: "contents", children: [
|
|
13440
|
+
/* @__PURE__ */ jsx53("dt", { className: "text-xs text-muted-foreground", children: key }),
|
|
13441
|
+
/* @__PURE__ */ jsx53("dd", { className: "text-sm", children: String(value ?? "") })
|
|
13088
13442
|
] }, key)) });
|
|
13089
13443
|
}
|
|
13090
|
-
return /* @__PURE__ */
|
|
13091
|
-
/* @__PURE__ */
|
|
13092
|
-
/* @__PURE__ */
|
|
13444
|
+
return /* @__PURE__ */ jsx53("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: fields.map((field) => /* @__PURE__ */ jsxs49("div", { className: "contents", children: [
|
|
13445
|
+
/* @__PURE__ */ jsx53("dt", { className: "text-xs text-muted-foreground", children: field.label }),
|
|
13446
|
+
/* @__PURE__ */ jsx53("dd", { className: "text-sm", children: /* @__PURE__ */ jsx53(RecordValue, { field, value: document2[field.key], document: row.document }) })
|
|
13093
13447
|
] }, field.key)) });
|
|
13094
13448
|
}
|
|
13095
13449
|
|
|
13096
13450
|
// src/EmbedFrame.tsx
|
|
13097
|
-
import { useCallback as
|
|
13098
|
-
import { useRecordsClient as
|
|
13099
|
-
import { Button as
|
|
13451
|
+
import { useCallback as useCallback35, useEffect as useEffect39, useState as useState49 } from "react";
|
|
13452
|
+
import { useRecordsClient as useRecordsClient41 } from "@ai-matrx/records/react";
|
|
13453
|
+
import { Button as Button44, Input as Input5, Skeleton as Skeleton32, Textarea as Textarea4, cn as cn48 } from "@ai-matrx/design-system";
|
|
13100
13454
|
import { useTable as useTable21 } from "@ai-matrx/records/react";
|
|
13101
|
-
import { Fragment as
|
|
13455
|
+
import { Fragment as Fragment25, jsx as jsx54, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
13102
13456
|
function EmbedFrame({
|
|
13103
13457
|
tableId,
|
|
13104
13458
|
formId,
|
|
@@ -13107,18 +13461,18 @@ function EmbedFrame({
|
|
|
13107
13461
|
embedUrl,
|
|
13108
13462
|
className
|
|
13109
13463
|
}) {
|
|
13110
|
-
const client =
|
|
13464
|
+
const client = useRecordsClient41();
|
|
13111
13465
|
const host = useRecordsUi();
|
|
13112
13466
|
const table = useTable21(tableId);
|
|
13113
13467
|
const rights = useTableRights(table.data);
|
|
13114
|
-
const [origins, setOrigins] =
|
|
13115
|
-
const [secret, setSecret] =
|
|
13116
|
-
const [tokenId, setTokenId] =
|
|
13117
|
-
const [error, setError] =
|
|
13118
|
-
const [busy, setBusy] =
|
|
13468
|
+
const [origins, setOrigins] = useState49("");
|
|
13469
|
+
const [secret, setSecret] = useState49(null);
|
|
13470
|
+
const [tokenId, setTokenId] = useState49(null);
|
|
13471
|
+
const [error, setError] = useState49(null);
|
|
13472
|
+
const [busy, setBusy] = useState49(false);
|
|
13119
13473
|
const mode = formId ? "write" : "read";
|
|
13120
13474
|
const parsed = origins.split(/[\s,]+/).map((o) => o.trim()).filter((o) => o.length > 0);
|
|
13121
|
-
const issue =
|
|
13475
|
+
const issue = useCallback35(async () => {
|
|
13122
13476
|
setBusy(true);
|
|
13123
13477
|
setError(null);
|
|
13124
13478
|
const minted = await client.anonTokenIssue({
|
|
@@ -13137,7 +13491,7 @@ function EmbedFrame({
|
|
|
13137
13491
|
setTokenId(minted.data.token_id);
|
|
13138
13492
|
host.notify?.success("Embed token issued. Copy it now \u2014 it is never shown again.");
|
|
13139
13493
|
}, [client, formId, host, mode, parsed, recordId, savedViewId]);
|
|
13140
|
-
const revoke =
|
|
13494
|
+
const revoke = useCallback35(async () => {
|
|
13141
13495
|
if (!tokenId) return;
|
|
13142
13496
|
setBusy(true);
|
|
13143
13497
|
const done = await client.anonTokenRevoke({ token_id: tokenId });
|
|
@@ -13149,24 +13503,24 @@ function EmbedFrame({
|
|
|
13149
13503
|
setSecret(null);
|
|
13150
13504
|
setTokenId(null);
|
|
13151
13505
|
}, [client, tokenId]);
|
|
13152
|
-
if (table.error) return /* @__PURE__ */
|
|
13153
|
-
if (table.loading) return /* @__PURE__ */
|
|
13506
|
+
if (table.error) return /* @__PURE__ */ jsx54(RefusalNotice, { error: table.error, className });
|
|
13507
|
+
if (table.loading) return /* @__PURE__ */ jsx54(Skeleton32, { className: cn48("h-48 w-full", className) });
|
|
13154
13508
|
if (!rights.admin) {
|
|
13155
|
-
return /* @__PURE__ */
|
|
13509
|
+
return /* @__PURE__ */ jsxs50("p", { className: cn48("rounded border border-dashed px-2 py-1 text-xs text-muted-foreground", className), children: [
|
|
13156
13510
|
rights.why("structure"),
|
|
13157
13511
|
" 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."
|
|
13158
13512
|
] });
|
|
13159
13513
|
}
|
|
13160
13514
|
const snippet = secret ? `<iframe src="${embedUrl}#t=${secret}" style="width:100%;height:640px;border:0" loading="lazy"></iframe>` : null;
|
|
13161
|
-
return /* @__PURE__ */
|
|
13162
|
-
/* @__PURE__ */
|
|
13163
|
-
/* @__PURE__ */
|
|
13164
|
-
/* @__PURE__ */
|
|
13515
|
+
return /* @__PURE__ */ jsxs50("section", { className: cn48("flex min-h-0 flex-col gap-2", className), children: [
|
|
13516
|
+
/* @__PURE__ */ jsxs50("header", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
13517
|
+
/* @__PURE__ */ jsx54("span", { className: "font-medium text-foreground", children: "Embed" }),
|
|
13518
|
+
/* @__PURE__ */ jsx54("span", { children: mode === "write" ? "a form people can send" : "a read-only view" })
|
|
13165
13519
|
] }),
|
|
13166
|
-
error ? /* @__PURE__ */
|
|
13167
|
-
/* @__PURE__ */
|
|
13168
|
-
/* @__PURE__ */
|
|
13169
|
-
/* @__PURE__ */
|
|
13520
|
+
error ? /* @__PURE__ */ jsx54(RefusalNotice, { error }) : null,
|
|
13521
|
+
/* @__PURE__ */ jsxs50("label", { className: "flex flex-col gap-1 text-xs", children: [
|
|
13522
|
+
/* @__PURE__ */ jsx54("span", { className: "text-muted-foreground", children: "Sites this embed works on" }),
|
|
13523
|
+
/* @__PURE__ */ jsx54(
|
|
13170
13524
|
Input5,
|
|
13171
13525
|
{
|
|
13172
13526
|
"aria-label": "Allowed origins",
|
|
@@ -13176,18 +13530,18 @@ function EmbedFrame({
|
|
|
13176
13530
|
onChange: (e) => setOrigins(e.target.value)
|
|
13177
13531
|
}
|
|
13178
13532
|
),
|
|
13179
|
-
/* @__PURE__ */
|
|
13533
|
+
/* @__PURE__ */ jsxs50("span", { className: "text-[11px] text-muted-foreground", children: [
|
|
13180
13534
|
`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 `,
|
|
13181
|
-
/* @__PURE__ */
|
|
13535
|
+
/* @__PURE__ */ jsx54("code", { children: "example.com.evil.test" }),
|
|
13182
13536
|
" will not pass."
|
|
13183
13537
|
] })
|
|
13184
13538
|
] }),
|
|
13185
|
-
!secret ? /* @__PURE__ */
|
|
13186
|
-
/* @__PURE__ */
|
|
13187
|
-
/* @__PURE__ */
|
|
13188
|
-
/* @__PURE__ */
|
|
13189
|
-
/* @__PURE__ */
|
|
13190
|
-
|
|
13539
|
+
!secret ? /* @__PURE__ */ jsx54(Button44, { size: "sm", className: "self-start", disabled: busy || parsed.length === 0, onClick: () => void issue(), children: busy ? "Issuing\u2026" : "Issue embed" }) : /* @__PURE__ */ jsxs50(Fragment25, { children: [
|
|
13540
|
+
/* @__PURE__ */ jsx54("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." }),
|
|
13541
|
+
/* @__PURE__ */ jsx54(Textarea4, { "aria-label": "Embed snippet", readOnly: true, rows: 3, className: "font-mono text-[11px]", value: snippet ?? "" }),
|
|
13542
|
+
/* @__PURE__ */ jsxs50("div", { className: "flex gap-2", children: [
|
|
13543
|
+
/* @__PURE__ */ jsx54(
|
|
13544
|
+
Button44,
|
|
13191
13545
|
{
|
|
13192
13546
|
size: "sm",
|
|
13193
13547
|
variant: "outline",
|
|
@@ -13195,19 +13549,19 @@ function EmbedFrame({
|
|
|
13195
13549
|
children: "Copy"
|
|
13196
13550
|
}
|
|
13197
13551
|
),
|
|
13198
|
-
/* @__PURE__ */
|
|
13552
|
+
/* @__PURE__ */ jsx54(Button44, { size: "sm", variant: "ghost", disabled: busy, onClick: () => void revoke(), children: "Revoke" })
|
|
13199
13553
|
] })
|
|
13200
13554
|
] })
|
|
13201
13555
|
] });
|
|
13202
13556
|
}
|
|
13203
13557
|
function useEmbedHandshake(args) {
|
|
13204
|
-
const client =
|
|
13205
|
-
const [binding, setBinding] =
|
|
13206
|
-
const [error, setError] =
|
|
13207
|
-
const [loading, setLoading] =
|
|
13558
|
+
const client = useRecordsClient41();
|
|
13559
|
+
const [binding, setBinding] = useState49(null);
|
|
13560
|
+
const [error, setError] = useState49(null);
|
|
13561
|
+
const [loading, setLoading] = useState49(true);
|
|
13208
13562
|
const origin = args.origin ?? (typeof location === "undefined" ? "" : location.origin);
|
|
13209
13563
|
const { secret, requiredMode } = args;
|
|
13210
|
-
|
|
13564
|
+
useEffect39(() => {
|
|
13211
13565
|
let cancelled = false;
|
|
13212
13566
|
setLoading(true);
|
|
13213
13567
|
setError(null);
|
|
@@ -13230,7 +13584,7 @@ function useEmbedHandshake(args) {
|
|
|
13230
13584
|
|
|
13231
13585
|
// src/RecordsMount.tsx
|
|
13232
13586
|
import { RecordsProvider } from "@ai-matrx/records/react";
|
|
13233
|
-
import { jsx as
|
|
13587
|
+
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
13234
13588
|
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.";
|
|
13235
13589
|
function storeDecidesRights(_table) {
|
|
13236
13590
|
return NO_RIGHTS;
|
|
@@ -13243,7 +13597,7 @@ function RecordsMount({
|
|
|
13243
13597
|
}) {
|
|
13244
13598
|
const bound = { ...host ?? {} };
|
|
13245
13599
|
void letTheStoreDecideRights;
|
|
13246
|
-
return /* @__PURE__ */
|
|
13600
|
+
return /* @__PURE__ */ jsx55(RecordsProvider, { config, children: /* @__PURE__ */ jsx55(RecordsUiProvider, { value: bound, children: /* @__PURE__ */ jsx55(RecordLabelProvider, { children }) }) });
|
|
13247
13601
|
}
|
|
13248
13602
|
function personActor(userId) {
|
|
13249
13603
|
return userId ? { actor: "user", user_id: userId } : { actor: "user" };
|
|
@@ -13262,9 +13616,9 @@ function recordsDataSource(client, fallbackSchema = "custom") {
|
|
|
13262
13616
|
}
|
|
13263
13617
|
|
|
13264
13618
|
// src/TablesHome.tsx
|
|
13265
|
-
import { useCallback as
|
|
13266
|
-
import { useRecordsClient as
|
|
13267
|
-
import { BasicInput as
|
|
13619
|
+
import { useCallback as useCallback36, useEffect as useEffect40, useState as useState50 } from "react";
|
|
13620
|
+
import { useRecordsClient as useRecordsClient42, useTables as useTables3 } from "@ai-matrx/records/react";
|
|
13621
|
+
import { BasicInput as BasicInput16, Button as Button45, Skeleton as Skeleton33, cn as cn49 } from "@ai-matrx/design-system";
|
|
13268
13622
|
|
|
13269
13623
|
// src/createTable.ts
|
|
13270
13624
|
function tokenFor(name) {
|
|
@@ -13374,7 +13728,7 @@ function declaredType(field) {
|
|
|
13374
13728
|
}
|
|
13375
13729
|
|
|
13376
13730
|
// src/TablesHome.tsx
|
|
13377
|
-
import { Fragment as
|
|
13731
|
+
import { Fragment as Fragment26, jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
13378
13732
|
var TABLE_LANES = ["mine", "organization", "system", "community", "app"];
|
|
13379
13733
|
var LANE_TITLE = {
|
|
13380
13734
|
mine: "Mine",
|
|
@@ -13399,15 +13753,15 @@ function laneFor(table) {
|
|
|
13399
13753
|
return "organization";
|
|
13400
13754
|
}
|
|
13401
13755
|
function TablesHome({ onOpenTable, className }) {
|
|
13402
|
-
const client =
|
|
13756
|
+
const client = useRecordsClient42();
|
|
13403
13757
|
const tables = useTables3();
|
|
13404
|
-
const [creating, setCreating] =
|
|
13405
|
-
const [name, setName] =
|
|
13406
|
-
const [busy, setBusy] =
|
|
13407
|
-
const [error, setError] =
|
|
13408
|
-
const [importInto, setImportInto] =
|
|
13409
|
-
const [boards, setBoards] =
|
|
13410
|
-
|
|
13758
|
+
const [creating, setCreating] = useState50(false);
|
|
13759
|
+
const [name, setName] = useState50("");
|
|
13760
|
+
const [busy, setBusy] = useState50(false);
|
|
13761
|
+
const [error, setError] = useState50(null);
|
|
13762
|
+
const [importInto, setImportInto] = useState50(null);
|
|
13763
|
+
const [boards, setBoards] = useState50(null);
|
|
13764
|
+
useEffect40(() => {
|
|
13411
13765
|
let cancelled = false;
|
|
13412
13766
|
void client.dashboards({}).then((result) => {
|
|
13413
13767
|
if (cancelled) return;
|
|
@@ -13417,7 +13771,7 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13417
13771
|
cancelled = true;
|
|
13418
13772
|
};
|
|
13419
13773
|
}, [client]);
|
|
13420
|
-
const create =
|
|
13774
|
+
const create = useCallback36(
|
|
13421
13775
|
async (mode) => {
|
|
13422
13776
|
const trimmed = name.trim();
|
|
13423
13777
|
if (!trimmed) return;
|
|
@@ -13437,10 +13791,10 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13437
13791
|
},
|
|
13438
13792
|
[client, name, onOpenTable, tables]
|
|
13439
13793
|
);
|
|
13440
|
-
return /* @__PURE__ */
|
|
13441
|
-
/* @__PURE__ */
|
|
13442
|
-
/* @__PURE__ */
|
|
13443
|
-
|
|
13794
|
+
return /* @__PURE__ */ jsxs51("div", { className: cn49("flex min-h-0 flex-col gap-4", className), children: [
|
|
13795
|
+
/* @__PURE__ */ jsx56("div", { className: "flex items-center gap-2", children: creating ? /* @__PURE__ */ jsxs51(Fragment26, { children: [
|
|
13796
|
+
/* @__PURE__ */ jsx56(
|
|
13797
|
+
BasicInput16,
|
|
13444
13798
|
{
|
|
13445
13799
|
autoFocus: true,
|
|
13446
13800
|
value: name,
|
|
@@ -13453,9 +13807,9 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13453
13807
|
className: "h-8 max-w-xs"
|
|
13454
13808
|
}
|
|
13455
13809
|
),
|
|
13456
|
-
/* @__PURE__ */
|
|
13457
|
-
/* @__PURE__ */
|
|
13458
|
-
|
|
13810
|
+
/* @__PURE__ */ jsx56(Button45, { size: "sm", disabled: busy || name.trim().length === 0, onClick: () => void create("open"), children: busy ? "Declaring\u2026" : "Create" }),
|
|
13811
|
+
/* @__PURE__ */ jsx56(
|
|
13812
|
+
Button45,
|
|
13459
13813
|
{
|
|
13460
13814
|
size: "sm",
|
|
13461
13815
|
variant: "outline",
|
|
@@ -13464,37 +13818,37 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13464
13818
|
children: "Create and import a file"
|
|
13465
13819
|
}
|
|
13466
13820
|
),
|
|
13467
|
-
/* @__PURE__ */
|
|
13468
|
-
] }) : /* @__PURE__ */
|
|
13469
|
-
error ? /* @__PURE__ */
|
|
13470
|
-
importInto ? /* @__PURE__ */
|
|
13471
|
-
/* @__PURE__ */
|
|
13472
|
-
/* @__PURE__ */
|
|
13821
|
+
/* @__PURE__ */ jsx56(Button45, { size: "sm", variant: "ghost", onClick: () => setCreating(false), children: "Cancel" })
|
|
13822
|
+
] }) : /* @__PURE__ */ jsx56(Button45, { size: "sm", onClick: () => setCreating(true), children: "New table" }) }),
|
|
13823
|
+
error ? /* @__PURE__ */ jsx56(RefusalNotice, { error }) : null,
|
|
13824
|
+
importInto ? /* @__PURE__ */ jsxs51("div", { className: "rounded-md border p-3", children: [
|
|
13825
|
+
/* @__PURE__ */ jsx56(ImportWizard, { tableId: importInto, onDone: () => setImportInto(null) }),
|
|
13826
|
+
/* @__PURE__ */ jsx56(Button45, { size: "sm", variant: "ghost", className: "mt-2", onClick: () => onOpenTable?.(importInto), children: "Open the table" })
|
|
13473
13827
|
] }) : null,
|
|
13474
|
-
tables.error ? /* @__PURE__ */
|
|
13475
|
-
tables.loading && !tables.data ? /* @__PURE__ */
|
|
13476
|
-
/* @__PURE__ */
|
|
13477
|
-
/* @__PURE__ */
|
|
13828
|
+
tables.error ? /* @__PURE__ */ jsx56(RefusalNotice, { error: tables.error }) : null,
|
|
13829
|
+
tables.loading && !tables.data ? /* @__PURE__ */ jsxs51("div", { className: "space-y-2", children: [
|
|
13830
|
+
/* @__PURE__ */ jsx56(Skeleton33, { className: "h-6 w-40" }),
|
|
13831
|
+
/* @__PURE__ */ jsx56(Skeleton33, { className: "h-16 w-full" })
|
|
13478
13832
|
] }) : null,
|
|
13479
|
-
/* @__PURE__ */
|
|
13480
|
-
boards && boards.length > 0 ? /* @__PURE__ */
|
|
13481
|
-
/* @__PURE__ */
|
|
13482
|
-
/* @__PURE__ */
|
|
13483
|
-
/* @__PURE__ */
|
|
13833
|
+
/* @__PURE__ */ jsx56(BookingSlots, {}),
|
|
13834
|
+
boards && boards.length > 0 ? /* @__PURE__ */ jsxs51("section", { className: "space-y-1.5", children: [
|
|
13835
|
+
/* @__PURE__ */ jsxs51("div", { className: "flex items-baseline gap-2", children: [
|
|
13836
|
+
/* @__PURE__ */ jsx56("h2", { className: "text-sm font-medium", children: "Dashboards" }),
|
|
13837
|
+
/* @__PURE__ */ jsx56("span", { className: "text-xs opacity-60", children: boards.length })
|
|
13484
13838
|
] }),
|
|
13485
|
-
/* @__PURE__ */
|
|
13839
|
+
/* @__PURE__ */ jsx56("ul", { className: "grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3", children: boards.map((board) => /* @__PURE__ */ jsx56("li", { children: /* @__PURE__ */ jsxs51(
|
|
13486
13840
|
"button",
|
|
13487
13841
|
{
|
|
13488
13842
|
type: "button",
|
|
13489
13843
|
disabled: !board.table_id,
|
|
13490
13844
|
onClick: () => board.table_id ? onOpenTable?.(board.table_id, board.dashboard_id) : void 0,
|
|
13491
|
-
className:
|
|
13845
|
+
className: cn49(
|
|
13492
13846
|
"w-full rounded-md border px-3 py-2 text-left transition-colors",
|
|
13493
13847
|
onOpenTable && board.table_id ? "hover:bg-accent" : "cursor-default"
|
|
13494
13848
|
),
|
|
13495
13849
|
children: [
|
|
13496
|
-
/* @__PURE__ */
|
|
13497
|
-
/* @__PURE__ */
|
|
13850
|
+
/* @__PURE__ */ jsx56("span", { className: "block truncate text-sm", children: board.name }),
|
|
13851
|
+
/* @__PURE__ */ jsxs51("span", { className: "block truncate text-xs opacity-60", children: [
|
|
13498
13852
|
board.block_count,
|
|
13499
13853
|
" block",
|
|
13500
13854
|
board.block_count === 1 ? "" : "s",
|
|
@@ -13510,23 +13864,23 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13510
13864
|
] }) : null,
|
|
13511
13865
|
tables.data ? TABLE_LANES.map((lane) => {
|
|
13512
13866
|
const rows = tables.data.filter((t) => laneFor(t) === lane);
|
|
13513
|
-
return /* @__PURE__ */
|
|
13514
|
-
/* @__PURE__ */
|
|
13515
|
-
/* @__PURE__ */
|
|
13516
|
-
/* @__PURE__ */
|
|
13867
|
+
return /* @__PURE__ */ jsxs51("section", { className: "space-y-1.5", children: [
|
|
13868
|
+
/* @__PURE__ */ jsxs51("div", { className: "flex items-baseline gap-2", children: [
|
|
13869
|
+
/* @__PURE__ */ jsx56("h2", { className: "text-sm font-medium", children: LANE_TITLE[lane] }),
|
|
13870
|
+
/* @__PURE__ */ jsx56("span", { className: "text-xs opacity-60", children: rows.length })
|
|
13517
13871
|
] }),
|
|
13518
|
-
rows.length === 0 ? /* @__PURE__ */
|
|
13872
|
+
rows.length === 0 ? /* @__PURE__ */ jsx56("p", { className: "text-xs opacity-70", children: LANE_EMPTY[lane] }) : /* @__PURE__ */ jsx56("ul", { className: "grid gap-1.5 sm:grid-cols-2 lg:grid-cols-3", children: rows.map((table) => /* @__PURE__ */ jsx56("li", { children: /* @__PURE__ */ jsxs51(
|
|
13519
13873
|
"button",
|
|
13520
13874
|
{
|
|
13521
13875
|
type: "button",
|
|
13522
13876
|
onClick: () => onOpenTable?.(table.id),
|
|
13523
|
-
className:
|
|
13877
|
+
className: cn49(
|
|
13524
13878
|
"w-full rounded-md border px-3 py-2 text-left transition-colors",
|
|
13525
13879
|
onOpenTable ? "hover:bg-accent" : "cursor-default"
|
|
13526
13880
|
),
|
|
13527
13881
|
children: [
|
|
13528
|
-
/* @__PURE__ */
|
|
13529
|
-
/* @__PURE__ */
|
|
13882
|
+
/* @__PURE__ */ jsx56("span", { className: "block truncate text-sm", children: tableName(table) }),
|
|
13883
|
+
/* @__PURE__ */ jsxs51("span", { className: "block truncate text-xs opacity-60", children: [
|
|
13530
13884
|
table.fields.length,
|
|
13531
13885
|
" field",
|
|
13532
13886
|
table.fields.length === 1 ? "" : "s",
|
|
@@ -13541,10 +13895,10 @@ function TablesHome({ onOpenTable, className }) {
|
|
|
13541
13895
|
}
|
|
13542
13896
|
|
|
13543
13897
|
// src/TablePage.tsx
|
|
13544
|
-
import { useCallback as
|
|
13545
|
-
import { useRecordsClient as
|
|
13546
|
-
import { Button as
|
|
13547
|
-
import { Fragment as
|
|
13898
|
+
import { useCallback as useCallback37, useEffect as useEffect41, useState as useState51 } from "react";
|
|
13899
|
+
import { useRecordsClient as useRecordsClient43, useTable as useTable22 } from "@ai-matrx/records/react";
|
|
13900
|
+
import { Button as Button46, Separator as Separator12, Skeleton as Skeleton34, cn as cn50 } from "@ai-matrx/design-system";
|
|
13901
|
+
import { Fragment as Fragment27, jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
13548
13902
|
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.";
|
|
13549
13903
|
var DEFAULT_VIEW_NAME = "All records";
|
|
13550
13904
|
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.";
|
|
@@ -13575,29 +13929,29 @@ function TablePage({
|
|
|
13575
13929
|
activeRecordId,
|
|
13576
13930
|
className
|
|
13577
13931
|
}) {
|
|
13578
|
-
const client =
|
|
13932
|
+
const client = useRecordsClient43();
|
|
13579
13933
|
const table = useTable22(tableId);
|
|
13580
13934
|
const rights = useTableRights(table.data);
|
|
13581
|
-
const organizationId =
|
|
13582
|
-
const [view, setView] =
|
|
13935
|
+
const organizationId = useRecordsClient43().config.organizationId;
|
|
13936
|
+
const [view, setView] = useState51(null);
|
|
13583
13937
|
const opening = openingRail(activeRecordId);
|
|
13584
|
-
const [asking, setAsking] =
|
|
13585
|
-
const [surface, setSurface] =
|
|
13938
|
+
const [asking, setAsking] = useState51(null);
|
|
13939
|
+
const [surface, setSurface] = useState51({
|
|
13586
13940
|
main: activeDashboardId ? "dashboards" : "records",
|
|
13587
13941
|
rail: opening.rail
|
|
13588
13942
|
});
|
|
13589
13943
|
const { main, rail } = surface;
|
|
13590
13944
|
const setRail = (next) => setSurface((now) => ({ ...now, rail: next }));
|
|
13591
|
-
const [openRecord, setOpenRecord] =
|
|
13945
|
+
const [openRecord, setOpenRecord] = useState51(opening.record);
|
|
13592
13946
|
const viewVersion = useRecordVersion(view?.id ?? null);
|
|
13593
13947
|
const press = (pressed) => setSurface((now) => chooseSurface(now, pressed));
|
|
13594
13948
|
const show = (next) => press({ rail: next });
|
|
13595
|
-
|
|
13949
|
+
useEffect41(() => {
|
|
13596
13950
|
if (!activeRecordId) return;
|
|
13597
13951
|
setOpenRecord(activeRecordId);
|
|
13598
13952
|
setSurface((now) => ({ ...now, rail: "record" }));
|
|
13599
13953
|
}, [activeRecordId]);
|
|
13600
|
-
const patchView =
|
|
13954
|
+
const patchView = useCallback37(
|
|
13601
13955
|
async (patch) => {
|
|
13602
13956
|
const current = view;
|
|
13603
13957
|
if (!current) return;
|
|
@@ -13613,19 +13967,19 @@ function TablePage({
|
|
|
13613
13967
|
},
|
|
13614
13968
|
[client, view, viewVersion]
|
|
13615
13969
|
);
|
|
13616
|
-
if (table.error) return /* @__PURE__ */
|
|
13617
|
-
if (table.loading) return /* @__PURE__ */
|
|
13970
|
+
if (table.error) return /* @__PURE__ */ jsx57(RefusalNotice, { error: table.error });
|
|
13971
|
+
if (table.loading) return /* @__PURE__ */ jsx57(Skeleton34, { className: "h-40 w-full" });
|
|
13618
13972
|
if (!table.data) {
|
|
13619
|
-
return /* @__PURE__ */
|
|
13620
|
-
/* @__PURE__ */
|
|
13621
|
-
/* @__PURE__ */
|
|
13622
|
-
onLeave ? /* @__PURE__ */
|
|
13973
|
+
return /* @__PURE__ */ jsxs52("div", { className: cn50("flex flex-col items-start gap-2 rounded-md border border-dashed p-6", className), children: [
|
|
13974
|
+
/* @__PURE__ */ jsx57("p", { className: "text-sm font-medium", children: "This table is not here" }),
|
|
13975
|
+
/* @__PURE__ */ jsx57("p", { className: "max-w-prose text-xs text-muted-foreground", children: TABLE_NOT_REACHABLE }),
|
|
13976
|
+
onLeave ? /* @__PURE__ */ jsx57(Button46, { size: "sm", variant: "outline", onClick: onLeave, children: leaveLabel }) : null
|
|
13623
13977
|
] });
|
|
13624
13978
|
}
|
|
13625
|
-
return /* @__PURE__ */
|
|
13626
|
-
/* @__PURE__ */
|
|
13627
|
-
/* @__PURE__ */
|
|
13628
|
-
/* @__PURE__ */
|
|
13979
|
+
return /* @__PURE__ */ jsxs52("div", { className: cn50("flex min-h-0 gap-4", className), children: [
|
|
13980
|
+
/* @__PURE__ */ jsxs52("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
|
|
13981
|
+
/* @__PURE__ */ jsxs52("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
13982
|
+
/* @__PURE__ */ jsx57(
|
|
13629
13983
|
ViewBar,
|
|
13630
13984
|
{
|
|
13631
13985
|
tableId,
|
|
@@ -13634,10 +13988,10 @@ function TablePage({
|
|
|
13634
13988
|
className: "min-w-0 flex-1"
|
|
13635
13989
|
}
|
|
13636
13990
|
),
|
|
13637
|
-
rights.write && view && view.layout !== "grid" ? /* @__PURE__ */
|
|
13638
|
-
rights.structure ? /* @__PURE__ */
|
|
13639
|
-
/* @__PURE__ */
|
|
13640
|
-
|
|
13991
|
+
rights.write && view && view.layout !== "grid" ? /* @__PURE__ */ jsx57(Button46, { size: "sm", onClick: () => show("new-record"), children: "New record" }) : null,
|
|
13992
|
+
rights.structure ? /* @__PURE__ */ jsxs52(Fragment27, { children: [
|
|
13993
|
+
/* @__PURE__ */ jsx57(
|
|
13994
|
+
Button46,
|
|
13641
13995
|
{
|
|
13642
13996
|
size: "sm",
|
|
13643
13997
|
variant: surfaceChosen(surface, { rail: "field" }) ? "secondary" : "outline",
|
|
@@ -13646,8 +14000,8 @@ function TablePage({
|
|
|
13646
14000
|
children: "Add field"
|
|
13647
14001
|
}
|
|
13648
14002
|
),
|
|
13649
|
-
/* @__PURE__ */
|
|
13650
|
-
|
|
14003
|
+
/* @__PURE__ */ jsx57(
|
|
14004
|
+
Button46,
|
|
13651
14005
|
{
|
|
13652
14006
|
size: "sm",
|
|
13653
14007
|
variant: surfaceChosen(surface, { rail: "settings" }) ? "secondary" : "ghost",
|
|
@@ -13656,8 +14010,8 @@ function TablePage({
|
|
|
13656
14010
|
children: "Settings"
|
|
13657
14011
|
}
|
|
13658
14012
|
),
|
|
13659
|
-
/* @__PURE__ */
|
|
13660
|
-
|
|
14013
|
+
/* @__PURE__ */ jsx57(
|
|
14014
|
+
Button46,
|
|
13661
14015
|
{
|
|
13662
14016
|
size: "sm",
|
|
13663
14017
|
variant: surfaceChosen(surface, { rail: "import" }) ? "secondary" : "ghost",
|
|
@@ -13667,8 +14021,8 @@ function TablePage({
|
|
|
13667
14021
|
}
|
|
13668
14022
|
)
|
|
13669
14023
|
] }) : null,
|
|
13670
|
-
/* @__PURE__ */
|
|
13671
|
-
|
|
14024
|
+
/* @__PURE__ */ jsx57(
|
|
14025
|
+
Button46,
|
|
13672
14026
|
{
|
|
13673
14027
|
size: "sm",
|
|
13674
14028
|
variant: surfaceChosen(surface, { main: "dashboards" }) ? "secondary" : "ghost",
|
|
@@ -13677,8 +14031,8 @@ function TablePage({
|
|
|
13677
14031
|
children: "Dashboards"
|
|
13678
14032
|
}
|
|
13679
14033
|
),
|
|
13680
|
-
/* @__PURE__ */
|
|
13681
|
-
|
|
14034
|
+
/* @__PURE__ */ jsx57(
|
|
14035
|
+
Button46,
|
|
13682
14036
|
{
|
|
13683
14037
|
size: "sm",
|
|
13684
14038
|
variant: surfaceChosen(surface, { rail: "forms" }) ? "secondary" : "ghost",
|
|
@@ -13687,8 +14041,8 @@ function TablePage({
|
|
|
13687
14041
|
children: "Forms"
|
|
13688
14042
|
}
|
|
13689
14043
|
),
|
|
13690
|
-
/* @__PURE__ */
|
|
13691
|
-
|
|
14044
|
+
/* @__PURE__ */ jsx57(
|
|
14045
|
+
Button46,
|
|
13692
14046
|
{
|
|
13693
14047
|
size: "sm",
|
|
13694
14048
|
variant: surfaceChosen(surface, { rail: "bookings" }) ? "secondary" : "ghost",
|
|
@@ -13697,8 +14051,8 @@ function TablePage({
|
|
|
13697
14051
|
children: "Bookings"
|
|
13698
14052
|
}
|
|
13699
14053
|
),
|
|
13700
|
-
/* @__PURE__ */
|
|
13701
|
-
|
|
14054
|
+
/* @__PURE__ */ jsx57(
|
|
14055
|
+
Button46,
|
|
13702
14056
|
{
|
|
13703
14057
|
size: "sm",
|
|
13704
14058
|
variant: surfaceChosen(surface, { rail: "checklists" }) ? "secondary" : "ghost",
|
|
@@ -13707,8 +14061,8 @@ function TablePage({
|
|
|
13707
14061
|
children: "Checklists"
|
|
13708
14062
|
}
|
|
13709
14063
|
),
|
|
13710
|
-
/* @__PURE__ */
|
|
13711
|
-
|
|
14064
|
+
/* @__PURE__ */ jsx57(
|
|
14065
|
+
Button46,
|
|
13712
14066
|
{
|
|
13713
14067
|
size: "sm",
|
|
13714
14068
|
variant: surfaceChosen(surface, { rail: "notifications" }) ? "secondary" : "ghost",
|
|
@@ -13717,8 +14071,8 @@ function TablePage({
|
|
|
13717
14071
|
children: "Notifications"
|
|
13718
14072
|
}
|
|
13719
14073
|
),
|
|
13720
|
-
/* @__PURE__ */
|
|
13721
|
-
|
|
14074
|
+
/* @__PURE__ */ jsx57(
|
|
14075
|
+
Button46,
|
|
13722
14076
|
{
|
|
13723
14077
|
size: "sm",
|
|
13724
14078
|
variant: surfaceChosen(surface, { rail: "portals" }) ? "secondary" : "ghost",
|
|
@@ -13727,8 +14081,8 @@ function TablePage({
|
|
|
13727
14081
|
children: "Portals"
|
|
13728
14082
|
}
|
|
13729
14083
|
),
|
|
13730
|
-
/* @__PURE__ */
|
|
13731
|
-
|
|
14084
|
+
/* @__PURE__ */ jsx57(
|
|
14085
|
+
Button46,
|
|
13732
14086
|
{
|
|
13733
14087
|
size: "sm",
|
|
13734
14088
|
variant: surfaceChosen(surface, { rail: "inbox" }) ? "secondary" : "ghost",
|
|
@@ -13737,7 +14091,7 @@ function TablePage({
|
|
|
13737
14091
|
children: "Inbox"
|
|
13738
14092
|
}
|
|
13739
14093
|
),
|
|
13740
|
-
/* @__PURE__ */
|
|
14094
|
+
/* @__PURE__ */ jsx57(
|
|
13741
14095
|
ShareControl,
|
|
13742
14096
|
{
|
|
13743
14097
|
kind: "table",
|
|
@@ -13747,10 +14101,10 @@ function TablePage({
|
|
|
13747
14101
|
may: rights.share
|
|
13748
14102
|
}
|
|
13749
14103
|
),
|
|
13750
|
-
/* @__PURE__ */
|
|
14104
|
+
/* @__PURE__ */ jsx57(ExportMenu, { tableId })
|
|
13751
14105
|
] }),
|
|
13752
|
-
main === "dashboards" ? /* @__PURE__ */
|
|
13753
|
-
/* @__PURE__ */
|
|
14106
|
+
main === "dashboards" ? /* @__PURE__ */ jsx57(DashboardCanvas, { tableId, activeDashboardId: activeDashboardId ?? null }) : /* @__PURE__ */ jsxs52(Fragment27, { children: [
|
|
14107
|
+
/* @__PURE__ */ jsx57(
|
|
13754
14108
|
ViewSwitcher,
|
|
13755
14109
|
{
|
|
13756
14110
|
view: view ?? defaultView(tableId),
|
|
@@ -13767,18 +14121,18 @@ function TablePage({
|
|
|
13767
14121
|
}
|
|
13768
14122
|
}
|
|
13769
14123
|
),
|
|
13770
|
-
view ? null : /* @__PURE__ */
|
|
14124
|
+
view ? null : /* @__PURE__ */ jsx57("p", { className: "text-xs text-muted-foreground", children: VIEW_NOT_SAVED_YET })
|
|
13771
14125
|
] })
|
|
13772
14126
|
] }),
|
|
13773
|
-
rail === "none" ? null : /* @__PURE__ */
|
|
13774
|
-
rail === "settings" ? /* @__PURE__ */
|
|
14127
|
+
rail === "none" ? null : /* @__PURE__ */ jsxs52("aside", { className: "w-[26rem] shrink-0 overflow-y-auto rounded-md border p-3", children: [
|
|
14128
|
+
rail === "settings" ? /* @__PURE__ */ jsx57(
|
|
13775
14129
|
TableSettings,
|
|
13776
14130
|
{
|
|
13777
14131
|
tableId,
|
|
13778
14132
|
...onLeave ? { onDeleted: onLeave } : {}
|
|
13779
14133
|
}
|
|
13780
14134
|
) : null,
|
|
13781
|
-
rail === "inbox" ? /* @__PURE__ */
|
|
14135
|
+
rail === "inbox" ? /* @__PURE__ */ jsx57(
|
|
13782
14136
|
ActionInbox,
|
|
13783
14137
|
{
|
|
13784
14138
|
tableId,
|
|
@@ -13788,9 +14142,9 @@ function TablePage({
|
|
|
13788
14142
|
}
|
|
13789
14143
|
}
|
|
13790
14144
|
) : null,
|
|
13791
|
-
rail === "forms" ? /* @__PURE__ */
|
|
13792
|
-
rail === "bookings" ? /* @__PURE__ */
|
|
13793
|
-
rail === "checklists" ? /* @__PURE__ */
|
|
14145
|
+
rail === "forms" ? /* @__PURE__ */ jsx57(FormsPanel, { tableId }) : null,
|
|
14146
|
+
rail === "bookings" ? /* @__PURE__ */ jsx57(BookingSlots, { tableId }) : null,
|
|
14147
|
+
rail === "checklists" ? /* @__PURE__ */ jsx57(
|
|
13794
14148
|
ChecklistsPanel,
|
|
13795
14149
|
{
|
|
13796
14150
|
tableId,
|
|
@@ -13800,11 +14154,11 @@ function TablePage({
|
|
|
13800
14154
|
}
|
|
13801
14155
|
}
|
|
13802
14156
|
) : null,
|
|
13803
|
-
rail === "notifications" ? /* @__PURE__ */
|
|
13804
|
-
rail === "portals" ? /* @__PURE__ */
|
|
13805
|
-
rail === "import" ? /* @__PURE__ */
|
|
13806
|
-
rail === "field" ? /* @__PURE__ */
|
|
13807
|
-
rail === "new-record" ? /* @__PURE__ */
|
|
14157
|
+
rail === "notifications" ? /* @__PURE__ */ jsx57(SubscriptionsPanel, { tableId }) : null,
|
|
14158
|
+
rail === "portals" ? /* @__PURE__ */ jsx57(PortalsPanel, { tableId }) : null,
|
|
14159
|
+
rail === "import" ? /* @__PURE__ */ jsx57(ImportWizard, { tableId, onDone: () => setRail("none") }) : null,
|
|
14160
|
+
rail === "field" ? /* @__PURE__ */ jsx57(FieldEditor, { tableId, onSaved: () => setRail("none"), onCancel: () => setRail("none") }) : null,
|
|
14161
|
+
rail === "new-record" ? /* @__PURE__ */ jsx57(
|
|
13808
14162
|
RecordForm,
|
|
13809
14163
|
{
|
|
13810
14164
|
tableId,
|
|
@@ -13815,7 +14169,7 @@ function TablePage({
|
|
|
13815
14169
|
onCancel: () => setRail("none")
|
|
13816
14170
|
}
|
|
13817
14171
|
) : null,
|
|
13818
|
-
rail === "who-changed" && asking ? /* @__PURE__ */
|
|
14172
|
+
rail === "who-changed" && asking ? /* @__PURE__ */ jsx57(
|
|
13819
14173
|
FieldHistoryPanel,
|
|
13820
14174
|
{
|
|
13821
14175
|
tableId,
|
|
@@ -13828,10 +14182,10 @@ function TablePage({
|
|
|
13828
14182
|
}
|
|
13829
14183
|
}
|
|
13830
14184
|
) : null,
|
|
13831
|
-
rail === "record" && openRecord ? /* @__PURE__ */
|
|
13832
|
-
/* @__PURE__ */
|
|
13833
|
-
/* @__PURE__ */
|
|
13834
|
-
/* @__PURE__ */
|
|
14185
|
+
rail === "record" && openRecord ? /* @__PURE__ */ jsxs52("div", { className: "space-y-3", children: [
|
|
14186
|
+
/* @__PURE__ */ jsx57(Peek, { tableId, recordId: openRecord, onClose: () => setRail("none") }),
|
|
14187
|
+
/* @__PURE__ */ jsx57(Separator12, {}),
|
|
14188
|
+
/* @__PURE__ */ jsx57(
|
|
13835
14189
|
HistoryPanel,
|
|
13836
14190
|
{
|
|
13837
14191
|
tableId,
|
|
@@ -13842,10 +14196,10 @@ function TablePage({
|
|
|
13842
14196
|
}
|
|
13843
14197
|
}
|
|
13844
14198
|
),
|
|
13845
|
-
/* @__PURE__ */
|
|
13846
|
-
/* @__PURE__ */
|
|
13847
|
-
/* @__PURE__ */
|
|
13848
|
-
/* @__PURE__ */
|
|
14199
|
+
/* @__PURE__ */ jsx57(Separator12, {}),
|
|
14200
|
+
/* @__PURE__ */ jsx57(ChecklistRunner, { tableId, recordId: openRecord }),
|
|
14201
|
+
/* @__PURE__ */ jsx57(Separator12, {}),
|
|
14202
|
+
/* @__PURE__ */ jsx57(CommentThread, { tableId, recordId: openRecord })
|
|
13849
14203
|
] }) : null
|
|
13850
14204
|
] })
|
|
13851
14205
|
] });
|
|
@@ -13876,6 +14230,7 @@ export {
|
|
|
13876
14230
|
DEFAULT_FIELDS,
|
|
13877
14231
|
DEFAULT_VIEW_NAME,
|
|
13878
14232
|
DashboardCanvas,
|
|
14233
|
+
DigestScheduler,
|
|
13879
14234
|
DocRender,
|
|
13880
14235
|
DocTemplate,
|
|
13881
14236
|
EMPTY_PRESENTATION,
|