@flytedan/flytebot-design-system 0.19.0 → 0.20.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 +892 -698
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -1
- package/dist/index.d.ts +54 -1
- package/dist/index.js +891 -698
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6376,11 +6376,203 @@ function ProfilePage({
|
|
|
6376
6376
|
] });
|
|
6377
6377
|
}
|
|
6378
6378
|
|
|
6379
|
+
// src/components/platform/SignInPage.tsx
|
|
6380
|
+
import * as React42 from "react";
|
|
6381
|
+
import { Fragment as Fragment18, jsx as jsx67, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
6382
|
+
function SignInPage({ productName, onSignIn, continueAs }) {
|
|
6383
|
+
const [signingIn, setSigningIn] = React42.useState(false);
|
|
6384
|
+
const [resuming, setResuming] = React42.useState(false);
|
|
6385
|
+
function handleSignIn() {
|
|
6386
|
+
setSigningIn(true);
|
|
6387
|
+
onSignIn();
|
|
6388
|
+
}
|
|
6389
|
+
function handleContinue() {
|
|
6390
|
+
setResuming(true);
|
|
6391
|
+
continueAs.onContinue().finally(() => setResuming(false));
|
|
6392
|
+
}
|
|
6393
|
+
return /* @__PURE__ */ jsxs61(
|
|
6394
|
+
"div",
|
|
6395
|
+
{
|
|
6396
|
+
style: {
|
|
6397
|
+
position: "relative",
|
|
6398
|
+
display: "grid",
|
|
6399
|
+
placeItems: "center",
|
|
6400
|
+
minHeight: "100vh",
|
|
6401
|
+
padding: "24px 16px",
|
|
6402
|
+
boxSizing: "border-box",
|
|
6403
|
+
overflow: "hidden",
|
|
6404
|
+
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%)"
|
|
6405
|
+
},
|
|
6406
|
+
children: [
|
|
6407
|
+
/* @__PURE__ */ jsx67(
|
|
6408
|
+
"div",
|
|
6409
|
+
{
|
|
6410
|
+
"aria-hidden": true,
|
|
6411
|
+
style: {
|
|
6412
|
+
position: "absolute",
|
|
6413
|
+
inset: 0,
|
|
6414
|
+
backgroundImage: "linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px)",
|
|
6415
|
+
backgroundSize: "48px 48px",
|
|
6416
|
+
maskImage: "radial-gradient(circle at 50% 40%, black, transparent 70%)"
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
),
|
|
6420
|
+
/* @__PURE__ */ jsxs61(
|
|
6421
|
+
"div",
|
|
6422
|
+
{
|
|
6423
|
+
style: {
|
|
6424
|
+
position: "relative",
|
|
6425
|
+
width: "100%",
|
|
6426
|
+
maxWidth: 408,
|
|
6427
|
+
display: "flex",
|
|
6428
|
+
flexDirection: "column",
|
|
6429
|
+
alignItems: "center"
|
|
6430
|
+
},
|
|
6431
|
+
children: [
|
|
6432
|
+
/* @__PURE__ */ jsx67("div", { style: { marginBottom: "var(--s-32)" }, "data-theme": "dark", children: /* @__PURE__ */ jsx67(FlytedeskMark, { size: "lg" }) }),
|
|
6433
|
+
/* @__PURE__ */ jsxs61(
|
|
6434
|
+
"div",
|
|
6435
|
+
{
|
|
6436
|
+
style: {
|
|
6437
|
+
width: "100%",
|
|
6438
|
+
borderRadius: "var(--r-2xl)",
|
|
6439
|
+
overflow: "hidden",
|
|
6440
|
+
boxShadow: "0 24px 64px -12px rgba(2, 8, 20, 0.55), 0 2px 8px rgba(2, 8, 20, 0.3)"
|
|
6441
|
+
},
|
|
6442
|
+
children: [
|
|
6443
|
+
/* @__PURE__ */ jsx67(
|
|
6444
|
+
"div",
|
|
6445
|
+
{
|
|
6446
|
+
style: {
|
|
6447
|
+
height: 4,
|
|
6448
|
+
background: "linear-gradient(90deg, var(--blue-400), var(--blue-600), var(--navy))"
|
|
6449
|
+
}
|
|
6450
|
+
}
|
|
6451
|
+
),
|
|
6452
|
+
/* @__PURE__ */ jsx67(Card, { children: /* @__PURE__ */ jsxs61(
|
|
6453
|
+
"div",
|
|
6454
|
+
{
|
|
6455
|
+
style: {
|
|
6456
|
+
display: "flex",
|
|
6457
|
+
flexDirection: "column",
|
|
6458
|
+
gap: "var(--s-20)",
|
|
6459
|
+
alignItems: "center",
|
|
6460
|
+
textAlign: "center",
|
|
6461
|
+
padding: "var(--s-8) 0"
|
|
6462
|
+
},
|
|
6463
|
+
children: [
|
|
6464
|
+
/* @__PURE__ */ jsxs61("div", { children: [
|
|
6465
|
+
/* @__PURE__ */ jsx67("h1", { className: "fd-h3", style: { color: "var(--navy)" }, children: productName }),
|
|
6466
|
+
/* @__PURE__ */ jsx67("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" })
|
|
6467
|
+
] }),
|
|
6468
|
+
continueAs ? /* @__PURE__ */ jsxs61(Fragment18, { children: [
|
|
6469
|
+
/* @__PURE__ */ jsx67(
|
|
6470
|
+
Button,
|
|
6471
|
+
{
|
|
6472
|
+
variant: "primary",
|
|
6473
|
+
style: { width: "100%" },
|
|
6474
|
+
loading: resuming,
|
|
6475
|
+
disabled: resuming,
|
|
6476
|
+
onClick: handleContinue,
|
|
6477
|
+
children: resuming ? "Resuming\u2026" : `Continue as ${continueAs.name}`
|
|
6478
|
+
}
|
|
6479
|
+
),
|
|
6480
|
+
/* @__PURE__ */ jsx67(
|
|
6481
|
+
"button",
|
|
6482
|
+
{
|
|
6483
|
+
type: "button",
|
|
6484
|
+
className: "fd-body-sm fd-muted",
|
|
6485
|
+
style: {
|
|
6486
|
+
background: "none",
|
|
6487
|
+
border: "none",
|
|
6488
|
+
cursor: "pointer",
|
|
6489
|
+
textDecoration: "underline",
|
|
6490
|
+
padding: 0
|
|
6491
|
+
},
|
|
6492
|
+
disabled: resuming,
|
|
6493
|
+
onClick: continueAs.onDecline,
|
|
6494
|
+
children: "Not you? Sign in with flytedesk ID"
|
|
6495
|
+
}
|
|
6496
|
+
)
|
|
6497
|
+
] }) : /* @__PURE__ */ jsx67(
|
|
6498
|
+
Button,
|
|
6499
|
+
{
|
|
6500
|
+
variant: "primary",
|
|
6501
|
+
style: { width: "100%" },
|
|
6502
|
+
loading: signingIn,
|
|
6503
|
+
disabled: signingIn,
|
|
6504
|
+
onClick: handleSignIn,
|
|
6505
|
+
children: /* @__PURE__ */ jsxs61(
|
|
6506
|
+
"span",
|
|
6507
|
+
{
|
|
6508
|
+
style: {
|
|
6509
|
+
display: "flex",
|
|
6510
|
+
flexDirection: "row",
|
|
6511
|
+
alignItems: "center",
|
|
6512
|
+
justifyContent: "center",
|
|
6513
|
+
gap: "var(--s-8)",
|
|
6514
|
+
flexWrap: "nowrap"
|
|
6515
|
+
},
|
|
6516
|
+
children: [
|
|
6517
|
+
/* @__PURE__ */ jsx67(GoogleGlyph, {}),
|
|
6518
|
+
/* @__PURE__ */ jsx67("span", { children: signingIn ? "Signing in\u2026" : "Sign in with flytedesk ID" })
|
|
6519
|
+
]
|
|
6520
|
+
}
|
|
6521
|
+
)
|
|
6522
|
+
}
|
|
6523
|
+
),
|
|
6524
|
+
/* @__PURE__ */ jsx67("p", { className: "fd-body-sm fd-muted", style: { fontSize: "12px" }, children: "One account, every flytedesk app." })
|
|
6525
|
+
]
|
|
6526
|
+
}
|
|
6527
|
+
) })
|
|
6528
|
+
]
|
|
6529
|
+
}
|
|
6530
|
+
)
|
|
6531
|
+
]
|
|
6532
|
+
}
|
|
6533
|
+
)
|
|
6534
|
+
]
|
|
6535
|
+
}
|
|
6536
|
+
);
|
|
6537
|
+
}
|
|
6538
|
+
function GoogleGlyph() {
|
|
6539
|
+
return /* @__PURE__ */ jsxs61("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": true, children: [
|
|
6540
|
+
/* @__PURE__ */ jsx67(
|
|
6541
|
+
"path",
|
|
6542
|
+
{
|
|
6543
|
+
fill: "#4285F4",
|
|
6544
|
+
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"
|
|
6545
|
+
}
|
|
6546
|
+
),
|
|
6547
|
+
/* @__PURE__ */ jsx67(
|
|
6548
|
+
"path",
|
|
6549
|
+
{
|
|
6550
|
+
fill: "#34A853",
|
|
6551
|
+
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"
|
|
6552
|
+
}
|
|
6553
|
+
),
|
|
6554
|
+
/* @__PURE__ */ jsx67(
|
|
6555
|
+
"path",
|
|
6556
|
+
{
|
|
6557
|
+
fill: "#FBBC05",
|
|
6558
|
+
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"
|
|
6559
|
+
}
|
|
6560
|
+
),
|
|
6561
|
+
/* @__PURE__ */ jsx67(
|
|
6562
|
+
"path",
|
|
6563
|
+
{
|
|
6564
|
+
fill: "#EA4335",
|
|
6565
|
+
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"
|
|
6566
|
+
}
|
|
6567
|
+
)
|
|
6568
|
+
] });
|
|
6569
|
+
}
|
|
6570
|
+
|
|
6379
6571
|
// src/components/platform/RoadmapTimeline.tsx
|
|
6380
|
-
import * as
|
|
6572
|
+
import * as React45 from "react";
|
|
6381
6573
|
|
|
6382
6574
|
// src/kits/session.ts
|
|
6383
|
-
import * as
|
|
6575
|
+
import * as React43 from "react";
|
|
6384
6576
|
var PERMISSION_CATALOG = [
|
|
6385
6577
|
{ group: "Plans", items: [
|
|
6386
6578
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -7947,8 +8139,8 @@ function roadmap(overrides) {
|
|
|
7947
8139
|
};
|
|
7948
8140
|
}
|
|
7949
8141
|
function useSession() {
|
|
7950
|
-
const [s, setS] =
|
|
7951
|
-
|
|
8142
|
+
const [s, setS] = React43.useState(getSession);
|
|
8143
|
+
React43.useEffect(() => subscribe(setS), []);
|
|
7952
8144
|
return s;
|
|
7953
8145
|
}
|
|
7954
8146
|
var SessionKit = {
|
|
@@ -7981,7 +8173,7 @@ var SessionKit = {
|
|
|
7981
8173
|
};
|
|
7982
8174
|
function DemoSessionProvider({ children }) {
|
|
7983
8175
|
const session = useSession();
|
|
7984
|
-
const value =
|
|
8176
|
+
const value = React43.useMemo(
|
|
7985
8177
|
() => ({
|
|
7986
8178
|
user: session.user,
|
|
7987
8179
|
roles: session.roles,
|
|
@@ -7997,11 +8189,11 @@ function DemoSessionProvider({ children }) {
|
|
|
7997
8189
|
}),
|
|
7998
8190
|
[session]
|
|
7999
8191
|
);
|
|
8000
|
-
return
|
|
8192
|
+
return React43.createElement(SessionProvider, { value }, children);
|
|
8001
8193
|
}
|
|
8002
8194
|
|
|
8003
8195
|
// src/kits/runtime.ts
|
|
8004
|
-
import * as
|
|
8196
|
+
import * as React44 from "react";
|
|
8005
8197
|
var WIRED_ENDPOINTS = [
|
|
8006
8198
|
// Nothing yet. Every id below would come from a real service:
|
|
8007
8199
|
// "plan.get", "placements.list", …
|
|
@@ -8172,8 +8364,8 @@ var RuntimeKit = {
|
|
|
8172
8364
|
};
|
|
8173
8365
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
8174
8366
|
function useRuntimeMode() {
|
|
8175
|
-
const [m, setM] =
|
|
8176
|
-
|
|
8367
|
+
const [m, setM] = React44.useState(RuntimeKit.getMode());
|
|
8368
|
+
React44.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
8177
8369
|
return m;
|
|
8178
8370
|
}
|
|
8179
8371
|
function useFeatureStatus(key) {
|
|
@@ -8192,7 +8384,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
8192
8384
|
var UseFeatureStatus = useFeatureStatus;
|
|
8193
8385
|
|
|
8194
8386
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8195
|
-
import { jsx as
|
|
8387
|
+
import { jsx as jsx68, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
8196
8388
|
var STATUS = {
|
|
8197
8389
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
8198
8390
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -8207,45 +8399,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8207
8399
|
const s = STATUS[item.status] || STATUS.planned;
|
|
8208
8400
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
8209
8401
|
const blocking = deps.filter((d) => !d.implemented);
|
|
8210
|
-
return /* @__PURE__ */
|
|
8211
|
-
/* @__PURE__ */
|
|
8212
|
-
/* @__PURE__ */
|
|
8213
|
-
/* @__PURE__ */
|
|
8214
|
-
/* @__PURE__ */
|
|
8402
|
+
return /* @__PURE__ */ jsx68(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs62("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8403
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
8404
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
8405
|
+
/* @__PURE__ */ jsx68(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
8406
|
+
/* @__PURE__ */ jsx68(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
8215
8407
|
] }),
|
|
8216
|
-
/* @__PURE__ */
|
|
8217
|
-
item.backend ? /* @__PURE__ */
|
|
8218
|
-
/* @__PURE__ */
|
|
8219
|
-
/* @__PURE__ */
|
|
8408
|
+
/* @__PURE__ */ jsx68("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
8409
|
+
item.backend ? /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
8410
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
8411
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
8220
8412
|
] }) : null,
|
|
8221
|
-
/* @__PURE__ */
|
|
8222
|
-
item.effort ? /* @__PURE__ */
|
|
8223
|
-
/* @__PURE__ */
|
|
8413
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8414
|
+
item.effort ? /* @__PURE__ */ jsxs62("span", { className: "fd-body-sm fd-muted", children: [
|
|
8415
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-hourglass-medium" }),
|
|
8224
8416
|
" ",
|
|
8225
8417
|
item.effort
|
|
8226
8418
|
] }) : null,
|
|
8227
|
-
/* @__PURE__ */
|
|
8228
|
-
/* @__PURE__ */
|
|
8419
|
+
/* @__PURE__ */ jsxs62("span", { className: "fd-body-sm fd-muted", children: [
|
|
8420
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-user" }),
|
|
8229
8421
|
" ",
|
|
8230
8422
|
item.owner
|
|
8231
8423
|
] }),
|
|
8232
|
-
item.screen ? /* @__PURE__ */
|
|
8233
|
-
/* @__PURE__ */
|
|
8234
|
-
/* @__PURE__ */
|
|
8424
|
+
item.screen ? /* @__PURE__ */ jsx68(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
8425
|
+
/* @__PURE__ */ jsx68("span", { style: { flex: 1 } }),
|
|
8426
|
+
/* @__PURE__ */ jsx68(
|
|
8235
8427
|
"button",
|
|
8236
8428
|
{
|
|
8237
8429
|
type: "button",
|
|
8238
8430
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
8239
8431
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
8240
|
-
children: /* @__PURE__ */
|
|
8432
|
+
children: /* @__PURE__ */ jsx68("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
8241
8433
|
}
|
|
8242
8434
|
)
|
|
8243
8435
|
] }),
|
|
8244
|
-
deps.length ? /* @__PURE__ */
|
|
8245
|
-
/* @__PURE__ */
|
|
8246
|
-
deps.map((d) => /* @__PURE__ */
|
|
8436
|
+
deps.length ? /* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
8437
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
8438
|
+
deps.map((d) => /* @__PURE__ */ jsx68(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
8247
8439
|
] }) : null,
|
|
8248
|
-
blocking.length && !item.implemented ? /* @__PURE__ */
|
|
8440
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ jsxs62("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
8249
8441
|
"Blocked until ",
|
|
8250
8442
|
blocking.map((d) => d.label).join(" and "),
|
|
8251
8443
|
" ",
|
|
@@ -8256,12 +8448,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
8256
8448
|
}
|
|
8257
8449
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
8258
8450
|
const session = SessionKit.useSession();
|
|
8259
|
-
const [project, setProject] =
|
|
8260
|
-
const [q, setQ] =
|
|
8261
|
-
const scrollRef =
|
|
8262
|
-
const nowRef =
|
|
8263
|
-
const rm =
|
|
8264
|
-
const byKey =
|
|
8451
|
+
const [project, setProject] = React45.useState("");
|
|
8452
|
+
const [q, setQ] = React45.useState("");
|
|
8453
|
+
const scrollRef = React45.useRef(null);
|
|
8454
|
+
const nowRef = React45.useRef(null);
|
|
8455
|
+
const rm = React45.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
8456
|
+
const byKey = React45.useMemo(() => {
|
|
8265
8457
|
const m = {};
|
|
8266
8458
|
rm.items.forEach((i) => {
|
|
8267
8459
|
m[i.key] = i;
|
|
@@ -8270,7 +8462,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8270
8462
|
}, [rm]);
|
|
8271
8463
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
8272
8464
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
8273
|
-
|
|
8465
|
+
React45.useEffect(() => {
|
|
8274
8466
|
let raf1 = 0, raf2 = 0;
|
|
8275
8467
|
const place = () => {
|
|
8276
8468
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -8298,23 +8490,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8298
8490
|
}, 0);
|
|
8299
8491
|
const nextPhase = items.find((i) => !i.implemented);
|
|
8300
8492
|
let lastPhase = null;
|
|
8301
|
-
return /* @__PURE__ */
|
|
8302
|
-
/* @__PURE__ */
|
|
8303
|
-
/* @__PURE__ */
|
|
8304
|
-
/* @__PURE__ */
|
|
8305
|
-
/* @__PURE__ */
|
|
8493
|
+
return /* @__PURE__ */ jsxs62("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
8494
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8495
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
8496
|
+
/* @__PURE__ */ jsx68("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
8497
|
+
/* @__PURE__ */ jsx68("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." })
|
|
8306
8498
|
] }),
|
|
8307
|
-
/* @__PURE__ */
|
|
8308
|
-
/* @__PURE__ */
|
|
8309
|
-
/* @__PURE__ */
|
|
8310
|
-
/* @__PURE__ */
|
|
8311
|
-
/* @__PURE__ */
|
|
8499
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-grid-stats is-thin", children: [
|
|
8500
|
+
/* @__PURE__ */ jsx68(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
8501
|
+
/* @__PURE__ */ jsx68(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
8502
|
+
/* @__PURE__ */ jsx68(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
8503
|
+
/* @__PURE__ */ jsx68(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
8312
8504
|
] }),
|
|
8313
|
-
/* @__PURE__ */
|
|
8314
|
-
/* @__PURE__ */
|
|
8315
|
-
/* @__PURE__ */
|
|
8316
|
-
/* @__PURE__ */
|
|
8317
|
-
/* @__PURE__ */
|
|
8505
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
8506
|
+
/* @__PURE__ */ jsx68(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 } }),
|
|
8507
|
+
/* @__PURE__ */ jsx68(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
8508
|
+
/* @__PURE__ */ jsx68("span", { style: { flex: 1 } }),
|
|
8509
|
+
/* @__PURE__ */ jsx68(
|
|
8318
8510
|
Button,
|
|
8319
8511
|
{
|
|
8320
8512
|
size: "sm",
|
|
@@ -8328,7 +8520,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8328
8520
|
}
|
|
8329
8521
|
)
|
|
8330
8522
|
] }),
|
|
8331
|
-
/* @__PURE__ */
|
|
8523
|
+
/* @__PURE__ */ jsx68(
|
|
8332
8524
|
Flag,
|
|
8333
8525
|
{
|
|
8334
8526
|
tone: "info",
|
|
@@ -8337,60 +8529,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
8337
8529
|
actions: null
|
|
8338
8530
|
}
|
|
8339
8531
|
),
|
|
8340
|
-
/* @__PURE__ */
|
|
8341
|
-
/* @__PURE__ */
|
|
8532
|
+
/* @__PURE__ */ jsx68("div", { className: "fd-rm", children: /* @__PURE__ */ jsx68("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs62("div", { className: "fd-rm-track", children: [
|
|
8533
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx68("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
8342
8534
|
items.map((item, n) => {
|
|
8343
8535
|
const showPhase = item.phase !== lastPhase;
|
|
8344
8536
|
lastPhase = item.phase;
|
|
8345
8537
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
8346
8538
|
const isBoundary = n === firstPending;
|
|
8347
|
-
return /* @__PURE__ */
|
|
8348
|
-
showPhase ? /* @__PURE__ */
|
|
8349
|
-
/* @__PURE__ */
|
|
8350
|
-
/* @__PURE__ */
|
|
8351
|
-
item.phase === 0 ? null : /* @__PURE__ */
|
|
8539
|
+
return /* @__PURE__ */ jsxs62(React45.Fragment, { children: [
|
|
8540
|
+
showPhase ? /* @__PURE__ */ jsxs62("div", { className: "fd-rm-era", children: [
|
|
8541
|
+
/* @__PURE__ */ jsxs62("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
8542
|
+
/* @__PURE__ */ jsx68("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
8543
|
+
item.phase === 0 ? null : /* @__PURE__ */ jsxs62("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8352
8544
|
fmtDate(item.phaseStart),
|
|
8353
8545
|
" \u2013 ",
|
|
8354
8546
|
fmtDate(item.date)
|
|
8355
8547
|
] }),
|
|
8356
|
-
/* @__PURE__ */
|
|
8548
|
+
/* @__PURE__ */ jsxs62("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
8357
8549
|
"\xB7 ",
|
|
8358
8550
|
inPhase,
|
|
8359
8551
|
" feature",
|
|
8360
8552
|
inPhase === 1 ? "" : "s"
|
|
8361
8553
|
] })
|
|
8362
8554
|
] }),
|
|
8363
|
-
item.phaseWhy ? /* @__PURE__ */
|
|
8555
|
+
item.phaseWhy ? /* @__PURE__ */ jsx68("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
8364
8556
|
] }) : null,
|
|
8365
|
-
isBoundary ? /* @__PURE__ */
|
|
8366
|
-
/* @__PURE__ */
|
|
8557
|
+
isBoundary ? /* @__PURE__ */ jsx68("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs62("span", { className: "fd-rm-now-pill", children: [
|
|
8558
|
+
/* @__PURE__ */ jsx68("i", { className: "ph ph-map-pin" }),
|
|
8367
8559
|
" You are here \u2014 everything above is wired"
|
|
8368
8560
|
] }) }) : null,
|
|
8369
|
-
/* @__PURE__ */
|
|
8370
|
-
/* @__PURE__ */
|
|
8371
|
-
/* @__PURE__ */
|
|
8561
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-rm-row", children: [
|
|
8562
|
+
/* @__PURE__ */ jsx68("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
8563
|
+
/* @__PURE__ */ jsxs62("div", { className: "fd-rm-date", children: [
|
|
8372
8564
|
fmtDate(item.date),
|
|
8373
|
-
/* @__PURE__ */
|
|
8374
|
-
/* @__PURE__ */
|
|
8565
|
+
/* @__PURE__ */ jsx68("br", {}),
|
|
8566
|
+
/* @__PURE__ */ jsx68("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
8375
8567
|
] }),
|
|
8376
|
-
/* @__PURE__ */
|
|
8568
|
+
/* @__PURE__ */ jsx68(RoadmapCard, { item, byKey, onOpenFlag })
|
|
8377
8569
|
] })
|
|
8378
8570
|
] }, item.key);
|
|
8379
8571
|
}),
|
|
8380
|
-
!items.length ? /* @__PURE__ */
|
|
8572
|
+
!items.length ? /* @__PURE__ */ jsx68("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
8381
8573
|
] }) }) }),
|
|
8382
|
-
/* @__PURE__ */
|
|
8574
|
+
/* @__PURE__ */ jsxs62("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
8383
8575
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
8384
|
-
/* @__PURE__ */
|
|
8576
|
+
/* @__PURE__ */ jsx68("code", { className: "fd-mono", children: "implemented" }),
|
|
8385
8577
|
" field, so this page cannot drift from what the apps actually do."
|
|
8386
8578
|
] })
|
|
8387
8579
|
] });
|
|
8388
8580
|
}
|
|
8389
8581
|
|
|
8390
8582
|
// src/components/platform/ComingSoon.tsx
|
|
8391
|
-
import * as
|
|
8583
|
+
import * as React46 from "react";
|
|
8392
8584
|
import { createPortal as createPortal5 } from "react-dom";
|
|
8393
|
-
import { Fragment as
|
|
8585
|
+
import { Fragment as Fragment20, jsx as jsx69, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8394
8586
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
8395
8587
|
function readBypassed() {
|
|
8396
8588
|
try {
|
|
@@ -8406,8 +8598,8 @@ function writeBypassed(list) {
|
|
|
8406
8598
|
}
|
|
8407
8599
|
}
|
|
8408
8600
|
function useBypass(key) {
|
|
8409
|
-
const [on, setOn] =
|
|
8410
|
-
|
|
8601
|
+
const [on, setOn] = React46.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
8602
|
+
React46.useEffect(() => {
|
|
8411
8603
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
8412
8604
|
}, [key]);
|
|
8413
8605
|
const set = (next) => {
|
|
@@ -8420,43 +8612,43 @@ function useBypass(key) {
|
|
|
8420
8612
|
return [on, set];
|
|
8421
8613
|
}
|
|
8422
8614
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
8423
|
-
return /* @__PURE__ */
|
|
8424
|
-
/* @__PURE__ */
|
|
8425
|
-
/* @__PURE__ */
|
|
8615
|
+
return /* @__PURE__ */ jsxs63(Fragment20, { children: [
|
|
8616
|
+
/* @__PURE__ */ jsxs63("span", { className: "fd-soon-badge", children: [
|
|
8617
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8426
8618
|
label
|
|
8427
8619
|
] }),
|
|
8428
|
-
detail ? /* @__PURE__ */
|
|
8429
|
-
backend ? /* @__PURE__ */
|
|
8430
|
-
/* @__PURE__ */
|
|
8620
|
+
detail ? /* @__PURE__ */ jsx69("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
8621
|
+
backend ? /* @__PURE__ */ jsxs63("span", { className: "fd-soon-backend", children: [
|
|
8622
|
+
/* @__PURE__ */ jsx69("span", { className: "fd-overline", children: "Needs" }),
|
|
8431
8623
|
" ",
|
|
8432
8624
|
backend
|
|
8433
8625
|
] }) : null,
|
|
8434
|
-
eta || effort || onRoadmap ? /* @__PURE__ */
|
|
8435
|
-
eta ? /* @__PURE__ */
|
|
8436
|
-
/* @__PURE__ */
|
|
8626
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ jsxs63("span", { className: "fd-soon-meta", children: [
|
|
8627
|
+
eta ? /* @__PURE__ */ jsxs63("span", { children: [
|
|
8628
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
8437
8629
|
" ",
|
|
8438
8630
|
eta
|
|
8439
8631
|
] }) : null,
|
|
8440
|
-
effort ? /* @__PURE__ */
|
|
8441
|
-
/* @__PURE__ */
|
|
8632
|
+
effort ? /* @__PURE__ */ jsxs63("span", { children: [
|
|
8633
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
8442
8634
|
" ",
|
|
8443
8635
|
effort
|
|
8444
8636
|
] }) : null,
|
|
8445
|
-
onRoadmap ? /* @__PURE__ */
|
|
8637
|
+
onRoadmap ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8446
8638
|
"See the roadmap ",
|
|
8447
|
-
/* @__PURE__ */
|
|
8639
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8448
8640
|
] }) : null
|
|
8449
8641
|
] }) : null,
|
|
8450
|
-
allowed ? /* @__PURE__ */
|
|
8451
|
-
/* @__PURE__ */
|
|
8642
|
+
allowed ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
8643
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
8452
8644
|
" View and use it anyway"
|
|
8453
8645
|
] }) : null
|
|
8454
8646
|
] });
|
|
8455
8647
|
}
|
|
8456
8648
|
function useHoverCard(open) {
|
|
8457
|
-
const anchor =
|
|
8458
|
-
const [pos, setPos] =
|
|
8459
|
-
|
|
8649
|
+
const anchor = React46.useRef(null);
|
|
8650
|
+
const [pos, setPos] = React46.useState(null);
|
|
8651
|
+
React46.useLayoutEffect(() => {
|
|
8460
8652
|
if (!open || !anchor.current) {
|
|
8461
8653
|
setPos(null);
|
|
8462
8654
|
return;
|
|
@@ -8508,9 +8700,9 @@ function ComingSoon({
|
|
|
8508
8700
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
8509
8701
|
if (inline) {
|
|
8510
8702
|
if (allowed && bypassed) {
|
|
8511
|
-
return /* @__PURE__ */
|
|
8703
|
+
return /* @__PURE__ */ jsxs63("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
8512
8704
|
children,
|
|
8513
|
-
/* @__PURE__ */
|
|
8705
|
+
/* @__PURE__ */ jsx69(
|
|
8514
8706
|
"button",
|
|
8515
8707
|
{
|
|
8516
8708
|
type: "button",
|
|
@@ -8518,12 +8710,12 @@ function ComingSoon({
|
|
|
8518
8710
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
8519
8711
|
onClick: () => setBypassed(false),
|
|
8520
8712
|
"aria-label": "Re-blur this unwired feature",
|
|
8521
|
-
children: /* @__PURE__ */
|
|
8713
|
+
children: /* @__PURE__ */ jsx69("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8522
8714
|
}
|
|
8523
8715
|
)
|
|
8524
8716
|
] });
|
|
8525
8717
|
}
|
|
8526
|
-
return /* @__PURE__ */
|
|
8718
|
+
return /* @__PURE__ */ jsx69(
|
|
8527
8719
|
InlineSoon,
|
|
8528
8720
|
{
|
|
8529
8721
|
label,
|
|
@@ -8543,20 +8735,20 @@ function ComingSoon({
|
|
|
8543
8735
|
);
|
|
8544
8736
|
}
|
|
8545
8737
|
if (allowed && bypassed) {
|
|
8546
|
-
return /* @__PURE__ */
|
|
8547
|
-
/* @__PURE__ */
|
|
8548
|
-
/* @__PURE__ */
|
|
8549
|
-
/* @__PURE__ */
|
|
8738
|
+
return /* @__PURE__ */ jsxs63("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
8739
|
+
/* @__PURE__ */ jsxs63("div", { className: "fd-soon-bar", role: "status", children: [
|
|
8740
|
+
/* @__PURE__ */ jsxs63("span", { className: "fd-soon-badge", children: [
|
|
8741
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
8550
8742
|
"Unwired feature \u2014 you are using it anyway"
|
|
8551
8743
|
] }),
|
|
8552
|
-
/* @__PURE__ */
|
|
8553
|
-
/* @__PURE__ */
|
|
8554
|
-
onRoadmap ? /* @__PURE__ */
|
|
8744
|
+
/* @__PURE__ */ jsx69("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
8745
|
+
/* @__PURE__ */ jsxs63("span", { className: "fd-soon-bar-actions", children: [
|
|
8746
|
+
onRoadmap ? /* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
8555
8747
|
"Roadmap ",
|
|
8556
|
-
/* @__PURE__ */
|
|
8748
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8557
8749
|
] }) : null,
|
|
8558
|
-
/* @__PURE__ */
|
|
8559
|
-
/* @__PURE__ */
|
|
8750
|
+
/* @__PURE__ */ jsxs63("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
8751
|
+
/* @__PURE__ */ jsx69("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
8560
8752
|
" Re-blur"
|
|
8561
8753
|
] })
|
|
8562
8754
|
] })
|
|
@@ -8564,10 +8756,10 @@ function ComingSoon({
|
|
|
8564
8756
|
children
|
|
8565
8757
|
] });
|
|
8566
8758
|
}
|
|
8567
|
-
return /* @__PURE__ */
|
|
8568
|
-
/* @__PURE__ */
|
|
8569
|
-
/* @__PURE__ */
|
|
8570
|
-
/* @__PURE__ */
|
|
8759
|
+
return /* @__PURE__ */ jsxs63("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
8760
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
8761
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-soon-veil" }),
|
|
8762
|
+
/* @__PURE__ */ jsx69("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx69(
|
|
8571
8763
|
SoonCard,
|
|
8572
8764
|
{
|
|
8573
8765
|
label,
|
|
@@ -8583,10 +8775,10 @@ function ComingSoon({
|
|
|
8583
8775
|
] });
|
|
8584
8776
|
}
|
|
8585
8777
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
8586
|
-
const [open, setOpen] =
|
|
8778
|
+
const [open, setOpen] = React46.useState(false);
|
|
8587
8779
|
const [anchor, pos] = useHoverCard(open);
|
|
8588
8780
|
const zIndex = useOverlayLayer(open);
|
|
8589
|
-
const close =
|
|
8781
|
+
const close = React46.useRef(null);
|
|
8590
8782
|
const show = () => {
|
|
8591
8783
|
if (close.current) {
|
|
8592
8784
|
clearTimeout(close.current);
|
|
@@ -8602,10 +8794,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8602
8794
|
setOpen(false);
|
|
8603
8795
|
}, 140);
|
|
8604
8796
|
};
|
|
8605
|
-
|
|
8797
|
+
React46.useEffect(() => () => {
|
|
8606
8798
|
if (close.current) clearTimeout(close.current);
|
|
8607
8799
|
}, []);
|
|
8608
|
-
return /* @__PURE__ */
|
|
8800
|
+
return /* @__PURE__ */ jsxs63(
|
|
8609
8801
|
"span",
|
|
8610
8802
|
{
|
|
8611
8803
|
ref: anchor,
|
|
@@ -8616,8 +8808,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8616
8808
|
onBlur: hide,
|
|
8617
8809
|
...rest,
|
|
8618
8810
|
children: [
|
|
8619
|
-
/* @__PURE__ */
|
|
8620
|
-
/* @__PURE__ */
|
|
8811
|
+
/* @__PURE__ */ jsx69("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
8812
|
+
/* @__PURE__ */ jsx69(
|
|
8621
8813
|
"button",
|
|
8622
8814
|
{
|
|
8623
8815
|
type: "button",
|
|
@@ -8628,11 +8820,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8628
8820
|
onFocus: show,
|
|
8629
8821
|
onBlur: hide,
|
|
8630
8822
|
onClick: () => open ? setOpen(false) : show(),
|
|
8631
|
-
children: /* @__PURE__ */
|
|
8823
|
+
children: /* @__PURE__ */ jsx69("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
8632
8824
|
}
|
|
8633
8825
|
),
|
|
8634
8826
|
open && pos ? createPortal5(
|
|
8635
|
-
/* @__PURE__ */
|
|
8827
|
+
/* @__PURE__ */ jsx69(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx69(
|
|
8636
8828
|
"div",
|
|
8637
8829
|
{
|
|
8638
8830
|
className: "fd-soon-note fd-soon-hovercard",
|
|
@@ -8640,7 +8832,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8640
8832
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
8641
8833
|
onMouseEnter: show,
|
|
8642
8834
|
onMouseLeave: hide,
|
|
8643
|
-
children: /* @__PURE__ */
|
|
8835
|
+
children: /* @__PURE__ */ jsx69(
|
|
8644
8836
|
SoonCard,
|
|
8645
8837
|
{
|
|
8646
8838
|
label,
|
|
@@ -8670,10 +8862,10 @@ function formatEta(iso2) {
|
|
|
8670
8862
|
var FormatEta = formatEta;
|
|
8671
8863
|
|
|
8672
8864
|
// src/components/platform/Gate.tsx
|
|
8673
|
-
import { jsx as
|
|
8865
|
+
import { jsx as jsx70, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
8674
8866
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
8675
8867
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
8676
|
-
return /* @__PURE__ */
|
|
8868
|
+
return /* @__PURE__ */ jsxs64(
|
|
8677
8869
|
"div",
|
|
8678
8870
|
{
|
|
8679
8871
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -8689,14 +8881,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
8689
8881
|
},
|
|
8690
8882
|
...rest,
|
|
8691
8883
|
children: [
|
|
8692
|
-
/* @__PURE__ */
|
|
8693
|
-
/* @__PURE__ */
|
|
8694
|
-
/* @__PURE__ */
|
|
8884
|
+
/* @__PURE__ */ jsxs64("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
8885
|
+
/* @__PURE__ */ jsx70("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
8886
|
+
/* @__PURE__ */ jsx70("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
8695
8887
|
] }),
|
|
8696
|
-
/* @__PURE__ */
|
|
8697
|
-
need.length ? /* @__PURE__ */
|
|
8698
|
-
/* @__PURE__ */
|
|
8699
|
-
need.map((p) => /* @__PURE__ */
|
|
8888
|
+
/* @__PURE__ */ jsx70("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." }),
|
|
8889
|
+
need.length ? /* @__PURE__ */ jsxs64("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
8890
|
+
/* @__PURE__ */ jsx70("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
8891
|
+
need.map((p) => /* @__PURE__ */ jsx70("code", { className: "fd-mono", style: {
|
|
8700
8892
|
fontSize: 11.5,
|
|
8701
8893
|
padding: "2px 7px",
|
|
8702
8894
|
borderRadius: 5,
|
|
@@ -8717,7 +8909,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, compact: compact3 =
|
|
|
8717
8909
|
if (ok) return children;
|
|
8718
8910
|
if (fallback !== void 0) return fallback;
|
|
8719
8911
|
if (silent) return null;
|
|
8720
|
-
return /* @__PURE__ */
|
|
8912
|
+
return /* @__PURE__ */ jsx70(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
8721
8913
|
}
|
|
8722
8914
|
function FeatureGate({
|
|
8723
8915
|
flag,
|
|
@@ -8740,7 +8932,7 @@ function FeatureGate({
|
|
|
8740
8932
|
const f = SessionKit.findFlag(flag) || {};
|
|
8741
8933
|
const missing = rt.missing || [];
|
|
8742
8934
|
const canBypass = bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
8743
|
-
return /* @__PURE__ */
|
|
8935
|
+
return /* @__PURE__ */ jsx70(
|
|
8744
8936
|
ComingSoon,
|
|
8745
8937
|
{
|
|
8746
8938
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -8761,26 +8953,26 @@ function FeatureGate({
|
|
|
8761
8953
|
function PermissionHint({ perm, children }) {
|
|
8762
8954
|
const { can: can2 } = useSessionContext();
|
|
8763
8955
|
if (can2(perm)) return children;
|
|
8764
|
-
return /* @__PURE__ */
|
|
8956
|
+
return /* @__PURE__ */ jsx70(
|
|
8765
8957
|
"span",
|
|
8766
8958
|
{
|
|
8767
8959
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
8768
8960
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
8769
8961
|
"aria-disabled": "true",
|
|
8770
|
-
children: /* @__PURE__ */
|
|
8962
|
+
children: /* @__PURE__ */ jsx70("span", { style: { pointerEvents: "none" }, children })
|
|
8771
8963
|
}
|
|
8772
8964
|
);
|
|
8773
8965
|
}
|
|
8774
8966
|
|
|
8775
8967
|
// src/components/platform/ModeSwitch.tsx
|
|
8776
|
-
import * as
|
|
8777
|
-
import { Fragment as
|
|
8968
|
+
import * as React47 from "react";
|
|
8969
|
+
import { Fragment as Fragment21, jsx as jsx71, jsxs as jsxs65 } from "react/jsx-runtime";
|
|
8778
8970
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
8779
8971
|
const mode2 = useRuntimeMode();
|
|
8780
|
-
const [open, setOpen] =
|
|
8972
|
+
const [open, setOpen] = React47.useState(false);
|
|
8781
8973
|
const zIndex = useOverlayLayer(open);
|
|
8782
|
-
const ref =
|
|
8783
|
-
|
|
8974
|
+
const ref = React47.useRef(null);
|
|
8975
|
+
React47.useEffect(() => {
|
|
8784
8976
|
if (!open) return;
|
|
8785
8977
|
const away = (e) => {
|
|
8786
8978
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -8802,8 +8994,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
8802
8994
|
RuntimeKit.setMode(next);
|
|
8803
8995
|
setOpen(false);
|
|
8804
8996
|
};
|
|
8805
|
-
return /* @__PURE__ */
|
|
8806
|
-
/* @__PURE__ */
|
|
8997
|
+
return /* @__PURE__ */ jsxs65("span", { style: { position: "relative", display: "inline-flex" }, ref, children: [
|
|
8998
|
+
/* @__PURE__ */ jsxs65(
|
|
8807
8999
|
"button",
|
|
8808
9000
|
{
|
|
8809
9001
|
type: "button",
|
|
@@ -8813,29 +9005,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
8813
9005
|
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.",
|
|
8814
9006
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open ? " is-open" : ""),
|
|
8815
9007
|
children: [
|
|
8816
|
-
/* @__PURE__ */
|
|
8817
|
-
test && requestCount ? /* @__PURE__ */
|
|
9008
|
+
/* @__PURE__ */ jsx71("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
9009
|
+
test && requestCount ? /* @__PURE__ */ jsx71("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
8818
9010
|
]
|
|
8819
9011
|
}
|
|
8820
9012
|
),
|
|
8821
|
-
open ? /* @__PURE__ */
|
|
8822
|
-
/* @__PURE__ */
|
|
8823
|
-
/* @__PURE__ */
|
|
8824
|
-
/* @__PURE__ */
|
|
9013
|
+
open ? /* @__PURE__ */ jsx71(LayerProvider, { zIndex, children: /* @__PURE__ */ jsxs65("span", { className: "fd-view-enter fd-mode-pop", style: { zIndex }, children: [
|
|
9014
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9015
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
9016
|
+
/* @__PURE__ */ jsx71("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
8825
9017
|
test ? "Test mode" : "Live mode"
|
|
8826
9018
|
] }),
|
|
8827
|
-
test ? /* @__PURE__ */
|
|
9019
|
+
test ? /* @__PURE__ */ jsxs65("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
8828
9020
|
requestCount,
|
|
8829
9021
|
" simulated request",
|
|
8830
9022
|
requestCount === 1 ? "" : "s"
|
|
8831
9023
|
] }) : null,
|
|
8832
|
-
/* @__PURE__ */
|
|
8833
|
-
test && onClearLog ? /* @__PURE__ */
|
|
9024
|
+
/* @__PURE__ */ jsx71("span", { style: { flex: 1 } }),
|
|
9025
|
+
test && onClearLog ? /* @__PURE__ */ jsx71("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
8834
9026
|
] }),
|
|
8835
|
-
/* @__PURE__ */
|
|
8836
|
-
/* @__PURE__ */
|
|
8837
|
-
/* @__PURE__ */
|
|
8838
|
-
/* @__PURE__ */
|
|
9027
|
+
/* @__PURE__ */ jsxs65("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
9028
|
+
/* @__PURE__ */ jsx71("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." }),
|
|
9029
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
9030
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
8839
9031
|
s.endpointsWired,
|
|
8840
9032
|
" endpoint",
|
|
8841
9033
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -8845,58 +9037,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
8845
9037
|
s.total,
|
|
8846
9038
|
" features complete"
|
|
8847
9039
|
] }),
|
|
8848
|
-
onOpenSpec ? /* @__PURE__ */
|
|
8849
|
-
/* @__PURE__ */
|
|
8850
|
-
/* @__PURE__ */
|
|
9040
|
+
onOpenSpec ? /* @__PURE__ */ jsxs65(Fragment21, { children: [
|
|
9041
|
+
/* @__PURE__ */ jsx71("span", { style: { flex: 1 } }),
|
|
9042
|
+
/* @__PURE__ */ jsxs65("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
8851
9043
|
setOpen(false);
|
|
8852
9044
|
onOpenSpec();
|
|
8853
9045
|
}, children: [
|
|
8854
9046
|
"API spec ",
|
|
8855
|
-
/* @__PURE__ */
|
|
9047
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
8856
9048
|
] })
|
|
8857
9049
|
] }) : null
|
|
8858
9050
|
] })
|
|
8859
9051
|
] }),
|
|
8860
|
-
/* @__PURE__ */
|
|
8861
|
-
/* @__PURE__ */
|
|
8862
|
-
/* @__PURE__ */
|
|
8863
|
-
/* @__PURE__ */
|
|
8864
|
-
/* @__PURE__ */
|
|
8865
|
-
/* @__PURE__ */
|
|
9052
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-mode-choice", children: [
|
|
9053
|
+
/* @__PURE__ */ jsxs65("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
9054
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
9055
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-mode-opt-text", children: [
|
|
9056
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
9057
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
8866
9058
|
] }),
|
|
8867
|
-
!test ? /* @__PURE__ */
|
|
9059
|
+
!test ? /* @__PURE__ */ jsx71("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
8868
9060
|
] }),
|
|
8869
|
-
/* @__PURE__ */
|
|
8870
|
-
/* @__PURE__ */
|
|
8871
|
-
/* @__PURE__ */
|
|
8872
|
-
/* @__PURE__ */
|
|
8873
|
-
/* @__PURE__ */
|
|
9061
|
+
/* @__PURE__ */ jsxs65("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
9062
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
9063
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-mode-opt-text", children: [
|
|
9064
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
9065
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
8874
9066
|
] }),
|
|
8875
|
-
test ? /* @__PURE__ */
|
|
9067
|
+
test ? /* @__PURE__ */ jsx71("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
8876
9068
|
] })
|
|
8877
9069
|
] }),
|
|
8878
|
-
test && renderLog ? /* @__PURE__ */
|
|
9070
|
+
test && renderLog ? /* @__PURE__ */ jsx71("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
8879
9071
|
] }) }) : null
|
|
8880
9072
|
] });
|
|
8881
9073
|
}
|
|
8882
9074
|
function TestModeBar({ onExit }) {
|
|
8883
9075
|
const mode2 = useRuntimeMode();
|
|
8884
9076
|
if (mode2 !== "test") return null;
|
|
8885
|
-
return /* @__PURE__ */
|
|
8886
|
-
/* @__PURE__ */
|
|
8887
|
-
/* @__PURE__ */
|
|
9077
|
+
return /* @__PURE__ */ jsxs65("div", { className: "fd-testbar", role: "status", children: [
|
|
9078
|
+
/* @__PURE__ */ jsxs65("span", { className: "fd-badge fd-badge-warning", children: [
|
|
9079
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
8888
9080
|
"Test mode"
|
|
8889
9081
|
] }),
|
|
8890
|
-
/* @__PURE__ */
|
|
8891
|
-
/* @__PURE__ */
|
|
8892
|
-
/* @__PURE__ */
|
|
9082
|
+
/* @__PURE__ */ jsx71("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
9083
|
+
/* @__PURE__ */ jsxs65("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
9084
|
+
/* @__PURE__ */ jsx71("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
8893
9085
|
" Back to live mode"
|
|
8894
9086
|
] })
|
|
8895
9087
|
] });
|
|
8896
9088
|
}
|
|
8897
9089
|
|
|
8898
9090
|
// src/components/planner/ChannelMeta.tsx
|
|
8899
|
-
import { jsx as
|
|
9091
|
+
import { jsx as jsx72, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8900
9092
|
var CHANNEL_WEIGHTS = {
|
|
8901
9093
|
"OOH": 50,
|
|
8902
9094
|
"DOOH": 50,
|
|
@@ -8949,9 +9141,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
8949
9141
|
const m = ChannelMeta(channel);
|
|
8950
9142
|
const wt = channelWeightOf(channel || "");
|
|
8951
9143
|
if (dot) {
|
|
8952
|
-
return /* @__PURE__ */
|
|
9144
|
+
return /* @__PURE__ */ jsx72("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
8953
9145
|
}
|
|
8954
|
-
return /* @__PURE__ */
|
|
9146
|
+
return /* @__PURE__ */ jsxs66(
|
|
8955
9147
|
"span",
|
|
8956
9148
|
{
|
|
8957
9149
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -8959,16 +9151,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
8959
9151
|
style: { "--chan": m.color },
|
|
8960
9152
|
...rest,
|
|
8961
9153
|
children: [
|
|
8962
|
-
/* @__PURE__ */
|
|
8963
|
-
showLabel ? /* @__PURE__ */
|
|
8964
|
-
weight ? /* @__PURE__ */
|
|
9154
|
+
/* @__PURE__ */ jsx72("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
9155
|
+
showLabel ? /* @__PURE__ */ jsx72("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
9156
|
+
weight ? /* @__PURE__ */ jsx72("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
8965
9157
|
]
|
|
8966
9158
|
}
|
|
8967
9159
|
);
|
|
8968
9160
|
}
|
|
8969
9161
|
|
|
8970
9162
|
// src/components/planner/SaturationDistribution.tsx
|
|
8971
|
-
import { jsx as
|
|
9163
|
+
import { jsx as jsx73, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
8972
9164
|
var BANDS2 = [
|
|
8973
9165
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
8974
9166
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -8979,24 +9171,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8979
9171
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
8980
9172
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
8981
9173
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
8982
|
-
return /* @__PURE__ */
|
|
8983
|
-
/* @__PURE__ */
|
|
9174
|
+
return /* @__PURE__ */ jsxs67("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9175
|
+
/* @__PURE__ */ jsx73("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
8984
9176
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
8985
9177
|
const active = selectedBand === g.key;
|
|
8986
|
-
return /* @__PURE__ */
|
|
9178
|
+
return /* @__PURE__ */ jsxs67(
|
|
8987
9179
|
"button",
|
|
8988
9180
|
{
|
|
8989
9181
|
type: "button",
|
|
8990
9182
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
8991
9183
|
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)" },
|
|
8992
9184
|
children: [
|
|
8993
|
-
/* @__PURE__ */
|
|
9185
|
+
/* @__PURE__ */ jsx73("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx73("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
|
|
8994
9186
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
8995
9187
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
8996
9188
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
8997
9189
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
8998
9190
|
// is still one hover away via `title`.
|
|
8999
|
-
/* @__PURE__ */
|
|
9191
|
+
/* @__PURE__ */ jsx73(
|
|
9000
9192
|
"span",
|
|
9001
9193
|
{
|
|
9002
9194
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -9006,13 +9198,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9006
9198
|
c.name
|
|
9007
9199
|
)
|
|
9008
9200
|
)) }),
|
|
9009
|
-
/* @__PURE__ */
|
|
9010
|
-
/* @__PURE__ */
|
|
9011
|
-
/* @__PURE__ */
|
|
9201
|
+
/* @__PURE__ */ jsxs67("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
9202
|
+
/* @__PURE__ */ jsx73("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
9203
|
+
/* @__PURE__ */ jsx73("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx73("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
9012
9204
|
] }),
|
|
9013
|
-
/* @__PURE__ */
|
|
9014
|
-
/* @__PURE__ */
|
|
9015
|
-
/* @__PURE__ */
|
|
9205
|
+
/* @__PURE__ */ jsxs67("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
9206
|
+
/* @__PURE__ */ jsx73("span", { className: "fd-label-lg", children: g.label }),
|
|
9207
|
+
/* @__PURE__ */ jsxs67("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
9016
9208
|
"CRP ",
|
|
9017
9209
|
g.range
|
|
9018
9210
|
] })
|
|
@@ -9022,10 +9214,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9022
9214
|
g.key
|
|
9023
9215
|
);
|
|
9024
9216
|
}) }),
|
|
9025
|
-
floorBand ? /* @__PURE__ */
|
|
9026
|
-
/* @__PURE__ */
|
|
9027
|
-
/* @__PURE__ */
|
|
9028
|
-
/* @__PURE__ */
|
|
9217
|
+
floorBand ? /* @__PURE__ */ jsxs67("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: [
|
|
9218
|
+
/* @__PURE__ */ jsx73("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx73("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
9219
|
+
/* @__PURE__ */ jsxs67("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
9220
|
+
/* @__PURE__ */ jsxs67("strong", { style: { color: "var(--text)" }, children: [
|
|
9029
9221
|
"Plan floor ",
|
|
9030
9222
|
floorScore
|
|
9031
9223
|
] }),
|
|
@@ -9036,8 +9228,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
9036
9228
|
}
|
|
9037
9229
|
|
|
9038
9230
|
// src/components/planner/MixGap.tsx
|
|
9039
|
-
import * as
|
|
9040
|
-
import { Fragment as
|
|
9231
|
+
import * as React48 from "react";
|
|
9232
|
+
import { Fragment as Fragment22, jsx as jsx74, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
9041
9233
|
var MIX_GAP_LAYOUT = {
|
|
9042
9234
|
trackHeight: 30,
|
|
9043
9235
|
barHeight: 20,
|
|
@@ -9051,19 +9243,19 @@ function mixGapOffset(value, max) {
|
|
|
9051
9243
|
}
|
|
9052
9244
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
9053
9245
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
9054
|
-
const [hover, setHover] =
|
|
9246
|
+
const [hover, setHover] = React48.useState(null);
|
|
9055
9247
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
9056
9248
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
9057
9249
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
9058
9250
|
const barTop = (trackHeight - barHeight) / 2;
|
|
9059
|
-
return /* @__PURE__ */
|
|
9060
|
-
/* @__PURE__ */
|
|
9061
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */
|
|
9062
|
-
/* @__PURE__ */
|
|
9251
|
+
return /* @__PURE__ */ jsxs68("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
9252
|
+
/* @__PURE__ */ jsxs68("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
9253
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs68("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9254
|
+
/* @__PURE__ */ jsx74("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
9063
9255
|
l
|
|
9064
9256
|
] }, l)),
|
|
9065
|
-
/* @__PURE__ */
|
|
9066
|
-
/* @__PURE__ */
|
|
9257
|
+
/* @__PURE__ */ jsxs68("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
9258
|
+
/* @__PURE__ */ jsx74("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
|
|
9067
9259
|
"Target"
|
|
9068
9260
|
] })
|
|
9069
9261
|
] }),
|
|
@@ -9072,7 +9264,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9072
9264
|
const tone = toneOf(gap);
|
|
9073
9265
|
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 : "");
|
|
9074
9266
|
const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
|
|
9075
|
-
return /* @__PURE__ */
|
|
9267
|
+
return /* @__PURE__ */ jsxs68(
|
|
9076
9268
|
"div",
|
|
9077
9269
|
{
|
|
9078
9270
|
className: "fd-row",
|
|
@@ -9080,15 +9272,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9080
9272
|
onMouseEnter: () => setHover(r.channel),
|
|
9081
9273
|
onMouseLeave: () => setHover(null),
|
|
9082
9274
|
children: [
|
|
9083
|
-
/* @__PURE__ */
|
|
9084
|
-
/* @__PURE__ */
|
|
9085
|
-
/* @__PURE__ */
|
|
9086
|
-
/* @__PURE__ */
|
|
9087
|
-
/* @__PURE__ */
|
|
9275
|
+
/* @__PURE__ */ jsx74("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx74(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
9276
|
+
/* @__PURE__ */ jsx74("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx74("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs68(Fragment22, { children: [
|
|
9277
|
+
/* @__PURE__ */ jsx74("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)" } }),
|
|
9278
|
+
/* @__PURE__ */ jsx74("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 } }),
|
|
9279
|
+
/* @__PURE__ */ jsxs68("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: [
|
|
9088
9280
|
r.realized,
|
|
9089
9281
|
"%"
|
|
9090
9282
|
] }),
|
|
9091
|
-
hover === r.channel ? /* @__PURE__ */
|
|
9283
|
+
hover === r.channel ? /* @__PURE__ */ jsx74("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
|
|
9092
9284
|
] }) })
|
|
9093
9285
|
]
|
|
9094
9286
|
},
|
|
@@ -9099,7 +9291,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
9099
9291
|
}
|
|
9100
9292
|
|
|
9101
9293
|
// src/components/planner/ChannelContribution.tsx
|
|
9102
|
-
import { jsx as
|
|
9294
|
+
import { jsx as jsx75, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
9103
9295
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
9104
9296
|
function ChannelContribution({
|
|
9105
9297
|
channels = [],
|
|
@@ -9115,9 +9307,9 @@ function ChannelContribution({
|
|
|
9115
9307
|
const grand = total !== void 0 ? total : base + bonus;
|
|
9116
9308
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
9117
9309
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
9118
|
-
return /* @__PURE__ */
|
|
9119
|
-
loading ? /* @__PURE__ */
|
|
9120
|
-
channels.map((c) => /* @__PURE__ */
|
|
9310
|
+
return /* @__PURE__ */ jsxs69("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
9311
|
+
loading ? /* @__PURE__ */ jsx75("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
9312
|
+
channels.map((c) => /* @__PURE__ */ jsx75(
|
|
9121
9313
|
"span",
|
|
9122
9314
|
{
|
|
9123
9315
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -9126,7 +9318,7 @@ function ChannelContribution({
|
|
|
9126
9318
|
},
|
|
9127
9319
|
c.name
|
|
9128
9320
|
)),
|
|
9129
|
-
bonus > 0 ? /* @__PURE__ */
|
|
9321
|
+
bonus > 0 ? /* @__PURE__ */ jsx75(
|
|
9130
9322
|
"span",
|
|
9131
9323
|
{
|
|
9132
9324
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -9135,18 +9327,18 @@ function ChannelContribution({
|
|
|
9135
9327
|
}
|
|
9136
9328
|
) : null
|
|
9137
9329
|
] }),
|
|
9138
|
-
showTable ? /* @__PURE__ */
|
|
9139
|
-
/* @__PURE__ */
|
|
9140
|
-
/* @__PURE__ */
|
|
9141
|
-
/* @__PURE__ */
|
|
9142
|
-
/* @__PURE__ */
|
|
9143
|
-
/* @__PURE__ */
|
|
9144
|
-
/* @__PURE__ */
|
|
9330
|
+
showTable ? /* @__PURE__ */ jsxs69("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
9331
|
+
/* @__PURE__ */ jsx75("thead", { children: /* @__PURE__ */ jsxs69("tr", { children: [
|
|
9332
|
+
/* @__PURE__ */ jsx75("th", { style: { width: "34%" }, children: "Channel" }),
|
|
9333
|
+
/* @__PURE__ */ jsx75("th", { style: { width: "16%" }, children: "Weight" }),
|
|
9334
|
+
/* @__PURE__ */ jsx75("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
9335
|
+
/* @__PURE__ */ jsx75("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
9336
|
+
/* @__PURE__ */ jsx75("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
9145
9337
|
] }) }),
|
|
9146
|
-
/* @__PURE__ */
|
|
9147
|
-
channels.map((c) => /* @__PURE__ */
|
|
9148
|
-
/* @__PURE__ */
|
|
9149
|
-
/* @__PURE__ */
|
|
9338
|
+
/* @__PURE__ */ jsxs69("tbody", { children: [
|
|
9339
|
+
channels.map((c) => /* @__PURE__ */ jsxs69("tr", { children: [
|
|
9340
|
+
/* @__PURE__ */ jsx75("td", { children: /* @__PURE__ */ jsx75(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
9341
|
+
/* @__PURE__ */ jsx75("td", { children: /* @__PURE__ */ jsx75(
|
|
9150
9342
|
"span",
|
|
9151
9343
|
{
|
|
9152
9344
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -9155,38 +9347,38 @@ function ChannelContribution({
|
|
|
9155
9347
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
9156
9348
|
}
|
|
9157
9349
|
) }),
|
|
9158
|
-
/* @__PURE__ */
|
|
9159
|
-
/* @__PURE__ */
|
|
9160
|
-
/* @__PURE__ */
|
|
9350
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", children: c.spend }),
|
|
9351
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
9352
|
+
/* @__PURE__ */ jsxs69("td", { className: "is-num", children: [
|
|
9161
9353
|
pct(c.crp).toFixed(0),
|
|
9162
9354
|
"%"
|
|
9163
9355
|
] })
|
|
9164
9356
|
] }, c.name)),
|
|
9165
|
-
bonus > 0 ? /* @__PURE__ */
|
|
9166
|
-
/* @__PURE__ */
|
|
9167
|
-
/* @__PURE__ */
|
|
9357
|
+
bonus > 0 ? /* @__PURE__ */ jsxs69("tr", { children: [
|
|
9358
|
+
/* @__PURE__ */ jsx75("td", { children: /* @__PURE__ */ jsxs69("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
9359
|
+
/* @__PURE__ */ jsx75("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" } }),
|
|
9168
9360
|
"Surround-sound bonus"
|
|
9169
9361
|
] }) }),
|
|
9170
|
-
/* @__PURE__ */
|
|
9362
|
+
/* @__PURE__ */ jsx75("td", { children: /* @__PURE__ */ jsxs69("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
9171
9363
|
"+",
|
|
9172
9364
|
bonusPct,
|
|
9173
9365
|
"% of +",
|
|
9174
9366
|
bonusMax,
|
|
9175
9367
|
"%"
|
|
9176
9368
|
] }) }),
|
|
9177
|
-
/* @__PURE__ */
|
|
9178
|
-
/* @__PURE__ */
|
|
9179
|
-
/* @__PURE__ */
|
|
9369
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
9370
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
9371
|
+
/* @__PURE__ */ jsxs69("td", { className: "is-num", children: [
|
|
9180
9372
|
pct(bonus).toFixed(0),
|
|
9181
9373
|
"%"
|
|
9182
9374
|
] })
|
|
9183
9375
|
] }) : null,
|
|
9184
|
-
/* @__PURE__ */
|
|
9185
|
-
/* @__PURE__ */
|
|
9186
|
-
/* @__PURE__ */
|
|
9187
|
-
/* @__PURE__ */
|
|
9188
|
-
/* @__PURE__ */
|
|
9189
|
-
/* @__PURE__ */
|
|
9376
|
+
/* @__PURE__ */ jsxs69("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
9377
|
+
/* @__PURE__ */ jsx75("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
9378
|
+
/* @__PURE__ */ jsx75("td", {}),
|
|
9379
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
9380
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
9381
|
+
/* @__PURE__ */ jsx75("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
9190
9382
|
] })
|
|
9191
9383
|
] })
|
|
9192
9384
|
] }) : null
|
|
@@ -9194,8 +9386,8 @@ function ChannelContribution({
|
|
|
9194
9386
|
}
|
|
9195
9387
|
|
|
9196
9388
|
// src/components/planner/BudgetReallocator.tsx
|
|
9197
|
-
import * as
|
|
9198
|
-
import { Fragment as
|
|
9389
|
+
import * as React49 from "react";
|
|
9390
|
+
import { Fragment as Fragment23, jsx as jsx76, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9199
9391
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
9200
9392
|
function BudgetReallocator({
|
|
9201
9393
|
campus,
|
|
@@ -9210,8 +9402,8 @@ function BudgetReallocator({
|
|
|
9210
9402
|
onCancel,
|
|
9211
9403
|
className = ""
|
|
9212
9404
|
}) {
|
|
9213
|
-
const [draft, setDraft] =
|
|
9214
|
-
|
|
9405
|
+
const [draft, setDraft] = React49.useState(spend);
|
|
9406
|
+
React49.useEffect(() => setDraft(spend), [spend]);
|
|
9215
9407
|
const dirty = draft !== spend;
|
|
9216
9408
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
9217
9409
|
const nextBand = bandFor(nextCrp);
|
|
@@ -9226,10 +9418,10 @@ function BudgetReallocator({
|
|
|
9226
9418
|
setDraft(spend);
|
|
9227
9419
|
if (onCancel) onCancel();
|
|
9228
9420
|
};
|
|
9229
|
-
const trackRef =
|
|
9230
|
-
const chipRef =
|
|
9231
|
-
const [chipLeft, setChipLeft] =
|
|
9232
|
-
|
|
9421
|
+
const trackRef = React49.useRef(null);
|
|
9422
|
+
const chipRef = React49.useRef(null);
|
|
9423
|
+
const [chipLeft, setChipLeft] = React49.useState(null);
|
|
9424
|
+
React49.useLayoutEffect(() => {
|
|
9233
9425
|
const track = trackRef.current;
|
|
9234
9426
|
if (!dirty || !track) {
|
|
9235
9427
|
setChipLeft(null);
|
|
@@ -9250,23 +9442,23 @@ function BudgetReallocator({
|
|
|
9250
9442
|
ro.observe(track);
|
|
9251
9443
|
return () => ro.disconnect();
|
|
9252
9444
|
}, [dirty, pct]);
|
|
9253
|
-
return /* @__PURE__ */
|
|
9445
|
+
return /* @__PURE__ */ jsxs70(
|
|
9254
9446
|
"div",
|
|
9255
9447
|
{
|
|
9256
9448
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
9257
9449
|
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)" },
|
|
9258
9450
|
children: [
|
|
9259
|
-
/* @__PURE__ */
|
|
9260
|
-
/* @__PURE__ */
|
|
9261
|
-
/* @__PURE__ */
|
|
9262
|
-
dirty ? /* @__PURE__ */
|
|
9263
|
-
/* @__PURE__ */
|
|
9264
|
-
/* @__PURE__ */
|
|
9451
|
+
/* @__PURE__ */ jsxs70("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9452
|
+
/* @__PURE__ */ jsx76("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
9453
|
+
/* @__PURE__ */ jsx76(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
9454
|
+
dirty ? /* @__PURE__ */ jsxs70(Fragment23, { children: [
|
|
9455
|
+
/* @__PURE__ */ jsx76("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
9456
|
+
/* @__PURE__ */ jsx76(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
9265
9457
|
] }) : null
|
|
9266
9458
|
] }),
|
|
9267
|
-
/* @__PURE__ */
|
|
9268
|
-
/* @__PURE__ */
|
|
9269
|
-
dirty ? /* @__PURE__ */
|
|
9459
|
+
/* @__PURE__ */ jsxs70("div", { className: "fd-slider", ref: trackRef, children: [
|
|
9460
|
+
/* @__PURE__ */ jsx76("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
9461
|
+
dirty ? /* @__PURE__ */ jsx76(
|
|
9270
9462
|
"span",
|
|
9271
9463
|
{
|
|
9272
9464
|
ref: chipRef,
|
|
@@ -9278,7 +9470,7 @@ function BudgetReallocator({
|
|
|
9278
9470
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
9279
9471
|
}
|
|
9280
9472
|
) : null,
|
|
9281
|
-
/* @__PURE__ */
|
|
9473
|
+
/* @__PURE__ */ jsx76(
|
|
9282
9474
|
"input",
|
|
9283
9475
|
{
|
|
9284
9476
|
type: "range",
|
|
@@ -9294,13 +9486,13 @@ function BudgetReallocator({
|
|
|
9294
9486
|
}
|
|
9295
9487
|
)
|
|
9296
9488
|
] }),
|
|
9297
|
-
/* @__PURE__ */
|
|
9298
|
-
/* @__PURE__ */
|
|
9299
|
-
/* @__PURE__ */
|
|
9300
|
-
/* @__PURE__ */
|
|
9489
|
+
/* @__PURE__ */ jsxs70("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
9490
|
+
/* @__PURE__ */ jsxs70("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
9491
|
+
/* @__PURE__ */ jsx76("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
9492
|
+
/* @__PURE__ */ jsx76("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
9301
9493
|
] }),
|
|
9302
|
-
/* @__PURE__ */
|
|
9303
|
-
/* @__PURE__ */
|
|
9494
|
+
/* @__PURE__ */ jsx76("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
9495
|
+
/* @__PURE__ */ jsx76(
|
|
9304
9496
|
"button",
|
|
9305
9497
|
{
|
|
9306
9498
|
type: "button",
|
|
@@ -9319,7 +9511,7 @@ function BudgetReallocator({
|
|
|
9319
9511
|
}
|
|
9320
9512
|
|
|
9321
9513
|
// src/components/planner/SurroundSound.tsx
|
|
9322
|
-
import { jsx as
|
|
9514
|
+
import { jsx as jsx77, jsxs as jsxs71 } from "react/jsx-runtime";
|
|
9323
9515
|
var CATEGORIES = [
|
|
9324
9516
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
9325
9517
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -9331,26 +9523,26 @@ var CATEGORIES = [
|
|
|
9331
9523
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
9332
9524
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
9333
9525
|
const single = present.length <= 2;
|
|
9334
|
-
return /* @__PURE__ */
|
|
9335
|
-
/* @__PURE__ */
|
|
9526
|
+
return /* @__PURE__ */ jsxs71("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
9527
|
+
/* @__PURE__ */ jsx77("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
9336
9528
|
const on = present.includes(c.key);
|
|
9337
|
-
return /* @__PURE__ */
|
|
9529
|
+
return /* @__PURE__ */ jsxs71(
|
|
9338
9530
|
"span",
|
|
9339
9531
|
{
|
|
9340
9532
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
9341
9533
|
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)" },
|
|
9342
9534
|
children: [
|
|
9343
|
-
/* @__PURE__ */
|
|
9344
|
-
/* @__PURE__ */
|
|
9535
|
+
/* @__PURE__ */ jsx77("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
9536
|
+
/* @__PURE__ */ jsx77("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
9345
9537
|
]
|
|
9346
9538
|
},
|
|
9347
9539
|
c.key
|
|
9348
9540
|
);
|
|
9349
9541
|
}) }),
|
|
9350
|
-
/* @__PURE__ */
|
|
9351
|
-
/* @__PURE__ */
|
|
9352
|
-
/* @__PURE__ */
|
|
9353
|
-
/* @__PURE__ */
|
|
9542
|
+
/* @__PURE__ */ jsxs71("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
9543
|
+
/* @__PURE__ */ jsxs71("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
9544
|
+
/* @__PURE__ */ jsx77("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
9545
|
+
/* @__PURE__ */ jsxs71("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
9354
9546
|
"+",
|
|
9355
9547
|
bonusPct,
|
|
9356
9548
|
"% of +",
|
|
@@ -9358,8 +9550,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9358
9550
|
"%"
|
|
9359
9551
|
] })
|
|
9360
9552
|
] }),
|
|
9361
|
-
/* @__PURE__ */
|
|
9362
|
-
/* @__PURE__ */
|
|
9553
|
+
/* @__PURE__ */ jsx77("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx77("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
9554
|
+
/* @__PURE__ */ jsxs71("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
9363
9555
|
present.length,
|
|
9364
9556
|
" of 6 channel categories present.",
|
|
9365
9557
|
" ",
|
|
@@ -9371,7 +9563,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
9371
9563
|
}
|
|
9372
9564
|
|
|
9373
9565
|
// src/components/planner/Importance.tsx
|
|
9374
|
-
import { jsx as
|
|
9566
|
+
import { jsx as jsx78, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
9375
9567
|
var IMPORTANCE_LEVELS = [
|
|
9376
9568
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
9377
9569
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -9401,23 +9593,23 @@ function importanceTokens(id) {
|
|
|
9401
9593
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "" }) {
|
|
9402
9594
|
const lvl = importanceLevel(level);
|
|
9403
9595
|
const t = importanceTokens(level);
|
|
9404
|
-
return /* @__PURE__ */
|
|
9596
|
+
return /* @__PURE__ */ jsxs72(
|
|
9405
9597
|
"span",
|
|
9406
9598
|
{
|
|
9407
9599
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", className].filter(Boolean).join(" "),
|
|
9408
9600
|
style: { background: t.fill, borderColor: t.edge, color: t.text },
|
|
9409
9601
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
9410
9602
|
children: [
|
|
9411
|
-
/* @__PURE__ */
|
|
9412
|
-
showLabel ? lvl.label : /* @__PURE__ */
|
|
9603
|
+
/* @__PURE__ */ jsx78("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
9604
|
+
showLabel ? lvl.label : /* @__PURE__ */ jsx78("span", { className: "fd-sr", children: lvl.label })
|
|
9413
9605
|
]
|
|
9414
9606
|
}
|
|
9415
9607
|
);
|
|
9416
9608
|
}
|
|
9417
9609
|
|
|
9418
9610
|
// src/components/planner/PreferenceMeter.tsx
|
|
9419
|
-
import * as
|
|
9420
|
-
import { jsx as
|
|
9611
|
+
import * as React50 from "react";
|
|
9612
|
+
import { jsx as jsx79, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
9421
9613
|
function preferenceScore(criteria) {
|
|
9422
9614
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
9423
9615
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -9446,8 +9638,8 @@ function PreferenceMeter({
|
|
|
9446
9638
|
className = ""
|
|
9447
9639
|
}) {
|
|
9448
9640
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
9449
|
-
const segments =
|
|
9450
|
-
return /* @__PURE__ */
|
|
9641
|
+
const segments = React50.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
9642
|
+
return /* @__PURE__ */ jsx79(
|
|
9451
9643
|
ScoreMeter,
|
|
9452
9644
|
{
|
|
9453
9645
|
score: value,
|
|
@@ -9459,22 +9651,22 @@ function PreferenceMeter({
|
|
|
9459
9651
|
placement,
|
|
9460
9652
|
className,
|
|
9461
9653
|
breakdownLabel: breakdownTitle,
|
|
9462
|
-
breakdown: /* @__PURE__ */
|
|
9463
|
-
/* @__PURE__ */
|
|
9464
|
-
/* @__PURE__ */
|
|
9465
|
-
/* @__PURE__ */
|
|
9654
|
+
breakdown: /* @__PURE__ */ jsxs73("div", { className: "fd-prefbreak", children: [
|
|
9655
|
+
/* @__PURE__ */ jsxs73("div", { className: "fd-prefbreak-head", children: [
|
|
9656
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
9657
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
9466
9658
|
] }),
|
|
9467
|
-
/* @__PURE__ */
|
|
9659
|
+
/* @__PURE__ */ jsx79("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
9468
9660
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
9469
|
-
return /* @__PURE__ */
|
|
9470
|
-
/* @__PURE__ */
|
|
9471
|
-
/* @__PURE__ */
|
|
9472
|
-
/* @__PURE__ */
|
|
9473
|
-
c.note ? /* @__PURE__ */
|
|
9661
|
+
return /* @__PURE__ */ jsxs73("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
9662
|
+
/* @__PURE__ */ jsx79(ImportanceTag, { level: c.importance }),
|
|
9663
|
+
/* @__PURE__ */ jsxs73("span", { className: "fd-prefbreak-text", children: [
|
|
9664
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
9665
|
+
c.note ? /* @__PURE__ */ jsx79("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
9474
9666
|
] }),
|
|
9475
|
-
/* @__PURE__ */
|
|
9667
|
+
/* @__PURE__ */ jsxs73("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
9476
9668
|
Math.round(Number(c.earned) || 0),
|
|
9477
|
-
/* @__PURE__ */
|
|
9669
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
9478
9670
|
Math.round(c.weight)
|
|
9479
9671
|
] })
|
|
9480
9672
|
] }, c.id);
|
|
@@ -9485,10 +9677,10 @@ function PreferenceMeter({
|
|
|
9485
9677
|
}
|
|
9486
9678
|
|
|
9487
9679
|
// src/components/chat/AgentChatPanel.tsx
|
|
9488
|
-
import * as
|
|
9680
|
+
import * as React56 from "react";
|
|
9489
9681
|
|
|
9490
9682
|
// src/components/chat/chatEngine.ts
|
|
9491
|
-
import * as
|
|
9683
|
+
import * as React51 from "react";
|
|
9492
9684
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
9493
9685
|
var JOB_PENDING = ["queued", "running"];
|
|
9494
9686
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -9542,22 +9734,22 @@ function useChatEngine(opts) {
|
|
|
9542
9734
|
onClear,
|
|
9543
9735
|
onFeedback
|
|
9544
9736
|
} = opts || {};
|
|
9545
|
-
const [status, setStatus] =
|
|
9546
|
-
const [threadId, setThreadId] =
|
|
9547
|
-
const [messages, setMessages] =
|
|
9548
|
-
const [queue, setQueue] =
|
|
9549
|
-
const [fatal, setFatal] =
|
|
9550
|
-
const [busy, setBusy] =
|
|
9551
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
9552
|
-
const listRef =
|
|
9553
|
-
const queueRef =
|
|
9554
|
-
const busyRef =
|
|
9555
|
-
const stoppedRef =
|
|
9556
|
-
const abortRef =
|
|
9557
|
-
const serverCount =
|
|
9558
|
-
const threadRef =
|
|
9559
|
-
const mounted =
|
|
9560
|
-
|
|
9737
|
+
const [status, setStatus] = React51.useState("idle");
|
|
9738
|
+
const [threadId, setThreadId] = React51.useState(null);
|
|
9739
|
+
const [messages, setMessages] = React51.useState([]);
|
|
9740
|
+
const [queue, setQueue] = React51.useState([]);
|
|
9741
|
+
const [fatal, setFatal] = React51.useState(null);
|
|
9742
|
+
const [busy, setBusy] = React51.useState(false);
|
|
9743
|
+
const [turnStartedAt, setTurnStartedAt] = React51.useState(null);
|
|
9744
|
+
const listRef = React51.useRef([]);
|
|
9745
|
+
const queueRef = React51.useRef([]);
|
|
9746
|
+
const busyRef = React51.useRef(false);
|
|
9747
|
+
const stoppedRef = React51.useRef(false);
|
|
9748
|
+
const abortRef = React51.useRef(null);
|
|
9749
|
+
const serverCount = React51.useRef(0);
|
|
9750
|
+
const threadRef = React51.useRef(null);
|
|
9751
|
+
const mounted = React51.useRef(true);
|
|
9752
|
+
React51.useEffect(() => {
|
|
9561
9753
|
mounted.current = true;
|
|
9562
9754
|
return () => {
|
|
9563
9755
|
mounted.current = false;
|
|
@@ -9579,14 +9771,14 @@ function useChatEngine(opts) {
|
|
|
9579
9771
|
}
|
|
9580
9772
|
return false;
|
|
9581
9773
|
};
|
|
9582
|
-
const loadThread =
|
|
9774
|
+
const loadThread = React51.useCallback(async (id) => {
|
|
9583
9775
|
const data = await apiAdapter.getThread(id);
|
|
9584
9776
|
const list = [...data && data.messages || []];
|
|
9585
9777
|
serverCount.current = list.length;
|
|
9586
9778
|
commit(list);
|
|
9587
9779
|
return list;
|
|
9588
9780
|
}, [apiAdapter]);
|
|
9589
|
-
|
|
9781
|
+
React51.useEffect(() => {
|
|
9590
9782
|
if (!apiAdapter) {
|
|
9591
9783
|
setStatus("idle");
|
|
9592
9784
|
setFatal(null);
|
|
@@ -9799,7 +9991,7 @@ function useChatEngine(opts) {
|
|
|
9799
9991
|
await dispatchTurn(turn);
|
|
9800
9992
|
}
|
|
9801
9993
|
}
|
|
9802
|
-
const send =
|
|
9994
|
+
const send = React51.useCallback((text, attachments) => {
|
|
9803
9995
|
const body = (text || "").trim();
|
|
9804
9996
|
if (!body && !(attachments && attachments.length)) return;
|
|
9805
9997
|
if (status === "disconnected") return;
|
|
@@ -9809,7 +10001,7 @@ function useChatEngine(opts) {
|
|
|
9809
10001
|
stoppedRef.current = false;
|
|
9810
10002
|
drain();
|
|
9811
10003
|
}, [status]);
|
|
9812
|
-
const stop =
|
|
10004
|
+
const stop = React51.useCallback(() => {
|
|
9813
10005
|
stoppedRef.current = true;
|
|
9814
10006
|
const ac = abortRef.current;
|
|
9815
10007
|
if (ac) {
|
|
@@ -9828,11 +10020,11 @@ function useChatEngine(opts) {
|
|
|
9828
10020
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
9829
10021
|
}
|
|
9830
10022
|
}, [apiAdapter]);
|
|
9831
|
-
const removeQueued =
|
|
10023
|
+
const removeQueued = React51.useCallback((id) => {
|
|
9832
10024
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
9833
10025
|
setQueue(queueRef.current.slice());
|
|
9834
10026
|
}, []);
|
|
9835
|
-
const retry =
|
|
10027
|
+
const retry = React51.useCallback(() => {
|
|
9836
10028
|
const list = listRef.current;
|
|
9837
10029
|
let at = -1;
|
|
9838
10030
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -9848,19 +10040,19 @@ function useChatEngine(opts) {
|
|
|
9848
10040
|
setQueue(queueRef.current.slice());
|
|
9849
10041
|
drain();
|
|
9850
10042
|
}, []);
|
|
9851
|
-
const clear =
|
|
10043
|
+
const clear = React51.useCallback(() => {
|
|
9852
10044
|
commit([]);
|
|
9853
10045
|
serverCount.current = 0;
|
|
9854
10046
|
queueRef.current = [];
|
|
9855
10047
|
setQueue([]);
|
|
9856
10048
|
onClear && onClear();
|
|
9857
10049
|
}, [onClear]);
|
|
9858
|
-
const setFeedback =
|
|
10050
|
+
const setFeedback = React51.useCallback((id, value) => {
|
|
9859
10051
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
9860
10052
|
const msg = listRef.current.find((m) => m.id === id);
|
|
9861
10053
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
9862
10054
|
}, [onFeedback]);
|
|
9863
|
-
const reload =
|
|
10055
|
+
const reload = React51.useCallback(async () => {
|
|
9864
10056
|
if (!threadRef.current) return;
|
|
9865
10057
|
setStatus("loading");
|
|
9866
10058
|
try {
|
|
@@ -9898,11 +10090,11 @@ var ChatKit = {
|
|
|
9898
10090
|
};
|
|
9899
10091
|
|
|
9900
10092
|
// src/components/chat/ChatTranscript.tsx
|
|
9901
|
-
import * as
|
|
10093
|
+
import * as React53 from "react";
|
|
9902
10094
|
|
|
9903
10095
|
// src/components/chat/ChatTurn.tsx
|
|
9904
|
-
import * as
|
|
9905
|
-
import { jsx as
|
|
10096
|
+
import * as React52 from "react";
|
|
10097
|
+
import { jsx as jsx80, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
9906
10098
|
function JsonView({ value }) {
|
|
9907
10099
|
let text;
|
|
9908
10100
|
try {
|
|
@@ -9910,67 +10102,67 @@ function JsonView({ value }) {
|
|
|
9910
10102
|
} catch (e) {
|
|
9911
10103
|
text = String(value);
|
|
9912
10104
|
}
|
|
9913
|
-
return /* @__PURE__ */
|
|
10105
|
+
return /* @__PURE__ */ jsx80(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
9914
10106
|
}
|
|
9915
10107
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
9916
10108
|
if (!packet) return null;
|
|
9917
10109
|
const s = schema || {};
|
|
9918
10110
|
const invalid = packet.valid === false;
|
|
9919
10111
|
const title = s.heading || packet.type;
|
|
9920
|
-
return /* @__PURE__ */
|
|
9921
|
-
/* @__PURE__ */
|
|
9922
|
-
/* @__PURE__ */
|
|
9923
|
-
/* @__PURE__ */
|
|
9924
|
-
packet.repaired ? /* @__PURE__ */
|
|
9925
|
-
invalid ? /* @__PURE__ */
|
|
10112
|
+
return /* @__PURE__ */ jsxs74("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
10113
|
+
/* @__PURE__ */ jsxs74("header", { className: "fdc-packet-head", children: [
|
|
10114
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
10115
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
|
|
10116
|
+
packet.repaired ? /* @__PURE__ */ jsx80("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
10117
|
+
invalid ? /* @__PURE__ */ jsx80("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
9926
10118
|
] }),
|
|
9927
|
-
invalid ? /* @__PURE__ */
|
|
9928
|
-
/* @__PURE__ */
|
|
9929
|
-
/* @__PURE__ */
|
|
9930
|
-
] }) : /* @__PURE__ */
|
|
9931
|
-
!invalid && onApply ? /* @__PURE__ */
|
|
9932
|
-
packet.repaired ? /* @__PURE__ */
|
|
9933
|
-
/* @__PURE__ */
|
|
9934
|
-
/* @__PURE__ */
|
|
10119
|
+
invalid ? /* @__PURE__ */ jsxs74("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
10120
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10121
|
+
/* @__PURE__ */ jsx80("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
10122
|
+
] }) : /* @__PURE__ */ jsx80("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx80(JsonView, { value: packet.payload }) }),
|
|
10123
|
+
!invalid && onApply ? /* @__PURE__ */ jsxs74("footer", { className: "fdc-packet-foot", children: [
|
|
10124
|
+
packet.repaired ? /* @__PURE__ */ jsx80("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx80("span", {}),
|
|
10125
|
+
/* @__PURE__ */ jsxs74("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
10126
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
9935
10127
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
9936
10128
|
] })
|
|
9937
10129
|
] }) : null
|
|
9938
10130
|
] });
|
|
9939
10131
|
}
|
|
9940
10132
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
9941
|
-
const [open, setOpen] =
|
|
10133
|
+
const [open, setOpen] = React52.useState(defaultOpen);
|
|
9942
10134
|
if (!text) return null;
|
|
9943
|
-
return /* @__PURE__ */
|
|
9944
|
-
/* @__PURE__ */
|
|
9945
|
-
/* @__PURE__ */
|
|
9946
|
-
/* @__PURE__ */
|
|
9947
|
-
streaming ? /* @__PURE__ */
|
|
9948
|
-
/* @__PURE__ */
|
|
9949
|
-
/* @__PURE__ */
|
|
9950
|
-
/* @__PURE__ */
|
|
10135
|
+
return /* @__PURE__ */ jsxs74("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
10136
|
+
/* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10137
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
10138
|
+
/* @__PURE__ */ jsx80("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
10139
|
+
streaming ? /* @__PURE__ */ jsxs74("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10140
|
+
/* @__PURE__ */ jsx80("span", {}),
|
|
10141
|
+
/* @__PURE__ */ jsx80("span", {}),
|
|
10142
|
+
/* @__PURE__ */ jsx80("span", {})
|
|
9951
10143
|
] }) : null,
|
|
9952
|
-
/* @__PURE__ */
|
|
10144
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
9953
10145
|
] }),
|
|
9954
|
-
open ? /* @__PURE__ */
|
|
10146
|
+
open ? /* @__PURE__ */ jsx80("div", { className: "fdc-think-body", children: text }) : null
|
|
9955
10147
|
] });
|
|
9956
10148
|
}
|
|
9957
10149
|
function Citations({ items = [], onOpen }) {
|
|
9958
|
-
const [open, setOpen] =
|
|
10150
|
+
const [open, setOpen] = React52.useState(false);
|
|
9959
10151
|
if (!items.length) return null;
|
|
9960
|
-
return /* @__PURE__ */
|
|
9961
|
-
/* @__PURE__ */
|
|
9962
|
-
/* @__PURE__ */
|
|
9963
|
-
/* @__PURE__ */
|
|
10152
|
+
return /* @__PURE__ */ jsxs74("div", { className: "fdc-cites", children: [
|
|
10153
|
+
/* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
10154
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
10155
|
+
/* @__PURE__ */ jsxs74("span", { children: [
|
|
9964
10156
|
items.length,
|
|
9965
10157
|
" source",
|
|
9966
10158
|
items.length === 1 ? "" : "s"
|
|
9967
10159
|
] }),
|
|
9968
|
-
/* @__PURE__ */
|
|
10160
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" })
|
|
9969
10161
|
] }),
|
|
9970
|
-
open ? /* @__PURE__ */
|
|
9971
|
-
/* @__PURE__ */
|
|
9972
|
-
c.url ? /* @__PURE__ */
|
|
9973
|
-
c.detail ? /* @__PURE__ */
|
|
10162
|
+
open ? /* @__PURE__ */ jsx80("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs74("li", { children: [
|
|
10163
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
10164
|
+
c.url ? /* @__PURE__ */ jsx80("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx80("span", { children: c.title || "Source" }),
|
|
10165
|
+
c.detail ? /* @__PURE__ */ jsx80("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
9974
10166
|
] }, c.id || i)) }) : null
|
|
9975
10167
|
] });
|
|
9976
10168
|
}
|
|
@@ -9981,29 +10173,29 @@ function clampText(text, max) {
|
|
|
9981
10173
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
9982
10174
|
}
|
|
9983
10175
|
function MessageBody({ message: m, ctx }) {
|
|
9984
|
-
const [expanded, setExpanded] =
|
|
10176
|
+
const [expanded, setExpanded] = React52.useState(false);
|
|
9985
10177
|
const isUser = m.role === "user";
|
|
9986
10178
|
const raw = m.text || "";
|
|
9987
10179
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
9988
10180
|
const body = clamped != null ? clamped : raw;
|
|
9989
10181
|
const showMd = ctx.markdown && !isUser;
|
|
9990
|
-
return /* @__PURE__ */
|
|
9991
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */
|
|
9992
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */
|
|
9993
|
-
body ? /* @__PURE__ */
|
|
9994
|
-
showMd ? /* @__PURE__ */
|
|
9995
|
-
m.streaming ? /* @__PURE__ */
|
|
10182
|
+
return /* @__PURE__ */ jsxs74("div", { className: "fdc-body", children: [
|
|
10183
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx80(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
10184
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx80(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
10185
|
+
body ? /* @__PURE__ */ jsxs74("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
10186
|
+
showMd ? /* @__PURE__ */ jsx80(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx80("div", { className: "fdc-plain", children: body }),
|
|
10187
|
+
m.streaming ? /* @__PURE__ */ jsx80("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
9996
10188
|
] }) : null,
|
|
9997
|
-
clamped != null ? /* @__PURE__ */
|
|
9998
|
-
/* @__PURE__ */
|
|
10189
|
+
clamped != null ? /* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
10190
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
9999
10191
|
"Show more",
|
|
10000
|
-
/* @__PURE__ */
|
|
10001
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */
|
|
10002
|
-
/* @__PURE__ */
|
|
10192
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
10193
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
10194
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
10003
10195
|
"Show less"
|
|
10004
10196
|
] }) : null,
|
|
10005
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */
|
|
10006
|
-
m.packet ? /* @__PURE__ */
|
|
10197
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ jsx80(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
10198
|
+
m.packet ? /* @__PURE__ */ jsx80(
|
|
10007
10199
|
PacketCard,
|
|
10008
10200
|
{
|
|
10009
10201
|
packet: m.packet,
|
|
@@ -10013,44 +10205,44 @@ function MessageBody({ message: m, ctx }) {
|
|
|
10013
10205
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
10014
10206
|
}
|
|
10015
10207
|
) : null,
|
|
10016
|
-
m.citations && m.citations.length ? /* @__PURE__ */
|
|
10017
|
-
m.working ? /* @__PURE__ */
|
|
10018
|
-
/* @__PURE__ */
|
|
10019
|
-
/* @__PURE__ */
|
|
10020
|
-
/* @__PURE__ */
|
|
10021
|
-
/* @__PURE__ */
|
|
10208
|
+
m.citations && m.citations.length ? /* @__PURE__ */ jsx80(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
10209
|
+
m.working ? /* @__PURE__ */ jsxs74("div", { className: "fdc-working", role: "status", children: [
|
|
10210
|
+
/* @__PURE__ */ jsxs74("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
10211
|
+
/* @__PURE__ */ jsx80("span", {}),
|
|
10212
|
+
/* @__PURE__ */ jsx80("span", {}),
|
|
10213
|
+
/* @__PURE__ */ jsx80("span", {})
|
|
10022
10214
|
] }),
|
|
10023
|
-
/* @__PURE__ */
|
|
10215
|
+
/* @__PURE__ */ jsxs74("span", { className: "fdc-working-label", children: [
|
|
10024
10216
|
m.resumed ? "Resuming" : "Working",
|
|
10025
|
-
m.job && m.job.status ? /* @__PURE__ */
|
|
10217
|
+
m.job && m.job.status ? /* @__PURE__ */ jsxs74("span", { className: "fdc-working-job", children: [
|
|
10026
10218
|
" \xB7 ",
|
|
10027
10219
|
m.job.status
|
|
10028
10220
|
] }) : null,
|
|
10029
|
-
m.job && m.job.detail ? /* @__PURE__ */
|
|
10221
|
+
m.job && m.job.detail ? /* @__PURE__ */ jsxs74("span", { className: "fdc-working-job", children: [
|
|
10030
10222
|
" \xB7 ",
|
|
10031
10223
|
m.job.detail
|
|
10032
10224
|
] }) : null
|
|
10033
10225
|
] }),
|
|
10034
|
-
m.jobId ? /* @__PURE__ */
|
|
10226
|
+
m.jobId ? /* @__PURE__ */ jsx80("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
10035
10227
|
] }) : null,
|
|
10036
|
-
m.stopped ? /* @__PURE__ */
|
|
10037
|
-
/* @__PURE__ */
|
|
10228
|
+
m.stopped ? /* @__PURE__ */ jsxs74("div", { className: "fdc-stopped", children: [
|
|
10229
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10038
10230
|
"Stopped"
|
|
10039
10231
|
] }) : null,
|
|
10040
|
-
m.error ? /* @__PURE__ */
|
|
10041
|
-
/* @__PURE__ */
|
|
10042
|
-
/* @__PURE__ */
|
|
10043
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */
|
|
10044
|
-
/* @__PURE__ */
|
|
10232
|
+
m.error ? /* @__PURE__ */ jsxs74("div", { className: "fdc-error", role: "alert", children: [
|
|
10233
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10234
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
10235
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
10236
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10045
10237
|
"Retry"
|
|
10046
10238
|
] }) : null
|
|
10047
10239
|
] }) : null
|
|
10048
10240
|
] });
|
|
10049
10241
|
}
|
|
10050
10242
|
function useCopyRun() {
|
|
10051
|
-
const [done, setDone] =
|
|
10052
|
-
const t =
|
|
10053
|
-
|
|
10243
|
+
const [done, setDone] = React52.useState(false);
|
|
10244
|
+
const t = React52.useRef(null);
|
|
10245
|
+
React52.useEffect(() => () => {
|
|
10054
10246
|
if (t.current) clearTimeout(t.current);
|
|
10055
10247
|
}, []);
|
|
10056
10248
|
return [done, (text) => {
|
|
@@ -10070,16 +10262,16 @@ function RunActions({ group, ctx }) {
|
|
|
10070
10262
|
const isAssistant = group.role === "assistant";
|
|
10071
10263
|
const fb = last.feedback;
|
|
10072
10264
|
if (!ctx.messageActions) return null;
|
|
10073
|
-
return /* @__PURE__ */
|
|
10074
|
-
/* @__PURE__ */
|
|
10075
|
-
/* @__PURE__ */
|
|
10076
|
-
/* @__PURE__ */
|
|
10265
|
+
return /* @__PURE__ */ jsxs74("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
10266
|
+
/* @__PURE__ */ jsxs74("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
10267
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
10268
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
10077
10269
|
] }),
|
|
10078
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */
|
|
10079
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */
|
|
10080
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */
|
|
10081
|
-
/* @__PURE__ */
|
|
10082
|
-
/* @__PURE__ */
|
|
10270
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx80("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx80("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
10271
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx80("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx80("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
10272
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs74(React52.Fragment, { children: [
|
|
10273
|
+
/* @__PURE__ */ jsx80("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__ */ jsx80("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
10274
|
+
/* @__PURE__ */ jsx80("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__ */ jsx80("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
10083
10275
|
] }) : null,
|
|
10084
10276
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
10085
10277
|
] });
|
|
@@ -10089,22 +10281,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
10089
10281
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
10090
10282
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
10091
10283
|
const stamp = group.messages[0].timestamp;
|
|
10092
|
-
return /* @__PURE__ */
|
|
10093
|
-
/* @__PURE__ */
|
|
10094
|
-
ctx.showAvatars ? /* @__PURE__ */
|
|
10095
|
-
/* @__PURE__ */
|
|
10096
|
-
stamp ? /* @__PURE__ */
|
|
10097
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */
|
|
10284
|
+
return /* @__PURE__ */ jsxs74("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
10285
|
+
/* @__PURE__ */ jsxs74("div", { className: "fdc-turn-head", children: [
|
|
10286
|
+
ctx.showAvatars ? /* @__PURE__ */ jsx80("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx80("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx80("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx80("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
10287
|
+
/* @__PURE__ */ jsx80("span", { className: "fdc-who", children: name }),
|
|
10288
|
+
stamp ? /* @__PURE__ */ jsx80(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
10289
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx80("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
10098
10290
|
] }),
|
|
10099
|
-
/* @__PURE__ */
|
|
10100
|
-
group.messages.map((m) => /* @__PURE__ */
|
|
10101
|
-
/* @__PURE__ */
|
|
10291
|
+
/* @__PURE__ */ jsxs74("div", { className: "fdc-turn-body", children: [
|
|
10292
|
+
group.messages.map((m) => /* @__PURE__ */ jsx80("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx80(MessageBody, { message: m, ctx }) }, m.id)),
|
|
10293
|
+
/* @__PURE__ */ jsx80(RunActions, { group, ctx })
|
|
10102
10294
|
] })
|
|
10103
10295
|
] });
|
|
10104
10296
|
}
|
|
10105
10297
|
|
|
10106
10298
|
// src/components/chat/ChatTranscript.tsx
|
|
10107
|
-
import { jsx as
|
|
10299
|
+
import { jsx as jsx81, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
10108
10300
|
var GROUP_WINDOW = 6e4;
|
|
10109
10301
|
var STICK_PX = 100;
|
|
10110
10302
|
function groupMessages(list) {
|
|
@@ -10137,25 +10329,25 @@ function dayLabel(key) {
|
|
|
10137
10329
|
}
|
|
10138
10330
|
function Suggestions({ items = [], onPick }) {
|
|
10139
10331
|
if (!items.length) return null;
|
|
10140
|
-
return /* @__PURE__ */
|
|
10332
|
+
return /* @__PURE__ */ jsx81("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
10141
10333
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
10142
|
-
return /* @__PURE__ */
|
|
10143
|
-
it.icon ? /* @__PURE__ */
|
|
10144
|
-
/* @__PURE__ */
|
|
10145
|
-
/* @__PURE__ */
|
|
10146
|
-
it.description ? /* @__PURE__ */
|
|
10334
|
+
return /* @__PURE__ */ jsxs75("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
10335
|
+
it.icon ? /* @__PURE__ */ jsx81("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
10336
|
+
/* @__PURE__ */ jsxs75("span", { className: "fdc-suggest-text", children: [
|
|
10337
|
+
/* @__PURE__ */ jsx81("span", { className: "fdc-suggest-label", children: it.label }),
|
|
10338
|
+
it.description ? /* @__PURE__ */ jsx81("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
10147
10339
|
] }),
|
|
10148
|
-
/* @__PURE__ */
|
|
10340
|
+
/* @__PURE__ */ jsx81("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
10149
10341
|
] }, it.id || i);
|
|
10150
10342
|
}) });
|
|
10151
10343
|
}
|
|
10152
10344
|
function LoadingTurns() {
|
|
10153
|
-
return /* @__PURE__ */
|
|
10154
|
-
/* @__PURE__ */
|
|
10155
|
-
/* @__PURE__ */
|
|
10156
|
-
/* @__PURE__ */
|
|
10157
|
-
/* @__PURE__ */
|
|
10158
|
-
/* @__PURE__ */
|
|
10345
|
+
return /* @__PURE__ */ jsx81("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs75("div", { className: "fdc-skel-turn", children: [
|
|
10346
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
10347
|
+
/* @__PURE__ */ jsxs75("div", { className: "fdc-skel-lines", children: [
|
|
10348
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
10349
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
10350
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
10159
10351
|
] })
|
|
10160
10352
|
] }, i)) });
|
|
10161
10353
|
}
|
|
@@ -10172,10 +10364,10 @@ function ChatTranscript({
|
|
|
10172
10364
|
renderEmpty,
|
|
10173
10365
|
className = ""
|
|
10174
10366
|
}) {
|
|
10175
|
-
const scroller =
|
|
10176
|
-
const stick =
|
|
10177
|
-
const [pill, setPill] =
|
|
10178
|
-
const seen =
|
|
10367
|
+
const scroller = React53.useRef(null);
|
|
10368
|
+
const stick = React53.useRef(true);
|
|
10369
|
+
const [pill, setPill] = React53.useState(0);
|
|
10370
|
+
const seen = React53.useRef(0);
|
|
10179
10371
|
const toBottom = (smooth) => {
|
|
10180
10372
|
const el = scroller.current;
|
|
10181
10373
|
if (!el) return;
|
|
@@ -10194,7 +10386,7 @@ function ChatTranscript({
|
|
|
10194
10386
|
seen.current = messages.length;
|
|
10195
10387
|
}
|
|
10196
10388
|
};
|
|
10197
|
-
|
|
10389
|
+
React53.useLayoutEffect(() => {
|
|
10198
10390
|
const el = scroller.current;
|
|
10199
10391
|
if (!el) return;
|
|
10200
10392
|
if (stick.current) {
|
|
@@ -10202,7 +10394,7 @@ function ChatTranscript({
|
|
|
10202
10394
|
seen.current = messages.length;
|
|
10203
10395
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
10204
10396
|
}, [messages]);
|
|
10205
|
-
|
|
10397
|
+
React53.useEffect(() => {
|
|
10206
10398
|
const el = scroller.current;
|
|
10207
10399
|
const inner = el && el.firstChild;
|
|
10208
10400
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -10212,38 +10404,38 @@ function ChatTranscript({
|
|
|
10212
10404
|
ro.observe(inner);
|
|
10213
10405
|
return () => ro.disconnect();
|
|
10214
10406
|
}, []);
|
|
10215
|
-
const groups =
|
|
10407
|
+
const groups = React53.useMemo(() => groupMessages(messages), [messages]);
|
|
10216
10408
|
const empty = !messages.length && status === "ready";
|
|
10217
|
-
return /* @__PURE__ */
|
|
10218
|
-
/* @__PURE__ */
|
|
10219
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */
|
|
10220
|
-
status === "disconnected" ? /* @__PURE__ */
|
|
10221
|
-
/* @__PURE__ */
|
|
10222
|
-
/* @__PURE__ */
|
|
10223
|
-
/* @__PURE__ */
|
|
10224
|
-
ctx.onReconnect ? /* @__PURE__ */
|
|
10225
|
-
/* @__PURE__ */
|
|
10409
|
+
return /* @__PURE__ */ jsxs75("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
10410
|
+
/* @__PURE__ */ jsxs75("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
10411
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx81(LoadingTurns, {}) : null,
|
|
10412
|
+
status === "disconnected" ? /* @__PURE__ */ jsxs75("div", { className: "fdc-dead", children: [
|
|
10413
|
+
/* @__PURE__ */ jsx81("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx81("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
10414
|
+
/* @__PURE__ */ jsx81("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
10415
|
+
/* @__PURE__ */ jsx81("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." }),
|
|
10416
|
+
ctx.onReconnect ? /* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
10417
|
+
/* @__PURE__ */ jsx81("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
10226
10418
|
"Try again"
|
|
10227
10419
|
] }) : null
|
|
10228
10420
|
] }) : null,
|
|
10229
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
10230
|
-
/* @__PURE__ */
|
|
10231
|
-
/* @__PURE__ */
|
|
10232
|
-
emptyDescription ? /* @__PURE__ */
|
|
10233
|
-
/* @__PURE__ */
|
|
10421
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs75("div", { className: "fdc-empty", children: [
|
|
10422
|
+
/* @__PURE__ */ jsx81("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx81("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
10423
|
+
/* @__PURE__ */ jsx81("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
10424
|
+
emptyDescription ? /* @__PURE__ */ jsx81("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
10425
|
+
/* @__PURE__ */ jsx81(Suggestions, { items: suggestions, onPick })
|
|
10234
10426
|
] }) : null,
|
|
10235
10427
|
groups.map((g, i) => {
|
|
10236
10428
|
const prev = groups[i - 1];
|
|
10237
10429
|
const k = dayKey(g.messages[0].timestamp);
|
|
10238
10430
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
10239
|
-
return /* @__PURE__ */
|
|
10240
|
-
showDay ? /* @__PURE__ */
|
|
10241
|
-
/* @__PURE__ */
|
|
10431
|
+
return /* @__PURE__ */ jsxs75(React53.Fragment, { children: [
|
|
10432
|
+
showDay ? /* @__PURE__ */ jsx81("div", { className: "fdc-day", children: /* @__PURE__ */ jsx81("span", { children: dayLabel(k) }) }) : null,
|
|
10433
|
+
/* @__PURE__ */ jsx81(ChatTurn, { group: g, ctx })
|
|
10242
10434
|
] }, g.key || i);
|
|
10243
10435
|
})
|
|
10244
10436
|
] }),
|
|
10245
|
-
pill ? /* @__PURE__ */
|
|
10246
|
-
/* @__PURE__ */
|
|
10437
|
+
pill ? /* @__PURE__ */ jsxs75("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
10438
|
+
/* @__PURE__ */ jsx81("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
10247
10439
|
pill,
|
|
10248
10440
|
" new message",
|
|
10249
10441
|
pill === 1 ? "" : "s"
|
|
@@ -10253,8 +10445,8 @@ function ChatTranscript({
|
|
|
10253
10445
|
var TranscriptKit = { groupMessages };
|
|
10254
10446
|
|
|
10255
10447
|
// src/components/chat/ChatComposer.tsx
|
|
10256
|
-
import * as
|
|
10257
|
-
import { jsx as
|
|
10448
|
+
import * as React54 from "react";
|
|
10449
|
+
import { jsx as jsx82, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
10258
10450
|
function ChatComposer({
|
|
10259
10451
|
onSubmit,
|
|
10260
10452
|
onStop,
|
|
@@ -10281,17 +10473,17 @@ function ChatComposer({
|
|
|
10281
10473
|
onReject,
|
|
10282
10474
|
onOpenAttachment
|
|
10283
10475
|
}) {
|
|
10284
|
-
const [text, setText] =
|
|
10285
|
-
const [trigger, setTrigger] =
|
|
10286
|
-
const [mentionItems, setMentionItems] =
|
|
10287
|
-
const [listening, setListening] =
|
|
10288
|
-
const [notice, setNotice] =
|
|
10289
|
-
const editor =
|
|
10290
|
-
const wrap =
|
|
10291
|
-
const stopVoice =
|
|
10476
|
+
const [text, setText] = React54.useState(draft || "");
|
|
10477
|
+
const [trigger, setTrigger] = React54.useState(null);
|
|
10478
|
+
const [mentionItems, setMentionItems] = React54.useState([]);
|
|
10479
|
+
const [listening, setListening] = React54.useState(false);
|
|
10480
|
+
const [notice, setNotice] = React54.useState(null);
|
|
10481
|
+
const editor = React54.useRef(null);
|
|
10482
|
+
const wrap = React54.useRef(null);
|
|
10483
|
+
const stopVoice = React54.useRef(null);
|
|
10292
10484
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
10293
10485
|
} });
|
|
10294
|
-
|
|
10486
|
+
React54.useEffect(() => {
|
|
10295
10487
|
if (draft != null && draft !== text) setText(draft);
|
|
10296
10488
|
}, [draft]);
|
|
10297
10489
|
const change = (v) => {
|
|
@@ -10327,7 +10519,7 @@ function ChatComposer({
|
|
|
10327
10519
|
e.preventDefault();
|
|
10328
10520
|
staged.add(found.files);
|
|
10329
10521
|
};
|
|
10330
|
-
|
|
10522
|
+
React54.useEffect(() => {
|
|
10331
10523
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
10332
10524
|
setMentionItems([]);
|
|
10333
10525
|
return;
|
|
@@ -10345,7 +10537,7 @@ function ChatComposer({
|
|
|
10345
10537
|
const q = (trigger.query || "").toLowerCase();
|
|
10346
10538
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
10347
10539
|
}, [trigger, mentionSources]);
|
|
10348
|
-
const slashItems =
|
|
10540
|
+
const slashItems = React54.useMemo(() => {
|
|
10349
10541
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
10350
10542
|
const q = (trigger.query || "").toLowerCase();
|
|
10351
10543
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -10359,7 +10551,7 @@ function ChatComposer({
|
|
|
10359
10551
|
description: it.description,
|
|
10360
10552
|
icon: it.icon,
|
|
10361
10553
|
meta: mention.meta,
|
|
10362
|
-
shortcut: slash.shortcut ? /* @__PURE__ */
|
|
10554
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ jsx82(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
10363
10555
|
onSelect: () => {
|
|
10364
10556
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
10365
10557
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -10422,14 +10614,14 @@ function ChatComposer({
|
|
|
10422
10614
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
10423
10615
|
};
|
|
10424
10616
|
};
|
|
10425
|
-
return /* @__PURE__ */
|
|
10426
|
-
queue.length ? /* @__PURE__ */
|
|
10427
|
-
/* @__PURE__ */
|
|
10428
|
-
/* @__PURE__ */
|
|
10429
|
-
onRemoveQueued ? /* @__PURE__ */
|
|
10617
|
+
return /* @__PURE__ */ jsxs76("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
10618
|
+
queue.length ? /* @__PURE__ */ jsx82("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs76("div", { className: "fdc-queue-row", children: [
|
|
10619
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
10620
|
+
/* @__PURE__ */ jsx82("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)" : "") }),
|
|
10621
|
+
onRemoveQueued ? /* @__PURE__ */ jsx82("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx82("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
10430
10622
|
] }, q.id)) }) : null,
|
|
10431
10623
|
sessionBar,
|
|
10432
|
-
/* @__PURE__ */
|
|
10624
|
+
/* @__PURE__ */ jsx82(
|
|
10433
10625
|
Dropzone,
|
|
10434
10626
|
{
|
|
10435
10627
|
className: "fdc-field",
|
|
@@ -10443,9 +10635,9 @@ function ChatComposer({
|
|
|
10443
10635
|
disabled: !fileUploadHandler || disabled,
|
|
10444
10636
|
label: "Drop to attach",
|
|
10445
10637
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
10446
|
-
children: /* @__PURE__ */
|
|
10447
|
-
staged.items.length ? /* @__PURE__ */
|
|
10448
|
-
/* @__PURE__ */
|
|
10638
|
+
children: /* @__PURE__ */ jsxs76("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
10639
|
+
staged.items.length ? /* @__PURE__ */ jsx82("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx82(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
10640
|
+
/* @__PURE__ */ jsx82(
|
|
10449
10641
|
MarkdownEditor,
|
|
10450
10642
|
{
|
|
10451
10643
|
ref: editor,
|
|
@@ -10464,33 +10656,33 @@ function ChatComposer({
|
|
|
10464
10656
|
ariaLabel: "Message"
|
|
10465
10657
|
}
|
|
10466
10658
|
),
|
|
10467
|
-
/* @__PURE__ */
|
|
10468
|
-
fileUploadHandler ? /* @__PURE__ */
|
|
10469
|
-
voiceHandler ? /* @__PURE__ */
|
|
10659
|
+
/* @__PURE__ */ jsxs76("div", { className: "fdc-tools", children: [
|
|
10660
|
+
fileUploadHandler ? /* @__PURE__ */ jsx82(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
10661
|
+
voiceHandler ? /* @__PURE__ */ jsx82("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx82("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
10470
10662
|
toolbarExtras,
|
|
10471
|
-
/* @__PURE__ */
|
|
10472
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */
|
|
10663
|
+
/* @__PURE__ */ jsx82("span", { className: "fdc-tools-gap" }),
|
|
10664
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs76("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
10473
10665
|
text.length,
|
|
10474
10666
|
"/",
|
|
10475
10667
|
maxLength
|
|
10476
10668
|
] }) : null,
|
|
10477
|
-
busy ? /* @__PURE__ */
|
|
10478
|
-
/* @__PURE__ */
|
|
10479
|
-
/* @__PURE__ */
|
|
10480
|
-
] }) : /* @__PURE__ */
|
|
10481
|
-
/* @__PURE__ */
|
|
10482
|
-
/* @__PURE__ */
|
|
10669
|
+
busy ? /* @__PURE__ */ jsxs76("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
10670
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
10671
|
+
/* @__PURE__ */ jsx82("span", { children: "Stop" })
|
|
10672
|
+
] }) : /* @__PURE__ */ jsxs76("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
10673
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
10674
|
+
/* @__PURE__ */ jsx82("span", { className: "fdc-send-label", children: "Send" })
|
|
10483
10675
|
] })
|
|
10484
10676
|
] })
|
|
10485
10677
|
] })
|
|
10486
10678
|
}
|
|
10487
10679
|
),
|
|
10488
|
-
notice ? /* @__PURE__ */
|
|
10489
|
-
/* @__PURE__ */
|
|
10680
|
+
notice ? /* @__PURE__ */ jsxs76("div", { className: "fdc-notice", role: "status", children: [
|
|
10681
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
10490
10682
|
notice
|
|
10491
10683
|
] }) : null,
|
|
10492
|
-
hint && !notice ? /* @__PURE__ */
|
|
10493
|
-
/* @__PURE__ */
|
|
10684
|
+
hint && !notice ? /* @__PURE__ */ jsx82("div", { className: "fdc-hint", children: hint }) : null,
|
|
10685
|
+
/* @__PURE__ */ jsx82(
|
|
10494
10686
|
Popover,
|
|
10495
10687
|
{
|
|
10496
10688
|
open: menuOpen,
|
|
@@ -10504,12 +10696,12 @@ function ChatComposer({
|
|
|
10504
10696
|
returnFocus: false,
|
|
10505
10697
|
closeOnOutside: true,
|
|
10506
10698
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
10507
|
-
children: /* @__PURE__ */
|
|
10699
|
+
children: /* @__PURE__ */ jsx82(
|
|
10508
10700
|
Menu,
|
|
10509
10701
|
{
|
|
10510
10702
|
items: menuItems,
|
|
10511
10703
|
autoFocus: false,
|
|
10512
|
-
header: /* @__PURE__ */
|
|
10704
|
+
header: /* @__PURE__ */ jsx82("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
10513
10705
|
onClose: () => setTrigger(null)
|
|
10514
10706
|
}
|
|
10515
10707
|
)
|
|
@@ -10519,12 +10711,12 @@ function ChatComposer({
|
|
|
10519
10711
|
}
|
|
10520
10712
|
|
|
10521
10713
|
// src/components/chat/ChatSessionBar.tsx
|
|
10522
|
-
import * as
|
|
10523
|
-
import { jsx as
|
|
10714
|
+
import * as React55 from "react";
|
|
10715
|
+
import { jsx as jsx83, jsxs as jsxs77 } from "react/jsx-runtime";
|
|
10524
10716
|
var compact2 = meterFormats.compact;
|
|
10525
10717
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
10526
|
-
const [open, setOpen] =
|
|
10527
|
-
const anchor =
|
|
10718
|
+
const [open, setOpen] = React55.useState(false);
|
|
10719
|
+
const anchor = React55.useRef(null);
|
|
10528
10720
|
const stats = sessionStats || null;
|
|
10529
10721
|
const cu = contextUsage || null;
|
|
10530
10722
|
const limits = usageLimits || null;
|
|
@@ -10539,9 +10731,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10539
10731
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
10540
10732
|
if (cu) bits.push(pct + "% context");
|
|
10541
10733
|
const expandable = !!(cu || limits);
|
|
10542
|
-
return /* @__PURE__ */
|
|
10543
|
-
/* @__PURE__ */
|
|
10544
|
-
/* @__PURE__ */
|
|
10734
|
+
return /* @__PURE__ */ jsxs77(React55.Fragment, { children: [
|
|
10735
|
+
/* @__PURE__ */ jsxs77("div", { className: "fdc-bar", children: [
|
|
10736
|
+
/* @__PURE__ */ jsxs77(
|
|
10545
10737
|
"button",
|
|
10546
10738
|
{
|
|
10547
10739
|
type: "button",
|
|
@@ -10552,15 +10744,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10552
10744
|
"aria-expanded": expandable ? open : void 0,
|
|
10553
10745
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
10554
10746
|
children: [
|
|
10555
|
-
cu ? /* @__PURE__ */
|
|
10556
|
-
/* @__PURE__ */
|
|
10557
|
-
expandable ? /* @__PURE__ */
|
|
10747
|
+
cu ? /* @__PURE__ */ jsx83("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx83(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
10748
|
+
/* @__PURE__ */ jsx83("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
|
|
10749
|
+
expandable ? /* @__PURE__ */ jsx83("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
10558
10750
|
]
|
|
10559
10751
|
}
|
|
10560
10752
|
),
|
|
10561
10753
|
extras
|
|
10562
10754
|
] }),
|
|
10563
|
-
/* @__PURE__ */
|
|
10755
|
+
/* @__PURE__ */ jsx83(
|
|
10564
10756
|
Popover,
|
|
10565
10757
|
{
|
|
10566
10758
|
open,
|
|
@@ -10571,15 +10763,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10571
10763
|
maxHeight: 460,
|
|
10572
10764
|
padded: true,
|
|
10573
10765
|
label: "Usage",
|
|
10574
|
-
footer: onClear ? /* @__PURE__ */
|
|
10766
|
+
footer: onClear ? /* @__PURE__ */ jsxs77("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
10575
10767
|
setOpen(false);
|
|
10576
10768
|
onClear();
|
|
10577
10769
|
}, children: [
|
|
10578
|
-
/* @__PURE__ */
|
|
10770
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
10579
10771
|
"Clear conversation"
|
|
10580
10772
|
] }) : void 0,
|
|
10581
|
-
children: /* @__PURE__ */
|
|
10582
|
-
cu ? /* @__PURE__ */
|
|
10773
|
+
children: /* @__PURE__ */ jsxs77("div", { className: "fdc-usage", children: [
|
|
10774
|
+
cu ? /* @__PURE__ */ jsx83("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx83(
|
|
10583
10775
|
SegmentedMeter,
|
|
10584
10776
|
{
|
|
10585
10777
|
total,
|
|
@@ -10591,9 +10783,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10591
10783
|
remainderLabel: "Free"
|
|
10592
10784
|
}
|
|
10593
10785
|
) }) : null,
|
|
10594
|
-
limits && limits.length ? /* @__PURE__ */
|
|
10595
|
-
/* @__PURE__ */
|
|
10596
|
-
/* @__PURE__ */
|
|
10786
|
+
limits && limits.length ? /* @__PURE__ */ jsxs77("section", { className: "fdc-usage-sec", children: [
|
|
10787
|
+
/* @__PURE__ */ jsx83("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
10788
|
+
/* @__PURE__ */ jsx83("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx83(
|
|
10597
10789
|
QuotaRow,
|
|
10598
10790
|
{
|
|
10599
10791
|
label: l.label,
|
|
@@ -10603,25 +10795,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10603
10795
|
l.id
|
|
10604
10796
|
)) })
|
|
10605
10797
|
] }) : null,
|
|
10606
|
-
stats ? /* @__PURE__ */
|
|
10607
|
-
stats.elapsedMs ? /* @__PURE__ */
|
|
10608
|
-
/* @__PURE__ */
|
|
10609
|
-
/* @__PURE__ */
|
|
10798
|
+
stats ? /* @__PURE__ */ jsxs77("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
10799
|
+
stats.elapsedMs ? /* @__PURE__ */ jsxs77("div", { children: [
|
|
10800
|
+
/* @__PURE__ */ jsx83("span", { children: "Session" }),
|
|
10801
|
+
/* @__PURE__ */ jsx83("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
10610
10802
|
] }) : null,
|
|
10611
|
-
stats.tokens ? /* @__PURE__ */
|
|
10612
|
-
/* @__PURE__ */
|
|
10613
|
-
/* @__PURE__ */
|
|
10803
|
+
stats.tokens ? /* @__PURE__ */ jsxs77("div", { children: [
|
|
10804
|
+
/* @__PURE__ */ jsx83("span", { children: "Tokens" }),
|
|
10805
|
+
/* @__PURE__ */ jsx83("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
10614
10806
|
] }) : null,
|
|
10615
|
-
stats.costUsd != null ? /* @__PURE__ */
|
|
10616
|
-
/* @__PURE__ */
|
|
10617
|
-
/* @__PURE__ */
|
|
10807
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs77("div", { children: [
|
|
10808
|
+
/* @__PURE__ */ jsx83("span", { children: "Cost" }),
|
|
10809
|
+
/* @__PURE__ */ jsxs77("b", { className: "fd-tabular", children: [
|
|
10618
10810
|
"$",
|
|
10619
10811
|
Number(stats.costUsd).toFixed(3)
|
|
10620
10812
|
] })
|
|
10621
10813
|
] }) : null,
|
|
10622
|
-
stats.turns ? /* @__PURE__ */
|
|
10623
|
-
/* @__PURE__ */
|
|
10624
|
-
/* @__PURE__ */
|
|
10814
|
+
stats.turns ? /* @__PURE__ */ jsxs77("div", { children: [
|
|
10815
|
+
/* @__PURE__ */ jsx83("span", { children: "Turns" }),
|
|
10816
|
+
/* @__PURE__ */ jsx83("b", { className: "fd-tabular", children: stats.turns })
|
|
10625
10817
|
] }) : null
|
|
10626
10818
|
] }) : null
|
|
10627
10819
|
] })
|
|
@@ -10660,7 +10852,7 @@ function ModelControls({
|
|
|
10660
10852
|
disabled: m.disabled,
|
|
10661
10853
|
checked: m.id === (current2 && current2.id),
|
|
10662
10854
|
meta: m.meta,
|
|
10663
|
-
shortcut: m.shortcut ? /* @__PURE__ */
|
|
10855
|
+
shortcut: m.shortcut ? /* @__PURE__ */ jsx83(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
10664
10856
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
10665
10857
|
});
|
|
10666
10858
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -10673,15 +10865,15 @@ function ModelControls({
|
|
|
10673
10865
|
items.push({ kind: "section", label: "Fast mode" });
|
|
10674
10866
|
items.push({
|
|
10675
10867
|
kind: "custom",
|
|
10676
|
-
render: () => /* @__PURE__ */
|
|
10677
|
-
/* @__PURE__ */
|
|
10678
|
-
/* @__PURE__ */
|
|
10679
|
-
/* @__PURE__ */
|
|
10868
|
+
render: () => /* @__PURE__ */ jsxs77("label", { className: "fdc-switchrow", children: [
|
|
10869
|
+
/* @__PURE__ */ jsx83("span", { children: fastModeLabel }),
|
|
10870
|
+
/* @__PURE__ */ jsx83("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
10871
|
+
/* @__PURE__ */ jsx83("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx83("span", { className: "fd-switch-thumb" }) })
|
|
10680
10872
|
] })
|
|
10681
10873
|
});
|
|
10682
10874
|
}
|
|
10683
|
-
return /* @__PURE__ */
|
|
10684
|
-
/* @__PURE__ */
|
|
10875
|
+
return /* @__PURE__ */ jsxs77(React55.Fragment, { children: [
|
|
10876
|
+
/* @__PURE__ */ jsx83(
|
|
10685
10877
|
MenuButton,
|
|
10686
10878
|
{
|
|
10687
10879
|
items,
|
|
@@ -10692,7 +10884,7 @@ function ModelControls({
|
|
|
10692
10884
|
title: "Choose a model"
|
|
10693
10885
|
}
|
|
10694
10886
|
),
|
|
10695
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */
|
|
10887
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ jsx83(
|
|
10696
10888
|
MenuButton,
|
|
10697
10889
|
{
|
|
10698
10890
|
placement: "top-end",
|
|
@@ -10713,7 +10905,7 @@ function ModelControls({
|
|
|
10713
10905
|
}
|
|
10714
10906
|
|
|
10715
10907
|
// src/components/chat/AgentChatPanel.tsx
|
|
10716
|
-
import { jsx as
|
|
10908
|
+
import { jsx as jsx84, jsxs as jsxs78 } from "react/jsx-runtime";
|
|
10717
10909
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
10718
10910
|
function AgentChatPanel({
|
|
10719
10911
|
/* required */
|
|
@@ -10797,11 +10989,11 @@ function AgentChatPanel({
|
|
|
10797
10989
|
onFeedback,
|
|
10798
10990
|
onEditMessage
|
|
10799
10991
|
}) {
|
|
10800
|
-
const [panelWidth, setPanelWidth] =
|
|
10801
|
-
const [applied, setApplied] =
|
|
10802
|
-
const [draft, setDraft] =
|
|
10803
|
-
const dragging =
|
|
10804
|
-
|
|
10992
|
+
const [panelWidth, setPanelWidth] = React56.useState(width);
|
|
10993
|
+
const [applied, setApplied] = React56.useState({});
|
|
10994
|
+
const [draft, setDraft] = React56.useState("");
|
|
10995
|
+
const dragging = React56.useRef(null);
|
|
10996
|
+
React56.useEffect(() => setPanelWidth(width), [width]);
|
|
10805
10997
|
const engine = useChatEngine({
|
|
10806
10998
|
contextType,
|
|
10807
10999
|
contextId,
|
|
@@ -10867,7 +11059,7 @@ function AgentChatPanel({
|
|
|
10867
11059
|
onReconnect: engine.reload,
|
|
10868
11060
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
10869
11061
|
};
|
|
10870
|
-
const sessionBar = /* @__PURE__ */
|
|
11062
|
+
const sessionBar = /* @__PURE__ */ jsx84(
|
|
10871
11063
|
ChatSessionBar,
|
|
10872
11064
|
{
|
|
10873
11065
|
sessionStats,
|
|
@@ -10876,7 +11068,7 @@ function AgentChatPanel({
|
|
|
10876
11068
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
10877
11069
|
}
|
|
10878
11070
|
);
|
|
10879
|
-
const modelControls = /* @__PURE__ */
|
|
11071
|
+
const modelControls = /* @__PURE__ */ jsx84(
|
|
10880
11072
|
ModelControls,
|
|
10881
11073
|
{
|
|
10882
11074
|
models,
|
|
@@ -10891,7 +11083,7 @@ function AgentChatPanel({
|
|
|
10891
11083
|
narrow
|
|
10892
11084
|
}
|
|
10893
11085
|
);
|
|
10894
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */
|
|
11086
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx84(
|
|
10895
11087
|
MenuButton,
|
|
10896
11088
|
{
|
|
10897
11089
|
variant: "ghost",
|
|
@@ -10918,7 +11110,7 @@ function AgentChatPanel({
|
|
|
10918
11110
|
})))
|
|
10919
11111
|
}
|
|
10920
11112
|
) : null;
|
|
10921
|
-
return /* @__PURE__ */
|
|
11113
|
+
return /* @__PURE__ */ jsxs78(
|
|
10922
11114
|
"aside",
|
|
10923
11115
|
{
|
|
10924
11116
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -10929,7 +11121,7 @@ function AgentChatPanel({
|
|
|
10929
11121
|
},
|
|
10930
11122
|
"aria-label": title,
|
|
10931
11123
|
children: [
|
|
10932
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */
|
|
11124
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ jsx84(
|
|
10933
11125
|
"div",
|
|
10934
11126
|
{
|
|
10935
11127
|
className: "fdc-grip",
|
|
@@ -10944,20 +11136,20 @@ function AgentChatPanel({
|
|
|
10944
11136
|
}
|
|
10945
11137
|
}
|
|
10946
11138
|
) : null,
|
|
10947
|
-
showHeader ? /* @__PURE__ */
|
|
10948
|
-
/* @__PURE__ */
|
|
10949
|
-
/* @__PURE__ */
|
|
10950
|
-
/* @__PURE__ */
|
|
10951
|
-
subtitle ? /* @__PURE__ */
|
|
11139
|
+
showHeader ? /* @__PURE__ */ jsxs78("header", { className: "fdc-head", children: [
|
|
11140
|
+
/* @__PURE__ */ jsx84("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx84("i", { className: "ph ph-" + assistantIcon }) }),
|
|
11141
|
+
/* @__PURE__ */ jsxs78("span", { className: "fdc-head-titles", children: [
|
|
11142
|
+
/* @__PURE__ */ jsx84("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
|
|
11143
|
+
subtitle ? /* @__PURE__ */ jsx84("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
|
|
10952
11144
|
] }),
|
|
10953
|
-
/* @__PURE__ */
|
|
11145
|
+
/* @__PURE__ */ jsxs78("span", { className: "fdc-head-acts", children: [
|
|
10954
11146
|
headerActions,
|
|
10955
11147
|
threadMenu,
|
|
10956
|
-
onNewThread ? /* @__PURE__ */
|
|
10957
|
-
onClose ? /* @__PURE__ */
|
|
11148
|
+
onNewThread ? /* @__PURE__ */ jsx84("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx84("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
11149
|
+
onClose ? /* @__PURE__ */ jsx84("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx84("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
10958
11150
|
] })
|
|
10959
11151
|
] }) : null,
|
|
10960
|
-
/* @__PURE__ */
|
|
11152
|
+
/* @__PURE__ */ jsx84(
|
|
10961
11153
|
ChatTranscript,
|
|
10962
11154
|
{
|
|
10963
11155
|
messages: engine.visible,
|
|
@@ -10972,7 +11164,7 @@ function AgentChatPanel({
|
|
|
10972
11164
|
renderEmpty
|
|
10973
11165
|
}
|
|
10974
11166
|
),
|
|
10975
|
-
/* @__PURE__ */
|
|
11167
|
+
/* @__PURE__ */ jsx84(
|
|
10976
11168
|
ChatComposer,
|
|
10977
11169
|
{
|
|
10978
11170
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -11005,8 +11197,8 @@ function AgentChatPanel({
|
|
|
11005
11197
|
}
|
|
11006
11198
|
|
|
11007
11199
|
// src/components/files/FileViewer.tsx
|
|
11008
|
-
import * as
|
|
11009
|
-
import { jsx as
|
|
11200
|
+
import * as React57 from "react";
|
|
11201
|
+
import { jsx as jsx85, jsxs as jsxs79 } from "react/jsx-runtime";
|
|
11010
11202
|
function previewKindOf(file) {
|
|
11011
11203
|
const mime = (file.mime || "").toLowerCase();
|
|
11012
11204
|
const ext = extensionOf(file.name || "");
|
|
@@ -11062,13 +11254,13 @@ function parseDelimited(text, delimiter) {
|
|
|
11062
11254
|
return rows;
|
|
11063
11255
|
}
|
|
11064
11256
|
function usePreview(file, kind, resolveUrl) {
|
|
11065
|
-
const [state, setState] =
|
|
11066
|
-
const [attempt, setAttempt] =
|
|
11067
|
-
const resolveRef =
|
|
11068
|
-
|
|
11257
|
+
const [state, setState] = React57.useState({ status: "loading" });
|
|
11258
|
+
const [attempt, setAttempt] = React57.useState(0);
|
|
11259
|
+
const resolveRef = React57.useRef(resolveUrl);
|
|
11260
|
+
React57.useEffect(() => {
|
|
11069
11261
|
resolveRef.current = resolveUrl;
|
|
11070
11262
|
}, [resolveUrl]);
|
|
11071
|
-
|
|
11263
|
+
React57.useEffect(() => {
|
|
11072
11264
|
if (kind === "none") {
|
|
11073
11265
|
setState({ status: "ready" });
|
|
11074
11266
|
return;
|
|
@@ -11098,19 +11290,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
11098
11290
|
if (ac) ac.abort();
|
|
11099
11291
|
};
|
|
11100
11292
|
}, [file.id, kind, attempt]);
|
|
11101
|
-
return { ...state, retry:
|
|
11293
|
+
return { ...state, retry: React57.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
11102
11294
|
}
|
|
11103
11295
|
function PreviewBody({ file, kind, state }) {
|
|
11104
|
-
if (kind === "image") return /* @__PURE__ */
|
|
11105
|
-
if (kind === "pdf") return /* @__PURE__ */
|
|
11106
|
-
if (kind === "markdown") return /* @__PURE__ */
|
|
11296
|
+
if (kind === "image") return /* @__PURE__ */ jsx85("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
11297
|
+
if (kind === "pdf") return /* @__PURE__ */ jsx85("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
|
|
11298
|
+
if (kind === "markdown") return /* @__PURE__ */ jsx85(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
|
|
11107
11299
|
if (kind === "json") {
|
|
11108
11300
|
let pretty = state.text || "";
|
|
11109
11301
|
try {
|
|
11110
11302
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
11111
11303
|
} catch {
|
|
11112
11304
|
}
|
|
11113
|
-
return /* @__PURE__ */
|
|
11305
|
+
return /* @__PURE__ */ jsx85(CodeBlock, { code: pretty, language: "json" });
|
|
11114
11306
|
}
|
|
11115
11307
|
if (kind === "csv") {
|
|
11116
11308
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -11118,12 +11310,12 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11118
11310
|
const head = rows[0] || [];
|
|
11119
11311
|
const dataRows = rows.slice(1);
|
|
11120
11312
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
11121
|
-
return /* @__PURE__ */
|
|
11122
|
-
/* @__PURE__ */
|
|
11123
|
-
/* @__PURE__ */
|
|
11124
|
-
/* @__PURE__ */
|
|
11313
|
+
return /* @__PURE__ */ jsxs79("div", { className: "fd-fv-csv", children: [
|
|
11314
|
+
/* @__PURE__ */ jsxs79("table", { className: "fd-fv-csv-table", children: [
|
|
11315
|
+
/* @__PURE__ */ jsx85("thead", { children: /* @__PURE__ */ jsx85("tr", { children: head.map((c, i) => /* @__PURE__ */ jsx85("th", { children: c }, i)) }) }),
|
|
11316
|
+
/* @__PURE__ */ jsx85("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ jsx85("tr", { children: head.map((_, ci) => /* @__PURE__ */ jsx85("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
|
|
11125
11317
|
] }),
|
|
11126
|
-
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */
|
|
11318
|
+
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ jsxs79("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
|
|
11127
11319
|
"Showing the first ",
|
|
11128
11320
|
FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
|
|
11129
11321
|
" of ",
|
|
@@ -11132,24 +11324,24 @@ function PreviewBody({ file, kind, state }) {
|
|
|
11132
11324
|
] }) : null
|
|
11133
11325
|
] });
|
|
11134
11326
|
}
|
|
11135
|
-
if (kind === "text") return /* @__PURE__ */
|
|
11136
|
-
return /* @__PURE__ */
|
|
11137
|
-
/* @__PURE__ */
|
|
11138
|
-
/* @__PURE__ */
|
|
11139
|
-
/* @__PURE__ */
|
|
11327
|
+
if (kind === "text") return /* @__PURE__ */ jsx85(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
|
|
11328
|
+
return /* @__PURE__ */ jsxs79("div", { className: "fd-fv-fallback", children: [
|
|
11329
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx85("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11330
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
|
|
11331
|
+
/* @__PURE__ */ jsxs79("span", { className: "fd-fv-fallback-meta", children: [
|
|
11140
11332
|
file.mime || "Unknown type",
|
|
11141
11333
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11142
11334
|
] })
|
|
11143
11335
|
] });
|
|
11144
11336
|
}
|
|
11145
11337
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
11146
|
-
const kind =
|
|
11338
|
+
const kind = React57.useMemo(() => previewKindOf(file), [file]);
|
|
11147
11339
|
const preview = usePreview(file, kind, resolveUrl);
|
|
11148
|
-
const [tab, setTab] =
|
|
11149
|
-
const [downloading, setDownloading] =
|
|
11150
|
-
const [downloadError, setDownloadError] =
|
|
11340
|
+
const [tab, setTab] = React57.useState("preview");
|
|
11341
|
+
const [downloading, setDownloading] = React57.useState(false);
|
|
11342
|
+
const [downloadError, setDownloadError] = React57.useState(null);
|
|
11151
11343
|
const hasSide = sidePanel != null;
|
|
11152
|
-
|
|
11344
|
+
React57.useEffect(() => {
|
|
11153
11345
|
setTab("preview");
|
|
11154
11346
|
}, [file.id]);
|
|
11155
11347
|
const download = () => {
|
|
@@ -11165,29 +11357,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11165
11357
|
a.remove();
|
|
11166
11358
|
}).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
|
|
11167
11359
|
};
|
|
11168
|
-
return /* @__PURE__ */
|
|
11360
|
+
return /* @__PURE__ */ jsxs79(
|
|
11169
11361
|
"section",
|
|
11170
11362
|
{
|
|
11171
11363
|
className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
|
|
11172
11364
|
"aria-label": file.name || "File",
|
|
11173
11365
|
children: [
|
|
11174
|
-
/* @__PURE__ */
|
|
11175
|
-
/* @__PURE__ */
|
|
11176
|
-
/* @__PURE__ */
|
|
11177
|
-
/* @__PURE__ */
|
|
11178
|
-
/* @__PURE__ */
|
|
11366
|
+
/* @__PURE__ */ jsxs79("header", { className: "fd-fv-head", children: [
|
|
11367
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx85("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
11368
|
+
/* @__PURE__ */ jsxs79("span", { className: "fd-fv-head-titles", children: [
|
|
11369
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
|
|
11370
|
+
/* @__PURE__ */ jsxs79("span", { className: "fd-fv-head-meta", children: [
|
|
11179
11371
|
file.mime || "Unknown type",
|
|
11180
11372
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
11181
11373
|
] })
|
|
11182
11374
|
] }),
|
|
11183
|
-
/* @__PURE__ */
|
|
11375
|
+
/* @__PURE__ */ jsxs79("span", { className: "fd-fv-head-actions", children: [
|
|
11184
11376
|
actions,
|
|
11185
|
-
/* @__PURE__ */
|
|
11186
|
-
onClose ? /* @__PURE__ */
|
|
11377
|
+
/* @__PURE__ */ jsx85(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
|
|
11378
|
+
onClose ? /* @__PURE__ */ jsx85(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
|
|
11187
11379
|
] })
|
|
11188
11380
|
] }),
|
|
11189
|
-
downloadError ? /* @__PURE__ */
|
|
11190
|
-
hasSide ? /* @__PURE__ */
|
|
11381
|
+
downloadError ? /* @__PURE__ */ jsx85("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
|
|
11382
|
+
hasSide ? /* @__PURE__ */ jsx85(
|
|
11191
11383
|
Tabs,
|
|
11192
11384
|
{
|
|
11193
11385
|
className: "fd-fv-tabs",
|
|
@@ -11196,19 +11388,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11196
11388
|
onChange: (v) => setTab(v)
|
|
11197
11389
|
}
|
|
11198
11390
|
) : null,
|
|
11199
|
-
/* @__PURE__ */
|
|
11200
|
-
/* @__PURE__ */
|
|
11391
|
+
/* @__PURE__ */ jsxs79("div", { className: "fd-fv-body", children: [
|
|
11392
|
+
/* @__PURE__ */ jsx85("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ jsx85(
|
|
11201
11393
|
LoadingRegion,
|
|
11202
11394
|
{
|
|
11203
11395
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
11204
11396
|
error: preview.error,
|
|
11205
11397
|
label: "Loading preview of " + (file.name || "file"),
|
|
11206
11398
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
11207
|
-
skeleton: /* @__PURE__ */
|
|
11208
|
-
children: /* @__PURE__ */
|
|
11399
|
+
skeleton: /* @__PURE__ */ jsx85(Skeleton, { shape: "card", h: 220 }),
|
|
11400
|
+
children: /* @__PURE__ */ jsx85(PreviewBody, { file, kind, state: preview })
|
|
11209
11401
|
}
|
|
11210
11402
|
) }),
|
|
11211
|
-
hasSide ? /* @__PURE__ */
|
|
11403
|
+
hasSide ? /* @__PURE__ */ jsx85("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
11212
11404
|
] })
|
|
11213
11405
|
]
|
|
11214
11406
|
}
|
|
@@ -11216,8 +11408,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
11216
11408
|
}
|
|
11217
11409
|
|
|
11218
11410
|
// src/components/files/FileBrowser.tsx
|
|
11219
|
-
import * as
|
|
11220
|
-
import { Fragment as
|
|
11411
|
+
import * as React58 from "react";
|
|
11412
|
+
import { Fragment as Fragment27, jsx as jsx86, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
11221
11413
|
function childrenOf(folders, parentId) {
|
|
11222
11414
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
11223
11415
|
}
|
|
@@ -11287,10 +11479,10 @@ function FolderPickerMenu({
|
|
|
11287
11479
|
destinations,
|
|
11288
11480
|
onPick
|
|
11289
11481
|
}) {
|
|
11290
|
-
const [open, setOpen] =
|
|
11482
|
+
const [open, setOpen] = React58.useState(false);
|
|
11291
11483
|
const zIndex = useOverlayLayer(open);
|
|
11292
|
-
const ref =
|
|
11293
|
-
|
|
11484
|
+
const ref = React58.useRef(null);
|
|
11485
|
+
React58.useEffect(() => {
|
|
11294
11486
|
if (!open) return;
|
|
11295
11487
|
const away = (e) => {
|
|
11296
11488
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -11305,8 +11497,8 @@ function FolderPickerMenu({
|
|
|
11305
11497
|
document.removeEventListener("keydown", esc);
|
|
11306
11498
|
};
|
|
11307
11499
|
}, [open]);
|
|
11308
|
-
return /* @__PURE__ */
|
|
11309
|
-
/* @__PURE__ */
|
|
11500
|
+
return /* @__PURE__ */ jsxs80("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
11501
|
+
/* @__PURE__ */ jsx86(
|
|
11310
11502
|
IconButton,
|
|
11311
11503
|
{
|
|
11312
11504
|
icon: "arrows-out-cardinal",
|
|
@@ -11318,9 +11510,9 @@ function FolderPickerMenu({
|
|
|
11318
11510
|
onClick: () => setOpen((v) => !v)
|
|
11319
11511
|
}
|
|
11320
11512
|
),
|
|
11321
|
-
open ? /* @__PURE__ */
|
|
11322
|
-
/* @__PURE__ */
|
|
11323
|
-
destinations.map((d) => /* @__PURE__ */
|
|
11513
|
+
open ? /* @__PURE__ */ jsx86(LayerProvider, { zIndex, children: /* @__PURE__ */ jsxs80("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
|
|
11514
|
+
/* @__PURE__ */ jsx86("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
11515
|
+
destinations.map((d) => /* @__PURE__ */ jsxs80(
|
|
11324
11516
|
"button",
|
|
11325
11517
|
{
|
|
11326
11518
|
type: "button",
|
|
@@ -11332,7 +11524,7 @@ function FolderPickerMenu({
|
|
|
11332
11524
|
setOpen(false);
|
|
11333
11525
|
},
|
|
11334
11526
|
children: [
|
|
11335
|
-
/* @__PURE__ */
|
|
11527
|
+
/* @__PURE__ */ jsx86("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
11336
11528
|
d.name
|
|
11337
11529
|
]
|
|
11338
11530
|
},
|
|
@@ -11342,8 +11534,8 @@ function FolderPickerMenu({
|
|
|
11342
11534
|
] });
|
|
11343
11535
|
}
|
|
11344
11536
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
11345
|
-
const [over, setOver] =
|
|
11346
|
-
const dragCounter =
|
|
11537
|
+
const [over, setOver] = React58.useState(false);
|
|
11538
|
+
const dragCounter = React58.useRef(0);
|
|
11347
11539
|
const dropHandlers = isDropTarget ? {
|
|
11348
11540
|
onDragEnter: (e) => {
|
|
11349
11541
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11368,8 +11560,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11368
11560
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11369
11561
|
}
|
|
11370
11562
|
} : {};
|
|
11371
|
-
return /* @__PURE__ */
|
|
11372
|
-
/* @__PURE__ */
|
|
11563
|
+
return /* @__PURE__ */ jsxs80("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
11564
|
+
/* @__PURE__ */ jsxs80(
|
|
11373
11565
|
"button",
|
|
11374
11566
|
{
|
|
11375
11567
|
type: "button",
|
|
@@ -11378,26 +11570,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
11378
11570
|
draggable: !!draggableId,
|
|
11379
11571
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
11380
11572
|
children: [
|
|
11381
|
-
/* @__PURE__ */
|
|
11382
|
-
/* @__PURE__ */
|
|
11383
|
-
/* @__PURE__ */
|
|
11384
|
-
meta ? /* @__PURE__ */
|
|
11573
|
+
/* @__PURE__ */ jsx86("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx86("i", { className: "ph ph-" + icon }) }),
|
|
11574
|
+
/* @__PURE__ */ jsxs80("span", { className: "fd-fb-row-text", children: [
|
|
11575
|
+
/* @__PURE__ */ jsx86("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
11576
|
+
meta ? /* @__PURE__ */ jsx86("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
11385
11577
|
] })
|
|
11386
11578
|
]
|
|
11387
11579
|
}
|
|
11388
11580
|
),
|
|
11389
|
-
actions ? /* @__PURE__ */
|
|
11581
|
+
actions ? /* @__PURE__ */ jsx86("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
11390
11582
|
] });
|
|
11391
11583
|
}
|
|
11392
11584
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
11393
11585
|
const kids = childrenOf(folders, folder.id);
|
|
11394
|
-
const [expanded, setExpanded] =
|
|
11395
|
-
|
|
11586
|
+
const [expanded, setExpanded] = React58.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
11587
|
+
React58.useEffect(() => {
|
|
11396
11588
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
11397
11589
|
}, [currentFolderId, folder.id, folders]);
|
|
11398
11590
|
const isCurrent = folder.id === currentFolderId;
|
|
11399
|
-
return /* @__PURE__ */
|
|
11400
|
-
/* @__PURE__ */
|
|
11591
|
+
return /* @__PURE__ */ jsxs80("div", { className: "fd-fb-tree-node", children: [
|
|
11592
|
+
/* @__PURE__ */ jsx86(
|
|
11401
11593
|
RowShell,
|
|
11402
11594
|
{
|
|
11403
11595
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -11407,7 +11599,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11407
11599
|
isDropTarget: canMove,
|
|
11408
11600
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
11409
11601
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
11410
|
-
actions: kids.length ? /* @__PURE__ */
|
|
11602
|
+
actions: kids.length ? /* @__PURE__ */ jsx86(
|
|
11411
11603
|
IconButton,
|
|
11412
11604
|
{
|
|
11413
11605
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -11419,7 +11611,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
11419
11611
|
) : void 0
|
|
11420
11612
|
}
|
|
11421
11613
|
),
|
|
11422
|
-
expanded && kids.length ? /* @__PURE__ */
|
|
11614
|
+
expanded && kids.length ? /* @__PURE__ */ jsx86("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ jsx86(
|
|
11423
11615
|
TreeNode,
|
|
11424
11616
|
{
|
|
11425
11617
|
folder: k,
|
|
@@ -11458,15 +11650,15 @@ function FileBrowser({
|
|
|
11458
11650
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
11459
11651
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
11460
11652
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
11461
|
-
const [createOpen, setCreateOpen] =
|
|
11462
|
-
const [createName, setCreateName] =
|
|
11463
|
-
const [renameTarget, setRenameTarget] =
|
|
11464
|
-
const [renameValue, setRenameValue] =
|
|
11465
|
-
const [deleteTarget, setDeleteTarget] =
|
|
11466
|
-
const uploadInputRef =
|
|
11467
|
-
const crumbFolders =
|
|
11468
|
-
const subfolders =
|
|
11469
|
-
const currentFiles =
|
|
11653
|
+
const [createOpen, setCreateOpen] = React58.useState(false);
|
|
11654
|
+
const [createName, setCreateName] = React58.useState("");
|
|
11655
|
+
const [renameTarget, setRenameTarget] = React58.useState(null);
|
|
11656
|
+
const [renameValue, setRenameValue] = React58.useState("");
|
|
11657
|
+
const [deleteTarget, setDeleteTarget] = React58.useState(null);
|
|
11658
|
+
const uploadInputRef = React58.useRef(null);
|
|
11659
|
+
const crumbFolders = React58.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11660
|
+
const subfolders = React58.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11661
|
+
const currentFiles = React58.useMemo(
|
|
11470
11662
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
11471
11663
|
[files, currentFolderId]
|
|
11472
11664
|
);
|
|
@@ -11505,10 +11697,10 @@ function FileBrowser({
|
|
|
11505
11697
|
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
11506
11698
|
setDeleteTarget(null);
|
|
11507
11699
|
};
|
|
11508
|
-
const content = /* @__PURE__ */
|
|
11509
|
-
/* @__PURE__ */
|
|
11510
|
-
/* @__PURE__ */
|
|
11511
|
-
/* @__PURE__ */
|
|
11700
|
+
const content = /* @__PURE__ */ jsxs80("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
11701
|
+
/* @__PURE__ */ jsxs80("div", { className: "fd-fb-head", children: [
|
|
11702
|
+
/* @__PURE__ */ jsxs80("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
11703
|
+
/* @__PURE__ */ jsx86(
|
|
11512
11704
|
BreadcrumbCrumb,
|
|
11513
11705
|
{
|
|
11514
11706
|
label: "Home",
|
|
@@ -11518,7 +11710,7 @@ function FileBrowser({
|
|
|
11518
11710
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
11519
11711
|
}
|
|
11520
11712
|
),
|
|
11521
|
-
crumbFolders.map((f, i) => /* @__PURE__ */
|
|
11713
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ jsx86(
|
|
11522
11714
|
BreadcrumbCrumb,
|
|
11523
11715
|
{
|
|
11524
11716
|
label: f.name,
|
|
@@ -11530,11 +11722,11 @@ function FileBrowser({
|
|
|
11530
11722
|
f.id
|
|
11531
11723
|
))
|
|
11532
11724
|
] }),
|
|
11533
|
-
/* @__PURE__ */
|
|
11534
|
-
canCreateFolder ? /* @__PURE__ */
|
|
11535
|
-
canUpload ? /* @__PURE__ */
|
|
11536
|
-
/* @__PURE__ */
|
|
11537
|
-
/* @__PURE__ */
|
|
11725
|
+
/* @__PURE__ */ jsxs80("span", { className: "fd-fb-actions", children: [
|
|
11726
|
+
canCreateFolder ? /* @__PURE__ */ jsx86(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
11727
|
+
canUpload ? /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11728
|
+
/* @__PURE__ */ jsx86(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
11729
|
+
/* @__PURE__ */ jsx86(
|
|
11538
11730
|
"input",
|
|
11539
11731
|
{
|
|
11540
11732
|
ref: uploadInputRef,
|
|
@@ -11552,9 +11744,9 @@ function FileBrowser({
|
|
|
11552
11744
|
] }) : null
|
|
11553
11745
|
] })
|
|
11554
11746
|
] }),
|
|
11555
|
-
/* @__PURE__ */
|
|
11556
|
-
/* @__PURE__ */
|
|
11557
|
-
/* @__PURE__ */
|
|
11747
|
+
/* @__PURE__ */ jsxs80("div", { className: "fd-fb-body", children: [
|
|
11748
|
+
/* @__PURE__ */ jsxs80("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
11749
|
+
/* @__PURE__ */ jsx86(
|
|
11558
11750
|
RowShell,
|
|
11559
11751
|
{
|
|
11560
11752
|
icon: "house-simple",
|
|
@@ -11565,7 +11757,7 @@ function FileBrowser({
|
|
|
11565
11757
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
11566
11758
|
}
|
|
11567
11759
|
),
|
|
11568
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */
|
|
11760
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ jsx86(
|
|
11569
11761
|
TreeNode,
|
|
11570
11762
|
{
|
|
11571
11763
|
folder: f,
|
|
@@ -11579,18 +11771,18 @@ function FileBrowser({
|
|
|
11579
11771
|
f.id
|
|
11580
11772
|
))
|
|
11581
11773
|
] }),
|
|
11582
|
-
/* @__PURE__ */
|
|
11774
|
+
/* @__PURE__ */ jsx86("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ jsx86(
|
|
11583
11775
|
LoadingRegion,
|
|
11584
11776
|
{
|
|
11585
11777
|
state: loading ? "loading" : "ready",
|
|
11586
11778
|
label: "Loading folder contents",
|
|
11587
|
-
skeleton: /* @__PURE__ */
|
|
11588
|
-
/* @__PURE__ */
|
|
11589
|
-
/* @__PURE__ */
|
|
11590
|
-
/* @__PURE__ */
|
|
11779
|
+
skeleton: /* @__PURE__ */ jsxs80("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
11780
|
+
/* @__PURE__ */ jsx86(Skeleton, { h: 44, radius: "10px" }),
|
|
11781
|
+
/* @__PURE__ */ jsx86(Skeleton, { h: 44, radius: "10px" }),
|
|
11782
|
+
/* @__PURE__ */ jsx86(Skeleton, { h: 44, radius: "10px" })
|
|
11591
11783
|
] }),
|
|
11592
|
-
children: isEmpty ? /* @__PURE__ */
|
|
11593
|
-
subfolders.map((f) => /* @__PURE__ */
|
|
11784
|
+
children: isEmpty ? /* @__PURE__ */ jsx86(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__ */ jsxs80("div", { className: "fd-fb-list", children: [
|
|
11785
|
+
subfolders.map((f) => /* @__PURE__ */ jsx86(
|
|
11594
11786
|
RowShell,
|
|
11595
11787
|
{
|
|
11596
11788
|
icon: "folder-simple",
|
|
@@ -11599,9 +11791,9 @@ function FileBrowser({
|
|
|
11599
11791
|
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
11600
11792
|
isDropTarget: canMove,
|
|
11601
11793
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
11602
|
-
actions: /* @__PURE__ */
|
|
11603
|
-
canRenameFolder ? /* @__PURE__ */
|
|
11604
|
-
canMove ? /* @__PURE__ */
|
|
11794
|
+
actions: /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11795
|
+
canRenameFolder ? /* @__PURE__ */ jsx86(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
11796
|
+
canMove ? /* @__PURE__ */ jsx86(
|
|
11605
11797
|
FolderPickerMenu,
|
|
11606
11798
|
{
|
|
11607
11799
|
label: "Move " + f.name,
|
|
@@ -11609,12 +11801,12 @@ function FileBrowser({
|
|
|
11609
11801
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
11610
11802
|
}
|
|
11611
11803
|
) : null,
|
|
11612
|
-
canDeleteFolder ? /* @__PURE__ */
|
|
11804
|
+
canDeleteFolder ? /* @__PURE__ */ jsx86(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
11613
11805
|
] })
|
|
11614
11806
|
},
|
|
11615
11807
|
f.id
|
|
11616
11808
|
)),
|
|
11617
|
-
currentFiles.map((file) => /* @__PURE__ */
|
|
11809
|
+
currentFiles.map((file) => /* @__PURE__ */ jsx86(
|
|
11618
11810
|
RowShell,
|
|
11619
11811
|
{
|
|
11620
11812
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -11622,8 +11814,8 @@ function FileBrowser({
|
|
|
11622
11814
|
meta: file.size ? formatBytes(file.size) : void 0,
|
|
11623
11815
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
11624
11816
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
11625
|
-
actions: /* @__PURE__ */
|
|
11626
|
-
canMove ? /* @__PURE__ */
|
|
11817
|
+
actions: /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11818
|
+
canMove ? /* @__PURE__ */ jsx86(
|
|
11627
11819
|
FolderPickerMenu,
|
|
11628
11820
|
{
|
|
11629
11821
|
label: "Move " + file.name,
|
|
@@ -11631,7 +11823,7 @@ function FileBrowser({
|
|
|
11631
11823
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
11632
11824
|
}
|
|
11633
11825
|
) : null,
|
|
11634
|
-
canRemoveFile ? /* @__PURE__ */
|
|
11826
|
+
canRemoveFile ? /* @__PURE__ */ jsx86(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
11635
11827
|
] })
|
|
11636
11828
|
},
|
|
11637
11829
|
file.id
|
|
@@ -11640,10 +11832,10 @@ function FileBrowser({
|
|
|
11640
11832
|
}
|
|
11641
11833
|
) })
|
|
11642
11834
|
] }),
|
|
11643
|
-
/* @__PURE__ */
|
|
11644
|
-
/* @__PURE__ */
|
|
11645
|
-
/* @__PURE__ */
|
|
11646
|
-
] }), children: /* @__PURE__ */
|
|
11835
|
+
/* @__PURE__ */ jsx86(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11836
|
+
/* @__PURE__ */ jsx86(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
11837
|
+
/* @__PURE__ */ jsx86(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
11838
|
+
] }), children: /* @__PURE__ */ jsx86(
|
|
11647
11839
|
"input",
|
|
11648
11840
|
{
|
|
11649
11841
|
className: "fd-fb-input",
|
|
@@ -11657,10 +11849,10 @@ function FileBrowser({
|
|
|
11657
11849
|
autoFocus: true
|
|
11658
11850
|
}
|
|
11659
11851
|
) }),
|
|
11660
|
-
/* @__PURE__ */
|
|
11661
|
-
/* @__PURE__ */
|
|
11662
|
-
/* @__PURE__ */
|
|
11663
|
-
] }), children: /* @__PURE__ */
|
|
11852
|
+
/* @__PURE__ */ jsx86(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11853
|
+
/* @__PURE__ */ jsx86(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
11854
|
+
/* @__PURE__ */ jsx86(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
11855
|
+
] }), children: /* @__PURE__ */ jsx86(
|
|
11664
11856
|
"input",
|
|
11665
11857
|
{
|
|
11666
11858
|
className: "fd-fb-input",
|
|
@@ -11674,22 +11866,22 @@ function FileBrowser({
|
|
|
11674
11866
|
autoFocus: true
|
|
11675
11867
|
}
|
|
11676
11868
|
) }),
|
|
11677
|
-
/* @__PURE__ */
|
|
11869
|
+
/* @__PURE__ */ jsx86(
|
|
11678
11870
|
Modal,
|
|
11679
11871
|
{
|
|
11680
11872
|
open: deleteTarget != null,
|
|
11681
11873
|
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
11682
11874
|
description: "This can't be undone. The folder must be empty.",
|
|
11683
11875
|
onClose: () => setDeleteTarget(null),
|
|
11684
|
-
footer: /* @__PURE__ */
|
|
11685
|
-
/* @__PURE__ */
|
|
11686
|
-
/* @__PURE__ */
|
|
11876
|
+
footer: /* @__PURE__ */ jsxs80(Fragment27, { children: [
|
|
11877
|
+
/* @__PURE__ */ jsx86(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
11878
|
+
/* @__PURE__ */ jsx86(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
11687
11879
|
] })
|
|
11688
11880
|
}
|
|
11689
11881
|
)
|
|
11690
11882
|
] });
|
|
11691
11883
|
if (!canUpload) return content;
|
|
11692
|
-
return /* @__PURE__ */
|
|
11884
|
+
return /* @__PURE__ */ jsx86(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
11693
11885
|
}
|
|
11694
11886
|
function BreadcrumbCrumb({
|
|
11695
11887
|
label,
|
|
@@ -11698,8 +11890,8 @@ function BreadcrumbCrumb({
|
|
|
11698
11890
|
isDropTarget,
|
|
11699
11891
|
onDropPayload
|
|
11700
11892
|
}) {
|
|
11701
|
-
const [over, setOver] =
|
|
11702
|
-
const dragCounter =
|
|
11893
|
+
const [over, setOver] = React58.useState(false);
|
|
11894
|
+
const dragCounter = React58.useRef(0);
|
|
11703
11895
|
const dropHandlers = isDropTarget ? {
|
|
11704
11896
|
onDragEnter: (e) => {
|
|
11705
11897
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11724,11 +11916,11 @@ function BreadcrumbCrumb({
|
|
|
11724
11916
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
11725
11917
|
}
|
|
11726
11918
|
} : {};
|
|
11727
|
-
return /* @__PURE__ */
|
|
11919
|
+
return /* @__PURE__ */ jsx86("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ jsx86("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ jsx86("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
11728
11920
|
}
|
|
11729
11921
|
|
|
11730
11922
|
// src/kits/query.ts
|
|
11731
|
-
import * as
|
|
11923
|
+
import * as React59 from "react";
|
|
11732
11924
|
function eqFilter(get2) {
|
|
11733
11925
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
11734
11926
|
}
|
|
@@ -11760,22 +11952,22 @@ function compare(a, b, dir) {
|
|
|
11760
11952
|
var API = null;
|
|
11761
11953
|
var PREFS = null;
|
|
11762
11954
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
11763
|
-
const [query, setQuery] =
|
|
11955
|
+
const [query, setQuery] = React59.useState(() => {
|
|
11764
11956
|
const store = PREFS || window.PlannerPrefs;
|
|
11765
11957
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
11766
11958
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
11767
11959
|
});
|
|
11768
|
-
const savePref =
|
|
11960
|
+
const savePref = React59.useCallback((patch2) => {
|
|
11769
11961
|
const store = PREFS || window.PlannerPrefs;
|
|
11770
11962
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
11771
11963
|
}, [prefsKey]);
|
|
11772
|
-
const [res, setRes] =
|
|
11773
|
-
const [loading, setLoading] =
|
|
11774
|
-
const seq2 =
|
|
11964
|
+
const [res, setRes] = React59.useState(null);
|
|
11965
|
+
const [loading, setLoading] = React59.useState(true);
|
|
11966
|
+
const seq2 = React59.useRef(0);
|
|
11775
11967
|
const depKey = (deps || []).join("|");
|
|
11776
11968
|
const paramKey = JSON.stringify(params || {});
|
|
11777
11969
|
const queryKey = JSON.stringify(query);
|
|
11778
|
-
|
|
11970
|
+
React59.useEffect(() => {
|
|
11779
11971
|
const id = ++seq2.current;
|
|
11780
11972
|
setLoading(true);
|
|
11781
11973
|
const t = setTimeout(() => {
|
|
@@ -12074,12 +12266,12 @@ function createVersionStore(initialState, options) {
|
|
|
12074
12266
|
}
|
|
12075
12267
|
|
|
12076
12268
|
// src/kits/documentTitle.ts
|
|
12077
|
-
import * as
|
|
12269
|
+
import * as React60 from "react";
|
|
12078
12270
|
function formatDocumentTitle(routeTitle, appName) {
|
|
12079
12271
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
12080
12272
|
}
|
|
12081
12273
|
function useDocumentTitle(routeTitle, appName) {
|
|
12082
|
-
|
|
12274
|
+
React60.useEffect(() => {
|
|
12083
12275
|
if (typeof document === "undefined") return;
|
|
12084
12276
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
12085
12277
|
}, [routeTitle, appName]);
|
|
@@ -12201,6 +12393,7 @@ export {
|
|
|
12201
12393
|
SessionKit,
|
|
12202
12394
|
SessionProvider,
|
|
12203
12395
|
SidebarNav,
|
|
12396
|
+
SignInPage,
|
|
12204
12397
|
Skeleton,
|
|
12205
12398
|
SkeletonText,
|
|
12206
12399
|
Slider,
|