@flytedan/flytebot-design-system 0.19.0 → 0.21.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/dist/index.cjs +893 -698
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -1
- package/dist/index.d.ts +62 -1
- package/dist/index.js +892 -698
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -146,6 +146,7 @@ __export(index_exports, {
|
|
|
146
146
|
SessionKit: () => SessionKit,
|
|
147
147
|
SessionProvider: () => SessionProvider,
|
|
148
148
|
SidebarNav: () => SidebarNav,
|
|
149
|
+
SignInPage: () => SignInPage,
|
|
149
150
|
Skeleton: () => Skeleton,
|
|
150
151
|
SkeletonText: () => SkeletonText,
|
|
151
152
|
Slider: () => Slider,
|
|
@@ -6608,11 +6609,204 @@ function ProfilePage({
|
|
|
6608
6609
|
] });
|
|
6609
6610
|
}
|
|
6610
6611
|
|
|
6612
|
+
// src/components/platform/SignInPage.tsx
|
|
6613
|
+
var React42 = __toESM(require("react"), 1);
|
|
6614
|
+
var import_jsx_runtime68 = require("react/jsx-runtime");
|
|
6615
|
+
function SignInPage({ productName, onSignIn, continueAs, error }) {
|
|
6616
|
+
const [signingIn, setSigningIn] = React42.useState(false);
|
|
6617
|
+
const [resuming, setResuming] = React42.useState(false);
|
|
6618
|
+
function handleSignIn() {
|
|
6619
|
+
setSigningIn(true);
|
|
6620
|
+
onSignIn();
|
|
6621
|
+
}
|
|
6622
|
+
function handleContinue() {
|
|
6623
|
+
setResuming(true);
|
|
6624
|
+
continueAs.onContinue().finally(() => setResuming(false));
|
|
6625
|
+
}
|
|
6626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6627
|
+
"div",
|
|
6628
|
+
{
|
|
6629
|
+
style: {
|
|
6630
|
+
position: "relative",
|
|
6631
|
+
display: "grid",
|
|
6632
|
+
placeItems: "center",
|
|
6633
|
+
minHeight: "100vh",
|
|
6634
|
+
padding: "24px 16px",
|
|
6635
|
+
boxSizing: "border-box",
|
|
6636
|
+
overflow: "hidden",
|
|
6637
|
+
background: "radial-gradient(circle at 15% 15%, var(--blue-700) 0%, transparent 45%), radial-gradient(circle at 85% 85%, var(--blue-600) 0%, transparent 40%), linear-gradient(160deg, var(--navy) 0%, var(--blue-950) 55%, var(--blue-900) 100%)"
|
|
6638
|
+
},
|
|
6639
|
+
children: [
|
|
6640
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6641
|
+
"div",
|
|
6642
|
+
{
|
|
6643
|
+
"aria-hidden": true,
|
|
6644
|
+
style: {
|
|
6645
|
+
position: "absolute",
|
|
6646
|
+
inset: 0,
|
|
6647
|
+
backgroundImage: "linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px)",
|
|
6648
|
+
backgroundSize: "48px 48px",
|
|
6649
|
+
maskImage: "radial-gradient(circle at 50% 40%, black, transparent 70%)"
|
|
6650
|
+
}
|
|
6651
|
+
}
|
|
6652
|
+
),
|
|
6653
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6654
|
+
"div",
|
|
6655
|
+
{
|
|
6656
|
+
style: {
|
|
6657
|
+
position: "relative",
|
|
6658
|
+
width: "100%",
|
|
6659
|
+
maxWidth: 408,
|
|
6660
|
+
display: "flex",
|
|
6661
|
+
flexDirection: "column",
|
|
6662
|
+
alignItems: "center"
|
|
6663
|
+
},
|
|
6664
|
+
children: [
|
|
6665
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { style: { marginBottom: "var(--s-32)" }, "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(FlytedeskMark, { size: "lg" }) }),
|
|
6666
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6667
|
+
"div",
|
|
6668
|
+
{
|
|
6669
|
+
style: {
|
|
6670
|
+
width: "100%",
|
|
6671
|
+
borderRadius: "var(--r-2xl)",
|
|
6672
|
+
overflow: "hidden",
|
|
6673
|
+
boxShadow: "0 24px 64px -12px rgba(2, 8, 20, 0.55), 0 2px 8px rgba(2, 8, 20, 0.3)"
|
|
6674
|
+
},
|
|
6675
|
+
children: [
|
|
6676
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6677
|
+
"div",
|
|
6678
|
+
{
|
|
6679
|
+
style: {
|
|
6680
|
+
height: 4,
|
|
6681
|
+
background: "linear-gradient(90deg, var(--blue-400), var(--blue-600), var(--navy))"
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
),
|
|
6685
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6686
|
+
"div",
|
|
6687
|
+
{
|
|
6688
|
+
style: {
|
|
6689
|
+
display: "flex",
|
|
6690
|
+
flexDirection: "column",
|
|
6691
|
+
gap: "var(--s-20)",
|
|
6692
|
+
alignItems: "center",
|
|
6693
|
+
textAlign: "center",
|
|
6694
|
+
padding: "var(--s-8) 0"
|
|
6695
|
+
},
|
|
6696
|
+
children: [
|
|
6697
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { children: [
|
|
6698
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("h1", { className: "fd-h3", style: { color: "var(--navy)" }, children: productName }),
|
|
6699
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { marginTop: "var(--s-4)" }, children: continueAs ? "Your session timed out, but you're likely still signed in" : "Sign in with your flytedesk workspace account" })
|
|
6700
|
+
] }),
|
|
6701
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { role: "alert", style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Banner, { tone: "danger", title: error }) }) : null,
|
|
6702
|
+
continueAs ? /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
|
|
6703
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6704
|
+
Button,
|
|
6705
|
+
{
|
|
6706
|
+
variant: "primary",
|
|
6707
|
+
style: { width: "100%" },
|
|
6708
|
+
loading: resuming,
|
|
6709
|
+
disabled: resuming,
|
|
6710
|
+
onClick: handleContinue,
|
|
6711
|
+
children: resuming ? "Resuming\u2026" : `Continue as ${continueAs.name}`
|
|
6712
|
+
}
|
|
6713
|
+
),
|
|
6714
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6715
|
+
"button",
|
|
6716
|
+
{
|
|
6717
|
+
type: "button",
|
|
6718
|
+
className: "fd-body-sm fd-muted",
|
|
6719
|
+
style: {
|
|
6720
|
+
background: "none",
|
|
6721
|
+
border: "none",
|
|
6722
|
+
cursor: "pointer",
|
|
6723
|
+
textDecoration: "underline",
|
|
6724
|
+
padding: 0
|
|
6725
|
+
},
|
|
6726
|
+
disabled: resuming,
|
|
6727
|
+
onClick: continueAs.onDecline,
|
|
6728
|
+
children: "Not you? Sign in with flytedesk ID"
|
|
6729
|
+
}
|
|
6730
|
+
)
|
|
6731
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6732
|
+
Button,
|
|
6733
|
+
{
|
|
6734
|
+
variant: "primary",
|
|
6735
|
+
style: { width: "100%" },
|
|
6736
|
+
loading: signingIn,
|
|
6737
|
+
disabled: signingIn,
|
|
6738
|
+
onClick: handleSignIn,
|
|
6739
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
|
|
6740
|
+
"span",
|
|
6741
|
+
{
|
|
6742
|
+
style: {
|
|
6743
|
+
display: "flex",
|
|
6744
|
+
flexDirection: "row",
|
|
6745
|
+
alignItems: "center",
|
|
6746
|
+
justifyContent: "center",
|
|
6747
|
+
gap: "var(--s-8)",
|
|
6748
|
+
flexWrap: "nowrap"
|
|
6749
|
+
},
|
|
6750
|
+
children: [
|
|
6751
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(GoogleGlyph, {}),
|
|
6752
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: signingIn ? "Signing in\u2026" : "Sign in with flytedesk ID" })
|
|
6753
|
+
]
|
|
6754
|
+
}
|
|
6755
|
+
)
|
|
6756
|
+
}
|
|
6757
|
+
),
|
|
6758
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)("p", { className: "fd-body-sm fd-muted", style: { fontSize: "12px" }, children: "One account, every flytedesk app." })
|
|
6759
|
+
]
|
|
6760
|
+
}
|
|
6761
|
+
) })
|
|
6762
|
+
]
|
|
6763
|
+
}
|
|
6764
|
+
)
|
|
6765
|
+
]
|
|
6766
|
+
}
|
|
6767
|
+
)
|
|
6768
|
+
]
|
|
6769
|
+
}
|
|
6770
|
+
);
|
|
6771
|
+
}
|
|
6772
|
+
function GoogleGlyph() {
|
|
6773
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": true, children: [
|
|
6774
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6775
|
+
"path",
|
|
6776
|
+
{
|
|
6777
|
+
fill: "#4285F4",
|
|
6778
|
+
d: "M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.87 2.68-6.62Z"
|
|
6779
|
+
}
|
|
6780
|
+
),
|
|
6781
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6782
|
+
"path",
|
|
6783
|
+
{
|
|
6784
|
+
fill: "#34A853",
|
|
6785
|
+
d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.81.54-1.84.87-3.04.87-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"
|
|
6786
|
+
}
|
|
6787
|
+
),
|
|
6788
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6789
|
+
"path",
|
|
6790
|
+
{
|
|
6791
|
+
fill: "#FBBC05",
|
|
6792
|
+
d: "M3.97 10.73A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.19.29-1.73V4.94H.96A9 9 0 0 0 0 9c0 1.45.35 2.83.96 4.06l3.01-2.33Z"
|
|
6793
|
+
}
|
|
6794
|
+
),
|
|
6795
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
6796
|
+
"path",
|
|
6797
|
+
{
|
|
6798
|
+
fill: "#EA4335",
|
|
6799
|
+
d: "M9 3.58c1.32 0 2.51.45 3.44 1.35l2.59-2.59C13.46.89 11.43 0 9 0A9 9 0 0 0 .96 4.94l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"
|
|
6800
|
+
}
|
|
6801
|
+
)
|
|
6802
|
+
] });
|
|
6803
|
+
}
|
|
6804
|
+
|
|
6611
6805
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6612
|
-
var
|
|
6806
|
+
var React45 = __toESM(require("react"), 1);
|
|
6613
6807
|
|
|
6614
6808
|
// src/kits/session.ts
|
|
6615
|
-
var
|
|
6809
|
+
var React43 = __toESM(require("react"), 1);
|
|
6616
6810
|
var PERMISSION_CATALOG = [
|
|
6617
6811
|
{ group: "Plans", items: [
|
|
6618
6812
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -8179,8 +8373,8 @@ function roadmap(overrides) {
|
|
|
8179
8373
|
};
|
|
8180
8374
|
}
|
|
8181
8375
|
function useSession() {
|
|
8182
|
-
const [s, setS] =
|
|
8183
|
-
|
|
8376
|
+
const [s, setS] = React43.useState(getSession);
|
|
8377
|
+
React43.useEffect(() => subscribe(setS), []);
|
|
8184
8378
|
return s;
|
|
8185
8379
|
}
|
|
8186
8380
|
var SessionKit = {
|
|
@@ -8213,7 +8407,7 @@ var SessionKit = {
|
|
|
8213
8407
|
};
|
|
8214
8408
|
function DemoSessionProvider({ children }) {
|
|
8215
8409
|
const session = useSession();
|
|
8216
|
-
const value =
|
|
8410
|
+
const value = React43.useMemo(
|
|
8217
8411
|
() => ({
|
|
8218
8412
|
user: session.user,
|
|
8219
8413
|
roles: session.roles,
|
|
@@ -8229,11 +8423,11 @@ function DemoSessionProvider({ children }) {
|
|
|
8229
8423
|
}),
|
|
8230
8424
|
[session]
|
|
8231
8425
|
);
|
|
8232
|
-
return
|
|
8426
|
+
return React43.createElement(SessionProvider, { value }, children);
|
|
8233
8427
|
}
|
|
8234
8428
|
|
|
8235
8429
|
// src/kits/runtime.ts
|
|
8236
|
-
var
|
|
8430
|
+
var React44 = __toESM(require("react"), 1);
|
|
8237
8431
|
var WIRED_ENDPOINTS = [
|
|
8238
8432
|
// Nothing yet. Every id below would come from a real service:
|
|
8239
8433
|
// "plan.get", "placements.list", …
|
|
@@ -8404,8 +8598,8 @@ var RuntimeKit = {
|
|
|
8404
8598
|
};
|
|
8405
8599
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
8406
8600
|
function useRuntimeMode() {
|
|
8407
|
-
const [m, setM] =
|
|
8408
|
-
|
|
8601
|
+
const [m, setM] = React44.useState(RuntimeKit.getMode());
|
|
8602
|
+
React44.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
8409
8603
|
return m;
|
|
8410
8604
|
}
|
|
8411
8605
|
function useFeatureStatus(key) {
|
|
@@ -8424,7 +8618,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
8424
8618
|
var UseFeatureStatus = useFeatureStatus;
|
|
8425
8619
|
|
|
8426
8620
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8427
|
-
var
|
|
8621
|
+
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
8428
8622
|
var STATUS = {
|
|
8429
8623
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
8430
8624
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -8439,45 +8633,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8439
8633
|
const s = STATUS[item.status] || STATUS.planned;
|
|
8440
8634
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
8441
8635
|
const blocking = deps.filter((d) => !d.implemented);
|
|
8442
|
-
return /* @__PURE__ */ (0,
|
|
8443
|
-
/* @__PURE__ */ (0,
|
|
8444
|
-
/* @__PURE__ */ (0,
|
|
8445
|
-
/* @__PURE__ */ (0,
|
|
8446
|
-
/* @__PURE__ */ (0,
|
|
8636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8637
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
8638
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
8639
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
8640
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
8447
8641
|
] }),
|
|
8448
|
-
/* @__PURE__ */ (0,
|
|
8449
|
-
item.backend ? /* @__PURE__ */ (0,
|
|
8450
|
-
/* @__PURE__ */ (0,
|
|
8451
|
-
/* @__PURE__ */ (0,
|
|
8642
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
8643
|
+
item.backend ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
8644
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
8645
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
8452
8646
|
] }) : null,
|
|
8453
|
-
/* @__PURE__ */ (0,
|
|
8454
|
-
item.effort ? /* @__PURE__ */ (0,
|
|
8455
|
-
/* @__PURE__ */ (0,
|
|
8647
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8648
|
+
item.effort ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8649
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-hourglass-medium" }),
|
|
8456
8650
|
" ",
|
|
8457
8651
|
item.effort
|
|
8458
8652
|
] }) : null,
|
|
8459
|
-
/* @__PURE__ */ (0,
|
|
8460
|
-
/* @__PURE__ */ (0,
|
|
8653
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8654
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-user" }),
|
|
8461
8655
|
" ",
|
|
8462
8656
|
item.owner
|
|
8463
8657
|
] }),
|
|
8464
|
-
item.screen ? /* @__PURE__ */ (0,
|
|
8465
|
-
/* @__PURE__ */ (0,
|
|
8466
|
-
/* @__PURE__ */ (0,
|
|
8658
|
+
item.screen ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
8659
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
|
|
8660
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8467
8661
|
"button",
|
|
8468
8662
|
{
|
|
8469
8663
|
type: "button",
|
|
8470
8664
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
8471
8665
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
8472
|
-
children: /* @__PURE__ */ (0,
|
|
8666
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
8473
8667
|
}
|
|
8474
8668
|
)
|
|
8475
8669
|
] }),
|
|
8476
|
-
deps.length ? /* @__PURE__ */ (0,
|
|
8477
|
-
/* @__PURE__ */ (0,
|
|
8478
|
-
deps.map((d) => /* @__PURE__ */ (0,
|
|
8670
|
+
deps.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
8671
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
8672
|
+
deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
8479
8673
|
] }) : null,
|
|
8480
|
-
blocking.length && !item.implemented ? /* @__PURE__ */ (0,
|
|
8674
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
8481
8675
|
"Blocked until ",
|
|
8482
8676
|
blocking.map((d) => d.label).join(" and "),
|
|
8483
8677
|
" ",
|
|
@@ -8488,12 +8682,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8488
8682
|
}
|
|
8489
8683
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
8490
8684
|
const session = SessionKit.useSession();
|
|
8491
|
-
const [project, setProject] =
|
|
8492
|
-
const [q, setQ] =
|
|
8493
|
-
const scrollRef =
|
|
8494
|
-
const nowRef =
|
|
8495
|
-
const rm =
|
|
8496
|
-
const byKey =
|
|
8685
|
+
const [project, setProject] = React45.useState("");
|
|
8686
|
+
const [q, setQ] = React45.useState("");
|
|
8687
|
+
const scrollRef = React45.useRef(null);
|
|
8688
|
+
const nowRef = React45.useRef(null);
|
|
8689
|
+
const rm = React45.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
8690
|
+
const byKey = React45.useMemo(() => {
|
|
8497
8691
|
const m = {};
|
|
8498
8692
|
rm.items.forEach((i) => {
|
|
8499
8693
|
m[i.key] = i;
|
|
@@ -8502,7 +8696,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8502
8696
|
}, [rm]);
|
|
8503
8697
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
8504
8698
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
8505
|
-
|
|
8699
|
+
React45.useEffect(() => {
|
|
8506
8700
|
let raf1 = 0, raf2 = 0;
|
|
8507
8701
|
const place = () => {
|
|
8508
8702
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -8530,23 +8724,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8530
8724
|
}, 0);
|
|
8531
8725
|
const nextPhase = items.find((i) => !i.implemented);
|
|
8532
8726
|
let lastPhase = null;
|
|
8533
|
-
return /* @__PURE__ */ (0,
|
|
8534
|
-
/* @__PURE__ */ (0,
|
|
8535
|
-
/* @__PURE__ */ (0,
|
|
8536
|
-
/* @__PURE__ */ (0,
|
|
8537
|
-
/* @__PURE__ */ (0,
|
|
8727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
8728
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8729
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
8730
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
8731
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
|
|
8538
8732
|
] }),
|
|
8539
|
-
/* @__PURE__ */ (0,
|
|
8540
|
-
/* @__PURE__ */ (0,
|
|
8541
|
-
/* @__PURE__ */ (0,
|
|
8542
|
-
/* @__PURE__ */ (0,
|
|
8543
|
-
/* @__PURE__ */ (0,
|
|
8733
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
|
|
8734
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
8735
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
8736
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
8737
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
8544
8738
|
] }),
|
|
8545
|
-
/* @__PURE__ */ (0,
|
|
8546
|
-
/* @__PURE__ */ (0,
|
|
8547
|
-
/* @__PURE__ */ (0,
|
|
8548
|
-
/* @__PURE__ */ (0,
|
|
8549
|
-
/* @__PURE__ */ (0,
|
|
8739
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
8740
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
8741
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
8742
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { flex: 1 } }),
|
|
8743
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8550
8744
|
Button,
|
|
8551
8745
|
{
|
|
8552
8746
|
size: "sm",
|
|
@@ -8560,7 +8754,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8560
8754
|
}
|
|
8561
8755
|
)
|
|
8562
8756
|
] }),
|
|
8563
|
-
/* @__PURE__ */ (0,
|
|
8757
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
|
|
8564
8758
|
Flag,
|
|
8565
8759
|
{
|
|
8566
8760
|
tone: "info",
|
|
@@ -8569,60 +8763,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8569
8763
|
actions: null
|
|
8570
8764
|
}
|
|
8571
8765
|
),
|
|
8572
|
-
/* @__PURE__ */ (0,
|
|
8573
|
-
/* @__PURE__ */ (0,
|
|
8766
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-track", children: [
|
|
8767
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
8574
8768
|
items.map((item, n) => {
|
|
8575
8769
|
const showPhase = item.phase !== lastPhase;
|
|
8576
8770
|
lastPhase = item.phase;
|
|
8577
8771
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
8578
8772
|
const isBoundary = n === firstPending;
|
|
8579
|
-
return /* @__PURE__ */ (0,
|
|
8580
|
-
showPhase ? /* @__PURE__ */ (0,
|
|
8581
|
-
/* @__PURE__ */ (0,
|
|
8582
|
-
/* @__PURE__ */ (0,
|
|
8583
|
-
item.phase === 0 ? null : /* @__PURE__ */ (0,
|
|
8773
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(React45.Fragment, { children: [
|
|
8774
|
+
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-era", children: [
|
|
8775
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
8776
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
8777
|
+
item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8584
8778
|
fmtDate(item.phaseStart),
|
|
8585
8779
|
" \u2013 ",
|
|
8586
8780
|
fmtDate(item.date)
|
|
8587
8781
|
] }),
|
|
8588
|
-
/* @__PURE__ */ (0,
|
|
8782
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8589
8783
|
"\xB7 ",
|
|
8590
8784
|
inPhase,
|
|
8591
8785
|
" feature",
|
|
8592
8786
|
inPhase === 1 ? "" : "s"
|
|
8593
8787
|
] })
|
|
8594
8788
|
] }),
|
|
8595
|
-
item.phaseWhy ? /* @__PURE__ */ (0,
|
|
8789
|
+
item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
8596
8790
|
] }) : null,
|
|
8597
|
-
isBoundary ? /* @__PURE__ */ (0,
|
|
8598
|
-
/* @__PURE__ */ (0,
|
|
8791
|
+
isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { className: "fd-rm-now-pill", children: [
|
|
8792
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("i", { className: "ph ph-map-pin" }),
|
|
8599
8793
|
" You are here \u2014 everything above is wired"
|
|
8600
8794
|
] }) }) : null,
|
|
8601
|
-
/* @__PURE__ */ (0,
|
|
8602
|
-
/* @__PURE__ */ (0,
|
|
8603
|
-
/* @__PURE__ */ (0,
|
|
8795
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-row", children: [
|
|
8796
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
8797
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "fd-rm-date", children: [
|
|
8604
8798
|
fmtDate(item.date),
|
|
8605
|
-
/* @__PURE__ */ (0,
|
|
8606
|
-
/* @__PURE__ */ (0,
|
|
8799
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("br", {}),
|
|
8800
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
8607
8801
|
] }),
|
|
8608
|
-
/* @__PURE__ */ (0,
|
|
8802
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
|
|
8609
8803
|
] })
|
|
8610
8804
|
] }, item.key);
|
|
8611
8805
|
}),
|
|
8612
|
-
!items.length ? /* @__PURE__ */ (0,
|
|
8806
|
+
!items.length ? /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
8613
8807
|
] }) }) }),
|
|
8614
|
-
/* @__PURE__ */ (0,
|
|
8808
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
8615
8809
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
8616
|
-
/* @__PURE__ */ (0,
|
|
8810
|
+
/* @__PURE__ */ (0, import_jsx_runtime69.jsx)("code", { className: "fd-mono", children: "implemented" }),
|
|
8617
8811
|
" field, so this page cannot drift from what the apps actually do."
|
|
8618
8812
|
] })
|
|
8619
8813
|
] });
|
|
8620
8814
|
}
|
|
8621
8815
|
|
|
8622
8816
|
// src/components/platform/ComingSoon.tsx
|
|
8623
|
-
var
|
|
8817
|
+
var React46 = __toESM(require("react"), 1);
|
|
8624
8818
|
var import_react_dom6 = require("react-dom");
|
|
8625
|
-
var
|
|
8819
|
+
var import_jsx_runtime70 = require("react/jsx-runtime");
|
|
8626
8820
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
8627
8821
|
function readBypassed() {
|
|
8628
8822
|
try {
|
|
@@ -8638,8 +8832,8 @@ function writeBypassed(list) {
|
|
|
8638
8832
|
}
|
|
8639
8833
|
}
|
|
8640
8834
|
function useBypass(key) {
|
|
8641
|
-
const [on, setOn] =
|
|
8642
|
-
|
|
8835
|
+
const [on, setOn] = React46.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
8836
|
+
React46.useEffect(() => {
|
|
8643
8837
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
8644
8838
|
}, [key]);
|
|
8645
8839
|
const set = (next) => {
|
|
@@ -8652,43 +8846,43 @@ function useBypass(key) {
|
|
|
8652
8846
|
return [on, set];
|
|
8653
8847
|
}
|
|
8654
8848
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
8655
|
-
return /* @__PURE__ */ (0,
|
|
8656
|
-
/* @__PURE__ */ (0,
|
|
8657
|
-
/* @__PURE__ */ (0,
|
|
8849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(import_jsx_runtime70.Fragment, { children: [
|
|
8850
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
8851
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8658
8852
|
label
|
|
8659
8853
|
] }),
|
|
8660
|
-
detail ? /* @__PURE__ */ (0,
|
|
8661
|
-
backend ? /* @__PURE__ */ (0,
|
|
8662
|
-
/* @__PURE__ */ (0,
|
|
8854
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
8855
|
+
backend ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-backend", children: [
|
|
8856
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-overline", children: "Needs" }),
|
|
8663
8857
|
" ",
|
|
8664
8858
|
backend
|
|
8665
8859
|
] }) : null,
|
|
8666
|
-
eta || effort || onRoadmap ? /* @__PURE__ */ (0,
|
|
8667
|
-
eta ? /* @__PURE__ */ (0,
|
|
8668
|
-
/* @__PURE__ */ (0,
|
|
8860
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-meta", children: [
|
|
8861
|
+
eta ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
|
|
8862
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
8669
8863
|
" ",
|
|
8670
8864
|
eta
|
|
8671
8865
|
] }) : null,
|
|
8672
|
-
effort ? /* @__PURE__ */ (0,
|
|
8673
|
-
/* @__PURE__ */ (0,
|
|
8866
|
+
effort ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { children: [
|
|
8867
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
8674
8868
|
" ",
|
|
8675
8869
|
effort
|
|
8676
8870
|
] }) : null,
|
|
8677
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
8871
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8678
8872
|
"See the roadmap ",
|
|
8679
|
-
/* @__PURE__ */ (0,
|
|
8873
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8680
8874
|
] }) : null
|
|
8681
8875
|
] }) : null,
|
|
8682
|
-
allowed ? /* @__PURE__ */ (0,
|
|
8683
|
-
/* @__PURE__ */ (0,
|
|
8876
|
+
allowed ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
8877
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
8684
8878
|
" View and use it anyway"
|
|
8685
8879
|
] }) : null
|
|
8686
8880
|
] });
|
|
8687
8881
|
}
|
|
8688
8882
|
function useHoverCard(open) {
|
|
8689
|
-
const anchor =
|
|
8690
|
-
const [pos, setPos] =
|
|
8691
|
-
|
|
8883
|
+
const anchor = React46.useRef(null);
|
|
8884
|
+
const [pos, setPos] = React46.useState(null);
|
|
8885
|
+
React46.useLayoutEffect(() => {
|
|
8692
8886
|
if (!open || !anchor.current) {
|
|
8693
8887
|
setPos(null);
|
|
8694
8888
|
return;
|
|
@@ -8740,9 +8934,9 @@ function ComingSoon({
|
|
|
8740
8934
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
8741
8935
|
if (inline) {
|
|
8742
8936
|
if (allowed && bypassed) {
|
|
8743
|
-
return /* @__PURE__ */ (0,
|
|
8937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
8744
8938
|
children,
|
|
8745
|
-
/* @__PURE__ */ (0,
|
|
8939
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8746
8940
|
"button",
|
|
8747
8941
|
{
|
|
8748
8942
|
type: "button",
|
|
@@ -8750,12 +8944,12 @@ function ComingSoon({
|
|
|
8750
8944
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
8751
8945
|
onClick: () => setBypassed(false),
|
|
8752
8946
|
"aria-label": "Re-blur this unwired feature",
|
|
8753
|
-
children: /* @__PURE__ */ (0,
|
|
8947
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8754
8948
|
}
|
|
8755
8949
|
)
|
|
8756
8950
|
] });
|
|
8757
8951
|
}
|
|
8758
|
-
return /* @__PURE__ */ (0,
|
|
8952
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8759
8953
|
InlineSoon,
|
|
8760
8954
|
{
|
|
8761
8955
|
label,
|
|
@@ -8775,20 +8969,20 @@ function ComingSoon({
|
|
|
8775
8969
|
);
|
|
8776
8970
|
}
|
|
8777
8971
|
if (allowed && bypassed) {
|
|
8778
|
-
return /* @__PURE__ */ (0,
|
|
8779
|
-
/* @__PURE__ */ (0,
|
|
8780
|
-
/* @__PURE__ */ (0,
|
|
8781
|
-
/* @__PURE__ */ (0,
|
|
8972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
8973
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
|
|
8974
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
8975
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8782
8976
|
"Unwired feature \u2014 you are using it anyway"
|
|
8783
8977
|
] }),
|
|
8784
|
-
/* @__PURE__ */ (0,
|
|
8785
|
-
/* @__PURE__ */ (0,
|
|
8786
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
8978
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
8979
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("span", { className: "fd-soon-bar-actions", children: [
|
|
8980
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8787
8981
|
"Roadmap ",
|
|
8788
|
-
/* @__PURE__ */ (0,
|
|
8982
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8789
8983
|
] }) : null,
|
|
8790
|
-
/* @__PURE__ */ (0,
|
|
8791
|
-
/* @__PURE__ */ (0,
|
|
8984
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
8985
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
8792
8986
|
" Re-blur"
|
|
8793
8987
|
] })
|
|
8794
8988
|
] })
|
|
@@ -8796,10 +8990,10 @@ function ComingSoon({
|
|
|
8796
8990
|
children
|
|
8797
8991
|
] });
|
|
8798
8992
|
}
|
|
8799
|
-
return /* @__PURE__ */ (0,
|
|
8800
|
-
/* @__PURE__ */ (0,
|
|
8801
|
-
/* @__PURE__ */ (0,
|
|
8802
|
-
/* @__PURE__ */ (0,
|
|
8993
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
8994
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
8995
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-veil" }),
|
|
8996
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8803
8997
|
SoonCard,
|
|
8804
8998
|
{
|
|
8805
8999
|
label,
|
|
@@ -8815,10 +9009,10 @@ function ComingSoon({
|
|
|
8815
9009
|
] });
|
|
8816
9010
|
}
|
|
8817
9011
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
8818
|
-
const [open, setOpen] =
|
|
9012
|
+
const [open, setOpen] = React46.useState(false);
|
|
8819
9013
|
const [anchor, pos] = useHoverCard(open);
|
|
8820
9014
|
const zIndex = useOverlayLayer(open);
|
|
8821
|
-
const close =
|
|
9015
|
+
const close = React46.useRef(null);
|
|
8822
9016
|
const show = () => {
|
|
8823
9017
|
if (close.current) {
|
|
8824
9018
|
clearTimeout(close.current);
|
|
@@ -8834,10 +9028,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8834
9028
|
setOpen(false);
|
|
8835
9029
|
}, 140);
|
|
8836
9030
|
};
|
|
8837
|
-
|
|
9031
|
+
React46.useEffect(() => () => {
|
|
8838
9032
|
if (close.current) clearTimeout(close.current);
|
|
8839
9033
|
}, []);
|
|
8840
|
-
return /* @__PURE__ */ (0,
|
|
9034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)(
|
|
8841
9035
|
"span",
|
|
8842
9036
|
{
|
|
8843
9037
|
ref: anchor,
|
|
@@ -8848,8 +9042,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8848
9042
|
onBlur: hide,
|
|
8849
9043
|
...rest,
|
|
8850
9044
|
children: [
|
|
8851
|
-
/* @__PURE__ */ (0,
|
|
8852
|
-
/* @__PURE__ */ (0,
|
|
9045
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
9046
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8853
9047
|
"button",
|
|
8854
9048
|
{
|
|
8855
9049
|
type: "button",
|
|
@@ -8860,11 +9054,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8860
9054
|
onFocus: show,
|
|
8861
9055
|
onBlur: hide,
|
|
8862
9056
|
onClick: () => open ? setOpen(false) : show(),
|
|
8863
|
-
children: /* @__PURE__ */ (0,
|
|
9057
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8864
9058
|
}
|
|
8865
9059
|
),
|
|
8866
9060
|
open && pos ? (0, import_react_dom6.createPortal)(
|
|
8867
|
-
/* @__PURE__ */ (0,
|
|
9061
|
+
/* @__PURE__ */ (0, import_jsx_runtime70.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8868
9062
|
"div",
|
|
8869
9063
|
{
|
|
8870
9064
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -8872,7 +9066,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8872
9066
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
8873
9067
|
onMouseEnter: show,
|
|
8874
9068
|
onMouseLeave: hide,
|
|
8875
|
-
children: /* @__PURE__ */ (0,
|
|
9069
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
|
|
8876
9070
|
SoonCard,
|
|
8877
9071
|
{
|
|
8878
9072
|
label,
|
|
@@ -8902,10 +9096,10 @@ function formatEta(iso2) {
|
|
|
8902
9096
|
var FormatEta = formatEta;
|
|
8903
9097
|
|
|
8904
9098
|
// src/components/platform/Gate.tsx
|
|
8905
|
-
var
|
|
9099
|
+
var import_jsx_runtime71 = require("react/jsx-runtime");
|
|
8906
9100
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
8907
9101
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
8908
|
-
return /* @__PURE__ */ (0,
|
|
9102
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
|
|
8909
9103
|
"div",
|
|
8910
9104
|
{
|
|
8911
9105
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -8921,14 +9115,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
8921
9115
|
},
|
|
8922
9116
|
...rest,
|
|
8923
9117
|
children: [
|
|
8924
|
-
/* @__PURE__ */ (0,
|
|
8925
|
-
/* @__PURE__ */ (0,
|
|
8926
|
-
/* @__PURE__ */ (0,
|
|
9118
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
9119
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
9120
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
8927
9121
|
] }),
|
|
8928
|
-
/* @__PURE__ */ (0,
|
|
8929
|
-
need.length ? /* @__PURE__ */ (0,
|
|
8930
|
-
/* @__PURE__ */ (0,
|
|
8931
|
-
need.map((p) => /* @__PURE__ */ (0,
|
|
9122
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
|
|
9123
|
+
need.length ? /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
9124
|
+
/* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
9125
|
+
need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("code", { className: "fd-mono", style: {
|
|
8932
9126
|
fontSize: 11.5,
|
|
8933
9127
|
padding: "2px 7px",
|
|
8934
9128
|
borderRadius: 5,
|
|
@@ -8949,7 +9143,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
8949
9143
|
if (ok) return children;
|
|
8950
9144
|
if (fallback !== void 0) return fallback;
|
|
8951
9145
|
if (silent) return null;
|
|
8952
|
-
return /* @__PURE__ */ (0,
|
|
9146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
8953
9147
|
}
|
|
8954
9148
|
function FeatureGate({
|
|
8955
9149
|
flag,
|
|
@@ -8972,7 +9166,7 @@ function FeatureGate({
|
|
|
8972
9166
|
const f = SessionKit.findFlag(flag) || {};
|
|
8973
9167
|
const missing = rt.missing || [];
|
|
8974
9168
|
const canBypass = bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
8975
|
-
return /* @__PURE__ */ (0,
|
|
9169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
|
|
8976
9170
|
ComingSoon,
|
|
8977
9171
|
{
|
|
8978
9172
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -8993,26 +9187,26 @@ function FeatureGate({
|
|
|
8993
9187
|
function PermissionHint({ perm, children }) {
|
|
8994
9188
|
const { can: can2 } = useSessionContext();
|
|
8995
9189
|
if (can2(perm)) return children;
|
|
8996
|
-
return /* @__PURE__ */ (0,
|
|
9190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
|
|
8997
9191
|
"span",
|
|
8998
9192
|
{
|
|
8999
9193
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
9000
9194
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
9001
9195
|
"aria-disabled": "true",
|
|
9002
|
-
children: /* @__PURE__ */ (0,
|
|
9196
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { style: { pointerEvents: "none" }, children })
|
|
9003
9197
|
}
|
|
9004
9198
|
);
|
|
9005
9199
|
}
|
|
9006
9200
|
|
|
9007
9201
|
// src/components/platform/ModeSwitch.tsx
|
|
9008
|
-
var
|
|
9009
|
-
var
|
|
9202
|
+
var React47 = __toESM(require("react"), 1);
|
|
9203
|
+
var import_jsx_runtime72 = require("react/jsx-runtime");
|
|
9010
9204
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
9011
9205
|
const mode2 = useRuntimeMode();
|
|
9012
|
-
const [open, setOpen] =
|
|
9206
|
+
const [open, setOpen] = React47.useState(false);
|
|
9013
9207
|
const zIndex = useOverlayLayer(open);
|
|
9014
|
-
const ref =
|
|
9015
|
-
|
|
9208
|
+
const ref = React47.useRef(null);
|
|
9209
|
+
React47.useEffect(() => {
|
|
9016
9210
|
if (!open) return;
|
|
9017
9211
|
const away = (e) => {
|
|
9018
9212
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -9034,8 +9228,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9034
9228
|
RuntimeKit.setMode(next);
|
|
9035
9229
|
setOpen(false);
|
|
9036
9230
|
};
|
|
9037
|
-
return /* @__PURE__ */ (0,
|
|
9038
|
-
/* @__PURE__ */ (0,
|
|
9231
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
9232
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
9039
9233
|
"button",
|
|
9040
9234
|
{
|
|
9041
9235
|
type: "button",
|
|
@@ -9045,29 +9239,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9045
9239
|
title: test ? "Test mode \u2014 every response is simulated. Click to inspect requests or return to live mode." : "Live mode \u2014 incomplete features are shown under construction. Click for test mode.",
|
|
9046
9240
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
9047
9241
|
children: [
|
|
9048
|
-
/* @__PURE__ */ (0,
|
|
9049
|
-
test && requestCount ? /* @__PURE__ */ (0,
|
|
9242
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
9243
|
+
test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
9050
9244
|
]
|
|
9051
9245
|
}
|
|
9052
9246
|
),
|
|
9053
|
-
open ? /* @__PURE__ */ (0,
|
|
9054
|
-
/* @__PURE__ */ (0,
|
|
9055
|
-
/* @__PURE__ */ (0,
|
|
9056
|
-
/* @__PURE__ */ (0,
|
|
9247
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-view-enter fd-mode-pop", style: { zIndex }, children: [
|
|
9248
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9249
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
9250
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
9057
9251
|
test ? "Test mode" : "Live mode"
|
|
9058
9252
|
] }),
|
|
9059
|
-
test ? /* @__PURE__ */ (0,
|
|
9253
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
9060
9254
|
requestCount,
|
|
9061
9255
|
" simulated request",
|
|
9062
9256
|
requestCount === 1 ? "" : "s"
|
|
9063
9257
|
] }) : null,
|
|
9064
|
-
/* @__PURE__ */ (0,
|
|
9065
|
-
test && onClearLog ? /* @__PURE__ */ (0,
|
|
9258
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
|
|
9259
|
+
test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
9066
9260
|
] }),
|
|
9067
|
-
/* @__PURE__ */ (0,
|
|
9068
|
-
/* @__PURE__ */ (0,
|
|
9069
|
-
/* @__PURE__ */ (0,
|
|
9070
|
-
/* @__PURE__ */ (0,
|
|
9261
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9262
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
|
|
9263
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
9264
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
9071
9265
|
s.endpointsWired,
|
|
9072
9266
|
" endpoint",
|
|
9073
9267
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -9077,58 +9271,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
9077
9271
|
s.total,
|
|
9078
9272
|
" features complete"
|
|
9079
9273
|
] }),
|
|
9080
|
-
onOpenSpec ? /* @__PURE__ */ (0,
|
|
9081
|
-
/* @__PURE__ */ (0,
|
|
9082
|
-
/* @__PURE__ */ (0,
|
|
9274
|
+
onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(import_jsx_runtime72.Fragment, { children: [
|
|
9275
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { flex: 1 } }),
|
|
9276
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
9083
9277
|
setOpen(false);
|
|
9084
9278
|
onOpenSpec();
|
|
9085
9279
|
}, children: [
|
|
9086
9280
|
"API spec ",
|
|
9087
|
-
/* @__PURE__ */ (0,
|
|
9281
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
9088
9282
|
] })
|
|
9089
9283
|
] }) : null
|
|
9090
9284
|
] })
|
|
9091
9285
|
] }),
|
|
9092
|
-
/* @__PURE__ */ (0,
|
|
9093
|
-
/* @__PURE__ */ (0,
|
|
9094
|
-
/* @__PURE__ */ (0,
|
|
9095
|
-
/* @__PURE__ */ (0,
|
|
9096
|
-
/* @__PURE__ */ (0,
|
|
9097
|
-
/* @__PURE__ */ (0,
|
|
9286
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-choice", children: [
|
|
9287
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
9288
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
9289
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
9290
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
9291
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
9098
9292
|
] }),
|
|
9099
|
-
!test ? /* @__PURE__ */ (0,
|
|
9293
|
+
!test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
9100
9294
|
] }),
|
|
9101
|
-
/* @__PURE__ */ (0,
|
|
9102
|
-
/* @__PURE__ */ (0,
|
|
9103
|
-
/* @__PURE__ */ (0,
|
|
9104
|
-
/* @__PURE__ */ (0,
|
|
9105
|
-
/* @__PURE__ */ (0,
|
|
9295
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
9296
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
9297
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
9298
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
9299
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
9106
9300
|
] }),
|
|
9107
|
-
test ? /* @__PURE__ */ (0,
|
|
9301
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
9108
9302
|
] })
|
|
9109
9303
|
] }),
|
|
9110
|
-
test && renderLog ? /* @__PURE__ */ (0,
|
|
9304
|
+
test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
9111
9305
|
] }) }) : null
|
|
9112
9306
|
] });
|
|
9113
9307
|
}
|
|
9114
9308
|
function TestModeBar({ onExit }) {
|
|
9115
9309
|
const mode2 = useRuntimeMode();
|
|
9116
9310
|
if (mode2 !== "test") return null;
|
|
9117
|
-
return /* @__PURE__ */ (0,
|
|
9118
|
-
/* @__PURE__ */ (0,
|
|
9119
|
-
/* @__PURE__ */ (0,
|
|
9311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "fd-testbar", role: "status", children: [
|
|
9312
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
|
|
9313
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
9120
9314
|
"Test mode"
|
|
9121
9315
|
] }),
|
|
9122
|
-
/* @__PURE__ */ (0,
|
|
9123
|
-
/* @__PURE__ */ (0,
|
|
9124
|
-
/* @__PURE__ */ (0,
|
|
9316
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
9317
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
9318
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
9125
9319
|
" Back to live mode"
|
|
9126
9320
|
] })
|
|
9127
9321
|
] });
|
|
9128
9322
|
}
|
|
9129
9323
|
|
|
9130
9324
|
// src/components/planner/ChannelMeta.tsx
|
|
9131
|
-
var
|
|
9325
|
+
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
9132
9326
|
var CHANNEL_WEIGHTS = {
|
|
9133
9327
|
"OOH": 50,
|
|
9134
9328
|
"DOOH": 50,
|
|
@@ -9181,9 +9375,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
9181
9375
|
const m = ChannelMeta(channel);
|
|
9182
9376
|
const wt = channelWeightOf(channel || "");
|
|
9183
9377
|
if (dot) {
|
|
9184
|
-
return /* @__PURE__ */ (0,
|
|
9378
|
+
return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
9185
9379
|
}
|
|
9186
|
-
return /* @__PURE__ */ (0,
|
|
9380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
|
|
9187
9381
|
"span",
|
|
9188
9382
|
{
|
|
9189
9383
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -9191,16 +9385,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
9191
9385
|
style: { "--chan": m.color },
|
|
9192
9386
|
...rest,
|
|
9193
9387
|
children: [
|
|
9194
|
-
/* @__PURE__ */ (0,
|
|
9195
|
-
showLabel ? /* @__PURE__ */ (0,
|
|
9196
|
-
weight ? /* @__PURE__ */ (0,
|
|
9388
|
+
/* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
9389
|
+
showLabel ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
9390
|
+
weight ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
9197
9391
|
]
|
|
9198
9392
|
}
|
|
9199
9393
|
);
|
|
9200
9394
|
}
|
|
9201
9395
|
|
|
9202
9396
|
// src/components/planner/SaturationDistribution.tsx
|
|
9203
|
-
var
|
|
9397
|
+
var import_jsx_runtime74 = require("react/jsx-runtime");
|
|
9204
9398
|
var BANDS2 = [
|
|
9205
9399
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
9206
9400
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -9211,24 +9405,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9211
9405
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
9212
9406
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
9213
9407
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
9214
|
-
return /* @__PURE__ */ (0,
|
|
9215
|
-
/* @__PURE__ */ (0,
|
|
9408
|
+
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9409
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
9216
9410
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
9217
9411
|
const active = selectedBand === g.key;
|
|
9218
|
-
return /* @__PURE__ */ (0,
|
|
9412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
|
|
9219
9413
|
"button",
|
|
9220
9414
|
{
|
|
9221
9415
|
type: "button",
|
|
9222
9416
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
9223
9417
|
style: { display: "flex", flexDirection: "column", justifyContent: "flex-end", gap: 10, padding: 12, border: "1px solid " + (active ? "var(--border-strong)" : "var(--border)"), borderRadius: "var(--r-lg)", background: active ? "var(--surface-2)" : "var(--surface)", cursor: onSelectBand ? "pointer" : "default", textAlign: "left", minHeight: 190, minWidth: 0, transition: "background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease)" },
|
|
9224
9418
|
children: [
|
|
9225
|
-
/* @__PURE__ */ (0,
|
|
9419
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
|
|
9226
9420
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
9227
9421
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
9228
9422
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
9229
9423
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
9230
9424
|
// is still one hover away via `title`.
|
|
9231
|
-
/* @__PURE__ */ (0,
|
|
9425
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)(
|
|
9232
9426
|
"span",
|
|
9233
9427
|
{
|
|
9234
9428
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -9238,13 +9432,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9238
9432
|
c.name
|
|
9239
9433
|
)
|
|
9240
9434
|
)) }),
|
|
9241
|
-
/* @__PURE__ */ (0,
|
|
9242
|
-
/* @__PURE__ */ (0,
|
|
9243
|
-
/* @__PURE__ */ (0,
|
|
9435
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
9436
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
9437
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
9244
9438
|
] }),
|
|
9245
|
-
/* @__PURE__ */ (0,
|
|
9246
|
-
/* @__PURE__ */ (0,
|
|
9247
|
-
/* @__PURE__ */ (0,
|
|
9439
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
9440
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-label-lg", children: g.label }),
|
|
9441
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
9248
9442
|
"CRP ",
|
|
9249
9443
|
g.range
|
|
9250
9444
|
] })
|
|
@@ -9254,10 +9448,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9254
9448
|
g.key
|
|
9255
9449
|
);
|
|
9256
9450
|
}) }),
|
|
9257
|
-
floorBand ? /* @__PURE__ */ (0,
|
|
9258
|
-
/* @__PURE__ */ (0,
|
|
9259
|
-
/* @__PURE__ */ (0,
|
|
9260
|
-
/* @__PURE__ */ (0,
|
|
9451
|
+
floorBand ? /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
9452
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
9453
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
9454
|
+
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("strong", { style: { color: "var(--text)" }, children: [
|
|
9261
9455
|
"Plan floor ",
|
|
9262
9456
|
floorScore
|
|
9263
9457
|
] }),
|
|
@@ -9268,8 +9462,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9268
9462
|
}
|
|
9269
9463
|
|
|
9270
9464
|
// src/components/planner/MixGap.tsx
|
|
9271
|
-
var
|
|
9272
|
-
var
|
|
9465
|
+
var React48 = __toESM(require("react"), 1);
|
|
9466
|
+
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
9273
9467
|
var MIX_GAP_LAYOUT = {
|
|
9274
9468
|
trackHeight: 30,
|
|
9275
9469
|
barHeight: 20,
|
|
@@ -9283,19 +9477,19 @@ function mixGapOffset(value, max) {
|
|
|
9283
9477
|
}
|
|
9284
9478
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
9285
9479
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
9286
|
-
const [hover, setHover] =
|
|
9480
|
+
const [hover, setHover] = React48.useState(null);
|
|
9287
9481
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
9288
9482
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
9289
9483
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
9290
9484
|
const barTop = (trackHeight - barHeight) / 2;
|
|
9291
|
-
return /* @__PURE__ */ (0,
|
|
9292
|
-
/* @__PURE__ */ (0,
|
|
9293
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0,
|
|
9294
|
-
/* @__PURE__ */ (0,
|
|
9485
|
+
return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
9486
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
9487
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9488
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
9295
9489
|
l
|
|
9296
9490
|
] }, l)),
|
|
9297
|
-
/* @__PURE__ */ (0,
|
|
9298
|
-
/* @__PURE__ */ (0,
|
|
9491
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9492
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
|
|
9299
9493
|
"Target"
|
|
9300
9494
|
] })
|
|
9301
9495
|
] }),
|
|
@@ -9304,7 +9498,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9304
9498
|
const tone = toneOf(gap);
|
|
9305
9499
|
const tip = "Realized " + r.realized + "% vs " + r.target + "% target" + (gap < -1 ? " \xB7 " + Math.abs(gap).toFixed(0) + " pts short" : gap > 1 ? " \xB7 " + gap.toFixed(0) + " pts over" : " \xB7 on target") + (r.note ? " \u2014 " + r.note : "");
|
|
9306
9500
|
const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
|
|
9307
|
-
return /* @__PURE__ */ (0,
|
|
9501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(
|
|
9308
9502
|
"div",
|
|
9309
9503
|
{
|
|
9310
9504
|
className: "fd-row",
|
|
@@ -9312,15 +9506,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9312
9506
|
onMouseEnter: () => setHover(r.channel),
|
|
9313
9507
|
onMouseLeave: () => setHover(null),
|
|
9314
9508
|
children: [
|
|
9315
|
-
/* @__PURE__ */ (0,
|
|
9316
|
-
/* @__PURE__ */ (0,
|
|
9317
|
-
/* @__PURE__ */ (0,
|
|
9318
|
-
/* @__PURE__ */ (0,
|
|
9319
|
-
/* @__PURE__ */ (0,
|
|
9509
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime75.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
9510
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime75.jsxs)(import_jsx_runtime75.Fragment, { children: [
|
|
9511
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
|
|
9512
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
|
|
9513
|
+
/* @__PURE__ */ (0, import_jsx_runtime75.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
|
|
9320
9514
|
r.realized,
|
|
9321
9515
|
"%"
|
|
9322
9516
|
] }),
|
|
9323
|
-
hover === r.channel ? /* @__PURE__ */ (0,
|
|
9517
|
+
hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime75.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
|
|
9324
9518
|
] }) })
|
|
9325
9519
|
]
|
|
9326
9520
|
},
|
|
@@ -9331,7 +9525,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9331
9525
|
}
|
|
9332
9526
|
|
|
9333
9527
|
// src/components/planner/ChannelContribution.tsx
|
|
9334
|
-
var
|
|
9528
|
+
var import_jsx_runtime76 = require("react/jsx-runtime");
|
|
9335
9529
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
9336
9530
|
function ChannelContribution({
|
|
9337
9531
|
channels = [],
|
|
@@ -9347,9 +9541,9 @@ function ChannelContribution({
|
|
|
9347
9541
|
const grand = total !== void 0 ? total : base + bonus;
|
|
9348
9542
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
9349
9543
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
9350
|
-
return /* @__PURE__ */ (0,
|
|
9351
|
-
loading ? /* @__PURE__ */ (0,
|
|
9352
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
9544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9545
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
9546
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9353
9547
|
"span",
|
|
9354
9548
|
{
|
|
9355
9549
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -9358,7 +9552,7 @@ function ChannelContribution({
|
|
|
9358
9552
|
},
|
|
9359
9553
|
c.name
|
|
9360
9554
|
)),
|
|
9361
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
9555
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9362
9556
|
"span",
|
|
9363
9557
|
{
|
|
9364
9558
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -9367,18 +9561,18 @@ function ChannelContribution({
|
|
|
9367
9561
|
}
|
|
9368
9562
|
) : null
|
|
9369
9563
|
] }),
|
|
9370
|
-
showTable ? /* @__PURE__ */ (0,
|
|
9371
|
-
/* @__PURE__ */ (0,
|
|
9372
|
-
/* @__PURE__ */ (0,
|
|
9373
|
-
/* @__PURE__ */ (0,
|
|
9374
|
-
/* @__PURE__ */ (0,
|
|
9375
|
-
/* @__PURE__ */ (0,
|
|
9376
|
-
/* @__PURE__ */ (0,
|
|
9564
|
+
showTable ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
9565
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9566
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
|
|
9567
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
|
|
9568
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
9569
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
9570
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
9377
9571
|
] }) }),
|
|
9378
|
-
/* @__PURE__ */ (0,
|
|
9379
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
9380
|
-
/* @__PURE__ */ (0,
|
|
9381
|
-
/* @__PURE__ */ (0,
|
|
9572
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tbody", { children: [
|
|
9573
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9574
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
9575
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9382
9576
|
"span",
|
|
9383
9577
|
{
|
|
9384
9578
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -9387,38 +9581,38 @@ function ChannelContribution({
|
|
|
9387
9581
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
9388
9582
|
}
|
|
9389
9583
|
) }),
|
|
9390
|
-
/* @__PURE__ */ (0,
|
|
9391
|
-
/* @__PURE__ */ (0,
|
|
9392
|
-
/* @__PURE__ */ (0,
|
|
9584
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.spend }),
|
|
9585
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
9586
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
|
|
9393
9587
|
pct(c.crp).toFixed(0),
|
|
9394
9588
|
"%"
|
|
9395
9589
|
] })
|
|
9396
9590
|
] }, c.name)),
|
|
9397
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
9398
|
-
/* @__PURE__ */ (0,
|
|
9399
|
-
/* @__PURE__ */ (0,
|
|
9591
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { children: [
|
|
9592
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
9593
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
|
|
9400
9594
|
"Surround-sound bonus"
|
|
9401
9595
|
] }) }),
|
|
9402
|
-
/* @__PURE__ */ (0,
|
|
9596
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
9403
9597
|
"+",
|
|
9404
9598
|
bonusPct,
|
|
9405
9599
|
"% of +",
|
|
9406
9600
|
bonusMax,
|
|
9407
9601
|
"%"
|
|
9408
9602
|
] }) }),
|
|
9409
|
-
/* @__PURE__ */ (0,
|
|
9410
|
-
/* @__PURE__ */ (0,
|
|
9411
|
-
/* @__PURE__ */ (0,
|
|
9603
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
9604
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
9605
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("td", { className: "is-num", children: [
|
|
9412
9606
|
pct(bonus).toFixed(0),
|
|
9413
9607
|
"%"
|
|
9414
9608
|
] })
|
|
9415
9609
|
] }) : null,
|
|
9416
|
-
/* @__PURE__ */ (0,
|
|
9417
|
-
/* @__PURE__ */ (0,
|
|
9418
|
-
/* @__PURE__ */ (0,
|
|
9419
|
-
/* @__PURE__ */ (0,
|
|
9420
|
-
/* @__PURE__ */ (0,
|
|
9421
|
-
/* @__PURE__ */ (0,
|
|
9610
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
9611
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
9612
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", {}),
|
|
9613
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
9614
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
9615
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
9422
9616
|
] })
|
|
9423
9617
|
] })
|
|
9424
9618
|
] }) : null
|
|
@@ -9426,8 +9620,8 @@ function ChannelContribution({
|
|
|
9426
9620
|
}
|
|
9427
9621
|
|
|
9428
9622
|
// src/components/planner/BudgetReallocator.tsx
|
|
9429
|
-
var
|
|
9430
|
-
var
|
|
9623
|
+
var React49 = __toESM(require("react"), 1);
|
|
9624
|
+
var import_jsx_runtime77 = require("react/jsx-runtime");
|
|
9431
9625
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
9432
9626
|
function BudgetReallocator({
|
|
9433
9627
|
campus,
|
|
@@ -9442,8 +9636,8 @@ function BudgetReallocator({
|
|
|
9442
9636
|
onCancel,
|
|
9443
9637
|
className = ""
|
|
9444
9638
|
}) {
|
|
9445
|
-
const [draft, setDraft] =
|
|
9446
|
-
|
|
9639
|
+
const [draft, setDraft] = React49.useState(spend);
|
|
9640
|
+
React49.useEffect(() => setDraft(spend), [spend]);
|
|
9447
9641
|
const dirty = draft !== spend;
|
|
9448
9642
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
9449
9643
|
const nextBand = bandFor(nextCrp);
|
|
@@ -9458,10 +9652,10 @@ function BudgetReallocator({
|
|
|
9458
9652
|
setDraft(spend);
|
|
9459
9653
|
if (onCancel) onCancel();
|
|
9460
9654
|
};
|
|
9461
|
-
const trackRef =
|
|
9462
|
-
const chipRef =
|
|
9463
|
-
const [chipLeft, setChipLeft] =
|
|
9464
|
-
|
|
9655
|
+
const trackRef = React49.useRef(null);
|
|
9656
|
+
const chipRef = React49.useRef(null);
|
|
9657
|
+
const [chipLeft, setChipLeft] = React49.useState(null);
|
|
9658
|
+
React49.useLayoutEffect(() => {
|
|
9465
9659
|
const track = trackRef.current;
|
|
9466
9660
|
if (!dirty || !track) {
|
|
9467
9661
|
setChipLeft(null);
|
|
@@ -9482,23 +9676,23 @@ function BudgetReallocator({
|
|
|
9482
9676
|
ro.observe(track);
|
|
9483
9677
|
return () => ro.disconnect();
|
|
9484
9678
|
}, [dirty, pct]);
|
|
9485
|
-
return /* @__PURE__ */ (0,
|
|
9679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
|
|
9486
9680
|
"div",
|
|
9487
9681
|
{
|
|
9488
9682
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
9489
9683
|
style: { gap: 14, padding: 18, border: "1px solid " + (dirty ? "var(--border-brand)" : "var(--border)"), borderRadius: "var(--r-lg)", background: dirty ? "var(--surface-brand)" : "var(--surface)", color: "var(--text)", transition: "background var(--dur-base) var(--ease),border-color var(--dur-base) var(--ease)" },
|
|
9490
9684
|
children: [
|
|
9491
|
-
/* @__PURE__ */ (0,
|
|
9492
|
-
/* @__PURE__ */ (0,
|
|
9493
|
-
/* @__PURE__ */ (0,
|
|
9494
|
-
dirty ? /* @__PURE__ */ (0,
|
|
9495
|
-
/* @__PURE__ */ (0,
|
|
9496
|
-
/* @__PURE__ */ (0,
|
|
9685
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9686
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
9687
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
9688
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(import_jsx_runtime77.Fragment, { children: [
|
|
9689
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
9690
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
9497
9691
|
] }) : null
|
|
9498
9692
|
] }),
|
|
9499
|
-
/* @__PURE__ */ (0,
|
|
9500
|
-
/* @__PURE__ */ (0,
|
|
9501
|
-
dirty ? /* @__PURE__ */ (0,
|
|
9693
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
|
|
9694
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
9695
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9502
9696
|
"span",
|
|
9503
9697
|
{
|
|
9504
9698
|
ref: chipRef,
|
|
@@ -9510,7 +9704,7 @@ function BudgetReallocator({
|
|
|
9510
9704
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
9511
9705
|
}
|
|
9512
9706
|
) : null,
|
|
9513
|
-
/* @__PURE__ */ (0,
|
|
9707
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9514
9708
|
"input",
|
|
9515
9709
|
{
|
|
9516
9710
|
type: "range",
|
|
@@ -9526,13 +9720,13 @@ function BudgetReallocator({
|
|
|
9526
9720
|
}
|
|
9527
9721
|
)
|
|
9528
9722
|
] }),
|
|
9529
|
-
/* @__PURE__ */ (0,
|
|
9530
|
-
/* @__PURE__ */ (0,
|
|
9531
|
-
/* @__PURE__ */ (0,
|
|
9532
|
-
/* @__PURE__ */ (0,
|
|
9723
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9724
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
9725
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
9726
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
9533
9727
|
] }),
|
|
9534
|
-
/* @__PURE__ */ (0,
|
|
9535
|
-
/* @__PURE__ */ (0,
|
|
9728
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
9729
|
+
/* @__PURE__ */ (0, import_jsx_runtime77.jsx)(
|
|
9536
9730
|
"button",
|
|
9537
9731
|
{
|
|
9538
9732
|
type: "button",
|
|
@@ -9551,7 +9745,7 @@ function BudgetReallocator({
|
|
|
9551
9745
|
}
|
|
9552
9746
|
|
|
9553
9747
|
// src/components/planner/SurroundSound.tsx
|
|
9554
|
-
var
|
|
9748
|
+
var import_jsx_runtime78 = require("react/jsx-runtime");
|
|
9555
9749
|
var CATEGORIES = [
|
|
9556
9750
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
9557
9751
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -9563,26 +9757,26 @@ var CATEGORIES = [
|
|
|
9563
9757
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
9564
9758
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
9565
9759
|
const single = present.length <= 2;
|
|
9566
|
-
return /* @__PURE__ */ (0,
|
|
9567
|
-
/* @__PURE__ */ (0,
|
|
9760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
9761
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
9568
9762
|
const on = present.includes(c.key);
|
|
9569
|
-
return /* @__PURE__ */ (0,
|
|
9763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(
|
|
9570
9764
|
"span",
|
|
9571
9765
|
{
|
|
9572
9766
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
9573
9767
|
style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 5, width: 62, padding: "10px 0", borderRadius: "var(--r-md)", border: "1px solid " + (on ? "var(--csi-2-edge)" : "var(--border)"), background: on ? "var(--csi-2-fill)" : "var(--surface-2)", color: on ? "var(--csi-2-text)" : "var(--text-disabled)" },
|
|
9574
9768
|
children: [
|
|
9575
|
-
/* @__PURE__ */ (0,
|
|
9576
|
-
/* @__PURE__ */ (0,
|
|
9769
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
9770
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
9577
9771
|
]
|
|
9578
9772
|
},
|
|
9579
9773
|
c.key
|
|
9580
9774
|
);
|
|
9581
9775
|
}) }),
|
|
9582
|
-
/* @__PURE__ */ (0,
|
|
9583
|
-
/* @__PURE__ */ (0,
|
|
9584
|
-
/* @__PURE__ */ (0,
|
|
9585
|
-
/* @__PURE__ */ (0,
|
|
9776
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
9777
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
9778
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
9779
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
9586
9780
|
"+",
|
|
9587
9781
|
bonusPct,
|
|
9588
9782
|
"% of +",
|
|
@@ -9590,8 +9784,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9590
9784
|
"%"
|
|
9591
9785
|
] })
|
|
9592
9786
|
] }),
|
|
9593
|
-
/* @__PURE__ */ (0,
|
|
9594
|
-
/* @__PURE__ */ (0,
|
|
9787
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
9788
|
+
/* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
9595
9789
|
present.length,
|
|
9596
9790
|
" of 6 channel categories present.",
|
|
9597
9791
|
" ",
|
|
@@ -9603,7 +9797,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9603
9797
|
}
|
|
9604
9798
|
|
|
9605
9799
|
// src/components/planner/Importance.tsx
|
|
9606
|
-
var
|
|
9800
|
+
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
9607
9801
|
var IMPORTANCE_LEVELS = [
|
|
9608
9802
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
9609
9803
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -9633,23 +9827,23 @@ function importanceTokens(id) {
|
|
|
9633
9827
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
|
|
9634
9828
|
const lvl = importanceLevel(level);
|
|
9635
9829
|
const t = importanceTokens(level);
|
|
9636
|
-
return /* @__PURE__ */ (0,
|
|
9830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
|
|
9637
9831
|
"span",
|
|
9638
9832
|
{
|
|
9639
9833
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
|
|
9640
9834
|
style: { background: t.fill, borderColor: t.edge, color: t.text },
|
|
9641
9835
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
9642
9836
|
children: [
|
|
9643
|
-
/* @__PURE__ */ (0,
|
|
9644
|
-
showLabel ? lvl.label : /* @__PURE__ */ (0,
|
|
9837
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
9838
|
+
showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-sr", children: lvl.label })
|
|
9645
9839
|
]
|
|
9646
9840
|
}
|
|
9647
9841
|
);
|
|
9648
9842
|
}
|
|
9649
9843
|
|
|
9650
9844
|
// src/components/planner/PreferenceMeter.tsx
|
|
9651
|
-
var
|
|
9652
|
-
var
|
|
9845
|
+
var React50 = __toESM(require("react"), 1);
|
|
9846
|
+
var import_jsx_runtime80 = require("react/jsx-runtime");
|
|
9653
9847
|
function preferenceScore(criteria) {
|
|
9654
9848
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
9655
9849
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -9678,8 +9872,8 @@ function PreferenceMeter({
|
|
|
9678
9872
|
className = ""
|
|
9679
9873
|
}) {
|
|
9680
9874
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
9681
|
-
const segments =
|
|
9682
|
-
return /* @__PURE__ */ (0,
|
|
9875
|
+
const segments = React50.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
9876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
|
|
9683
9877
|
ScoreMeter,
|
|
9684
9878
|
{
|
|
9685
9879
|
score: value,
|
|
@@ -9691,22 +9885,22 @@ function PreferenceMeter({
|
|
|
9691
9885
|
placement,
|
|
9692
9886
|
className,
|
|
9693
9887
|
breakdownLabel: breakdownTitle,
|
|
9694
|
-
breakdown: /* @__PURE__ */ (0,
|
|
9695
|
-
/* @__PURE__ */ (0,
|
|
9696
|
-
/* @__PURE__ */ (0,
|
|
9697
|
-
/* @__PURE__ */ (0,
|
|
9888
|
+
breakdown: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak", children: [
|
|
9889
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-prefbreak-head", children: [
|
|
9890
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
9891
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
9698
9892
|
] }),
|
|
9699
|
-
/* @__PURE__ */ (0,
|
|
9893
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
9700
9894
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
9701
|
-
return /* @__PURE__ */ (0,
|
|
9702
|
-
/* @__PURE__ */ (0,
|
|
9703
|
-
/* @__PURE__ */ (0,
|
|
9704
|
-
/* @__PURE__ */ (0,
|
|
9705
|
-
c.note ? /* @__PURE__ */ (0,
|
|
9895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
9896
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(ImportanceTag, { level: c.importance }),
|
|
9897
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-text", children: [
|
|
9898
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
9899
|
+
c.note ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
9706
9900
|
] }),
|
|
9707
|
-
/* @__PURE__ */ (0,
|
|
9901
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
9708
9902
|
Math.round(Number(c.earned) || 0),
|
|
9709
|
-
/* @__PURE__ */ (0,
|
|
9903
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
9710
9904
|
Math.round(c.weight)
|
|
9711
9905
|
] })
|
|
9712
9906
|
] }, c.id);
|
|
@@ -9717,10 +9911,10 @@ function PreferenceMeter({
|
|
|
9717
9911
|
}
|
|
9718
9912
|
|
|
9719
9913
|
// src/components/chat/AgentChatPanel.tsx
|
|
9720
|
-
var
|
|
9914
|
+
var React56 = __toESM(require("react"), 1);
|
|
9721
9915
|
|
|
9722
9916
|
// src/components/chat/chatEngine.ts
|
|
9723
|
-
var
|
|
9917
|
+
var React51 = __toESM(require("react"), 1);
|
|
9724
9918
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
9725
9919
|
var JOB_PENDING = ["queued", "running"];
|
|
9726
9920
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -9774,22 +9968,22 @@ function useChatEngine(opts) {
|
|
|
9774
9968
|
onClear,
|
|
9775
9969
|
onFeedback
|
|
9776
9970
|
} = opts || {};
|
|
9777
|
-
const [status, setStatus] =
|
|
9778
|
-
const [threadId, setThreadId] =
|
|
9779
|
-
const [messages, setMessages] =
|
|
9780
|
-
const [queue, setQueue] =
|
|
9781
|
-
const [fatal, setFatal] =
|
|
9782
|
-
const [busy, setBusy] =
|
|
9783
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
9784
|
-
const listRef =
|
|
9785
|
-
const queueRef =
|
|
9786
|
-
const busyRef =
|
|
9787
|
-
const stoppedRef =
|
|
9788
|
-
const abortRef =
|
|
9789
|
-
const serverCount =
|
|
9790
|
-
const threadRef =
|
|
9791
|
-
const mounted =
|
|
9792
|
-
|
|
9971
|
+
const [status, setStatus] = React51.useState("idle");
|
|
9972
|
+
const [threadId, setThreadId] = React51.useState(null);
|
|
9973
|
+
const [messages, setMessages] = React51.useState([]);
|
|
9974
|
+
const [queue, setQueue] = React51.useState([]);
|
|
9975
|
+
const [fatal, setFatal] = React51.useState(null);
|
|
9976
|
+
const [busy, setBusy] = React51.useState(false);
|
|
9977
|
+
const [turnStartedAt, setTurnStartedAt] = React51.useState(null);
|
|
9978
|
+
const listRef = React51.useRef([]);
|
|
9979
|
+
const queueRef = React51.useRef([]);
|
|
9980
|
+
const busyRef = React51.useRef(false);
|
|
9981
|
+
const stoppedRef = React51.useRef(false);
|
|
9982
|
+
const abortRef = React51.useRef(null);
|
|
9983
|
+
const serverCount = React51.useRef(0);
|
|
9984
|
+
const threadRef = React51.useRef(null);
|
|
9985
|
+
const mounted = React51.useRef(true);
|
|
9986
|
+
React51.useEffect(() => {
|
|
9793
9987
|
mounted.current = true;
|
|
9794
9988
|
return () => {
|
|
9795
9989
|
mounted.current = false;
|
|
@@ -9811,14 +10005,14 @@ function useChatEngine(opts) {
|
|
|
9811
10005
|
}
|
|
9812
10006
|
return false;
|
|
9813
10007
|
};
|
|
9814
|
-
const loadThread =
|
|
10008
|
+
const loadThread = React51.useCallback(async (id) => {
|
|
9815
10009
|
const data = await apiAdapter.getThread(id);
|
|
9816
10010
|
const list = [...data && data.messages || []];
|
|
9817
10011
|
serverCount.current = list.length;
|
|
9818
10012
|
commit(list);
|
|
9819
10013
|
return list;
|
|
9820
10014
|
}, [apiAdapter]);
|
|
9821
|
-
|
|
10015
|
+
React51.useEffect(() => {
|
|
9822
10016
|
if (!apiAdapter) {
|
|
9823
10017
|
setStatus("idle");
|
|
9824
10018
|
setFatal(null);
|
|
@@ -10031,7 +10225,7 @@ function useChatEngine(opts) {
|
|
|
10031
10225
|
await dispatchTurn(turn);
|
|
10032
10226
|
}
|
|
10033
10227
|
}
|
|
10034
|
-
const send =
|
|
10228
|
+
const send = React51.useCallback((text, attachments) => {
|
|
10035
10229
|
const body = (text || "").trim();
|
|
10036
10230
|
if (!body && !(attachments && attachments.length)) return;
|
|
10037
10231
|
if (status === "disconnected") return;
|
|
@@ -10041,7 +10235,7 @@ function useChatEngine(opts) {
|
|
|
10041
10235
|
stoppedRef.current = false;
|
|
10042
10236
|
drain();
|
|
10043
10237
|
}, [status]);
|
|
10044
|
-
const stop =
|
|
10238
|
+
const stop = React51.useCallback(() => {
|
|
10045
10239
|
stoppedRef.current = true;
|
|
10046
10240
|
const ac = abortRef.current;
|
|
10047
10241
|
if (ac) {
|
|
@@ -10060,11 +10254,11 @@ function useChatEngine(opts) {
|
|
|
10060
10254
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
10061
10255
|
}
|
|
10062
10256
|
}, [apiAdapter]);
|
|
10063
|
-
const removeQueued =
|
|
10257
|
+
const removeQueued = React51.useCallback((id) => {
|
|
10064
10258
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
10065
10259
|
setQueue(queueRef.current.slice());
|
|
10066
10260
|
}, []);
|
|
10067
|
-
const retry =
|
|
10261
|
+
const retry = React51.useCallback(() => {
|
|
10068
10262
|
const list = listRef.current;
|
|
10069
10263
|
let at = -1;
|
|
10070
10264
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -10080,19 +10274,19 @@ function useChatEngine(opts) {
|
|
|
10080
10274
|
setQueue(queueRef.current.slice());
|
|
10081
10275
|
drain();
|
|
10082
10276
|
}, []);
|
|
10083
|
-
const clear =
|
|
10277
|
+
const clear = React51.useCallback(() => {
|
|
10084
10278
|
commit([]);
|
|
10085
10279
|
serverCount.current = 0;
|
|
10086
10280
|
queueRef.current = [];
|
|
10087
10281
|
setQueue([]);
|
|
10088
10282
|
onClear && onClear();
|
|
10089
10283
|
}, [onClear]);
|
|
10090
|
-
const setFeedback =
|
|
10284
|
+
const setFeedback = React51.useCallback((id, value) => {
|
|
10091
10285
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
10092
10286
|
const msg = listRef.current.find((m) => m.id === id);
|
|
10093
10287
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
10094
10288
|
}, [onFeedback]);
|
|
10095
|
-
const reload =
|
|
10289
|
+
const reload = React51.useCallback(async () => {
|
|
10096
10290
|
if (!threadRef.current) return;
|
|
10097
10291
|
setStatus("loading");
|
|
10098
10292
|
try {
|
|
@@ -10130,11 +10324,11 @@ var ChatKit = {
|
|
|
10130
10324
|
};
|
|
10131
10325
|
|
|
10132
10326
|
// src/components/chat/ChatTranscript.tsx
|
|
10133
|
-
var
|
|
10327
|
+
var React53 = __toESM(require("react"), 1);
|
|
10134
10328
|
|
|
10135
10329
|
// src/components/chat/ChatTurn.tsx
|
|
10136
|
-
var
|
|
10137
|
-
var
|
|
10330
|
+
var React52 = __toESM(require("react"), 1);
|
|
10331
|
+
var import_jsx_runtime81 = require("react/jsx-runtime");
|
|
10138
10332
|
function JsonView({ value }) {
|
|
10139
10333
|
let text;
|
|
10140
10334
|
try {
|
|
@@ -10142,67 +10336,67 @@ function JsonView({ value }) {
|
|
|
10142
10336
|
} catch (e) {
|
|
10143
10337
|
text = String(value);
|
|
10144
10338
|
}
|
|
10145
|
-
return /* @__PURE__ */ (0,
|
|
10339
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
10146
10340
|
}
|
|
10147
10341
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
10148
10342
|
if (!packet) return null;
|
|
10149
10343
|
const s = schema || {};
|
|
10150
10344
|
const invalid = packet.valid === false;
|
|
10151
10345
|
const title = s.heading || packet.type;
|
|
10152
|
-
return /* @__PURE__ */ (0,
|
|
10153
|
-
/* @__PURE__ */ (0,
|
|
10154
|
-
/* @__PURE__ */ (0,
|
|
10155
|
-
/* @__PURE__ */ (0,
|
|
10156
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
10157
|
-
invalid ? /* @__PURE__ */ (0,
|
|
10346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
10347
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("header", { className: "fdc-packet-head", children: [
|
|
10348
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
10349
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
|
|
10350
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
10351
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
10158
10352
|
] }),
|
|
10159
|
-
invalid ? /* @__PURE__ */ (0,
|
|
10160
|
-
/* @__PURE__ */ (0,
|
|
10161
|
-
/* @__PURE__ */ (0,
|
|
10162
|
-
] }) : /* @__PURE__ */ (0,
|
|
10163
|
-
!invalid && onApply ? /* @__PURE__ */ (0,
|
|
10164
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
10165
|
-
/* @__PURE__ */ (0,
|
|
10166
|
-
/* @__PURE__ */ (0,
|
|
10353
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
10354
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10355
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
10356
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(JsonView, { value: packet.payload }) }),
|
|
10357
|
+
!invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("footer", { className: "fdc-packet-foot", children: [
|
|
10358
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10359
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
10360
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
10167
10361
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
10168
10362
|
] })
|
|
10169
10363
|
] }) : null
|
|
10170
10364
|
] });
|
|
10171
10365
|
}
|
|
10172
10366
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
10173
|
-
const [open, setOpen] =
|
|
10367
|
+
const [open, setOpen] = React52.useState(defaultOpen);
|
|
10174
10368
|
if (!text) return null;
|
|
10175
|
-
return /* @__PURE__ */ (0,
|
|
10176
|
-
/* @__PURE__ */ (0,
|
|
10177
|
-
/* @__PURE__ */ (0,
|
|
10178
|
-
/* @__PURE__ */ (0,
|
|
10179
|
-
streaming ? /* @__PURE__ */ (0,
|
|
10180
|
-
/* @__PURE__ */ (0,
|
|
10181
|
-
/* @__PURE__ */ (0,
|
|
10182
|
-
/* @__PURE__ */ (0,
|
|
10369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
10370
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10371
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
10372
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
10373
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10374
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10375
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10376
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
|
|
10183
10377
|
] }) : null,
|
|
10184
|
-
/* @__PURE__ */ (0,
|
|
10378
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
10185
10379
|
] }),
|
|
10186
|
-
open ? /* @__PURE__ */ (0,
|
|
10380
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-think-body", children: text }) : null
|
|
10187
10381
|
] });
|
|
10188
10382
|
}
|
|
10189
10383
|
function Citations({ items = [], onOpen }) {
|
|
10190
|
-
const [open, setOpen] =
|
|
10384
|
+
const [open, setOpen] = React52.useState(false);
|
|
10191
10385
|
if (!items.length) return null;
|
|
10192
|
-
return /* @__PURE__ */ (0,
|
|
10193
|
-
/* @__PURE__ */ (0,
|
|
10194
|
-
/* @__PURE__ */ (0,
|
|
10195
|
-
/* @__PURE__ */ (0,
|
|
10386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-cites", children: [
|
|
10387
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10388
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
10389
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { children: [
|
|
10196
10390
|
items.length,
|
|
10197
10391
|
" source",
|
|
10198
10392
|
items.length === 1 ? "" : "s"
|
|
10199
10393
|
] }),
|
|
10200
|
-
/* @__PURE__ */ (0,
|
|
10394
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
10201
10395
|
] }),
|
|
10202
|
-
open ? /* @__PURE__ */ (0,
|
|
10203
|
-
/* @__PURE__ */ (0,
|
|
10204
|
-
c.url ? /* @__PURE__ */ (0,
|
|
10205
|
-
c.detail ? /* @__PURE__ */ (0,
|
|
10396
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("li", { children: [
|
|
10397
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
10398
|
+
c.url ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: c.title || "Source" }),
|
|
10399
|
+
c.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
10206
10400
|
] }, c.id || i)) }) : null
|
|
10207
10401
|
] });
|
|
10208
10402
|
}
|
|
@@ -10213,29 +10407,29 @@ function clampText(text, max) {
|
|
|
10213
10407
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
10214
10408
|
}
|
|
10215
10409
|
function MessageBody({ message: m, ctx }) {
|
|
10216
|
-
const [expanded, setExpanded] =
|
|
10410
|
+
const [expanded, setExpanded] = React52.useState(false);
|
|
10217
10411
|
const isUser = m.role === "user";
|
|
10218
10412
|
const raw = m.text || "";
|
|
10219
10413
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
10220
10414
|
const body = clamped != null ? clamped : raw;
|
|
10221
10415
|
const showMd = ctx.markdown && !isUser;
|
|
10222
|
-
return /* @__PURE__ */ (0,
|
|
10223
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0,
|
|
10224
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0,
|
|
10225
|
-
body ? /* @__PURE__ */ (0,
|
|
10226
|
-
showMd ? /* @__PURE__ */ (0,
|
|
10227
|
-
m.streaming ? /* @__PURE__ */ (0,
|
|
10416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-body", children: [
|
|
10417
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
10418
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
10419
|
+
body ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
10420
|
+
showMd ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-plain", children: body }),
|
|
10421
|
+
m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
10228
10422
|
] }) : null,
|
|
10229
|
-
clamped != null ? /* @__PURE__ */ (0,
|
|
10230
|
-
/* @__PURE__ */ (0,
|
|
10423
|
+
clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
10424
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
10231
10425
|
"Show more",
|
|
10232
|
-
/* @__PURE__ */ (0,
|
|
10233
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0,
|
|
10234
|
-
/* @__PURE__ */ (0,
|
|
10426
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
10427
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
10428
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
10235
10429
|
"Show less"
|
|
10236
10430
|
] }) : null,
|
|
10237
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */ (0,
|
|
10238
|
-
m.packet ? /* @__PURE__ */ (0,
|
|
10431
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
10432
|
+
m.packet ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
10239
10433
|
PacketCard,
|
|
10240
10434
|
{
|
|
10241
10435
|
packet: m.packet,
|
|
@@ -10245,44 +10439,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
10245
10439
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
10246
10440
|
}
|
|
10247
10441
|
) : null,
|
|
10248
|
-
m.citations && m.citations.length ? /* @__PURE__ */ (0,
|
|
10249
|
-
m.working ? /* @__PURE__ */ (0,
|
|
10250
|
-
/* @__PURE__ */ (0,
|
|
10251
|
-
/* @__PURE__ */ (0,
|
|
10252
|
-
/* @__PURE__ */ (0,
|
|
10253
|
-
/* @__PURE__ */ (0,
|
|
10442
|
+
m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
10443
|
+
m.working ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-working", role: "status", children: [
|
|
10444
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10445
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10446
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {}),
|
|
10447
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", {})
|
|
10254
10448
|
] }),
|
|
10255
|
-
/* @__PURE__ */ (0,
|
|
10449
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-label", children: [
|
|
10256
10450
|
m.resumed ? "Resuming" : "Working",
|
|
10257
|
-
m.job && m.job.status ? /* @__PURE__ */ (0,
|
|
10451
|
+
m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
|
|
10258
10452
|
" \xB7 ",
|
|
10259
10453
|
m.job.status
|
|
10260
10454
|
] }) : null,
|
|
10261
|
-
m.job && m.job.detail ? /* @__PURE__ */ (0,
|
|
10455
|
+
m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fdc-working-job", children: [
|
|
10262
10456
|
" \xB7 ",
|
|
10263
10457
|
m.job.detail
|
|
10264
10458
|
] }) : null
|
|
10265
10459
|
] }),
|
|
10266
|
-
m.jobId ? /* @__PURE__ */ (0,
|
|
10460
|
+
m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
10267
10461
|
] }) : null,
|
|
10268
|
-
m.stopped ? /* @__PURE__ */ (0,
|
|
10269
|
-
/* @__PURE__ */ (0,
|
|
10462
|
+
m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-stopped", children: [
|
|
10463
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10270
10464
|
"Stopped"
|
|
10271
10465
|
] }) : null,
|
|
10272
|
-
m.error ? /* @__PURE__ */ (0,
|
|
10273
|
-
/* @__PURE__ */ (0,
|
|
10274
|
-
/* @__PURE__ */ (0,
|
|
10275
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
10276
|
-
/* @__PURE__ */ (0,
|
|
10466
|
+
m.error ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-error", role: "alert", children: [
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10468
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
10469
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
10470
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10277
10471
|
"Retry"
|
|
10278
10472
|
] }) : null
|
|
10279
10473
|
] }) : null
|
|
10280
10474
|
] });
|
|
10281
10475
|
}
|
|
10282
10476
|
function useCopyRun() {
|
|
10283
|
-
const [done, setDone] =
|
|
10284
|
-
const t =
|
|
10285
|
-
|
|
10477
|
+
const [done, setDone] = React52.useState(false);
|
|
10478
|
+
const t = React52.useRef(null);
|
|
10479
|
+
React52.useEffect(() => () => {
|
|
10286
10480
|
if (t.current) clearTimeout(t.current);
|
|
10287
10481
|
}, []);
|
|
10288
10482
|
return [done, (text) => {
|
|
@@ -10302,16 +10496,16 @@ function RunActions({ group, ctx }) {
|
|
|
10302
10496
|
const isAssistant = group.role === "assistant";
|
|
10303
10497
|
const fb = last.feedback;
|
|
10304
10498
|
if (!ctx.messageActions) return null;
|
|
10305
|
-
return /* @__PURE__ */ (0,
|
|
10306
|
-
/* @__PURE__ */ (0,
|
|
10307
|
-
/* @__PURE__ */ (0,
|
|
10308
|
-
/* @__PURE__ */ (0,
|
|
10499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
10500
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
10501
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
10502
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
10309
10503
|
] }),
|
|
10310
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
10311
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0,
|
|
10312
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0,
|
|
10313
|
-
/* @__PURE__ */ (0,
|
|
10314
|
-
/* @__PURE__ */ (0,
|
|
10504
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
10505
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
10506
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(React52.Fragment, { children: [
|
|
10507
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
10508
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
10315
10509
|
] }) : null,
|
|
10316
10510
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
10317
10511
|
] });
|
|
@@ -10321,22 +10515,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
10321
10515
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
10322
10516
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
10323
10517
|
const stamp = group.messages[0].timestamp;
|
|
10324
|
-
return /* @__PURE__ */ (0,
|
|
10325
|
-
/* @__PURE__ */ (0,
|
|
10326
|
-
ctx.showAvatars ? /* @__PURE__ */ (0,
|
|
10327
|
-
/* @__PURE__ */ (0,
|
|
10328
|
-
stamp ? /* @__PURE__ */ (0,
|
|
10329
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0,
|
|
10518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
10519
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-head", children: [
|
|
10520
|
+
ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
10521
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-who", children: name }),
|
|
10522
|
+
stamp ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
10523
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
10330
10524
|
] }),
|
|
10331
|
-
/* @__PURE__ */ (0,
|
|
10332
|
-
group.messages.map((m) => /* @__PURE__ */ (0,
|
|
10333
|
-
/* @__PURE__ */ (0,
|
|
10525
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fdc-turn-body", children: [
|
|
10526
|
+
group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
|
|
10527
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(RunActions, { group, ctx })
|
|
10334
10528
|
] })
|
|
10335
10529
|
] });
|
|
10336
10530
|
}
|
|
10337
10531
|
|
|
10338
10532
|
// src/components/chat/ChatTranscript.tsx
|
|
10339
|
-
var
|
|
10533
|
+
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
10340
10534
|
var GROUP_WINDOW = 6e4;
|
|
10341
10535
|
var STICK_PX = 100;
|
|
10342
10536
|
function groupMessages(list) {
|
|
@@ -10369,25 +10563,25 @@ function dayLabel(key) {
|
|
|
10369
10563
|
}
|
|
10370
10564
|
function Suggestions({ items = [], onPick }) {
|
|
10371
10565
|
if (!items.length) return null;
|
|
10372
|
-
return /* @__PURE__ */ (0,
|
|
10566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
10373
10567
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
10374
|
-
return /* @__PURE__ */ (0,
|
|
10375
|
-
it.icon ? /* @__PURE__ */ (0,
|
|
10376
|
-
/* @__PURE__ */ (0,
|
|
10377
|
-
/* @__PURE__ */ (0,
|
|
10378
|
-
it.description ? /* @__PURE__ */ (0,
|
|
10568
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
10569
|
+
it.icon ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
10570
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("span", { className: "fdc-suggest-text", children: [
|
|
10571
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
|
|
10572
|
+
it.description ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
10379
10573
|
] }),
|
|
10380
|
-
/* @__PURE__ */ (0,
|
|
10574
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
10381
10575
|
] }, it.id || i);
|
|
10382
10576
|
}) });
|
|
10383
10577
|
}
|
|
10384
10578
|
function LoadingTurns() {
|
|
10385
|
-
return /* @__PURE__ */ (0,
|
|
10386
|
-
/* @__PURE__ */ (0,
|
|
10387
|
-
/* @__PURE__ */ (0,
|
|
10388
|
-
/* @__PURE__ */ (0,
|
|
10389
|
-
/* @__PURE__ */ (0,
|
|
10390
|
-
/* @__PURE__ */ (0,
|
|
10579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-turn", children: [
|
|
10580
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
10581
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-skel-lines", children: [
|
|
10582
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
10583
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
10584
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
10391
10585
|
] })
|
|
10392
10586
|
] }, i)) });
|
|
10393
10587
|
}
|
|
@@ -10404,10 +10598,10 @@ function ChatTranscript({
|
|
|
10404
10598
|
renderEmpty,
|
|
10405
10599
|
className = ""
|
|
10406
10600
|
}) {
|
|
10407
|
-
const scroller =
|
|
10408
|
-
const stick =
|
|
10409
|
-
const [pill, setPill] =
|
|
10410
|
-
const seen =
|
|
10601
|
+
const scroller = React53.useRef(null);
|
|
10602
|
+
const stick = React53.useRef(true);
|
|
10603
|
+
const [pill, setPill] = React53.useState(0);
|
|
10604
|
+
const seen = React53.useRef(0);
|
|
10411
10605
|
const toBottom = (smooth) => {
|
|
10412
10606
|
const el = scroller.current;
|
|
10413
10607
|
if (!el) return;
|
|
@@ -10426,7 +10620,7 @@ function ChatTranscript({
|
|
|
10426
10620
|
seen.current = messages.length;
|
|
10427
10621
|
}
|
|
10428
10622
|
};
|
|
10429
|
-
|
|
10623
|
+
React53.useLayoutEffect(() => {
|
|
10430
10624
|
const el = scroller.current;
|
|
10431
10625
|
if (!el) return;
|
|
10432
10626
|
if (stick.current) {
|
|
@@ -10434,7 +10628,7 @@ function ChatTranscript({
|
|
|
10434
10628
|
seen.current = messages.length;
|
|
10435
10629
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
10436
10630
|
}, [messages]);
|
|
10437
|
-
|
|
10631
|
+
React53.useEffect(() => {
|
|
10438
10632
|
const el = scroller.current;
|
|
10439
10633
|
const inner = el && el.firstChild;
|
|
10440
10634
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -10444,38 +10638,38 @@ function ChatTranscript({
|
|
|
10444
10638
|
ro.observe(inner);
|
|
10445
10639
|
return () => ro.disconnect();
|
|
10446
10640
|
}, []);
|
|
10447
|
-
const groups =
|
|
10641
|
+
const groups = React53.useMemo(() => groupMessages(messages), [messages]);
|
|
10448
10642
|
const empty = !messages.length && status === "ready";
|
|
10449
|
-
return /* @__PURE__ */ (0,
|
|
10450
|
-
/* @__PURE__ */ (0,
|
|
10451
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0,
|
|
10452
|
-
status === "disconnected" ? /* @__PURE__ */ (0,
|
|
10453
|
-
/* @__PURE__ */ (0,
|
|
10454
|
-
/* @__PURE__ */ (0,
|
|
10455
|
-
/* @__PURE__ */ (0,
|
|
10456
|
-
ctx.onReconnect ? /* @__PURE__ */ (0,
|
|
10457
|
-
/* @__PURE__ */ (0,
|
|
10643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
10644
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
10645
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(LoadingTurns, {}) : null,
|
|
10646
|
+
status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-dead", children: [
|
|
10647
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
10648
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
10649
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
|
|
10650
|
+
ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
10651
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10458
10652
|
"Try again"
|
|
10459
10653
|
] }) : null
|
|
10460
10654
|
] }) : null,
|
|
10461
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0,
|
|
10462
|
-
/* @__PURE__ */ (0,
|
|
10463
|
-
/* @__PURE__ */ (0,
|
|
10464
|
-
emptyDescription ? /* @__PURE__ */ (0,
|
|
10465
|
-
/* @__PURE__ */ (0,
|
|
10655
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fdc-empty", children: [
|
|
10656
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
10657
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
10658
|
+
emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
10659
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Suggestions, { items: suggestions, onPick })
|
|
10466
10660
|
] }) : null,
|
|
10467
10661
|
groups.map((g, i) => {
|
|
10468
10662
|
const prev = groups[i - 1];
|
|
10469
10663
|
const k = dayKey(g.messages[0].timestamp);
|
|
10470
10664
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
10471
|
-
return /* @__PURE__ */ (0,
|
|
10472
|
-
showDay ? /* @__PURE__ */ (0,
|
|
10473
|
-
/* @__PURE__ */ (0,
|
|
10665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(React53.Fragment, { children: [
|
|
10666
|
+
showDay ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
10667
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(ChatTurn, { group: g, ctx })
|
|
10474
10668
|
] }, g.key || i);
|
|
10475
10669
|
})
|
|
10476
10670
|
] }),
|
|
10477
|
-
pill ? /* @__PURE__ */ (0,
|
|
10478
|
-
/* @__PURE__ */ (0,
|
|
10671
|
+
pill ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
10672
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
10479
10673
|
pill,
|
|
10480
10674
|
" new message",
|
|
10481
10675
|
pill === 1 ? "" : "s"
|
|
@@ -10485,8 +10679,8 @@ function ChatTranscript({
|
|
|
10485
10679
|
var TranscriptKit = { groupMessages };
|
|
10486
10680
|
|
|
10487
10681
|
// src/components/chat/ChatComposer.tsx
|
|
10488
|
-
var
|
|
10489
|
-
var
|
|
10682
|
+
var React54 = __toESM(require("react"), 1);
|
|
10683
|
+
var import_jsx_runtime83 = require("react/jsx-runtime");
|
|
10490
10684
|
function ChatComposer({
|
|
10491
10685
|
onSubmit,
|
|
10492
10686
|
onStop,
|
|
@@ -10513,17 +10707,17 @@ function ChatComposer({
|
|
|
10513
10707
|
onReject,
|
|
10514
10708
|
onOpenAttachment
|
|
10515
10709
|
}) {
|
|
10516
|
-
const [text, setText] =
|
|
10517
|
-
const [trigger, setTrigger] =
|
|
10518
|
-
const [mentionItems, setMentionItems] =
|
|
10519
|
-
const [listening, setListening] =
|
|
10520
|
-
const [notice, setNotice] =
|
|
10521
|
-
const editor =
|
|
10522
|
-
const wrap =
|
|
10523
|
-
const stopVoice =
|
|
10710
|
+
const [text, setText] = React54.useState(draft || "");
|
|
10711
|
+
const [trigger, setTrigger] = React54.useState(null);
|
|
10712
|
+
const [mentionItems, setMentionItems] = React54.useState([]);
|
|
10713
|
+
const [listening, setListening] = React54.useState(false);
|
|
10714
|
+
const [notice, setNotice] = React54.useState(null);
|
|
10715
|
+
const editor = React54.useRef(null);
|
|
10716
|
+
const wrap = React54.useRef(null);
|
|
10717
|
+
const stopVoice = React54.useRef(null);
|
|
10524
10718
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
10525
10719
|
} });
|
|
10526
|
-
|
|
10720
|
+
React54.useEffect(() => {
|
|
10527
10721
|
if (draft != null && draft !== text) setText(draft);
|
|
10528
10722
|
}, [draft]);
|
|
10529
10723
|
const change = (v) => {
|
|
@@ -10559,7 +10753,7 @@ function ChatComposer({
|
|
|
10559
10753
|
e.preventDefault();
|
|
10560
10754
|
staged.add(found.files);
|
|
10561
10755
|
};
|
|
10562
|
-
|
|
10756
|
+
React54.useEffect(() => {
|
|
10563
10757
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
10564
10758
|
setMentionItems([]);
|
|
10565
10759
|
return;
|
|
@@ -10577,7 +10771,7 @@ function ChatComposer({
|
|
|
10577
10771
|
const q = (trigger.query || "").toLowerCase();
|
|
10578
10772
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
10579
10773
|
}, [trigger, mentionSources]);
|
|
10580
|
-
const slashItems =
|
|
10774
|
+
const slashItems = React54.useMemo(() => {
|
|
10581
10775
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
10582
10776
|
const q = (trigger.query || "").toLowerCase();
|
|
10583
10777
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -10591,7 +10785,7 @@ function ChatComposer({
|
|
|
10591
10785
|
description: it.description,
|
|
10592
10786
|
icon: it.icon,
|
|
10593
10787
|
meta: mention.meta,
|
|
10594
|
-
shortcut: slash.shortcut ? /* @__PURE__ */ (0,
|
|
10788
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
10595
10789
|
onSelect: () => {
|
|
10596
10790
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
10597
10791
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -10654,14 +10848,14 @@ function ChatComposer({
|
|
|
10654
10848
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
10655
10849
|
};
|
|
10656
10850
|
};
|
|
10657
|
-
return /* @__PURE__ */ (0,
|
|
10658
|
-
queue.length ? /* @__PURE__ */ (0,
|
|
10659
|
-
/* @__PURE__ */ (0,
|
|
10660
|
-
/* @__PURE__ */ (0,
|
|
10661
|
-
onRemoveQueued ? /* @__PURE__ */ (0,
|
|
10851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
10852
|
+
queue.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-queue-row", children: [
|
|
10853
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
10854
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
|
|
10855
|
+
onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
10662
10856
|
] }, q.id)) }) : null,
|
|
10663
10857
|
sessionBar,
|
|
10664
|
-
/* @__PURE__ */ (0,
|
|
10858
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10665
10859
|
Dropzone,
|
|
10666
10860
|
{
|
|
10667
10861
|
className: "fdc-field",
|
|
@@ -10675,9 +10869,9 @@ function ChatComposer({
|
|
|
10675
10869
|
disabled: !fileUploadHandler || disabled,
|
|
10676
10870
|
label: "Drop to attach",
|
|
10677
10871
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
10678
|
-
children: /* @__PURE__ */ (0,
|
|
10679
|
-
staged.items.length ? /* @__PURE__ */ (0,
|
|
10680
|
-
/* @__PURE__ */ (0,
|
|
10872
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
10873
|
+
staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
10874
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10681
10875
|
MarkdownEditor,
|
|
10682
10876
|
{
|
|
10683
10877
|
ref: editor,
|
|
@@ -10696,33 +10890,33 @@ function ChatComposer({
|
|
|
10696
10890
|
ariaLabel: "Message"
|
|
10697
10891
|
}
|
|
10698
10892
|
),
|
|
10699
|
-
/* @__PURE__ */ (0,
|
|
10700
|
-
fileUploadHandler ? /* @__PURE__ */ (0,
|
|
10701
|
-
voiceHandler ? /* @__PURE__ */ (0,
|
|
10893
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-tools", children: [
|
|
10894
|
+
fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
10895
|
+
voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
10702
10896
|
toolbarExtras,
|
|
10703
|
-
/* @__PURE__ */ (0,
|
|
10704
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0,
|
|
10897
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-tools-gap" }),
|
|
10898
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
10705
10899
|
text.length,
|
|
10706
10900
|
"/",
|
|
10707
10901
|
maxLength
|
|
10708
10902
|
] }) : null,
|
|
10709
|
-
busy ? /* @__PURE__ */ (0,
|
|
10710
|
-
/* @__PURE__ */ (0,
|
|
10711
|
-
/* @__PURE__ */ (0,
|
|
10712
|
-
] }) : /* @__PURE__ */ (0,
|
|
10713
|
-
/* @__PURE__ */ (0,
|
|
10714
|
-
/* @__PURE__ */ (0,
|
|
10903
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
10904
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10905
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { children: "Stop" })
|
|
10906
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
10907
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
10908
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fdc-send-label", children: "Send" })
|
|
10715
10909
|
] })
|
|
10716
10910
|
] })
|
|
10717
10911
|
] })
|
|
10718
10912
|
}
|
|
10719
10913
|
),
|
|
10720
|
-
notice ? /* @__PURE__ */ (0,
|
|
10721
|
-
/* @__PURE__ */ (0,
|
|
10914
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fdc-notice", role: "status", children: [
|
|
10915
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10722
10916
|
notice
|
|
10723
10917
|
] }) : null,
|
|
10724
|
-
hint && !notice ? /* @__PURE__ */ (0,
|
|
10725
|
-
/* @__PURE__ */ (0,
|
|
10918
|
+
hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fdc-hint", children: hint }) : null,
|
|
10919
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10726
10920
|
Popover,
|
|
10727
10921
|
{
|
|
10728
10922
|
open: menuOpen,
|
|
@@ -10736,12 +10930,12 @@ function ChatComposer({
|
|
|
10736
10930
|
returnFocus: false,
|
|
10737
10931
|
closeOnOutside: true,
|
|
10738
10932
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
10739
|
-
children: /* @__PURE__ */ (0,
|
|
10933
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10740
10934
|
Menu,
|
|
10741
10935
|
{
|
|
10742
10936
|
items: menuItems,
|
|
10743
10937
|
autoFocus: false,
|
|
10744
|
-
header: /* @__PURE__ */ (0,
|
|
10938
|
+
header: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
10745
10939
|
onClose: () => setTrigger(null)
|
|
10746
10940
|
}
|
|
10747
10941
|
)
|
|
@@ -10751,12 +10945,12 @@ function ChatComposer({
|
|
|
10751
10945
|
}
|
|
10752
10946
|
|
|
10753
10947
|
// src/components/chat/ChatSessionBar.tsx
|
|
10754
|
-
var
|
|
10755
|
-
var
|
|
10948
|
+
var React55 = __toESM(require("react"), 1);
|
|
10949
|
+
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10756
10950
|
var compact2 = meterFormats.compact;
|
|
10757
10951
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
10758
|
-
const [open, setOpen] =
|
|
10759
|
-
const anchor =
|
|
10952
|
+
const [open, setOpen] = React55.useState(false);
|
|
10953
|
+
const anchor = React55.useRef(null);
|
|
10760
10954
|
const stats = sessionStats || null;
|
|
10761
10955
|
const cu = contextUsage || null;
|
|
10762
10956
|
const limits = usageLimits || null;
|
|
@@ -10771,9 +10965,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10771
10965
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
10772
10966
|
if (cu) bits.push(pct + "% context");
|
|
10773
10967
|
const expandable = !!(cu || limits);
|
|
10774
|
-
return /* @__PURE__ */ (0,
|
|
10775
|
-
/* @__PURE__ */ (0,
|
|
10776
|
-
/* @__PURE__ */ (0,
|
|
10968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
|
|
10969
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-bar", children: [
|
|
10970
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
|
|
10777
10971
|
"button",
|
|
10778
10972
|
{
|
|
10779
10973
|
type: "button",
|
|
@@ -10784,15 +10978,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10784
10978
|
"aria-expanded": expandable ? open : void 0,
|
|
10785
10979
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
10786
10980
|
children: [
|
|
10787
|
-
cu ? /* @__PURE__ */ (0,
|
|
10788
|
-
/* @__PURE__ */ (0,
|
|
10789
|
-
expandable ? /* @__PURE__ */ (0,
|
|
10981
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
10982
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
|
|
10983
|
+
expandable ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
10790
10984
|
]
|
|
10791
10985
|
}
|
|
10792
10986
|
),
|
|
10793
10987
|
extras
|
|
10794
10988
|
] }),
|
|
10795
|
-
/* @__PURE__ */ (0,
|
|
10989
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10796
10990
|
Popover,
|
|
10797
10991
|
{
|
|
10798
10992
|
open,
|
|
@@ -10803,15 +10997,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10803
10997
|
maxHeight: 460,
|
|
10804
10998
|
padded: true,
|
|
10805
10999
|
label: "Usage",
|
|
10806
|
-
footer: onClear ? /* @__PURE__ */ (0,
|
|
11000
|
+
footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
10807
11001
|
setOpen(false);
|
|
10808
11002
|
onClear();
|
|
10809
11003
|
}, children: [
|
|
10810
|
-
/* @__PURE__ */ (0,
|
|
11004
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
10811
11005
|
"Clear conversation"
|
|
10812
11006
|
] }) : void 0,
|
|
10813
|
-
children: /* @__PURE__ */ (0,
|
|
10814
|
-
cu ? /* @__PURE__ */ (0,
|
|
11007
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fdc-usage", children: [
|
|
11008
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10815
11009
|
SegmentedMeter,
|
|
10816
11010
|
{
|
|
10817
11011
|
total,
|
|
@@ -10823,9 +11017,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10823
11017
|
remainderLabel: "Free"
|
|
10824
11018
|
}
|
|
10825
11019
|
) }) : null,
|
|
10826
|
-
limits && limits.length ? /* @__PURE__ */ (0,
|
|
10827
|
-
/* @__PURE__ */ (0,
|
|
10828
|
-
/* @__PURE__ */ (0,
|
|
11020
|
+
limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec", children: [
|
|
11021
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
11022
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10829
11023
|
QuotaRow,
|
|
10830
11024
|
{
|
|
10831
11025
|
label: l.label,
|
|
@@ -10835,25 +11029,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10835
11029
|
l.id
|
|
10836
11030
|
)) })
|
|
10837
11031
|
] }) : null,
|
|
10838
|
-
stats ? /* @__PURE__ */ (0,
|
|
10839
|
-
stats.elapsedMs ? /* @__PURE__ */ (0,
|
|
10840
|
-
/* @__PURE__ */ (0,
|
|
10841
|
-
/* @__PURE__ */ (0,
|
|
11032
|
+
stats ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
11033
|
+
stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11034
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Session" }),
|
|
11035
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
10842
11036
|
] }) : null,
|
|
10843
|
-
stats.tokens ? /* @__PURE__ */ (0,
|
|
10844
|
-
/* @__PURE__ */ (0,
|
|
10845
|
-
/* @__PURE__ */ (0,
|
|
11037
|
+
stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11038
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Tokens" }),
|
|
11039
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
10846
11040
|
] }) : null,
|
|
10847
|
-
stats.costUsd != null ? /* @__PURE__ */ (0,
|
|
10848
|
-
/* @__PURE__ */ (0,
|
|
10849
|
-
/* @__PURE__ */ (0,
|
|
11041
|
+
stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11042
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Cost" }),
|
|
11043
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("b", { className: "fd-tabular", children: [
|
|
10850
11044
|
"$",
|
|
10851
11045
|
Number(stats.costUsd).toFixed(3)
|
|
10852
11046
|
] })
|
|
10853
11047
|
] }) : null,
|
|
10854
|
-
stats.turns ? /* @__PURE__ */ (0,
|
|
10855
|
-
/* @__PURE__ */ (0,
|
|
10856
|
-
/* @__PURE__ */ (0,
|
|
11048
|
+
stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { children: [
|
|
11049
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: "Turns" }),
|
|
11050
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("b", { className: "fd-tabular", children: stats.turns })
|
|
10857
11051
|
] }) : null
|
|
10858
11052
|
] }) : null
|
|
10859
11053
|
] })
|
|
@@ -10892,7 +11086,7 @@ function ModelControls({
|
|
|
10892
11086
|
disabled: m.disabled,
|
|
10893
11087
|
checked: m.id === (current2 && current2.id),
|
|
10894
11088
|
meta: m.meta,
|
|
10895
|
-
shortcut: m.shortcut ? /* @__PURE__ */ (0,
|
|
11089
|
+
shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
10896
11090
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
10897
11091
|
});
|
|
10898
11092
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -10905,15 +11099,15 @@ function ModelControls({
|
|
|
10905
11099
|
items.push({ kind: "section", label: "Fast mode" });
|
|
10906
11100
|
items.push({
|
|
10907
11101
|
kind: "custom",
|
|
10908
|
-
render: () => /* @__PURE__ */ (0,
|
|
10909
|
-
/* @__PURE__ */ (0,
|
|
10910
|
-
/* @__PURE__ */ (0,
|
|
10911
|
-
/* @__PURE__ */ (0,
|
|
11102
|
+
render: () => /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("label", { className: "fdc-switchrow", children: [
|
|
11103
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { children: fastModeLabel }),
|
|
11104
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
11105
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-switch-thumb" }) })
|
|
10912
11106
|
] })
|
|
10913
11107
|
});
|
|
10914
11108
|
}
|
|
10915
|
-
return /* @__PURE__ */ (0,
|
|
10916
|
-
/* @__PURE__ */ (0,
|
|
11109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(React55.Fragment, { children: [
|
|
11110
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10917
11111
|
MenuButton,
|
|
10918
11112
|
{
|
|
10919
11113
|
items,
|
|
@@ -10924,7 +11118,7 @@ function ModelControls({
|
|
|
10924
11118
|
title: "Choose a model"
|
|
10925
11119
|
}
|
|
10926
11120
|
),
|
|
10927
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */ (0,
|
|
11121
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
10928
11122
|
MenuButton,
|
|
10929
11123
|
{
|
|
10930
11124
|
placement: "top-end",
|
|
@@ -10945,7 +11139,7 @@ function ModelControls({
|
|
|
10945
11139
|
}
|
|
10946
11140
|
|
|
10947
11141
|
// src/components/chat/AgentChatPanel.tsx
|
|
10948
|
-
var
|
|
11142
|
+
var import_jsx_runtime85 = require("react/jsx-runtime");
|
|
10949
11143
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
10950
11144
|
function AgentChatPanel({
|
|
10951
11145
|
/* required */
|
|
@@ -11029,11 +11223,11 @@ function AgentChatPanel({
|
|
|
11029
11223
|
onFeedback,
|
|
11030
11224
|
onEditMessage
|
|
11031
11225
|
}) {
|
|
11032
|
-
const [panelWidth, setPanelWidth] =
|
|
11033
|
-
const [applied, setApplied] =
|
|
11034
|
-
const [draft, setDraft] =
|
|
11035
|
-
const dragging =
|
|
11036
|
-
|
|
11226
|
+
const [panelWidth, setPanelWidth] = React56.useState(width);
|
|
11227
|
+
const [applied, setApplied] = React56.useState({});
|
|
11228
|
+
const [draft, setDraft] = React56.useState("");
|
|
11229
|
+
const dragging = React56.useRef(null);
|
|
11230
|
+
React56.useEffect(() => setPanelWidth(width), [width]);
|
|
11037
11231
|
const engine = useChatEngine({
|
|
11038
11232
|
contextType,
|
|
11039
11233
|
contextId,
|
|
@@ -11099,7 +11293,7 @@ function AgentChatPanel({
|
|
|
11099
11293
|
onReconnect: engine.reload,
|
|
11100
11294
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
11101
11295
|
};
|
|
11102
|
-
const sessionBar = /* @__PURE__ */ (0,
|
|
11296
|
+
const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11103
11297
|
ChatSessionBar,
|
|
11104
11298
|
{
|
|
11105
11299
|
sessionStats,
|
|
@@ -11108,7 +11302,7 @@ function AgentChatPanel({
|
|
|
11108
11302
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
11109
11303
|
}
|
|
11110
11304
|
);
|
|
11111
|
-
const modelControls = /* @__PURE__ */ (0,
|
|
11305
|
+
const modelControls = /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11112
11306
|
ModelControls,
|
|
11113
11307
|
{
|
|
11114
11308
|
models,
|
|
@@ -11123,7 +11317,7 @@ function AgentChatPanel({
|
|
|
11123
11317
|
narrow
|
|
11124
11318
|
}
|
|
11125
11319
|
);
|
|
11126
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0,
|
|
11320
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11127
11321
|
MenuButton,
|
|
11128
11322
|
{
|
|
11129
11323
|
variant: "ghost",
|
|
@@ -11150,7 +11344,7 @@ function AgentChatPanel({
|
|
|
11150
11344
|
})))
|
|
11151
11345
|
}
|
|
11152
11346
|
) : null;
|
|
11153
|
-
return /* @__PURE__ */ (0,
|
|
11347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11154
11348
|
"aside",
|
|
11155
11349
|
{
|
|
11156
11350
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -11161,7 +11355,7 @@ function AgentChatPanel({
|
|
|
11161
11355
|
},
|
|
11162
11356
|
"aria-label": title,
|
|
11163
11357
|
children: [
|
|
11164
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */ (0,
|
|
11358
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11165
11359
|
"div",
|
|
11166
11360
|
{
|
|
11167
11361
|
className: "fdc-grip",
|
|
@@ -11176,20 +11370,20 @@ function AgentChatPanel({
|
|
|
11176
11370
|
}
|
|
11177
11371
|
}
|
|
11178
11372
|
) : null,
|
|
11179
|
-
showHeader ? /* @__PURE__ */ (0,
|
|
11180
|
-
/* @__PURE__ */ (0,
|
|
11181
|
-
/* @__PURE__ */ (0,
|
|
11182
|
-
/* @__PURE__ */ (0,
|
|
11183
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
11373
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("header", { className: "fdc-head", children: [
|
|
11374
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
|
|
11375
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-titles", children: [
|
|
11376
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
|
|
11377
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
|
|
11184
11378
|
] }),
|
|
11185
|
-
/* @__PURE__ */ (0,
|
|
11379
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fdc-head-acts", children: [
|
|
11186
11380
|
headerActions,
|
|
11187
11381
|
threadMenu,
|
|
11188
|
-
onNewThread ? /* @__PURE__ */ (0,
|
|
11189
|
-
onClose ? /* @__PURE__ */ (0,
|
|
11382
|
+
onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
11383
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
11190
11384
|
] })
|
|
11191
11385
|
] }) : null,
|
|
11192
|
-
/* @__PURE__ */ (0,
|
|
11386
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11193
11387
|
ChatTranscript,
|
|
11194
11388
|
{
|
|
11195
11389
|
messages: engine.visible,
|
|
@@ -11204,7 +11398,7 @@ function AgentChatPanel({
|
|
|
11204
11398
|
renderEmpty
|
|
11205
11399
|
}
|
|
11206
11400
|
),
|
|
11207
|
-
/* @__PURE__ */ (0,
|
|
11401
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11208
11402
|
ChatComposer,
|
|
11209
11403
|
{
|
|
11210
11404
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -11237,8 +11431,8 @@ function AgentChatPanel({
|
|
|
11237
11431
|
}
|
|
11238
11432
|
|
|
11239
11433
|
// src/components/files/FileViewer.tsx
|
|
11240
|
-
var
|
|
11241
|
-
var
|
|
11434
|
+
var React57 = __toESM(require("react"), 1);
|
|
11435
|
+
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
11242
11436
|
function previewKindOf(file) {
|
|
11243
11437
|
const mime = (file.mime || "").toLowerCase();
|
|
11244
11438
|
const ext = extensionOf(file.name || "");
|
|
@@ -11294,13 +11488,13 @@ function parseDelimited(text, delimiter) {
|
|
|
11294
11488
|
return rows;
|
|
11295
11489
|
}
|
|
11296
11490
|
function usePreview(file, kind, resolveUrl) {
|
|
11297
|
-
const [state, setState] =
|
|
11298
|
-
const [attempt, setAttempt] =
|
|
11299
|
-
const resolveRef =
|
|
11300
|
-
|
|
11491
|
+
const [state, setState] = React57.useState({ status: "loading" });
|
|
11492
|
+
const [attempt, setAttempt] = React57.useState(0);
|
|
11493
|
+
const resolveRef = React57.useRef(resolveUrl);
|
|
11494
|
+
React57.useEffect(() => {
|
|
11301
11495
|
resolveRef.current = resolveUrl;
|
|
11302
11496
|
}, [resolveUrl]);
|
|
11303
|
-
|
|
11497
|
+
React57.useEffect(() => {
|
|
11304
11498
|
if (kind === "none") {
|
|
11305
11499
|
setState({ status: "ready" });
|
|
11306
11500
|
return;
|
|
@@ -11330,19 +11524,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
11330
11524
|
if (ac) ac.abort();
|
|
11331
11525
|
};
|
|
11332
11526
|
}, [file.id, kind, attempt]);
|
|
11333
|
-
return { ...state, retry:
|
|
11527
|
+
return { ...state, retry: React57.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
11334
11528
|
}
|
|
11335
11529
|
function PreviewBody({ file, kind, state }) {
|
|
11336
|
-
if (kind === "image") return /* @__PURE__ */ (0,
|
|
11337
|
-
if (kind === "pdf") return /* @__PURE__ */ (0,
|
|
11338
|
-
if (kind === "markdown") return /* @__PURE__ */ (0,
|
|
11530
|
+
if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
11531
|
+
if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
|
|
11532
|
+
if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
|
|
11339
11533
|
if (kind === "json") {
|
|
11340
11534
|
let pretty = state.text || "";
|
|
11341
11535
|
try {
|
|
11342
11536
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
11343
11537
|
} catch {
|
|
11344
11538
|
}
|
|
11345
|
-
return /* @__PURE__ */ (0,
|
|
11539
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: pretty, language: "json" });
|
|
11346
11540
|
}
|
|
11347
11541
|
if (kind === "csv") {
|
|
11348
11542
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -11350,12 +11544,12 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11350
11544
|
const head = rows[0] || [];
|
|
11351
11545
|
const dataRows = rows.slice(1);
|
|
11352
11546
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
11353
|
-
return /* @__PURE__ */ (0,
|
|
11354
|
-
/* @__PURE__ */ (0,
|
|
11355
|
-
/* @__PURE__ */ (0,
|
|
11356
|
-
/* @__PURE__ */ (0,
|
|
11547
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-csv", children: [
|
|
11548
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("table", { className: "fd-fv-csv-table", children: [
|
|
11549
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("th", { children: c }, i)) }) }),
|
|
11550
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
|
|
11357
11551
|
] }),
|
|
11358
|
-
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0,
|
|
11552
|
+
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
|
|
11359
11553
|
"Showing the first ",
|
|
11360
11554
|
FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
|
|
11361
11555
|
" of ",
|
|
@@ -11364,24 +11558,24 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11364
11558
|
] }) : null
|
|
11365
11559
|
] });
|
|
11366
11560
|
}
|
|
11367
|
-
if (kind === "text") return /* @__PURE__ */ (0,
|
|
11368
|
-
return /* @__PURE__ */ (0,
|
|
11369
|
-
/* @__PURE__ */ (0,
|
|
11370
|
-
/* @__PURE__ */ (0,
|
|
11371
|
-
/* @__PURE__ */ (0,
|
|
11561
|
+
if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
|
|
11562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-fallback", children: [
|
|
11563
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11564
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
|
|
11565
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
|
|
11372
11566
|
file.mime || "Unknown type",
|
|
11373
11567
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11374
11568
|
] })
|
|
11375
11569
|
] });
|
|
11376
11570
|
}
|
|
11377
11571
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
11378
|
-
const kind =
|
|
11572
|
+
const kind = React57.useMemo(() => previewKindOf(file), [file]);
|
|
11379
11573
|
const preview = usePreview(file, kind, resolveUrl);
|
|
11380
|
-
const [tab, setTab] =
|
|
11381
|
-
const [downloading, setDownloading] =
|
|
11382
|
-
const [downloadError, setDownloadError] =
|
|
11574
|
+
const [tab, setTab] = React57.useState("preview");
|
|
11575
|
+
const [downloading, setDownloading] = React57.useState(false);
|
|
11576
|
+
const [downloadError, setDownloadError] = React57.useState(null);
|
|
11383
11577
|
const hasSide = sidePanel != null;
|
|
11384
|
-
|
|
11578
|
+
React57.useEffect(() => {
|
|
11385
11579
|
setTab("preview");
|
|
11386
11580
|
}, [file.id]);
|
|
11387
11581
|
const download = () => {
|
|
@@ -11397,29 +11591,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11397
11591
|
a.remove();
|
|
11398
11592
|
}).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
|
|
11399
11593
|
};
|
|
11400
|
-
return /* @__PURE__ */ (0,
|
|
11594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
11401
11595
|
"section",
|
|
11402
11596
|
{
|
|
11403
11597
|
className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
|
|
11404
11598
|
"aria-label": file.name || "File",
|
|
11405
11599
|
children: [
|
|
11406
|
-
/* @__PURE__ */ (0,
|
|
11407
|
-
/* @__PURE__ */ (0,
|
|
11408
|
-
/* @__PURE__ */ (0,
|
|
11409
|
-
/* @__PURE__ */ (0,
|
|
11410
|
-
/* @__PURE__ */ (0,
|
|
11600
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("header", { className: "fd-fv-head", children: [
|
|
11601
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11602
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-titles", children: [
|
|
11603
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
|
|
11604
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-meta", children: [
|
|
11411
11605
|
file.mime || "Unknown type",
|
|
11412
11606
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11413
11607
|
] })
|
|
11414
11608
|
] }),
|
|
11415
|
-
/* @__PURE__ */ (0,
|
|
11609
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-fv-head-actions", children: [
|
|
11416
11610
|
actions,
|
|
11417
|
-
/* @__PURE__ */ (0,
|
|
11418
|
-
onClose ? /* @__PURE__ */ (0,
|
|
11611
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
|
|
11612
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
|
|
11419
11613
|
] })
|
|
11420
11614
|
] }),
|
|
11421
|
-
downloadError ? /* @__PURE__ */ (0,
|
|
11422
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
11615
|
+
downloadError ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
|
|
11616
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
11423
11617
|
Tabs,
|
|
11424
11618
|
{
|
|
11425
11619
|
className: "fd-fv-tabs",
|
|
@@ -11428,19 +11622,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11428
11622
|
onChange: (v) => setTab(v)
|
|
11429
11623
|
}
|
|
11430
11624
|
) : null,
|
|
11431
|
-
/* @__PURE__ */ (0,
|
|
11432
|
-
/* @__PURE__ */ (0,
|
|
11625
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-fv-body", children: [
|
|
11626
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
11433
11627
|
LoadingRegion,
|
|
11434
11628
|
{
|
|
11435
11629
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
11436
11630
|
error: preview.error,
|
|
11437
11631
|
label: "Loading preview of " + (file.name || "file"),
|
|
11438
11632
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
11439
|
-
skeleton: /* @__PURE__ */ (0,
|
|
11440
|
-
children: /* @__PURE__ */ (0,
|
|
11633
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(Skeleton, { shape: "card", h: 220 }),
|
|
11634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(PreviewBody, { file, kind, state: preview })
|
|
11441
11635
|
}
|
|
11442
11636
|
) }),
|
|
11443
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
11637
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
11444
11638
|
] })
|
|
11445
11639
|
]
|
|
11446
11640
|
}
|
|
@@ -11448,8 +11642,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11448
11642
|
}
|
|
11449
11643
|
|
|
11450
11644
|
// src/components/files/FileBrowser.tsx
|
|
11451
|
-
var
|
|
11452
|
-
var
|
|
11645
|
+
var React58 = __toESM(require("react"), 1);
|
|
11646
|
+
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
11453
11647
|
function childrenOf(folders, parentId) {
|
|
11454
11648
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
11455
11649
|
}
|
|
@@ -11519,10 +11713,10 @@ function FolderPickerMenu({
|
|
|
11519
11713
|
destinations,
|
|
11520
11714
|
onPick
|
|
11521
11715
|
}) {
|
|
11522
|
-
const [open, setOpen] =
|
|
11716
|
+
const [open, setOpen] = React58.useState(false);
|
|
11523
11717
|
const zIndex = useOverlayLayer(open);
|
|
11524
|
-
const ref =
|
|
11525
|
-
|
|
11718
|
+
const ref = React58.useRef(null);
|
|
11719
|
+
React58.useEffect(() => {
|
|
11526
11720
|
if (!open) return;
|
|
11527
11721
|
const away = (e) => {
|
|
11528
11722
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -11537,8 +11731,8 @@ function FolderPickerMenu({
|
|
|
11537
11731
|
document.removeEventListener("keydown", esc);
|
|
11538
11732
|
};
|
|
11539
11733
|
}, [open]);
|
|
11540
|
-
return /* @__PURE__ */ (0,
|
|
11541
|
-
/* @__PURE__ */ (0,
|
|
11734
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
11735
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11542
11736
|
IconButton,
|
|
11543
11737
|
{
|
|
11544
11738
|
icon: "arrows-out-cardinal",
|
|
@@ -11550,9 +11744,9 @@ function FolderPickerMenu({
|
|
|
11550
11744
|
onClick: () => setOpen((v) => !v)
|
|
11551
11745
|
}
|
|
11552
11746
|
),
|
|
11553
|
-
open ? /* @__PURE__ */ (0,
|
|
11554
|
-
/* @__PURE__ */ (0,
|
|
11555
|
-
destinations.map((d) => /* @__PURE__ */ (0,
|
|
11747
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
|
|
11748
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
11749
|
+
destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11556
11750
|
"button",
|
|
11557
11751
|
{
|
|
11558
11752
|
type: "button",
|
|
@@ -11564,7 +11758,7 @@ function FolderPickerMenu({
|
|
|
11564
11758
|
setOpen(false);
|
|
11565
11759
|
},
|
|
11566
11760
|
children: [
|
|
11567
|
-
/* @__PURE__ */ (0,
|
|
11761
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
11568
11762
|
d.name
|
|
11569
11763
|
]
|
|
11570
11764
|
},
|
|
@@ -11574,8 +11768,8 @@ function FolderPickerMenu({
|
|
|
11574
11768
|
] });
|
|
11575
11769
|
}
|
|
11576
11770
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
11577
|
-
const [over, setOver] =
|
|
11578
|
-
const dragCounter =
|
|
11771
|
+
const [over, setOver] = React58.useState(false);
|
|
11772
|
+
const dragCounter = React58.useRef(0);
|
|
11579
11773
|
const dropHandlers = isDropTarget ? {
|
|
11580
11774
|
onDragEnter: (e) => {
|
|
11581
11775
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11600,8 +11794,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11600
11794
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11601
11795
|
}
|
|
11602
11796
|
} : {};
|
|
11603
|
-
return /* @__PURE__ */ (0,
|
|
11604
|
-
/* @__PURE__ */ (0,
|
|
11797
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
11798
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11605
11799
|
"button",
|
|
11606
11800
|
{
|
|
11607
11801
|
type: "button",
|
|
@@ -11610,26 +11804,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11610
11804
|
draggable: !!draggableId,
|
|
11611
11805
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
11612
11806
|
children: [
|
|
11613
|
-
/* @__PURE__ */ (0,
|
|
11614
|
-
/* @__PURE__ */ (0,
|
|
11615
|
-
/* @__PURE__ */ (0,
|
|
11616
|
-
meta ? /* @__PURE__ */ (0,
|
|
11807
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + icon }) }),
|
|
11808
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-row-text", children: [
|
|
11809
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
11810
|
+
meta ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
11617
11811
|
] })
|
|
11618
11812
|
]
|
|
11619
11813
|
}
|
|
11620
11814
|
),
|
|
11621
|
-
actions ? /* @__PURE__ */ (0,
|
|
11815
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
11622
11816
|
] });
|
|
11623
11817
|
}
|
|
11624
11818
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
11625
11819
|
const kids = childrenOf(folders, folder.id);
|
|
11626
|
-
const [expanded, setExpanded] =
|
|
11627
|
-
|
|
11820
|
+
const [expanded, setExpanded] = React58.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
11821
|
+
React58.useEffect(() => {
|
|
11628
11822
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
11629
11823
|
}, [currentFolderId, folder.id, folders]);
|
|
11630
11824
|
const isCurrent = folder.id === currentFolderId;
|
|
11631
|
-
return /* @__PURE__ */ (0,
|
|
11632
|
-
/* @__PURE__ */ (0,
|
|
11825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree-node", children: [
|
|
11826
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11633
11827
|
RowShell,
|
|
11634
11828
|
{
|
|
11635
11829
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -11639,7 +11833,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11639
11833
|
isDropTarget: canMove,
|
|
11640
11834
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
11641
11835
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
11642
|
-
actions: kids.length ? /* @__PURE__ */ (0,
|
|
11836
|
+
actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11643
11837
|
IconButton,
|
|
11644
11838
|
{
|
|
11645
11839
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -11651,7 +11845,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11651
11845
|
) : void 0
|
|
11652
11846
|
}
|
|
11653
11847
|
),
|
|
11654
|
-
expanded && kids.length ? /* @__PURE__ */ (0,
|
|
11848
|
+
expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11655
11849
|
TreeNode,
|
|
11656
11850
|
{
|
|
11657
11851
|
folder: k,
|
|
@@ -11690,15 +11884,15 @@ function FileBrowser({
|
|
|
11690
11884
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
11691
11885
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
11692
11886
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
11693
|
-
const [createOpen, setCreateOpen] =
|
|
11694
|
-
const [createName, setCreateName] =
|
|
11695
|
-
const [renameTarget, setRenameTarget] =
|
|
11696
|
-
const [renameValue, setRenameValue] =
|
|
11697
|
-
const [deleteTarget, setDeleteTarget] =
|
|
11698
|
-
const uploadInputRef =
|
|
11699
|
-
const crumbFolders =
|
|
11700
|
-
const subfolders =
|
|
11701
|
-
const currentFiles =
|
|
11887
|
+
const [createOpen, setCreateOpen] = React58.useState(false);
|
|
11888
|
+
const [createName, setCreateName] = React58.useState("");
|
|
11889
|
+
const [renameTarget, setRenameTarget] = React58.useState(null);
|
|
11890
|
+
const [renameValue, setRenameValue] = React58.useState("");
|
|
11891
|
+
const [deleteTarget, setDeleteTarget] = React58.useState(null);
|
|
11892
|
+
const uploadInputRef = React58.useRef(null);
|
|
11893
|
+
const crumbFolders = React58.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11894
|
+
const subfolders = React58.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11895
|
+
const currentFiles = React58.useMemo(
|
|
11702
11896
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
11703
11897
|
[files, currentFolderId]
|
|
11704
11898
|
);
|
|
@@ -11737,10 +11931,10 @@ function FileBrowser({
|
|
|
11737
11931
|
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
11738
11932
|
setDeleteTarget(null);
|
|
11739
11933
|
};
|
|
11740
|
-
const content = /* @__PURE__ */ (0,
|
|
11741
|
-
/* @__PURE__ */ (0,
|
|
11742
|
-
/* @__PURE__ */ (0,
|
|
11743
|
-
/* @__PURE__ */ (0,
|
|
11934
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
11935
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-head", children: [
|
|
11936
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
11937
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11744
11938
|
BreadcrumbCrumb,
|
|
11745
11939
|
{
|
|
11746
11940
|
label: "Home",
|
|
@@ -11750,7 +11944,7 @@ function FileBrowser({
|
|
|
11750
11944
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
11751
11945
|
}
|
|
11752
11946
|
),
|
|
11753
|
-
crumbFolders.map((f, i) => /* @__PURE__ */ (0,
|
|
11947
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11754
11948
|
BreadcrumbCrumb,
|
|
11755
11949
|
{
|
|
11756
11950
|
label: f.name,
|
|
@@ -11762,11 +11956,11 @@ function FileBrowser({
|
|
|
11762
11956
|
f.id
|
|
11763
11957
|
))
|
|
11764
11958
|
] }),
|
|
11765
|
-
/* @__PURE__ */ (0,
|
|
11766
|
-
canCreateFolder ? /* @__PURE__ */ (0,
|
|
11767
|
-
canUpload ? /* @__PURE__ */ (0,
|
|
11768
|
-
/* @__PURE__ */ (0,
|
|
11769
|
-
/* @__PURE__ */ (0,
|
|
11959
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "fd-fb-actions", children: [
|
|
11960
|
+
canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
11961
|
+
canUpload ? /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
11962
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
11963
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11770
11964
|
"input",
|
|
11771
11965
|
{
|
|
11772
11966
|
ref: uploadInputRef,
|
|
@@ -11784,9 +11978,9 @@ function FileBrowser({
|
|
|
11784
11978
|
] }) : null
|
|
11785
11979
|
] })
|
|
11786
11980
|
] }),
|
|
11787
|
-
/* @__PURE__ */ (0,
|
|
11788
|
-
/* @__PURE__ */ (0,
|
|
11789
|
-
/* @__PURE__ */ (0,
|
|
11981
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-body", children: [
|
|
11982
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
11983
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11790
11984
|
RowShell,
|
|
11791
11985
|
{
|
|
11792
11986
|
icon: "house-simple",
|
|
@@ -11797,7 +11991,7 @@ function FileBrowser({
|
|
|
11797
11991
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
11798
11992
|
}
|
|
11799
11993
|
),
|
|
11800
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0,
|
|
11994
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11801
11995
|
TreeNode,
|
|
11802
11996
|
{
|
|
11803
11997
|
folder: f,
|
|
@@ -11811,18 +12005,18 @@ function FileBrowser({
|
|
|
11811
12005
|
f.id
|
|
11812
12006
|
))
|
|
11813
12007
|
] }),
|
|
11814
|
-
/* @__PURE__ */ (0,
|
|
12008
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11815
12009
|
LoadingRegion,
|
|
11816
12010
|
{
|
|
11817
12011
|
state: loading ? "loading" : "ready",
|
|
11818
12012
|
label: "Loading folder contents",
|
|
11819
|
-
skeleton: /* @__PURE__ */ (0,
|
|
11820
|
-
/* @__PURE__ */ (0,
|
|
11821
|
-
/* @__PURE__ */ (0,
|
|
11822
|
-
/* @__PURE__ */ (0,
|
|
12013
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
12014
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
12015
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
12016
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Skeleton, { h: 44, radius: "10px" })
|
|
11823
12017
|
] }),
|
|
11824
|
-
children: isEmpty ? /* @__PURE__ */ (0,
|
|
11825
|
-
subfolders.map((f) => /* @__PURE__ */ (0,
|
|
12018
|
+
children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "fd-fb-list", children: [
|
|
12019
|
+
subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11826
12020
|
RowShell,
|
|
11827
12021
|
{
|
|
11828
12022
|
icon: "folder-simple",
|
|
@@ -11831,9 +12025,9 @@ function FileBrowser({
|
|
|
11831
12025
|
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
11832
12026
|
isDropTarget: canMove,
|
|
11833
12027
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
11834
|
-
actions: /* @__PURE__ */ (0,
|
|
11835
|
-
canRenameFolder ? /* @__PURE__ */ (0,
|
|
11836
|
-
canMove ? /* @__PURE__ */ (0,
|
|
12028
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12029
|
+
canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
12030
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11837
12031
|
FolderPickerMenu,
|
|
11838
12032
|
{
|
|
11839
12033
|
label: "Move " + f.name,
|
|
@@ -11841,12 +12035,12 @@ function FileBrowser({
|
|
|
11841
12035
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
11842
12036
|
}
|
|
11843
12037
|
) : null,
|
|
11844
|
-
canDeleteFolder ? /* @__PURE__ */ (0,
|
|
12038
|
+
canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
11845
12039
|
] })
|
|
11846
12040
|
},
|
|
11847
12041
|
f.id
|
|
11848
12042
|
)),
|
|
11849
|
-
currentFiles.map((file) => /* @__PURE__ */ (0,
|
|
12043
|
+
currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11850
12044
|
RowShell,
|
|
11851
12045
|
{
|
|
11852
12046
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -11854,8 +12048,8 @@ function FileBrowser({
|
|
|
11854
12048
|
meta: file.size ? formatBytes(file.size) : void 0,
|
|
11855
12049
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
11856
12050
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
11857
|
-
actions: /* @__PURE__ */ (0,
|
|
11858
|
-
canMove ? /* @__PURE__ */ (0,
|
|
12051
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12052
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11859
12053
|
FolderPickerMenu,
|
|
11860
12054
|
{
|
|
11861
12055
|
label: "Move " + file.name,
|
|
@@ -11863,7 +12057,7 @@ function FileBrowser({
|
|
|
11863
12057
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
11864
12058
|
}
|
|
11865
12059
|
) : null,
|
|
11866
|
-
canRemoveFile ? /* @__PURE__ */ (0,
|
|
12060
|
+
canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
11867
12061
|
] })
|
|
11868
12062
|
},
|
|
11869
12063
|
file.id
|
|
@@ -11872,10 +12066,10 @@ function FileBrowser({
|
|
|
11872
12066
|
}
|
|
11873
12067
|
) })
|
|
11874
12068
|
] }),
|
|
11875
|
-
/* @__PURE__ */ (0,
|
|
11876
|
-
/* @__PURE__ */ (0,
|
|
11877
|
-
/* @__PURE__ */ (0,
|
|
11878
|
-
] }), children: /* @__PURE__ */ (0,
|
|
12069
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12070
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
12071
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
12072
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11879
12073
|
"input",
|
|
11880
12074
|
{
|
|
11881
12075
|
className: "fd-fb-input",
|
|
@@ -11889,10 +12083,10 @@ function FileBrowser({
|
|
|
11889
12083
|
autoFocus: true
|
|
11890
12084
|
}
|
|
11891
12085
|
) }),
|
|
11892
|
-
/* @__PURE__ */ (0,
|
|
11893
|
-
/* @__PURE__ */ (0,
|
|
11894
|
-
/* @__PURE__ */ (0,
|
|
11895
|
-
] }), children: /* @__PURE__ */ (0,
|
|
12086
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12087
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
12088
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
12089
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11896
12090
|
"input",
|
|
11897
12091
|
{
|
|
11898
12092
|
className: "fd-fb-input",
|
|
@@ -11906,22 +12100,22 @@ function FileBrowser({
|
|
|
11906
12100
|
autoFocus: true
|
|
11907
12101
|
}
|
|
11908
12102
|
) }),
|
|
11909
|
-
/* @__PURE__ */ (0,
|
|
12103
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
11910
12104
|
Modal,
|
|
11911
12105
|
{
|
|
11912
12106
|
open: deleteTarget != null,
|
|
11913
12107
|
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
11914
12108
|
description: "This can't be undone. The folder must be empty.",
|
|
11915
12109
|
onClose: () => setDeleteTarget(null),
|
|
11916
|
-
footer: /* @__PURE__ */ (0,
|
|
11917
|
-
/* @__PURE__ */ (0,
|
|
11918
|
-
/* @__PURE__ */ (0,
|
|
12110
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(import_jsx_runtime87.Fragment, { children: [
|
|
12111
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
12112
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
11919
12113
|
] })
|
|
11920
12114
|
}
|
|
11921
12115
|
)
|
|
11922
12116
|
] });
|
|
11923
12117
|
if (!canUpload) return content;
|
|
11924
|
-
return /* @__PURE__ */ (0,
|
|
12118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
11925
12119
|
}
|
|
11926
12120
|
function BreadcrumbCrumb({
|
|
11927
12121
|
label,
|
|
@@ -11930,8 +12124,8 @@ function BreadcrumbCrumb({
|
|
|
11930
12124
|
isDropTarget,
|
|
11931
12125
|
onDropPayload
|
|
11932
12126
|
}) {
|
|
11933
|
-
const [over, setOver] =
|
|
11934
|
-
const dragCounter =
|
|
12127
|
+
const [over, setOver] = React58.useState(false);
|
|
12128
|
+
const dragCounter = React58.useRef(0);
|
|
11935
12129
|
const dropHandlers = isDropTarget ? {
|
|
11936
12130
|
onDragEnter: (e) => {
|
|
11937
12131
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11956,11 +12150,11 @@ function BreadcrumbCrumb({
|
|
|
11956
12150
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11957
12151
|
}
|
|
11958
12152
|
} : {};
|
|
11959
|
-
return /* @__PURE__ */ (0,
|
|
12153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
11960
12154
|
}
|
|
11961
12155
|
|
|
11962
12156
|
// src/kits/query.ts
|
|
11963
|
-
var
|
|
12157
|
+
var React59 = __toESM(require("react"), 1);
|
|
11964
12158
|
function eqFilter(get2) {
|
|
11965
12159
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
11966
12160
|
}
|
|
@@ -11992,22 +12186,22 @@ function compare(a, b, dir) {
|
|
|
11992
12186
|
var API = null;
|
|
11993
12187
|
var PREFS = null;
|
|
11994
12188
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
11995
|
-
const [query, setQuery] =
|
|
12189
|
+
const [query, setQuery] = React59.useState(() => {
|
|
11996
12190
|
const store = PREFS || window.PlannerPrefs;
|
|
11997
12191
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
11998
12192
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
11999
12193
|
});
|
|
12000
|
-
const savePref =
|
|
12194
|
+
const savePref = React59.useCallback((patch2) => {
|
|
12001
12195
|
const store = PREFS || window.PlannerPrefs;
|
|
12002
12196
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
12003
12197
|
}, [prefsKey]);
|
|
12004
|
-
const [res, setRes] =
|
|
12005
|
-
const [loading, setLoading] =
|
|
12006
|
-
const seq2 =
|
|
12198
|
+
const [res, setRes] = React59.useState(null);
|
|
12199
|
+
const [loading, setLoading] = React59.useState(true);
|
|
12200
|
+
const seq2 = React59.useRef(0);
|
|
12007
12201
|
const depKey = (deps || []).join("|");
|
|
12008
12202
|
const paramKey = JSON.stringify(params || {});
|
|
12009
12203
|
const queryKey = JSON.stringify(query);
|
|
12010
|
-
|
|
12204
|
+
React59.useEffect(() => {
|
|
12011
12205
|
const id = ++seq2.current;
|
|
12012
12206
|
setLoading(true);
|
|
12013
12207
|
const t = setTimeout(() => {
|
|
@@ -12306,12 +12500,12 @@ function createVersionStore(initialState, options) {
|
|
|
12306
12500
|
}
|
|
12307
12501
|
|
|
12308
12502
|
// src/kits/documentTitle.ts
|
|
12309
|
-
var
|
|
12503
|
+
var React60 = __toESM(require("react"), 1);
|
|
12310
12504
|
function formatDocumentTitle(routeTitle, appName) {
|
|
12311
12505
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
12312
12506
|
}
|
|
12313
12507
|
function useDocumentTitle(routeTitle, appName) {
|
|
12314
|
-
|
|
12508
|
+
React60.useEffect(() => {
|
|
12315
12509
|
if (typeof document === "undefined") return;
|
|
12316
12510
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
12317
12511
|
}, [routeTitle, appName]);
|
|
@@ -12434,6 +12628,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
12434
12628
|
SessionKit,
|
|
12435
12629
|
SessionProvider,
|
|
12436
12630
|
SidebarNav,
|
|
12631
|
+
SignInPage,
|
|
12437
12632
|
Skeleton,
|
|
12438
12633
|
SkeletonText,
|
|
12439
12634
|
Slider,
|