@flytedan/flytebot-design-system 0.58.0 → 0.59.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 +899 -876
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -21
- package/dist/index.d.ts +60 -21
- package/dist/index.js +665 -646
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
AppShell: () => AppShell,
|
|
39
39
|
AppSwitcher: () => AppSwitcher,
|
|
40
40
|
AppearanceMenu: () => AppearanceMenu,
|
|
41
|
+
AppearanceProvider: () => AppearanceProvider,
|
|
41
42
|
Avatar: () => Avatar,
|
|
42
43
|
AvatarStack: () => AvatarStack,
|
|
43
44
|
Badge: () => Badge,
|
|
@@ -193,6 +194,7 @@ __export(index_exports, {
|
|
|
193
194
|
__resetLayerStackForTests: () => __resetLayerStackForTests,
|
|
194
195
|
acceptMatches: () => acceptMatches,
|
|
195
196
|
anyOfFilter: () => anyOfFilter,
|
|
197
|
+
applyAppearance: () => applyAppearance,
|
|
196
198
|
applyPrefs: () => applyPrefs,
|
|
197
199
|
channelWeightOf: () => channelWeightOf,
|
|
198
200
|
computeNeedMore: () => computeNeedMore,
|
|
@@ -238,6 +240,7 @@ __export(index_exports, {
|
|
|
238
240
|
toAttachment: () => toAttachment,
|
|
239
241
|
tokenize: () => tokenize,
|
|
240
242
|
useAppearancePrefs: () => useAppearancePrefs,
|
|
243
|
+
useAppearanceStore: () => useAppearanceStore,
|
|
241
244
|
useChatEngine: () => useChatEngine,
|
|
242
245
|
useCopyToClipboard: () => useCopyToClipboard,
|
|
243
246
|
useCornerStackSlot: () => useCornerStackSlot,
|
|
@@ -253,7 +256,8 @@ __export(index_exports, {
|
|
|
253
256
|
useStagedFiles: () => useStagedFiles,
|
|
254
257
|
useToast: () => useToast,
|
|
255
258
|
validateFilterValue: () => validateFilterValue,
|
|
256
|
-
visibleMessages: () => visibleMessages
|
|
259
|
+
visibleMessages: () => visibleMessages,
|
|
260
|
+
watchAppearance: () => watchAppearance
|
|
257
261
|
});
|
|
258
262
|
module.exports = __toCommonJS(index_exports);
|
|
259
263
|
|
|
@@ -8318,7 +8322,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
8318
8322
|
}
|
|
8319
8323
|
|
|
8320
8324
|
// src/components/platform/AppearanceMenu.tsx
|
|
8321
|
-
var
|
|
8325
|
+
var React53 = __toESM(require("react"), 1);
|
|
8322
8326
|
|
|
8323
8327
|
// src/kits/appearance.ts
|
|
8324
8328
|
var React51 = __toESM(require("react"), 1);
|
|
@@ -8415,20 +8419,25 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
8415
8419
|
if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
|
|
8416
8420
|
else root.removeAttribute("data-motion");
|
|
8417
8421
|
}
|
|
8422
|
+
function applyAppearance(store, root = document.documentElement) {
|
|
8423
|
+
applyPrefs(store.getSnapshot(), root);
|
|
8424
|
+
}
|
|
8425
|
+
function watchAppearance(store, root = document.documentElement) {
|
|
8426
|
+
const apply = () => applyAppearance(store, root);
|
|
8427
|
+
apply();
|
|
8428
|
+
const unsubscribe = store.subscribe(apply);
|
|
8429
|
+
const mq = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
8430
|
+
const onSchemeChange = () => {
|
|
8431
|
+
if (store.getSnapshot().theme === "system") apply();
|
|
8432
|
+
};
|
|
8433
|
+
mq?.addEventListener("change", onSchemeChange);
|
|
8434
|
+
return () => {
|
|
8435
|
+
unsubscribe();
|
|
8436
|
+
mq?.removeEventListener("change", onSchemeChange);
|
|
8437
|
+
};
|
|
8438
|
+
}
|
|
8418
8439
|
function useAppearancePrefs(store) {
|
|
8419
8440
|
const prefs = React51.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
8420
|
-
React51.useEffect(() => {
|
|
8421
|
-
applyPrefs(prefs);
|
|
8422
|
-
}, [prefs]);
|
|
8423
|
-
React51.useEffect(() => {
|
|
8424
|
-
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8425
|
-
return;
|
|
8426
|
-
}
|
|
8427
|
-
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
8428
|
-
const onChange = () => applyPrefs(prefs);
|
|
8429
|
-
mq.addEventListener("change", onChange);
|
|
8430
|
-
return () => mq.removeEventListener("change", onChange);
|
|
8431
|
-
}, [prefs]);
|
|
8432
8441
|
const update = React51.useCallback(
|
|
8433
8442
|
(patch) => {
|
|
8434
8443
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
@@ -8438,8 +8447,22 @@ function useAppearancePrefs(store) {
|
|
|
8438
8447
|
return [prefs, update];
|
|
8439
8448
|
}
|
|
8440
8449
|
|
|
8441
|
-
// src/components/platform/
|
|
8450
|
+
// src/components/platform/AppearanceProvider.tsx
|
|
8451
|
+
var React52 = __toESM(require("react"), 1);
|
|
8442
8452
|
var import_jsx_runtime78 = require("react/jsx-runtime");
|
|
8453
|
+
var AppearanceStoreContext = React52.createContext(null);
|
|
8454
|
+
function AppearanceProvider({ store, children }) {
|
|
8455
|
+
React52.useLayoutEffect(() => watchAppearance(store), [store]);
|
|
8456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(AppearanceStoreContext.Provider, { value: store, children });
|
|
8457
|
+
}
|
|
8458
|
+
function useAppearanceStore() {
|
|
8459
|
+
const store = React52.useContext(AppearanceStoreContext);
|
|
8460
|
+
if (!store) throw new Error("AppearanceMenu and useAppearanceStore must be rendered inside an <AppearanceProvider>.");
|
|
8461
|
+
return store;
|
|
8462
|
+
}
|
|
8463
|
+
|
|
8464
|
+
// src/components/platform/AppearanceMenu.tsx
|
|
8465
|
+
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
8443
8466
|
var THEME_OPTIONS = [
|
|
8444
8467
|
{ value: "light", label: "Light" },
|
|
8445
8468
|
{ value: "dark", label: "Dark" },
|
|
@@ -8451,17 +8474,13 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
8451
8474
|
{ value: "lg", label: "L" },
|
|
8452
8475
|
{ value: "xl", label: "XL" }
|
|
8453
8476
|
];
|
|
8454
|
-
function AppearanceMenu({ className = ""
|
|
8455
|
-
const
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
);
|
|
8459
|
-
const [prefs, update] = useAppearancePrefs(store);
|
|
8460
|
-
const [open2, setOpen] = React52.useState(false);
|
|
8461
|
-
const anchorRef = React52.useRef(null);
|
|
8477
|
+
function AppearanceMenu({ className = "" }) {
|
|
8478
|
+
const [prefs, update] = useAppearancePrefs(useAppearanceStore());
|
|
8479
|
+
const [open2, setOpen] = React53.useState(false);
|
|
8480
|
+
const anchorRef = React53.useRef(null);
|
|
8462
8481
|
const patch = (p) => update(p);
|
|
8463
|
-
return /* @__PURE__ */ (0,
|
|
8464
|
-
/* @__PURE__ */ (0,
|
|
8482
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(React53.Fragment, { children: [
|
|
8483
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8465
8484
|
IconButton,
|
|
8466
8485
|
{
|
|
8467
8486
|
icon: "circle-half",
|
|
@@ -8469,7 +8488,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8469
8488
|
onClick: () => setOpen((v) => !v)
|
|
8470
8489
|
}
|
|
8471
8490
|
) }),
|
|
8472
|
-
/* @__PURE__ */ (0,
|
|
8491
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8473
8492
|
Popover,
|
|
8474
8493
|
{
|
|
8475
8494
|
open: open2,
|
|
@@ -8479,10 +8498,10 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8479
8498
|
padded: true,
|
|
8480
8499
|
width: 260,
|
|
8481
8500
|
label: "Appearance settings",
|
|
8482
|
-
children: /* @__PURE__ */ (0,
|
|
8483
|
-
/* @__PURE__ */ (0,
|
|
8484
|
-
/* @__PURE__ */ (0,
|
|
8485
|
-
/* @__PURE__ */ (0,
|
|
8501
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
|
|
8502
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
8503
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-field-label", children: "Theme" }),
|
|
8504
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8486
8505
|
SegmentedControl,
|
|
8487
8506
|
{
|
|
8488
8507
|
options: THEME_OPTIONS,
|
|
@@ -8492,9 +8511,9 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8492
8511
|
}
|
|
8493
8512
|
)
|
|
8494
8513
|
] }),
|
|
8495
|
-
/* @__PURE__ */ (0,
|
|
8496
|
-
/* @__PURE__ */ (0,
|
|
8497
|
-
/* @__PURE__ */ (0,
|
|
8514
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
8515
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-field-label", children: "Text size" }),
|
|
8516
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8498
8517
|
SegmentedControl,
|
|
8499
8518
|
{
|
|
8500
8519
|
options: TEXT_SCALE_OPTIONS,
|
|
@@ -8504,7 +8523,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8504
8523
|
}
|
|
8505
8524
|
)
|
|
8506
8525
|
] }),
|
|
8507
|
-
/* @__PURE__ */ (0,
|
|
8526
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8508
8527
|
Switch,
|
|
8509
8528
|
{
|
|
8510
8529
|
label: "High contrast",
|
|
@@ -8513,7 +8532,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8513
8532
|
onChange: (e) => patch({ highContrast: e.target.checked })
|
|
8514
8533
|
}
|
|
8515
8534
|
),
|
|
8516
|
-
/* @__PURE__ */ (0,
|
|
8535
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8517
8536
|
Switch,
|
|
8518
8537
|
{
|
|
8519
8538
|
label: "Reduce motion",
|
|
@@ -8529,14 +8548,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8529
8548
|
}
|
|
8530
8549
|
|
|
8531
8550
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
8532
|
-
var
|
|
8533
|
-
var
|
|
8551
|
+
var React54 = __toESM(require("react"), 1);
|
|
8552
|
+
var import_jsx_runtime80 = require("react/jsx-runtime");
|
|
8534
8553
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
8535
8554
|
function Json({ obj }) {
|
|
8536
|
-
return /* @__PURE__ */ (0,
|
|
8555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
8537
8556
|
}
|
|
8538
8557
|
function Endpoint({ s, onRequest }) {
|
|
8539
|
-
const [tried, setTried] =
|
|
8558
|
+
const [tried, setTried] = React54.useState(null);
|
|
8540
8559
|
const run = async () => {
|
|
8541
8560
|
setTried("busy");
|
|
8542
8561
|
const t0 = (window.performance || Date).now();
|
|
@@ -8547,50 +8566,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
8547
8566
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
8548
8567
|
}
|
|
8549
8568
|
};
|
|
8550
|
-
return /* @__PURE__ */ (0,
|
|
8551
|
-
/* @__PURE__ */ (0,
|
|
8552
|
-
/* @__PURE__ */ (0,
|
|
8553
|
-
/* @__PURE__ */ (0,
|
|
8554
|
-
s.isList ? /* @__PURE__ */ (0,
|
|
8555
|
-
/* @__PURE__ */ (0,
|
|
8556
|
-
/* @__PURE__ */ (0,
|
|
8569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
8570
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
|
|
8571
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
|
|
8572
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
|
|
8573
|
+
s.isList ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
|
|
8574
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 } }),
|
|
8575
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
8557
8576
|
s.latency[0],
|
|
8558
8577
|
"\u2013",
|
|
8559
8578
|
s.latency[1],
|
|
8560
8579
|
"ms"
|
|
8561
8580
|
] }),
|
|
8562
|
-
/* @__PURE__ */ (0,
|
|
8581
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
8563
8582
|
] }),
|
|
8564
|
-
/* @__PURE__ */ (0,
|
|
8565
|
-
/* @__PURE__ */ (0,
|
|
8566
|
-
/* @__PURE__ */ (0,
|
|
8567
|
-
/* @__PURE__ */ (0,
|
|
8568
|
-
s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0,
|
|
8583
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
|
|
8584
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8585
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
|
|
8586
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
|
|
8587
|
+
s.usedBy && s.usedBy.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Tag, { children: u }, u)) }) : null
|
|
8569
8588
|
] }),
|
|
8570
|
-
/* @__PURE__ */ (0,
|
|
8571
|
-
s.request ? /* @__PURE__ */ (0,
|
|
8572
|
-
/* @__PURE__ */ (0,
|
|
8573
|
-
/* @__PURE__ */ (0,
|
|
8589
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
|
|
8590
|
+
s.request ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8591
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Request body" }),
|
|
8592
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.request })
|
|
8574
8593
|
] }) : null,
|
|
8575
|
-
s.query ? /* @__PURE__ */ (0,
|
|
8576
|
-
/* @__PURE__ */ (0,
|
|
8577
|
-
/* @__PURE__ */ (0,
|
|
8594
|
+
s.query ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8595
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Query" }),
|
|
8596
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.query })
|
|
8578
8597
|
] }) : null,
|
|
8579
|
-
/* @__PURE__ */ (0,
|
|
8580
|
-
/* @__PURE__ */ (0,
|
|
8581
|
-
/* @__PURE__ */ (0,
|
|
8598
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8599
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Response 200" }),
|
|
8600
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: s.response })
|
|
8582
8601
|
] })
|
|
8583
8602
|
] }),
|
|
8584
|
-
s.notes ? /* @__PURE__ */ (0,
|
|
8585
|
-
tried && tried !== "busy" ? /* @__PURE__ */ (0,
|
|
8586
|
-
/* @__PURE__ */ (0,
|
|
8587
|
-
/* @__PURE__ */ (0,
|
|
8588
|
-
/* @__PURE__ */ (0,
|
|
8603
|
+
s.notes ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
|
|
8604
|
+
tried && tried !== "busy" ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8605
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
8606
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
|
|
8607
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
|
|
8589
8608
|
tried.ms,
|
|
8590
8609
|
"ms"
|
|
8591
8610
|
] })
|
|
8592
8611
|
] }),
|
|
8593
|
-
/* @__PURE__ */ (0,
|
|
8612
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
8594
8613
|
] }) : null
|
|
8595
8614
|
] })
|
|
8596
8615
|
] }) });
|
|
@@ -8609,58 +8628,58 @@ function ApiSpecBrowser({
|
|
|
8609
8628
|
className = "",
|
|
8610
8629
|
...rest
|
|
8611
8630
|
}) {
|
|
8612
|
-
const [q, setQ] =
|
|
8613
|
-
const [method, setMethod] =
|
|
8614
|
-
const [mod, setMod] =
|
|
8615
|
-
const [listOnly, setListOnly] =
|
|
8631
|
+
const [q, setQ] = React54.useState("");
|
|
8632
|
+
const [method, setMethod] = React54.useState(null);
|
|
8633
|
+
const [mod, setMod] = React54.useState(null);
|
|
8634
|
+
const [listOnly, setListOnly] = React54.useState(false);
|
|
8616
8635
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
8617
8636
|
const hits = spec.filter((s) => (!method || s.method === method) && (!listOnly || s.isList) && (!activeModule || activeModule.endpoints.indexOf(s.id) >= 0) && (!q || (s.path + " " + s.title + " " + s.purpose + " " + (s.usedBy || []).join(" ")).toLowerCase().includes(q.toLowerCase())));
|
|
8618
8637
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
8619
8638
|
const methods = [...new Set(spec.map((s) => s.method))];
|
|
8620
8639
|
const listCount = spec.filter((s) => s.isList).length;
|
|
8621
|
-
return /* @__PURE__ */ (0,
|
|
8622
|
-
/* @__PURE__ */ (0,
|
|
8623
|
-
kicker ? /* @__PURE__ */ (0,
|
|
8624
|
-
/* @__PURE__ */ (0,
|
|
8625
|
-
lede ? /* @__PURE__ */ (0,
|
|
8640
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
|
|
8641
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8642
|
+
kicker ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: kicker }) : null,
|
|
8643
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
8644
|
+
lede ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
|
|
8626
8645
|
] }),
|
|
8627
|
-
modules && modules.length ? /* @__PURE__ */ (0,
|
|
8628
|
-
/* @__PURE__ */ (0,
|
|
8629
|
-
/* @__PURE__ */ (0,
|
|
8630
|
-
/* @__PURE__ */ (0,
|
|
8646
|
+
modules && modules.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
8647
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
|
|
8648
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
8649
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
|
|
8631
8650
|
"All screens ",
|
|
8632
|
-
/* @__PURE__ */ (0,
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.length })
|
|
8633
8652
|
] }),
|
|
8634
|
-
modules.map((m) => /* @__PURE__ */ (0,
|
|
8653
|
+
modules.map((m) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
|
|
8635
8654
|
m.label,
|
|
8636
8655
|
" ",
|
|
8637
|
-
/* @__PURE__ */ (0,
|
|
8656
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
|
|
8638
8657
|
] }, m.id))
|
|
8639
8658
|
] }),
|
|
8640
|
-
activeModule ? /* @__PURE__ */ (0,
|
|
8659
|
+
activeModule ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
|
|
8641
8660
|
Flag,
|
|
8642
8661
|
{
|
|
8643
8662
|
tone: "info",
|
|
8644
8663
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
8645
8664
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
8646
|
-
actions: /* @__PURE__ */ (0,
|
|
8665
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
|
|
8647
8666
|
}
|
|
8648
8667
|
) : null
|
|
8649
8668
|
] }) : null,
|
|
8650
|
-
sourceNote ? /* @__PURE__ */ (0,
|
|
8651
|
-
/* @__PURE__ */ (0,
|
|
8652
|
-
/* @__PURE__ */ (0,
|
|
8653
|
-
methods.map((m) => /* @__PURE__ */ (0,
|
|
8669
|
+
sourceNote ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
|
|
8670
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
8671
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
8672
|
+
methods.map((m) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
|
|
8654
8673
|
m,
|
|
8655
8674
|
" ",
|
|
8656
|
-
/* @__PURE__ */ (0,
|
|
8675
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
8657
8676
|
] }, m)),
|
|
8658
|
-
listCount ? /* @__PURE__ */ (0,
|
|
8677
|
+
listCount ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
8659
8678
|
"Paged lists ",
|
|
8660
|
-
/* @__PURE__ */ (0,
|
|
8679
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: listCount })
|
|
8661
8680
|
] }) : null,
|
|
8662
|
-
/* @__PURE__ */ (0,
|
|
8663
|
-
/* @__PURE__ */ (0,
|
|
8681
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { style: { flex: 1 } }),
|
|
8682
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8664
8683
|
hits.length,
|
|
8665
8684
|
" of ",
|
|
8666
8685
|
spec.length,
|
|
@@ -8668,31 +8687,31 @@ function ApiSpecBrowser({
|
|
|
8668
8687
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
8669
8688
|
] })
|
|
8670
8689
|
] }),
|
|
8671
|
-
hits.length === 0 ? /* @__PURE__ */ (0,
|
|
8690
|
+
hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
|
|
8672
8691
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
8673
8692
|
if (!items.length) return null;
|
|
8674
|
-
return /* @__PURE__ */ (0,
|
|
8675
|
-
/* @__PURE__ */ (0,
|
|
8676
|
-
items.map((s) => /* @__PURE__ */ (0,
|
|
8693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-stack", style: { gap: 12 }, children: [
|
|
8694
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-label-lg", children: g }),
|
|
8695
|
+
items.map((s) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Endpoint, { s, onRequest }, s.id))
|
|
8677
8696
|
] }, g);
|
|
8678
8697
|
}),
|
|
8679
|
-
conventions && conventions.length ? /* @__PURE__ */ (0,
|
|
8680
|
-
/* @__PURE__ */ (0,
|
|
8681
|
-
/* @__PURE__ */ (0,
|
|
8698
|
+
conventions && conventions.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
|
|
8699
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
|
|
8700
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
|
|
8682
8701
|
] }, k)) }) }) : null,
|
|
8683
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */ (0,
|
|
8684
|
-
/* @__PURE__ */ (0,
|
|
8685
|
-
/* @__PURE__ */ (0,
|
|
8686
|
-
/* @__PURE__ */ (0,
|
|
8687
|
-
/* @__PURE__ */ (0,
|
|
8702
|
+
openQuestions && openQuestions.length ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
|
|
8703
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Badge, { tone: "danger", children: id }),
|
|
8704
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
|
|
8705
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
|
|
8706
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-body-sm fd-muted", children: why })
|
|
8688
8707
|
] })
|
|
8689
8708
|
] }, id)) }) }) : null
|
|
8690
8709
|
] });
|
|
8691
8710
|
}
|
|
8692
8711
|
|
|
8693
8712
|
// src/components/platform/ProfilePage.tsx
|
|
8694
|
-
var
|
|
8695
|
-
var
|
|
8713
|
+
var React55 = __toESM(require("react"), 1);
|
|
8714
|
+
var import_jsx_runtime81 = require("react/jsx-runtime");
|
|
8696
8715
|
function fieldInitialValue(field, user) {
|
|
8697
8716
|
if (field.value) return field.value(user);
|
|
8698
8717
|
const raw = user[field.key];
|
|
@@ -8727,21 +8746,21 @@ function ProfilePage({
|
|
|
8727
8746
|
}) {
|
|
8728
8747
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
8729
8748
|
const user = userProp || sessionUser;
|
|
8730
|
-
const initialFieldValues =
|
|
8749
|
+
const initialFieldValues = React55.useMemo(() => {
|
|
8731
8750
|
const values2 = {};
|
|
8732
8751
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
8733
8752
|
return values2;
|
|
8734
8753
|
}, [user.id, fields]);
|
|
8735
|
-
const initialNotify =
|
|
8754
|
+
const initialNotify = React55.useMemo(() => {
|
|
8736
8755
|
const values2 = {};
|
|
8737
8756
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
8738
8757
|
return values2;
|
|
8739
8758
|
}, [user.id, notifications]);
|
|
8740
|
-
const [values, setValues] =
|
|
8741
|
-
const [notify, setNotify] =
|
|
8742
|
-
const [saving, setSaving] =
|
|
8743
|
-
const [saved, setSaved] =
|
|
8744
|
-
const [prevUserId, setPrevUserId] =
|
|
8759
|
+
const [values, setValues] = React55.useState(initialFieldValues);
|
|
8760
|
+
const [notify, setNotify] = React55.useState(initialNotify);
|
|
8761
|
+
const [saving, setSaving] = React55.useState(false);
|
|
8762
|
+
const [saved, setSaved] = React55.useState(false);
|
|
8763
|
+
const [prevUserId, setPrevUserId] = React55.useState(user.id);
|
|
8745
8764
|
if (user.id !== prevUserId) {
|
|
8746
8765
|
setPrevUserId(user.id);
|
|
8747
8766
|
setValues(initialFieldValues);
|
|
@@ -8778,37 +8797,37 @@ function ProfilePage({
|
|
|
8778
8797
|
};
|
|
8779
8798
|
const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
|
|
8780
8799
|
const fieldGroups = groupFields(fields);
|
|
8781
|
-
return /* @__PURE__ */ (0,
|
|
8782
|
-
/* @__PURE__ */ (0,
|
|
8783
|
-
/* @__PURE__ */ (0,
|
|
8784
|
-
/* @__PURE__ */ (0,
|
|
8785
|
-
/* @__PURE__ */ (0,
|
|
8800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
|
|
8801
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8802
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-overline fd-muted", children: "Account" }),
|
|
8803
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
|
|
8804
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: "How you appear to colleagues and clients across every flytedesk app, and what we send you." })
|
|
8786
8805
|
] }),
|
|
8787
|
-
/* @__PURE__ */ (0,
|
|
8788
|
-
/* @__PURE__ */ (0,
|
|
8789
|
-
/* @__PURE__ */ (0,
|
|
8790
|
-
/* @__PURE__ */ (0,
|
|
8791
|
-
/* @__PURE__ */ (0,
|
|
8792
|
-
roles.map((r) => /* @__PURE__ */ (0,
|
|
8793
|
-
user.sso ? /* @__PURE__ */ (0,
|
|
8806
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
|
|
8807
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Avatar, { name: displayName, size: "lg" }),
|
|
8808
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
|
|
8809
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
|
|
8810
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
|
|
8811
|
+
roles.map((r) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
|
|
8812
|
+
user.sso ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
|
|
8794
8813
|
] })
|
|
8795
8814
|
] }),
|
|
8796
|
-
onChangePhoto ? /* @__PURE__ */ (0,
|
|
8815
|
+
onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
|
|
8797
8816
|
] }) }),
|
|
8798
|
-
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0,
|
|
8817
|
+
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8799
8818
|
Card,
|
|
8800
8819
|
{
|
|
8801
|
-
title: description ? /* @__PURE__ */ (0,
|
|
8802
|
-
/* @__PURE__ */ (0,
|
|
8803
|
-
/* @__PURE__ */ (0,
|
|
8820
|
+
title: description ? /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
8821
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: group }),
|
|
8822
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
|
|
8804
8823
|
] }) : group,
|
|
8805
8824
|
elevation: "flat",
|
|
8806
|
-
children: /* @__PURE__ */ (0,
|
|
8807
|
-
/* @__PURE__ */ (0,
|
|
8825
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 14 }, children: [
|
|
8826
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
|
|
8808
8827
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8809
8828
|
const readOnly = field.readOnly || field.type === "readonly";
|
|
8810
8829
|
if (field.type === "select") {
|
|
8811
|
-
return /* @__PURE__ */ (0,
|
|
8830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8812
8831
|
Select,
|
|
8813
8832
|
{
|
|
8814
8833
|
label: field.label,
|
|
@@ -8822,7 +8841,7 @@ function ProfilePage({
|
|
|
8822
8841
|
field.key
|
|
8823
8842
|
);
|
|
8824
8843
|
}
|
|
8825
|
-
return /* @__PURE__ */ (0,
|
|
8844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8826
8845
|
Input,
|
|
8827
8846
|
{
|
|
8828
8847
|
label: field.label,
|
|
@@ -8838,7 +8857,7 @@ function ProfilePage({
|
|
|
8838
8857
|
}) }),
|
|
8839
8858
|
groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
|
|
8840
8859
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8841
|
-
return /* @__PURE__ */ (0,
|
|
8860
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8842
8861
|
Textarea,
|
|
8843
8862
|
{
|
|
8844
8863
|
label: field.label,
|
|
@@ -8858,16 +8877,16 @@ function ProfilePage({
|
|
|
8858
8877
|
group
|
|
8859
8878
|
)),
|
|
8860
8879
|
extra,
|
|
8861
|
-
notifications.length > 0 ? /* @__PURE__ */ (0,
|
|
8862
|
-
/* @__PURE__ */ (0,
|
|
8880
|
+
notifications.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
|
|
8881
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(
|
|
8863
8882
|
Card,
|
|
8864
8883
|
{
|
|
8865
|
-
title: /* @__PURE__ */ (0,
|
|
8866
|
-
/* @__PURE__ */ (0,
|
|
8867
|
-
/* @__PURE__ */ (0,
|
|
8884
|
+
title: /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
8885
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { children: "Access" }),
|
|
8886
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
|
|
8868
8887
|
] }),
|
|
8869
8888
|
elevation: "flat",
|
|
8870
|
-
action: /* @__PURE__ */ (0,
|
|
8889
|
+
action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8871
8890
|
Button,
|
|
8872
8891
|
{
|
|
8873
8892
|
size: "sm",
|
|
@@ -8878,39 +8897,39 @@ function ProfilePage({
|
|
|
8878
8897
|
}
|
|
8879
8898
|
),
|
|
8880
8899
|
children: [
|
|
8881
|
-
/* @__PURE__ */ (0,
|
|
8882
|
-
/* @__PURE__ */ (0,
|
|
8883
|
-
/* @__PURE__ */ (0,
|
|
8900
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
8901
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
|
|
8902
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)(CardRow, { label: "Permissions", children: [
|
|
8884
8903
|
permissions.length,
|
|
8885
8904
|
" granted"
|
|
8886
8905
|
] }),
|
|
8887
|
-
/* @__PURE__ */ (0,
|
|
8906
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
8888
8907
|
] }),
|
|
8889
|
-
/* @__PURE__ */ (0,
|
|
8908
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: "12px 0 0" }, children: "You cannot change your own roles \u2014 that is the point of them. An administrator manages roles from Admin \u2192 Users." })
|
|
8890
8909
|
]
|
|
8891
8910
|
}
|
|
8892
8911
|
),
|
|
8893
|
-
sessions ? /* @__PURE__ */ (0,
|
|
8912
|
+
sessions ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8894
8913
|
Card,
|
|
8895
8914
|
{
|
|
8896
8915
|
title: "Signed-in devices",
|
|
8897
8916
|
elevation: "flat",
|
|
8898
|
-
action: /* @__PURE__ */ (0,
|
|
8899
|
-
children: /* @__PURE__ */ (0,
|
|
8900
|
-
/* @__PURE__ */ (0,
|
|
8901
|
-
/* @__PURE__ */ (0,
|
|
8902
|
-
/* @__PURE__ */ (0,
|
|
8903
|
-
/* @__PURE__ */ (0,
|
|
8917
|
+
action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
|
|
8918
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
8919
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
8920
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
|
|
8921
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
|
|
8922
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
8904
8923
|
s.where,
|
|
8905
8924
|
" \xB7 ",
|
|
8906
8925
|
s.when
|
|
8907
8926
|
] })
|
|
8908
8927
|
] }),
|
|
8909
|
-
s.current ? /* @__PURE__ */ (0,
|
|
8928
|
+
s.current ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", children: "Revoke" })
|
|
8910
8929
|
] }, s.id)) })
|
|
8911
8930
|
}
|
|
8912
8931
|
) : null,
|
|
8913
|
-
/* @__PURE__ */ (0,
|
|
8932
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: {
|
|
8914
8933
|
gap: 10,
|
|
8915
8934
|
flexWrap: "wrap",
|
|
8916
8935
|
position: "sticky",
|
|
@@ -8921,16 +8940,16 @@ function ProfilePage({
|
|
|
8921
8940
|
border: "1px solid var(--border)",
|
|
8922
8941
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
8923
8942
|
}, children: [
|
|
8924
|
-
/* @__PURE__ */ (0,
|
|
8925
|
-
/* @__PURE__ */ (0,
|
|
8926
|
-
/* @__PURE__ */ (0,
|
|
8943
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
|
|
8944
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
|
|
8945
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
|
|
8927
8946
|
] })
|
|
8928
8947
|
] });
|
|
8929
8948
|
}
|
|
8930
8949
|
|
|
8931
8950
|
// src/components/platform/SessionScreen.tsx
|
|
8932
|
-
var
|
|
8933
|
-
var
|
|
8951
|
+
var React56 = __toESM(require("react"), 1);
|
|
8952
|
+
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
8934
8953
|
var COPY = {
|
|
8935
8954
|
"signing-in": { busy: "Signing you in\u2026" },
|
|
8936
8955
|
"session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
|
|
@@ -8943,28 +8962,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8943
8962
|
const copy = COPY[kind];
|
|
8944
8963
|
const busyMessage = "busy" in copy ? copy.busy : null;
|
|
8945
8964
|
const failureTitle = "failure" in copy ? copy.failure : null;
|
|
8946
|
-
const [announced, setAnnounced] =
|
|
8947
|
-
|
|
8965
|
+
const [announced, setAnnounced] = React56.useState("");
|
|
8966
|
+
React56.useEffect(() => {
|
|
8948
8967
|
setAnnounced(busyMessage ?? "");
|
|
8949
8968
|
}, [busyMessage]);
|
|
8950
|
-
const titleRef =
|
|
8969
|
+
const titleRef = React56.useRef(null);
|
|
8951
8970
|
const failed = failureTitle !== null;
|
|
8952
|
-
|
|
8971
|
+
React56.useEffect(() => {
|
|
8953
8972
|
titleRef.current?.focus({ preventScroll: true });
|
|
8954
8973
|
}, [failed]);
|
|
8955
|
-
return /* @__PURE__ */ (0,
|
|
8956
|
-
/* @__PURE__ */ (0,
|
|
8957
|
-
/* @__PURE__ */ (0,
|
|
8958
|
-
/* @__PURE__ */ (0,
|
|
8959
|
-
/* @__PURE__ */ (0,
|
|
8960
|
-
/* @__PURE__ */ (0,
|
|
8961
|
-
/* @__PURE__ */ (0,
|
|
8962
|
-
/* @__PURE__ */ (0,
|
|
8963
|
-
/* @__PURE__ */ (0,
|
|
8974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("main", { className: "fd-session-screen", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-inner", children: [
|
|
8975
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(FlytedeskMark, { size: "lg" }) }),
|
|
8976
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-frame", children: [
|
|
8977
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { className: "fd-session-screen-stripe" }),
|
|
8978
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-body", children: [
|
|
8979
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
|
|
8980
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(import_jsx_runtime82.Fragment, { children: [
|
|
8981
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
|
|
8982
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "fd-body fd-session-screen-message", children: announced })
|
|
8964
8983
|
] }) : null }),
|
|
8965
|
-
failureTitle !== null ? /* @__PURE__ */ (0,
|
|
8966
|
-
/* @__PURE__ */ (0,
|
|
8967
|
-
onRetry !== null ? /* @__PURE__ */ (0,
|
|
8984
|
+
failureTitle !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "fd-session-screen-failure", children: [
|
|
8985
|
+
/* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
|
|
8986
|
+
onRetry !== null ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
|
|
8968
8987
|
] }) : null
|
|
8969
8988
|
] }) })
|
|
8970
8989
|
] })
|
|
@@ -8972,10 +8991,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8972
8991
|
}
|
|
8973
8992
|
|
|
8974
8993
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8975
|
-
var
|
|
8994
|
+
var React59 = __toESM(require("react"), 1);
|
|
8976
8995
|
|
|
8977
8996
|
// src/kits/session.ts
|
|
8978
|
-
var
|
|
8997
|
+
var React57 = __toESM(require("react"), 1);
|
|
8979
8998
|
var PERMISSION_CATALOG = [
|
|
8980
8999
|
{ group: "Plans", items: [
|
|
8981
9000
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -10542,8 +10561,8 @@ function roadmap(overrides) {
|
|
|
10542
10561
|
};
|
|
10543
10562
|
}
|
|
10544
10563
|
function useSession() {
|
|
10545
|
-
const [s, setS] =
|
|
10546
|
-
|
|
10564
|
+
const [s, setS] = React57.useState(getSession);
|
|
10565
|
+
React57.useEffect(() => subscribe(setS), []);
|
|
10547
10566
|
return s;
|
|
10548
10567
|
}
|
|
10549
10568
|
var SessionKit = {
|
|
@@ -10576,7 +10595,7 @@ var SessionKit = {
|
|
|
10576
10595
|
};
|
|
10577
10596
|
function DemoSessionProvider({ children }) {
|
|
10578
10597
|
const session = useSession();
|
|
10579
|
-
const value =
|
|
10598
|
+
const value = React57.useMemo(
|
|
10580
10599
|
() => ({
|
|
10581
10600
|
user: session.user,
|
|
10582
10601
|
roles: session.roles,
|
|
@@ -10592,11 +10611,11 @@ function DemoSessionProvider({ children }) {
|
|
|
10592
10611
|
}),
|
|
10593
10612
|
[session]
|
|
10594
10613
|
);
|
|
10595
|
-
return
|
|
10614
|
+
return React57.createElement(SessionProvider, { value }, children);
|
|
10596
10615
|
}
|
|
10597
10616
|
|
|
10598
10617
|
// src/kits/runtime.ts
|
|
10599
|
-
var
|
|
10618
|
+
var React58 = __toESM(require("react"), 1);
|
|
10600
10619
|
var WIRED_ENDPOINTS = [
|
|
10601
10620
|
// Nothing yet. Every id below would come from a real service:
|
|
10602
10621
|
// "plan.get", "placements.list", …
|
|
@@ -10767,8 +10786,8 @@ var RuntimeKit = {
|
|
|
10767
10786
|
};
|
|
10768
10787
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
10769
10788
|
function useRuntimeMode() {
|
|
10770
|
-
const [m, setM] =
|
|
10771
|
-
|
|
10789
|
+
const [m, setM] = React58.useState(RuntimeKit.getMode());
|
|
10790
|
+
React58.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
10772
10791
|
return m;
|
|
10773
10792
|
}
|
|
10774
10793
|
function useFeatureStatus(key) {
|
|
@@ -10787,7 +10806,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
10787
10806
|
var UseFeatureStatus = useFeatureStatus;
|
|
10788
10807
|
|
|
10789
10808
|
// src/components/platform/RoadmapTimeline.tsx
|
|
10790
|
-
var
|
|
10809
|
+
var import_jsx_runtime83 = require("react/jsx-runtime");
|
|
10791
10810
|
var STATUS = {
|
|
10792
10811
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
10793
10812
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -10802,45 +10821,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10802
10821
|
const s = STATUS[item.status] || STATUS.planned;
|
|
10803
10822
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
10804
10823
|
const blocking = deps.filter((d) => !d.implemented);
|
|
10805
|
-
return /* @__PURE__ */ (0,
|
|
10806
|
-
/* @__PURE__ */ (0,
|
|
10807
|
-
/* @__PURE__ */ (0,
|
|
10808
|
-
/* @__PURE__ */ (0,
|
|
10809
|
-
/* @__PURE__ */ (0,
|
|
10824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Card, { elevation: "flat", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
10825
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
10826
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
10827
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
10828
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
10810
10829
|
] }),
|
|
10811
|
-
/* @__PURE__ */ (0,
|
|
10812
|
-
item.backend ? /* @__PURE__ */ (0,
|
|
10813
|
-
/* @__PURE__ */ (0,
|
|
10814
|
-
/* @__PURE__ */ (0,
|
|
10830
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
10831
|
+
item.backend ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
10832
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
10833
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
10815
10834
|
] }) : null,
|
|
10816
|
-
/* @__PURE__ */ (0,
|
|
10817
|
-
item.effort ? /* @__PURE__ */ (0,
|
|
10818
|
-
/* @__PURE__ */ (0,
|
|
10835
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
10836
|
+
item.effort ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
10837
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-hourglass-medium" }),
|
|
10819
10838
|
" ",
|
|
10820
10839
|
item.effort
|
|
10821
10840
|
] }) : null,
|
|
10822
|
-
/* @__PURE__ */ (0,
|
|
10823
|
-
/* @__PURE__ */ (0,
|
|
10841
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
10842
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-user" }),
|
|
10824
10843
|
" ",
|
|
10825
10844
|
item.owner
|
|
10826
10845
|
] }),
|
|
10827
|
-
item.screen ? /* @__PURE__ */ (0,
|
|
10828
|
-
/* @__PURE__ */ (0,
|
|
10829
|
-
/* @__PURE__ */ (0,
|
|
10846
|
+
item.screen ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
10847
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { flex: 1 } }),
|
|
10848
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10830
10849
|
"button",
|
|
10831
10850
|
{
|
|
10832
10851
|
type: "button",
|
|
10833
10852
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
10834
10853
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
10835
|
-
children: /* @__PURE__ */ (0,
|
|
10854
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
10836
10855
|
}
|
|
10837
10856
|
)
|
|
10838
10857
|
] }),
|
|
10839
|
-
deps.length ? /* @__PURE__ */ (0,
|
|
10840
|
-
/* @__PURE__ */ (0,
|
|
10841
|
-
deps.map((d) => /* @__PURE__ */ (0,
|
|
10858
|
+
deps.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
10859
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
10860
|
+
deps.map((d) => /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
10842
10861
|
] }) : null,
|
|
10843
|
-
blocking.length && !item.implemented ? /* @__PURE__ */ (0,
|
|
10862
|
+
blocking.length && !item.implemented ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
10844
10863
|
"Blocked until ",
|
|
10845
10864
|
blocking.map((d) => d.label).join(" and "),
|
|
10846
10865
|
" ",
|
|
@@ -10851,12 +10870,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10851
10870
|
}
|
|
10852
10871
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
10853
10872
|
const session = SessionKit.useSession();
|
|
10854
|
-
const [project, setProject] =
|
|
10855
|
-
const [q, setQ] =
|
|
10856
|
-
const scrollRef =
|
|
10857
|
-
const nowRef =
|
|
10858
|
-
const rm =
|
|
10859
|
-
const byKey =
|
|
10873
|
+
const [project, setProject] = React59.useState("");
|
|
10874
|
+
const [q, setQ] = React59.useState("");
|
|
10875
|
+
const scrollRef = React59.useRef(null);
|
|
10876
|
+
const nowRef = React59.useRef(null);
|
|
10877
|
+
const rm = React59.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
10878
|
+
const byKey = React59.useMemo(() => {
|
|
10860
10879
|
const m = {};
|
|
10861
10880
|
rm.items.forEach((i) => {
|
|
10862
10881
|
m[i.key] = i;
|
|
@@ -10865,7 +10884,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10865
10884
|
}, [rm]);
|
|
10866
10885
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
10867
10886
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
10868
|
-
|
|
10887
|
+
React59.useEffect(() => {
|
|
10869
10888
|
let raf1 = 0, raf2 = 0;
|
|
10870
10889
|
const place = () => {
|
|
10871
10890
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -10893,23 +10912,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10893
10912
|
}, 0);
|
|
10894
10913
|
const nextPhase = items.find((i) => !i.implemented);
|
|
10895
10914
|
let lastPhase = null;
|
|
10896
|
-
return /* @__PURE__ */ (0,
|
|
10897
|
-
/* @__PURE__ */ (0,
|
|
10898
|
-
/* @__PURE__ */ (0,
|
|
10899
|
-
/* @__PURE__ */ (0,
|
|
10900
|
-
/* @__PURE__ */ (0,
|
|
10915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
10916
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
10917
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
10918
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
10919
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede || "Every screen and feature in these tools is already designed and working against a simulated backend. This is the plan for connecting them to the real one \u2014 so the only work described here is server work." })
|
|
10901
10920
|
] }),
|
|
10902
|
-
/* @__PURE__ */ (0,
|
|
10903
|
-
/* @__PURE__ */ (0,
|
|
10904
|
-
/* @__PURE__ */ (0,
|
|
10905
|
-
/* @__PURE__ */ (0,
|
|
10906
|
-
/* @__PURE__ */ (0,
|
|
10921
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-grid-stats is-thin", children: [
|
|
10922
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
10923
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
10924
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
10925
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
10907
10926
|
] }),
|
|
10908
|
-
/* @__PURE__ */ (0,
|
|
10909
|
-
/* @__PURE__ */ (0,
|
|
10910
|
-
/* @__PURE__ */ (0,
|
|
10911
|
-
/* @__PURE__ */ (0,
|
|
10912
|
-
/* @__PURE__ */ (0,
|
|
10927
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
10928
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Input, { icon: "magnifying-glass", placeholder: "Find a feature or a piece of backend work", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
10929
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
10930
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { flex: 1 } }),
|
|
10931
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10913
10932
|
Button,
|
|
10914
10933
|
{
|
|
10915
10934
|
size: "sm",
|
|
@@ -10923,7 +10942,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10923
10942
|
}
|
|
10924
10943
|
)
|
|
10925
10944
|
] }),
|
|
10926
|
-
/* @__PURE__ */ (0,
|
|
10945
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10927
10946
|
Flag,
|
|
10928
10947
|
{
|
|
10929
10948
|
tone: "info",
|
|
@@ -10932,60 +10951,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10932
10951
|
actions: null
|
|
10933
10952
|
}
|
|
10934
10953
|
),
|
|
10935
|
-
/* @__PURE__ */ (0,
|
|
10936
|
-
/* @__PURE__ */ (0,
|
|
10954
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-track", children: [
|
|
10955
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-spine", children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
10937
10956
|
items.map((item, n) => {
|
|
10938
10957
|
const showPhase = item.phase !== lastPhase;
|
|
10939
10958
|
lastPhase = item.phase;
|
|
10940
10959
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
10941
10960
|
const isBoundary = n === firstPending;
|
|
10942
|
-
return /* @__PURE__ */ (0,
|
|
10943
|
-
showPhase ? /* @__PURE__ */ (0,
|
|
10944
|
-
/* @__PURE__ */ (0,
|
|
10945
|
-
/* @__PURE__ */ (0,
|
|
10946
|
-
item.phase === 0 ? null : /* @__PURE__ */ (0,
|
|
10961
|
+
return /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)(React59.Fragment, { children: [
|
|
10962
|
+
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-era", children: [
|
|
10963
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
10964
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
10965
|
+
item.phase === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
10947
10966
|
fmtDate(item.phaseStart),
|
|
10948
10967
|
" \u2013 ",
|
|
10949
10968
|
fmtDate(item.date)
|
|
10950
10969
|
] }),
|
|
10951
|
-
/* @__PURE__ */ (0,
|
|
10970
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
10952
10971
|
"\xB7 ",
|
|
10953
10972
|
inPhase,
|
|
10954
10973
|
" feature",
|
|
10955
10974
|
inPhase === 1 ? "" : "s"
|
|
10956
10975
|
] })
|
|
10957
10976
|
] }),
|
|
10958
|
-
item.phaseWhy ? /* @__PURE__ */ (0,
|
|
10977
|
+
item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
10959
10978
|
] }) : null,
|
|
10960
|
-
isBoundary ? /* @__PURE__ */ (0,
|
|
10961
|
-
/* @__PURE__ */ (0,
|
|
10979
|
+
isBoundary ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { className: "fd-rm-now-pill", children: [
|
|
10980
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("i", { className: "ph ph-map-pin" }),
|
|
10962
10981
|
" You are here \u2014 everything above is wired"
|
|
10963
10982
|
] }) }) : null,
|
|
10964
|
-
/* @__PURE__ */ (0,
|
|
10965
|
-
/* @__PURE__ */ (0,
|
|
10966
|
-
/* @__PURE__ */ (0,
|
|
10983
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-row", children: [
|
|
10984
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
10985
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("div", { className: "fd-rm-date", children: [
|
|
10967
10986
|
fmtDate(item.date),
|
|
10968
|
-
/* @__PURE__ */ (0,
|
|
10969
|
-
/* @__PURE__ */ (0,
|
|
10987
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("br", {}),
|
|
10988
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
10970
10989
|
] }),
|
|
10971
|
-
/* @__PURE__ */ (0,
|
|
10990
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
|
|
10972
10991
|
] })
|
|
10973
10992
|
] }, item.key);
|
|
10974
10993
|
}),
|
|
10975
|
-
!items.length ? /* @__PURE__ */ (0,
|
|
10994
|
+
!items.length ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
10976
10995
|
] }) }) }),
|
|
10977
|
-
/* @__PURE__ */ (0,
|
|
10996
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
10978
10997
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
10979
|
-
/* @__PURE__ */ (0,
|
|
10998
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", children: "implemented" }),
|
|
10980
10999
|
" field, so this page cannot drift from what the apps actually do."
|
|
10981
11000
|
] })
|
|
10982
11001
|
] });
|
|
10983
11002
|
}
|
|
10984
11003
|
|
|
10985
11004
|
// src/components/platform/ComingSoon.tsx
|
|
10986
|
-
var
|
|
11005
|
+
var React60 = __toESM(require("react"), 1);
|
|
10987
11006
|
var import_react_dom7 = require("react-dom");
|
|
10988
|
-
var
|
|
11007
|
+
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10989
11008
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
10990
11009
|
function readBypassed() {
|
|
10991
11010
|
try {
|
|
@@ -11001,8 +11020,8 @@ function writeBypassed(list) {
|
|
|
11001
11020
|
}
|
|
11002
11021
|
}
|
|
11003
11022
|
function useBypass(key) {
|
|
11004
|
-
const [on, setOn] =
|
|
11005
|
-
|
|
11023
|
+
const [on, setOn] = React60.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
11024
|
+
React60.useEffect(() => {
|
|
11006
11025
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
11007
11026
|
}, [key]);
|
|
11008
11027
|
const set = (next) => {
|
|
@@ -11015,43 +11034,43 @@ function useBypass(key) {
|
|
|
11015
11034
|
return [on, set];
|
|
11016
11035
|
}
|
|
11017
11036
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
11018
|
-
return /* @__PURE__ */ (0,
|
|
11019
|
-
/* @__PURE__ */ (0,
|
|
11020
|
-
/* @__PURE__ */ (0,
|
|
11037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(import_jsx_runtime84.Fragment, { children: [
|
|
11038
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
11039
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
11021
11040
|
label
|
|
11022
11041
|
] }),
|
|
11023
|
-
detail ? /* @__PURE__ */ (0,
|
|
11024
|
-
backend ? /* @__PURE__ */ (0,
|
|
11025
|
-
/* @__PURE__ */ (0,
|
|
11042
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
11043
|
+
backend ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-backend", children: [
|
|
11044
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-overline", children: "Needs" }),
|
|
11026
11045
|
" ",
|
|
11027
11046
|
backend
|
|
11028
11047
|
] }) : null,
|
|
11029
|
-
eta || effort || onRoadmap ? /* @__PURE__ */ (0,
|
|
11030
|
-
eta ? /* @__PURE__ */ (0,
|
|
11031
|
-
/* @__PURE__ */ (0,
|
|
11048
|
+
eta || effort || onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-meta", children: [
|
|
11049
|
+
eta ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { children: [
|
|
11050
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
11032
11051
|
" ",
|
|
11033
11052
|
eta
|
|
11034
11053
|
] }) : null,
|
|
11035
|
-
effort ? /* @__PURE__ */ (0,
|
|
11036
|
-
/* @__PURE__ */ (0,
|
|
11054
|
+
effort ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { children: [
|
|
11055
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
11037
11056
|
" ",
|
|
11038
11057
|
effort
|
|
11039
11058
|
] }) : null,
|
|
11040
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
11059
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
11041
11060
|
"See the roadmap ",
|
|
11042
|
-
/* @__PURE__ */ (0,
|
|
11061
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11043
11062
|
] }) : null
|
|
11044
11063
|
] }) : null,
|
|
11045
|
-
allowed ? /* @__PURE__ */ (0,
|
|
11046
|
-
/* @__PURE__ */ (0,
|
|
11064
|
+
allowed ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
11065
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
11047
11066
|
" View and use it anyway"
|
|
11048
11067
|
] }) : null
|
|
11049
11068
|
] });
|
|
11050
11069
|
}
|
|
11051
11070
|
function useHoverCard(open2) {
|
|
11052
|
-
const anchor =
|
|
11053
|
-
const [pos, setPos] =
|
|
11054
|
-
|
|
11071
|
+
const anchor = React60.useRef(null);
|
|
11072
|
+
const [pos, setPos] = React60.useState(null);
|
|
11073
|
+
React60.useLayoutEffect(() => {
|
|
11055
11074
|
if (!open2 || !anchor.current) {
|
|
11056
11075
|
setPos(null);
|
|
11057
11076
|
return;
|
|
@@ -11103,9 +11122,9 @@ function ComingSoon({
|
|
|
11103
11122
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
11104
11123
|
if (inline) {
|
|
11105
11124
|
if (allowed && bypassed) {
|
|
11106
|
-
return /* @__PURE__ */ (0,
|
|
11125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
11107
11126
|
children,
|
|
11108
|
-
/* @__PURE__ */ (0,
|
|
11127
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11109
11128
|
"button",
|
|
11110
11129
|
{
|
|
11111
11130
|
type: "button",
|
|
@@ -11113,12 +11132,12 @@ function ComingSoon({
|
|
|
11113
11132
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
11114
11133
|
onClick: () => setBypassed(false),
|
|
11115
11134
|
"aria-label": "Re-blur this unwired feature",
|
|
11116
|
-
children: /* @__PURE__ */ (0,
|
|
11135
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
11117
11136
|
}
|
|
11118
11137
|
)
|
|
11119
11138
|
] });
|
|
11120
11139
|
}
|
|
11121
|
-
return /* @__PURE__ */ (0,
|
|
11140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11122
11141
|
InlineSoon,
|
|
11123
11142
|
{
|
|
11124
11143
|
label,
|
|
@@ -11138,20 +11157,20 @@ function ComingSoon({
|
|
|
11138
11157
|
);
|
|
11139
11158
|
}
|
|
11140
11159
|
if (allowed && bypassed) {
|
|
11141
|
-
return /* @__PURE__ */ (0,
|
|
11142
|
-
/* @__PURE__ */ (0,
|
|
11143
|
-
/* @__PURE__ */ (0,
|
|
11144
|
-
/* @__PURE__ */ (0,
|
|
11160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
11161
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: "fd-soon-bar", role: "status", children: [
|
|
11162
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-badge", children: [
|
|
11163
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
11145
11164
|
"Unwired feature \u2014 you are using it anyway"
|
|
11146
11165
|
] }),
|
|
11147
|
-
/* @__PURE__ */ (0,
|
|
11148
|
-
/* @__PURE__ */ (0,
|
|
11149
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
11166
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
11167
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: "fd-soon-bar-actions", children: [
|
|
11168
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
11150
11169
|
"Roadmap ",
|
|
11151
|
-
/* @__PURE__ */ (0,
|
|
11170
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11152
11171
|
] }) : null,
|
|
11153
|
-
/* @__PURE__ */ (0,
|
|
11154
|
-
/* @__PURE__ */ (0,
|
|
11172
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
11173
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
11155
11174
|
" Re-blur"
|
|
11156
11175
|
] })
|
|
11157
11176
|
] })
|
|
@@ -11159,10 +11178,10 @@ function ComingSoon({
|
|
|
11159
11178
|
children
|
|
11160
11179
|
] });
|
|
11161
11180
|
}
|
|
11162
|
-
return /* @__PURE__ */ (0,
|
|
11163
|
-
/* @__PURE__ */ (0,
|
|
11164
|
-
/* @__PURE__ */ (0,
|
|
11165
|
-
/* @__PURE__ */ (0,
|
|
11181
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
11182
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
11183
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-veil" }),
|
|
11184
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11166
11185
|
SoonCard,
|
|
11167
11186
|
{
|
|
11168
11187
|
label,
|
|
@@ -11178,12 +11197,12 @@ function ComingSoon({
|
|
|
11178
11197
|
] });
|
|
11179
11198
|
}
|
|
11180
11199
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
11181
|
-
const [open2, setOpen] =
|
|
11200
|
+
const [open2, setOpen] = React60.useState(false);
|
|
11182
11201
|
const [anchor, pos] = useHoverCard(open2);
|
|
11183
|
-
const hoverCardRef =
|
|
11202
|
+
const hoverCardRef = React60.useRef(null);
|
|
11184
11203
|
const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
|
|
11185
11204
|
const zIndex = useLayerZIndex(hoverLayer);
|
|
11186
|
-
const close2 =
|
|
11205
|
+
const close2 = React60.useRef(null);
|
|
11187
11206
|
const show = () => {
|
|
11188
11207
|
if (close2.current) {
|
|
11189
11208
|
clearTimeout(close2.current);
|
|
@@ -11199,10 +11218,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11199
11218
|
setOpen(false);
|
|
11200
11219
|
}, 140);
|
|
11201
11220
|
};
|
|
11202
|
-
|
|
11221
|
+
React60.useEffect(() => () => {
|
|
11203
11222
|
if (close2.current) clearTimeout(close2.current);
|
|
11204
11223
|
}, []);
|
|
11205
|
-
return /* @__PURE__ */ (0,
|
|
11224
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
|
|
11206
11225
|
"span",
|
|
11207
11226
|
{
|
|
11208
11227
|
ref: anchor,
|
|
@@ -11213,8 +11232,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11213
11232
|
onBlur: hide,
|
|
11214
11233
|
...rest,
|
|
11215
11234
|
children: [
|
|
11216
|
-
/* @__PURE__ */ (0,
|
|
11217
|
-
/* @__PURE__ */ (0,
|
|
11235
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
11236
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11218
11237
|
"button",
|
|
11219
11238
|
{
|
|
11220
11239
|
type: "button",
|
|
@@ -11225,11 +11244,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11225
11244
|
onFocus: show,
|
|
11226
11245
|
onBlur: hide,
|
|
11227
11246
|
onClick: () => open2 ? setOpen(false) : show(),
|
|
11228
|
-
children: /* @__PURE__ */ (0,
|
|
11247
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
11229
11248
|
}
|
|
11230
11249
|
),
|
|
11231
11250
|
open2 && pos ? (0, import_react_dom7.createPortal)(
|
|
11232
|
-
/* @__PURE__ */ (0,
|
|
11251
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11233
11252
|
"div",
|
|
11234
11253
|
{
|
|
11235
11254
|
ref: hoverCardRef,
|
|
@@ -11238,7 +11257,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11238
11257
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
11239
11258
|
onMouseEnter: show,
|
|
11240
11259
|
onMouseLeave: hide,
|
|
11241
|
-
children: /* @__PURE__ */ (0,
|
|
11260
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11242
11261
|
SoonCard,
|
|
11243
11262
|
{
|
|
11244
11263
|
label,
|
|
@@ -11268,10 +11287,10 @@ function formatEta(iso2) {
|
|
|
11268
11287
|
var FormatEta = formatEta;
|
|
11269
11288
|
|
|
11270
11289
|
// src/components/platform/Gate.tsx
|
|
11271
|
-
var
|
|
11290
|
+
var import_jsx_runtime85 = require("react/jsx-runtime");
|
|
11272
11291
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
11273
11292
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
11274
|
-
return /* @__PURE__ */ (0,
|
|
11293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11275
11294
|
"div",
|
|
11276
11295
|
{
|
|
11277
11296
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -11287,14 +11306,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
11287
11306
|
},
|
|
11288
11307
|
...rest,
|
|
11289
11308
|
children: [
|
|
11290
|
-
/* @__PURE__ */ (0,
|
|
11291
|
-
/* @__PURE__ */ (0,
|
|
11292
|
-
/* @__PURE__ */ (0,
|
|
11309
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
11310
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11311
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
11293
11312
|
] }),
|
|
11294
|
-
/* @__PURE__ */ (0,
|
|
11295
|
-
need.length ? /* @__PURE__ */ (0,
|
|
11296
|
-
/* @__PURE__ */ (0,
|
|
11297
|
-
need.map((p) => /* @__PURE__ */ (0,
|
|
11313
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: detail || "Your roles do not grant this. An administrator can change that from Admin \u2192 Users." }),
|
|
11314
|
+
need.length ? /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
11315
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
11316
|
+
need.map((p) => /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("code", { className: "fd-mono", style: {
|
|
11298
11317
|
fontSize: 11.5,
|
|
11299
11318
|
padding: "2px 7px",
|
|
11300
11319
|
borderRadius: 5,
|
|
@@ -11307,7 +11326,7 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
11307
11326
|
);
|
|
11308
11327
|
}
|
|
11309
11328
|
function GatePending({ compact: compact3 = false, className = "" }) {
|
|
11310
|
-
return /* @__PURE__ */ (0,
|
|
11329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11311
11330
|
"div",
|
|
11312
11331
|
{
|
|
11313
11332
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -11323,11 +11342,11 @@ function GatePending({ compact: compact3 = false, className = "" }) {
|
|
|
11323
11342
|
textAlign: "left"
|
|
11324
11343
|
},
|
|
11325
11344
|
children: [
|
|
11326
|
-
/* @__PURE__ */ (0,
|
|
11327
|
-
/* @__PURE__ */ (0,
|
|
11328
|
-
/* @__PURE__ */ (0,
|
|
11345
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsxs)("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
11346
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11347
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
|
|
11329
11348
|
] }),
|
|
11330
|
-
/* @__PURE__ */ (0,
|
|
11349
|
+
/* @__PURE__ */ (0, import_jsx_runtime85.jsx)("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: "Your access can't be verified right now. This will resolve on its own once the connection is back." })
|
|
11331
11350
|
]
|
|
11332
11351
|
}
|
|
11333
11352
|
);
|
|
@@ -11337,7 +11356,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11337
11356
|
if (pending) {
|
|
11338
11357
|
if (pendingFallback !== void 0) return pendingFallback;
|
|
11339
11358
|
if (silent) return null;
|
|
11340
|
-
return /* @__PURE__ */ (0,
|
|
11359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(GatePending, { compact: compact3 });
|
|
11341
11360
|
}
|
|
11342
11361
|
let ok = true;
|
|
11343
11362
|
if (perm) ok = ok && can2(perm);
|
|
@@ -11346,7 +11365,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11346
11365
|
if (ok) return children;
|
|
11347
11366
|
if (fallback !== void 0) return fallback;
|
|
11348
11367
|
if (silent) return null;
|
|
11349
|
-
return /* @__PURE__ */ (0,
|
|
11368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
11350
11369
|
}
|
|
11351
11370
|
function FeatureGate({
|
|
11352
11371
|
flag,
|
|
@@ -11369,7 +11388,7 @@ function FeatureGate({
|
|
|
11369
11388
|
const f = SessionKit.findFlag(flag) || {};
|
|
11370
11389
|
const missing = rt.missing || [];
|
|
11371
11390
|
const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
11372
|
-
return /* @__PURE__ */ (0,
|
|
11391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11373
11392
|
ComingSoon,
|
|
11374
11393
|
{
|
|
11375
11394
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -11390,22 +11409,22 @@ function FeatureGate({
|
|
|
11390
11409
|
function PermissionHint({ perm, children }) {
|
|
11391
11410
|
const { can: can2, pending } = useSessionContext();
|
|
11392
11411
|
if (pending) {
|
|
11393
|
-
return /* @__PURE__ */ (0,
|
|
11412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { title: "Access can't be verified right now", style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" }, "aria-disabled": "true", children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { pointerEvents: "none" }, children }) });
|
|
11394
11413
|
}
|
|
11395
11414
|
if (can2(perm)) return children;
|
|
11396
|
-
return /* @__PURE__ */ (0,
|
|
11415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11397
11416
|
"span",
|
|
11398
11417
|
{
|
|
11399
11418
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
11400
11419
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
11401
11420
|
"aria-disabled": "true",
|
|
11402
|
-
children: /* @__PURE__ */ (0,
|
|
11421
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { pointerEvents: "none" }, children })
|
|
11403
11422
|
}
|
|
11404
11423
|
);
|
|
11405
11424
|
}
|
|
11406
11425
|
|
|
11407
11426
|
// src/components/platform/ModeSwitch.tsx
|
|
11408
|
-
var
|
|
11427
|
+
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
11409
11428
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
11410
11429
|
const mode2 = useRuntimeMode();
|
|
11411
11430
|
const panel = useInlinePanel();
|
|
@@ -11417,8 +11436,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11417
11436
|
RuntimeKit.setMode(next);
|
|
11418
11437
|
setOpen(false);
|
|
11419
11438
|
};
|
|
11420
|
-
return /* @__PURE__ */ (0,
|
|
11421
|
-
/* @__PURE__ */ (0,
|
|
11439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
|
|
11440
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
11422
11441
|
"button",
|
|
11423
11442
|
{
|
|
11424
11443
|
type: "button",
|
|
@@ -11428,29 +11447,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11428
11447
|
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.",
|
|
11429
11448
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
|
|
11430
11449
|
children: [
|
|
11431
|
-
/* @__PURE__ */ (0,
|
|
11432
|
-
test && requestCount ? /* @__PURE__ */ (0,
|
|
11450
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
11451
|
+
test && requestCount ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
11433
11452
|
]
|
|
11434
11453
|
}
|
|
11435
11454
|
),
|
|
11436
|
-
/* @__PURE__ */ (0,
|
|
11437
|
-
/* @__PURE__ */ (0,
|
|
11438
|
-
/* @__PURE__ */ (0,
|
|
11439
|
-
/* @__PURE__ */ (0,
|
|
11455
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
|
|
11456
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
11457
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
11458
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
11440
11459
|
test ? "Test mode" : "Live mode"
|
|
11441
11460
|
] }),
|
|
11442
|
-
test ? /* @__PURE__ */ (0,
|
|
11461
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
11443
11462
|
requestCount,
|
|
11444
11463
|
" simulated request",
|
|
11445
11464
|
requestCount === 1 ? "" : "s"
|
|
11446
11465
|
] }) : null,
|
|
11447
|
-
/* @__PURE__ */ (0,
|
|
11448
|
-
test && onClearLog ? /* @__PURE__ */ (0,
|
|
11466
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
|
|
11467
|
+
test && onClearLog ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
11449
11468
|
] }),
|
|
11450
|
-
/* @__PURE__ */ (0,
|
|
11451
|
-
/* @__PURE__ */ (0,
|
|
11452
|
-
/* @__PURE__ */ (0,
|
|
11453
|
-
/* @__PURE__ */ (0,
|
|
11469
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
11470
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-body-sm fd-secondary", style: { display: "block", textWrap: "pretty" }, children: test ? "Every feature is usable and nothing is obstructed, but no response comes from a real service \u2014 nothing you do here persists. Use this to review and demo the design." : "This is what a user would see today. " + s.incomplete + " of " + s.total + " features depend on backend work that is not wired yet, so they render under construction." }),
|
|
11471
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
11472
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
11454
11473
|
s.endpointsWired,
|
|
11455
11474
|
" endpoint",
|
|
11456
11475
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -11460,58 +11479,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11460
11479
|
s.total,
|
|
11461
11480
|
" features complete"
|
|
11462
11481
|
] }),
|
|
11463
|
-
onOpenSpec ? /* @__PURE__ */ (0,
|
|
11464
|
-
/* @__PURE__ */ (0,
|
|
11465
|
-
/* @__PURE__ */ (0,
|
|
11482
|
+
onOpenSpec ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(import_jsx_runtime86.Fragment, { children: [
|
|
11483
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { flex: 1 } }),
|
|
11484
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
11466
11485
|
setOpen(false);
|
|
11467
11486
|
onOpenSpec();
|
|
11468
11487
|
}, children: [
|
|
11469
11488
|
"API spec ",
|
|
11470
|
-
/* @__PURE__ */ (0,
|
|
11489
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11471
11490
|
] })
|
|
11472
11491
|
] }) : null
|
|
11473
11492
|
] })
|
|
11474
11493
|
] }),
|
|
11475
|
-
/* @__PURE__ */ (0,
|
|
11476
|
-
/* @__PURE__ */ (0,
|
|
11477
|
-
/* @__PURE__ */ (0,
|
|
11478
|
-
/* @__PURE__ */ (0,
|
|
11479
|
-
/* @__PURE__ */ (0,
|
|
11480
|
-
/* @__PURE__ */ (0,
|
|
11494
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-choice", children: [
|
|
11495
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
11496
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
11497
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
11498
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
11499
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
11481
11500
|
] }),
|
|
11482
|
-
!test ? /* @__PURE__ */ (0,
|
|
11501
|
+
!test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11483
11502
|
] }),
|
|
11484
|
-
/* @__PURE__ */ (0,
|
|
11485
|
-
/* @__PURE__ */ (0,
|
|
11486
|
-
/* @__PURE__ */ (0,
|
|
11487
|
-
/* @__PURE__ */ (0,
|
|
11488
|
-
/* @__PURE__ */ (0,
|
|
11503
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
11504
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
11505
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-mode-opt-text", children: [
|
|
11506
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
11507
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
11489
11508
|
] }),
|
|
11490
|
-
test ? /* @__PURE__ */ (0,
|
|
11509
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11491
11510
|
] })
|
|
11492
11511
|
] }),
|
|
11493
|
-
test && renderLog ? /* @__PURE__ */ (0,
|
|
11512
|
+
test && renderLog ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
11494
11513
|
] })
|
|
11495
11514
|
] });
|
|
11496
11515
|
}
|
|
11497
11516
|
function TestModeBar({ onExit }) {
|
|
11498
11517
|
const mode2 = useRuntimeMode();
|
|
11499
11518
|
if (mode2 !== "test") return null;
|
|
11500
|
-
return /* @__PURE__ */ (0,
|
|
11501
|
-
/* @__PURE__ */ (0,
|
|
11502
|
-
/* @__PURE__ */ (0,
|
|
11519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "fd-testbar", role: "status", children: [
|
|
11520
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-badge fd-badge-warning", children: [
|
|
11521
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
11503
11522
|
"Test mode"
|
|
11504
11523
|
] }),
|
|
11505
|
-
/* @__PURE__ */ (0,
|
|
11506
|
-
/* @__PURE__ */ (0,
|
|
11507
|
-
/* @__PURE__ */ (0,
|
|
11524
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
11525
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
11526
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
11508
11527
|
" Back to live mode"
|
|
11509
11528
|
] })
|
|
11510
11529
|
] });
|
|
11511
11530
|
}
|
|
11512
11531
|
|
|
11513
11532
|
// src/components/planner/ChannelMeta.tsx
|
|
11514
|
-
var
|
|
11533
|
+
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
11515
11534
|
var CHANNEL_WEIGHTS = {
|
|
11516
11535
|
"OOH": 50,
|
|
11517
11536
|
"DOOH": 50,
|
|
@@ -11564,9 +11583,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11564
11583
|
const m = ChannelMeta(channel);
|
|
11565
11584
|
const wt = channelWeightOf(channel || "");
|
|
11566
11585
|
if (dot) {
|
|
11567
|
-
return /* @__PURE__ */ (0,
|
|
11586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
11568
11587
|
}
|
|
11569
|
-
return /* @__PURE__ */ (0,
|
|
11588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11570
11589
|
"span",
|
|
11571
11590
|
{
|
|
11572
11591
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -11574,16 +11593,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11574
11593
|
style: { "--chan": m.color },
|
|
11575
11594
|
...rest,
|
|
11576
11595
|
children: [
|
|
11577
|
-
/* @__PURE__ */ (0,
|
|
11578
|
-
showLabel ? /* @__PURE__ */ (0,
|
|
11579
|
-
weight ? /* @__PURE__ */ (0,
|
|
11596
|
+
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
11597
|
+
showLabel ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
11598
|
+
weight ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
11580
11599
|
]
|
|
11581
11600
|
}
|
|
11582
11601
|
);
|
|
11583
11602
|
}
|
|
11584
11603
|
|
|
11585
11604
|
// src/components/planner/SaturationDistribution.tsx
|
|
11586
|
-
var
|
|
11605
|
+
var import_jsx_runtime88 = require("react/jsx-runtime");
|
|
11587
11606
|
var BANDS2 = [
|
|
11588
11607
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
11589
11608
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -11594,24 +11613,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11594
11613
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
11595
11614
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
11596
11615
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
11597
|
-
return /* @__PURE__ */ (0,
|
|
11598
|
-
/* @__PURE__ */ (0,
|
|
11616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
11617
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
11599
11618
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
11600
11619
|
const active = selectedBand === g.key;
|
|
11601
|
-
return /* @__PURE__ */ (0,
|
|
11620
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
11602
11621
|
"button",
|
|
11603
11622
|
{
|
|
11604
11623
|
type: "button",
|
|
11605
11624
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
11606
11625
|
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)" },
|
|
11607
11626
|
children: [
|
|
11608
|
-
/* @__PURE__ */ (0,
|
|
11627
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
|
|
11609
11628
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
11610
11629
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
11611
11630
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
11612
11631
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
11613
11632
|
// is still one hover away via `title`.
|
|
11614
|
-
/* @__PURE__ */ (0,
|
|
11633
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
11615
11634
|
"span",
|
|
11616
11635
|
{
|
|
11617
11636
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -11621,13 +11640,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11621
11640
|
c.name
|
|
11622
11641
|
)
|
|
11623
11642
|
)) }),
|
|
11624
|
-
/* @__PURE__ */ (0,
|
|
11625
|
-
/* @__PURE__ */ (0,
|
|
11626
|
-
/* @__PURE__ */ (0,
|
|
11643
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
11644
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
11645
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
11627
11646
|
] }),
|
|
11628
|
-
/* @__PURE__ */ (0,
|
|
11629
|
-
/* @__PURE__ */ (0,
|
|
11630
|
-
/* @__PURE__ */ (0,
|
|
11647
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
11648
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-label-lg", children: g.label }),
|
|
11649
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
11631
11650
|
"CRP ",
|
|
11632
11651
|
g.range
|
|
11633
11652
|
] })
|
|
@@ -11637,10 +11656,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11637
11656
|
g.key
|
|
11638
11657
|
);
|
|
11639
11658
|
}) }),
|
|
11640
|
-
floorBand ? /* @__PURE__ */ (0,
|
|
11641
|
-
/* @__PURE__ */ (0,
|
|
11642
|
-
/* @__PURE__ */ (0,
|
|
11643
|
-
/* @__PURE__ */ (0,
|
|
11659
|
+
floorBand ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderRadius: "var(--r-md)", background: "var(--surface-2)", border: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
11660
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
11661
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
11662
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("strong", { style: { color: "var(--text)" }, children: [
|
|
11644
11663
|
"Plan floor ",
|
|
11645
11664
|
floorScore
|
|
11646
11665
|
] }),
|
|
@@ -11651,8 +11670,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11651
11670
|
}
|
|
11652
11671
|
|
|
11653
11672
|
// src/components/planner/MixGap.tsx
|
|
11654
|
-
var
|
|
11655
|
-
var
|
|
11673
|
+
var React61 = __toESM(require("react"), 1);
|
|
11674
|
+
var import_jsx_runtime89 = require("react/jsx-runtime");
|
|
11656
11675
|
var MIX_GAP_LAYOUT = {
|
|
11657
11676
|
trackHeight: 30,
|
|
11658
11677
|
barHeight: 20,
|
|
@@ -11666,19 +11685,19 @@ function mixGapOffset(value, max) {
|
|
|
11666
11685
|
}
|
|
11667
11686
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
11668
11687
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
11669
|
-
const [hover, setHover] =
|
|
11688
|
+
const [hover, setHover] = React61.useState(null);
|
|
11670
11689
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
11671
11690
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
11672
11691
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
11673
11692
|
const barTop = (trackHeight - barHeight) / 2;
|
|
11674
|
-
return /* @__PURE__ */ (0,
|
|
11675
|
-
/* @__PURE__ */ (0,
|
|
11676
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0,
|
|
11677
|
-
/* @__PURE__ */ (0,
|
|
11693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
11694
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
11695
|
+
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
11696
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
11678
11697
|
l
|
|
11679
11698
|
] }, l)),
|
|
11680
|
-
/* @__PURE__ */ (0,
|
|
11681
|
-
/* @__PURE__ */ (0,
|
|
11699
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
11700
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
|
|
11682
11701
|
"Target"
|
|
11683
11702
|
] })
|
|
11684
11703
|
] }),
|
|
@@ -11687,7 +11706,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11687
11706
|
const tone = toneOf(gap);
|
|
11688
11707
|
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 : "");
|
|
11689
11708
|
const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
|
|
11690
|
-
return /* @__PURE__ */ (0,
|
|
11709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
|
|
11691
11710
|
"div",
|
|
11692
11711
|
{
|
|
11693
11712
|
className: "fd-row",
|
|
@@ -11695,15 +11714,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11695
11714
|
onMouseEnter: () => setHover(r.channel),
|
|
11696
11715
|
onMouseLeave: () => setHover(null),
|
|
11697
11716
|
children: [
|
|
11698
|
-
/* @__PURE__ */ (0,
|
|
11699
|
-
/* @__PURE__ */ (0,
|
|
11700
|
-
/* @__PURE__ */ (0,
|
|
11701
|
-
/* @__PURE__ */ (0,
|
|
11702
|
-
/* @__PURE__ */ (0,
|
|
11717
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
11718
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
|
|
11719
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-bar": "", style: { position: "absolute", left: 0, top: barTop, height: barHeight, width: mixGapOffset(r.realized, max), background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
|
|
11720
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "data-mixgap-target": "", style: { position: "absolute", left: `calc(${mixGapOffset(r.target, max)} - ${targetWidth / 2}px)`, top: 0, width: targetWidth, height: trackHeight, background: MIX_GAP_TARGET_STRIPE, borderRadius: 1 } }),
|
|
11721
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("span", { "data-mixgap-label": "", className: "fd-num", style: { position: "absolute", left: labelLeft, top: "50%", transform: "translateY(-50%)", fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap" }, children: [
|
|
11703
11722
|
r.realized,
|
|
11704
11723
|
"%"
|
|
11705
11724
|
] }),
|
|
11706
|
-
hover === r.channel ? /* @__PURE__ */ (0,
|
|
11725
|
+
hover === r.channel ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "fd-tooltip", role: "tooltip", style: { position: "absolute", left: 0, right: "auto", bottom: trackHeight + 4, maxWidth: "min(340px, 100%)", whiteSpace: "normal", textAlign: "left", width: "max-content" }, children: tip }) : null
|
|
11707
11726
|
] }) })
|
|
11708
11727
|
]
|
|
11709
11728
|
},
|
|
@@ -11714,7 +11733,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11714
11733
|
}
|
|
11715
11734
|
|
|
11716
11735
|
// src/components/planner/ChannelContribution.tsx
|
|
11717
|
-
var
|
|
11736
|
+
var import_jsx_runtime90 = require("react/jsx-runtime");
|
|
11718
11737
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
11719
11738
|
function ChannelContribution({
|
|
11720
11739
|
channels = [],
|
|
@@ -11730,9 +11749,9 @@ function ChannelContribution({
|
|
|
11730
11749
|
const grand = total !== void 0 ? total : base + bonus;
|
|
11731
11750
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
11732
11751
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
11733
|
-
return /* @__PURE__ */ (0,
|
|
11734
|
-
loading ? /* @__PURE__ */ (0,
|
|
11735
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
11752
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
11753
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
11754
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
11736
11755
|
"span",
|
|
11737
11756
|
{
|
|
11738
11757
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -11741,7 +11760,7 @@ function ChannelContribution({
|
|
|
11741
11760
|
},
|
|
11742
11761
|
c.name
|
|
11743
11762
|
)),
|
|
11744
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
11763
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
11745
11764
|
"span",
|
|
11746
11765
|
{
|
|
11747
11766
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -11750,18 +11769,18 @@ function ChannelContribution({
|
|
|
11750
11769
|
}
|
|
11751
11770
|
) : null
|
|
11752
11771
|
] }),
|
|
11753
|
-
showTable ? /* @__PURE__ */ (0,
|
|
11754
|
-
/* @__PURE__ */ (0,
|
|
11755
|
-
/* @__PURE__ */ (0,
|
|
11756
|
-
/* @__PURE__ */ (0,
|
|
11757
|
-
/* @__PURE__ */ (0,
|
|
11758
|
-
/* @__PURE__ */ (0,
|
|
11759
|
-
/* @__PURE__ */ (0,
|
|
11772
|
+
showTable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
11773
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
|
|
11774
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { style: { width: "34%" }, children: "Channel" }),
|
|
11775
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { style: { width: "16%" }, children: "Weight" }),
|
|
11776
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
11777
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
11778
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
11760
11779
|
] }) }),
|
|
11761
|
-
/* @__PURE__ */ (0,
|
|
11762
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
11763
|
-
/* @__PURE__ */ (0,
|
|
11764
|
-
/* @__PURE__ */ (0,
|
|
11780
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tbody", { children: [
|
|
11781
|
+
channels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
|
|
11782
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
11783
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
11765
11784
|
"span",
|
|
11766
11785
|
{
|
|
11767
11786
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -11770,38 +11789,38 @@ function ChannelContribution({
|
|
|
11770
11789
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
11771
11790
|
}
|
|
11772
11791
|
) }),
|
|
11773
|
-
/* @__PURE__ */ (0,
|
|
11774
|
-
/* @__PURE__ */ (0,
|
|
11775
|
-
/* @__PURE__ */ (0,
|
|
11792
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: c.spend }),
|
|
11793
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
11794
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("td", { className: "is-num", children: [
|
|
11776
11795
|
pct(c.crp).toFixed(0),
|
|
11777
11796
|
"%"
|
|
11778
11797
|
] })
|
|
11779
11798
|
] }, c.name)),
|
|
11780
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
11781
|
-
/* @__PURE__ */ (0,
|
|
11782
|
-
/* @__PURE__ */ (0,
|
|
11799
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
|
|
11800
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
11801
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { style: { width: 9, height: 9, borderRadius: 2, background: "repeating-linear-gradient(135deg,var(--csi-3-mark) 0 3px,var(--csi-2-mark) 3px 6px)", flex: "none" } }),
|
|
11783
11802
|
"Surround-sound bonus"
|
|
11784
11803
|
] }) }),
|
|
11785
|
-
/* @__PURE__ */ (0,
|
|
11804
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
11786
11805
|
"+",
|
|
11787
11806
|
bonusPct,
|
|
11788
11807
|
"% of +",
|
|
11789
11808
|
bonusMax,
|
|
11790
11809
|
"%"
|
|
11791
11810
|
] }) }),
|
|
11792
|
-
/* @__PURE__ */ (0,
|
|
11793
|
-
/* @__PURE__ */ (0,
|
|
11794
|
-
/* @__PURE__ */ (0,
|
|
11811
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
11812
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
11813
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("td", { className: "is-num", children: [
|
|
11795
11814
|
pct(bonus).toFixed(0),
|
|
11796
11815
|
"%"
|
|
11797
11816
|
] })
|
|
11798
11817
|
] }) : null,
|
|
11799
|
-
/* @__PURE__ */ (0,
|
|
11800
|
-
/* @__PURE__ */ (0,
|
|
11801
|
-
/* @__PURE__ */ (0,
|
|
11802
|
-
/* @__PURE__ */ (0,
|
|
11803
|
-
/* @__PURE__ */ (0,
|
|
11804
|
-
/* @__PURE__ */ (0,
|
|
11818
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
11819
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
11820
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", {}),
|
|
11821
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
11822
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
11823
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
11805
11824
|
] })
|
|
11806
11825
|
] })
|
|
11807
11826
|
] }) : null
|
|
@@ -11809,8 +11828,8 @@ function ChannelContribution({
|
|
|
11809
11828
|
}
|
|
11810
11829
|
|
|
11811
11830
|
// src/components/planner/BudgetReallocator.tsx
|
|
11812
|
-
var
|
|
11813
|
-
var
|
|
11831
|
+
var React62 = __toESM(require("react"), 1);
|
|
11832
|
+
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
11814
11833
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
11815
11834
|
function BudgetReallocator({
|
|
11816
11835
|
campus,
|
|
@@ -11825,8 +11844,8 @@ function BudgetReallocator({
|
|
|
11825
11844
|
onCancel,
|
|
11826
11845
|
className = ""
|
|
11827
11846
|
}) {
|
|
11828
|
-
const [draft, setDraft] =
|
|
11829
|
-
|
|
11847
|
+
const [draft, setDraft] = React62.useState(spend);
|
|
11848
|
+
React62.useEffect(() => setDraft(spend), [spend]);
|
|
11830
11849
|
const dirty = draft !== spend;
|
|
11831
11850
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
11832
11851
|
const nextBand = bandFor(nextCrp);
|
|
@@ -11841,10 +11860,10 @@ function BudgetReallocator({
|
|
|
11841
11860
|
setDraft(spend);
|
|
11842
11861
|
if (onCancel) onCancel();
|
|
11843
11862
|
};
|
|
11844
|
-
const trackRef =
|
|
11845
|
-
const chipRef =
|
|
11846
|
-
const [chipLeft, setChipLeft] =
|
|
11847
|
-
|
|
11863
|
+
const trackRef = React62.useRef(null);
|
|
11864
|
+
const chipRef = React62.useRef(null);
|
|
11865
|
+
const [chipLeft, setChipLeft] = React62.useState(null);
|
|
11866
|
+
React62.useLayoutEffect(() => {
|
|
11848
11867
|
const track = trackRef.current;
|
|
11849
11868
|
if (!dirty || !track) {
|
|
11850
11869
|
setChipLeft(null);
|
|
@@ -11865,23 +11884,23 @@ function BudgetReallocator({
|
|
|
11865
11884
|
ro.observe(track);
|
|
11866
11885
|
return () => ro.disconnect();
|
|
11867
11886
|
}, [dirty, pct]);
|
|
11868
|
-
return /* @__PURE__ */ (0,
|
|
11887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
11869
11888
|
"div",
|
|
11870
11889
|
{
|
|
11871
11890
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
11872
11891
|
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)" },
|
|
11873
11892
|
children: [
|
|
11874
|
-
/* @__PURE__ */ (0,
|
|
11875
|
-
/* @__PURE__ */ (0,
|
|
11876
|
-
/* @__PURE__ */ (0,
|
|
11877
|
-
dirty ? /* @__PURE__ */ (0,
|
|
11878
|
-
/* @__PURE__ */ (0,
|
|
11879
|
-
/* @__PURE__ */ (0,
|
|
11893
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
11894
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
11895
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
11896
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(import_jsx_runtime91.Fragment, { children: [
|
|
11897
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
11898
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
11880
11899
|
] }) : null
|
|
11881
11900
|
] }),
|
|
11882
|
-
/* @__PURE__ */ (0,
|
|
11883
|
-
/* @__PURE__ */ (0,
|
|
11884
|
-
dirty ? /* @__PURE__ */ (0,
|
|
11901
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-slider", ref: trackRef, children: [
|
|
11902
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
11903
|
+
dirty ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
11885
11904
|
"span",
|
|
11886
11905
|
{
|
|
11887
11906
|
ref: chipRef,
|
|
@@ -11893,7 +11912,7 @@ function BudgetReallocator({
|
|
|
11893
11912
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
11894
11913
|
}
|
|
11895
11914
|
) : null,
|
|
11896
|
-
/* @__PURE__ */ (0,
|
|
11915
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
11897
11916
|
"input",
|
|
11898
11917
|
{
|
|
11899
11918
|
type: "range",
|
|
@@ -11909,13 +11928,13 @@ function BudgetReallocator({
|
|
|
11909
11928
|
}
|
|
11910
11929
|
)
|
|
11911
11930
|
] }),
|
|
11912
|
-
/* @__PURE__ */ (0,
|
|
11913
|
-
/* @__PURE__ */ (0,
|
|
11914
|
-
/* @__PURE__ */ (0,
|
|
11915
|
-
/* @__PURE__ */ (0,
|
|
11931
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
11932
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
11933
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
11934
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
11916
11935
|
] }),
|
|
11917
|
-
/* @__PURE__ */ (0,
|
|
11918
|
-
/* @__PURE__ */ (0,
|
|
11936
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
11937
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
11919
11938
|
"button",
|
|
11920
11939
|
{
|
|
11921
11940
|
type: "button",
|
|
@@ -11934,7 +11953,7 @@ function BudgetReallocator({
|
|
|
11934
11953
|
}
|
|
11935
11954
|
|
|
11936
11955
|
// src/components/planner/SurroundSound.tsx
|
|
11937
|
-
var
|
|
11956
|
+
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
11938
11957
|
var CATEGORIES = [
|
|
11939
11958
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
11940
11959
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -11946,26 +11965,26 @@ var CATEGORIES = [
|
|
|
11946
11965
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
11947
11966
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
11948
11967
|
const single = present.length <= 2;
|
|
11949
|
-
return /* @__PURE__ */ (0,
|
|
11950
|
-
/* @__PURE__ */ (0,
|
|
11968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
11969
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
11951
11970
|
const on = present.includes(c.key);
|
|
11952
|
-
return /* @__PURE__ */ (0,
|
|
11971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
|
|
11953
11972
|
"span",
|
|
11954
11973
|
{
|
|
11955
11974
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
11956
11975
|
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)" },
|
|
11957
11976
|
children: [
|
|
11958
|
-
/* @__PURE__ */ (0,
|
|
11959
|
-
/* @__PURE__ */ (0,
|
|
11977
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11978
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
11960
11979
|
]
|
|
11961
11980
|
},
|
|
11962
11981
|
c.key
|
|
11963
11982
|
);
|
|
11964
11983
|
}) }),
|
|
11965
|
-
/* @__PURE__ */ (0,
|
|
11966
|
-
/* @__PURE__ */ (0,
|
|
11967
|
-
/* @__PURE__ */ (0,
|
|
11968
|
-
/* @__PURE__ */ (0,
|
|
11984
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
11985
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
11986
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
11987
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
11969
11988
|
"+",
|
|
11970
11989
|
bonusPct,
|
|
11971
11990
|
"% of +",
|
|
@@ -11973,8 +11992,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11973
11992
|
"%"
|
|
11974
11993
|
] })
|
|
11975
11994
|
] }),
|
|
11976
|
-
/* @__PURE__ */ (0,
|
|
11977
|
-
/* @__PURE__ */ (0,
|
|
11995
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
11996
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsxs)("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
11978
11997
|
present.length,
|
|
11979
11998
|
" of 6 channel categories present.",
|
|
11980
11999
|
" ",
|
|
@@ -11986,7 +12005,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11986
12005
|
}
|
|
11987
12006
|
|
|
11988
12007
|
// src/components/planner/Importance.tsx
|
|
11989
|
-
var
|
|
12008
|
+
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
11990
12009
|
var IMPORTANCE_LEVELS = [
|
|
11991
12010
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
11992
12011
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -12016,7 +12035,7 @@ function importanceTokens(id) {
|
|
|
12016
12035
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "", disabled = false }) {
|
|
12017
12036
|
const lvl = importanceLevel(level);
|
|
12018
12037
|
const t = importanceTokens(level);
|
|
12019
|
-
return /* @__PURE__ */ (0,
|
|
12038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
|
|
12020
12039
|
"span",
|
|
12021
12040
|
{
|
|
12022
12041
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "),
|
|
@@ -12024,16 +12043,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
|
|
|
12024
12043
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
12025
12044
|
"aria-disabled": disabled ? "true" : void 0,
|
|
12026
12045
|
children: [
|
|
12027
|
-
/* @__PURE__ */ (0,
|
|
12028
|
-
showLabel ? lvl.label : /* @__PURE__ */ (0,
|
|
12046
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
12047
|
+
showLabel ? lvl.label : /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("span", { className: "fd-sr", children: lvl.label })
|
|
12029
12048
|
]
|
|
12030
12049
|
}
|
|
12031
12050
|
);
|
|
12032
12051
|
}
|
|
12033
12052
|
|
|
12034
12053
|
// src/components/planner/PreferenceMeter.tsx
|
|
12035
|
-
var
|
|
12036
|
-
var
|
|
12054
|
+
var React63 = __toESM(require("react"), 1);
|
|
12055
|
+
var import_jsx_runtime94 = require("react/jsx-runtime");
|
|
12037
12056
|
function preferenceScore(criteria) {
|
|
12038
12057
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
12039
12058
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -12062,8 +12081,8 @@ function PreferenceMeter({
|
|
|
12062
12081
|
className = ""
|
|
12063
12082
|
}) {
|
|
12064
12083
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
12065
|
-
const segments =
|
|
12066
|
-
return /* @__PURE__ */ (0,
|
|
12084
|
+
const segments = React63.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
12085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
|
|
12067
12086
|
ScoreMeter,
|
|
12068
12087
|
{
|
|
12069
12088
|
score: value,
|
|
@@ -12075,22 +12094,22 @@ function PreferenceMeter({
|
|
|
12075
12094
|
placement,
|
|
12076
12095
|
className,
|
|
12077
12096
|
breakdownLabel: breakdownTitle,
|
|
12078
|
-
breakdown: /* @__PURE__ */ (0,
|
|
12079
|
-
/* @__PURE__ */ (0,
|
|
12080
|
-
/* @__PURE__ */ (0,
|
|
12081
|
-
/* @__PURE__ */ (0,
|
|
12097
|
+
breakdown: /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fd-prefbreak", children: [
|
|
12098
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("div", { className: "fd-prefbreak-head", children: [
|
|
12099
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
12100
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
12082
12101
|
] }),
|
|
12083
|
-
/* @__PURE__ */ (0,
|
|
12102
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
12084
12103
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
12085
|
-
return /* @__PURE__ */ (0,
|
|
12086
|
-
/* @__PURE__ */ (0,
|
|
12087
|
-
/* @__PURE__ */ (0,
|
|
12088
|
-
/* @__PURE__ */ (0,
|
|
12089
|
-
c.note ? /* @__PURE__ */ (0,
|
|
12104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
12105
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)(ImportanceTag, { level: c.importance }),
|
|
12106
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-prefbreak-text", children: [
|
|
12107
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
12108
|
+
c.note ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
12090
12109
|
] }),
|
|
12091
|
-
/* @__PURE__ */ (0,
|
|
12110
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
12092
12111
|
Math.round(Number(c.earned) || 0),
|
|
12093
|
-
/* @__PURE__ */ (0,
|
|
12112
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
12094
12113
|
Math.round(c.weight)
|
|
12095
12114
|
] })
|
|
12096
12115
|
] }, c.id);
|
|
@@ -12101,10 +12120,10 @@ function PreferenceMeter({
|
|
|
12101
12120
|
}
|
|
12102
12121
|
|
|
12103
12122
|
// src/components/chat/AgentChatPanel.tsx
|
|
12104
|
-
var
|
|
12123
|
+
var React69 = __toESM(require("react"), 1);
|
|
12105
12124
|
|
|
12106
12125
|
// src/components/chat/chatEngine.ts
|
|
12107
|
-
var
|
|
12126
|
+
var React64 = __toESM(require("react"), 1);
|
|
12108
12127
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
12109
12128
|
var JOB_PENDING = ["queued", "running"];
|
|
12110
12129
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -12158,22 +12177,22 @@ function useChatEngine(opts) {
|
|
|
12158
12177
|
onClear,
|
|
12159
12178
|
onFeedback
|
|
12160
12179
|
} = opts || {};
|
|
12161
|
-
const [status, setStatus] =
|
|
12162
|
-
const [threadId, setThreadId] =
|
|
12163
|
-
const [messages, setMessages] =
|
|
12164
|
-
const [queue, setQueue] =
|
|
12165
|
-
const [fatal, setFatal] =
|
|
12166
|
-
const [busy, setBusy] =
|
|
12167
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
12168
|
-
const listRef =
|
|
12169
|
-
const queueRef =
|
|
12170
|
-
const busyRef =
|
|
12171
|
-
const stoppedRef =
|
|
12172
|
-
const abortRef =
|
|
12173
|
-
const serverCount =
|
|
12174
|
-
const threadRef =
|
|
12175
|
-
const mounted =
|
|
12176
|
-
|
|
12180
|
+
const [status, setStatus] = React64.useState("idle");
|
|
12181
|
+
const [threadId, setThreadId] = React64.useState(null);
|
|
12182
|
+
const [messages, setMessages] = React64.useState([]);
|
|
12183
|
+
const [queue, setQueue] = React64.useState([]);
|
|
12184
|
+
const [fatal, setFatal] = React64.useState(null);
|
|
12185
|
+
const [busy, setBusy] = React64.useState(false);
|
|
12186
|
+
const [turnStartedAt, setTurnStartedAt] = React64.useState(null);
|
|
12187
|
+
const listRef = React64.useRef([]);
|
|
12188
|
+
const queueRef = React64.useRef([]);
|
|
12189
|
+
const busyRef = React64.useRef(false);
|
|
12190
|
+
const stoppedRef = React64.useRef(false);
|
|
12191
|
+
const abortRef = React64.useRef(null);
|
|
12192
|
+
const serverCount = React64.useRef(0);
|
|
12193
|
+
const threadRef = React64.useRef(null);
|
|
12194
|
+
const mounted = React64.useRef(true);
|
|
12195
|
+
React64.useEffect(() => {
|
|
12177
12196
|
mounted.current = true;
|
|
12178
12197
|
return () => {
|
|
12179
12198
|
mounted.current = false;
|
|
@@ -12195,14 +12214,14 @@ function useChatEngine(opts) {
|
|
|
12195
12214
|
}
|
|
12196
12215
|
return false;
|
|
12197
12216
|
};
|
|
12198
|
-
const loadThread =
|
|
12217
|
+
const loadThread = React64.useCallback(async (id) => {
|
|
12199
12218
|
const data = await apiAdapter.getThread(id);
|
|
12200
12219
|
const list = [...data && data.messages || []];
|
|
12201
12220
|
serverCount.current = list.length;
|
|
12202
12221
|
commit(list);
|
|
12203
12222
|
return list;
|
|
12204
12223
|
}, [apiAdapter]);
|
|
12205
|
-
|
|
12224
|
+
React64.useEffect(() => {
|
|
12206
12225
|
if (!apiAdapter) {
|
|
12207
12226
|
setStatus("idle");
|
|
12208
12227
|
setFatal(null);
|
|
@@ -12415,7 +12434,7 @@ function useChatEngine(opts) {
|
|
|
12415
12434
|
await dispatchTurn(turn);
|
|
12416
12435
|
}
|
|
12417
12436
|
}
|
|
12418
|
-
const send =
|
|
12437
|
+
const send = React64.useCallback((text, attachments) => {
|
|
12419
12438
|
const body = (text || "").trim();
|
|
12420
12439
|
if (!body && !(attachments && attachments.length)) return;
|
|
12421
12440
|
if (status === "disconnected") return;
|
|
@@ -12425,7 +12444,7 @@ function useChatEngine(opts) {
|
|
|
12425
12444
|
stoppedRef.current = false;
|
|
12426
12445
|
drain();
|
|
12427
12446
|
}, [status]);
|
|
12428
|
-
const stop =
|
|
12447
|
+
const stop = React64.useCallback(() => {
|
|
12429
12448
|
stoppedRef.current = true;
|
|
12430
12449
|
const ac = abortRef.current;
|
|
12431
12450
|
if (ac) {
|
|
@@ -12444,11 +12463,11 @@ function useChatEngine(opts) {
|
|
|
12444
12463
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
12445
12464
|
}
|
|
12446
12465
|
}, [apiAdapter]);
|
|
12447
|
-
const removeQueued =
|
|
12466
|
+
const removeQueued = React64.useCallback((id) => {
|
|
12448
12467
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
12449
12468
|
setQueue(queueRef.current.slice());
|
|
12450
12469
|
}, []);
|
|
12451
|
-
const retry =
|
|
12470
|
+
const retry = React64.useCallback(() => {
|
|
12452
12471
|
const list = listRef.current;
|
|
12453
12472
|
let at = -1;
|
|
12454
12473
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -12464,19 +12483,19 @@ function useChatEngine(opts) {
|
|
|
12464
12483
|
setQueue(queueRef.current.slice());
|
|
12465
12484
|
drain();
|
|
12466
12485
|
}, []);
|
|
12467
|
-
const clear =
|
|
12486
|
+
const clear = React64.useCallback(() => {
|
|
12468
12487
|
commit([]);
|
|
12469
12488
|
serverCount.current = 0;
|
|
12470
12489
|
queueRef.current = [];
|
|
12471
12490
|
setQueue([]);
|
|
12472
12491
|
onClear && onClear();
|
|
12473
12492
|
}, [onClear]);
|
|
12474
|
-
const setFeedback =
|
|
12493
|
+
const setFeedback = React64.useCallback((id, value) => {
|
|
12475
12494
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
12476
12495
|
const msg = listRef.current.find((m) => m.id === id);
|
|
12477
12496
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
12478
12497
|
}, [onFeedback]);
|
|
12479
|
-
const reload =
|
|
12498
|
+
const reload = React64.useCallback(async () => {
|
|
12480
12499
|
if (!threadRef.current) return;
|
|
12481
12500
|
setStatus("loading");
|
|
12482
12501
|
try {
|
|
@@ -12514,11 +12533,11 @@ var ChatKit = {
|
|
|
12514
12533
|
};
|
|
12515
12534
|
|
|
12516
12535
|
// src/components/chat/ChatTranscript.tsx
|
|
12517
|
-
var
|
|
12536
|
+
var React66 = __toESM(require("react"), 1);
|
|
12518
12537
|
|
|
12519
12538
|
// src/components/chat/ChatTurn.tsx
|
|
12520
|
-
var
|
|
12521
|
-
var
|
|
12539
|
+
var React65 = __toESM(require("react"), 1);
|
|
12540
|
+
var import_jsx_runtime95 = require("react/jsx-runtime");
|
|
12522
12541
|
function JsonView({ value }) {
|
|
12523
12542
|
let text;
|
|
12524
12543
|
try {
|
|
@@ -12526,67 +12545,67 @@ function JsonView({ value }) {
|
|
|
12526
12545
|
} catch (e) {
|
|
12527
12546
|
text = String(value);
|
|
12528
12547
|
}
|
|
12529
|
-
return /* @__PURE__ */ (0,
|
|
12548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
12530
12549
|
}
|
|
12531
12550
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
12532
12551
|
if (!packet) return null;
|
|
12533
12552
|
const s = schema || {};
|
|
12534
12553
|
const invalid = packet.valid === false;
|
|
12535
12554
|
const title = s.heading || packet.type;
|
|
12536
|
-
return /* @__PURE__ */ (0,
|
|
12537
|
-
/* @__PURE__ */ (0,
|
|
12538
|
-
/* @__PURE__ */ (0,
|
|
12539
|
-
/* @__PURE__ */ (0,
|
|
12540
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
12541
|
-
invalid ? /* @__PURE__ */ (0,
|
|
12555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
12556
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("header", { className: "fdc-packet-head", children: [
|
|
12557
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
12558
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
|
|
12559
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
12560
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
12542
12561
|
] }),
|
|
12543
|
-
invalid ? /* @__PURE__ */ (0,
|
|
12544
|
-
/* @__PURE__ */ (0,
|
|
12545
|
-
/* @__PURE__ */ (0,
|
|
12546
|
-
] }) : /* @__PURE__ */ (0,
|
|
12547
|
-
!invalid && onApply ? /* @__PURE__ */ (0,
|
|
12548
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
12549
|
-
/* @__PURE__ */ (0,
|
|
12550
|
-
/* @__PURE__ */ (0,
|
|
12562
|
+
invalid ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
12563
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
12564
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
12565
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(JsonView, { value: packet.payload }) }),
|
|
12566
|
+
!invalid && onApply ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("footer", { className: "fdc-packet-foot", children: [
|
|
12567
|
+
packet.repaired ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
|
|
12568
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
12569
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
12551
12570
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
12552
12571
|
] })
|
|
12553
12572
|
] }) : null
|
|
12554
12573
|
] });
|
|
12555
12574
|
}
|
|
12556
12575
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
12557
|
-
const [open2, setOpen] =
|
|
12576
|
+
const [open2, setOpen] = React65.useState(defaultOpen);
|
|
12558
12577
|
if (!text) return null;
|
|
12559
|
-
return /* @__PURE__ */ (0,
|
|
12560
|
-
/* @__PURE__ */ (0,
|
|
12561
|
-
/* @__PURE__ */ (0,
|
|
12562
|
-
/* @__PURE__ */ (0,
|
|
12563
|
-
streaming ? /* @__PURE__ */ (0,
|
|
12564
|
-
/* @__PURE__ */ (0,
|
|
12565
|
-
/* @__PURE__ */ (0,
|
|
12566
|
-
/* @__PURE__ */ (0,
|
|
12578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
|
|
12579
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
|
|
12580
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
12581
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
12582
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
12583
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
|
|
12584
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
|
|
12585
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {})
|
|
12567
12586
|
] }) : null,
|
|
12568
|
-
/* @__PURE__ */ (0,
|
|
12587
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12569
12588
|
] }),
|
|
12570
|
-
open2 ? /* @__PURE__ */ (0,
|
|
12589
|
+
open2 ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-think-body", children: text }) : null
|
|
12571
12590
|
] });
|
|
12572
12591
|
}
|
|
12573
12592
|
function Citations({ items = [], onOpen }) {
|
|
12574
|
-
const [open2, setOpen] =
|
|
12593
|
+
const [open2, setOpen] = React65.useState(false);
|
|
12575
12594
|
if (!items.length) return null;
|
|
12576
|
-
return /* @__PURE__ */ (0,
|
|
12577
|
-
/* @__PURE__ */ (0,
|
|
12578
|
-
/* @__PURE__ */ (0,
|
|
12579
|
-
/* @__PURE__ */ (0,
|
|
12595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-cites", children: [
|
|
12596
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
|
|
12597
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
12598
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { children: [
|
|
12580
12599
|
items.length,
|
|
12581
12600
|
" source",
|
|
12582
12601
|
items.length === 1 ? "" : "s"
|
|
12583
12602
|
] }),
|
|
12584
|
-
/* @__PURE__ */ (0,
|
|
12603
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12585
12604
|
] }),
|
|
12586
|
-
open2 ? /* @__PURE__ */ (0,
|
|
12587
|
-
/* @__PURE__ */ (0,
|
|
12588
|
-
c.url ? /* @__PURE__ */ (0,
|
|
12589
|
-
c.detail ? /* @__PURE__ */ (0,
|
|
12605
|
+
open2 ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("li", { children: [
|
|
12606
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
12607
|
+
c.url ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { children: c.title || "Source" }),
|
|
12608
|
+
c.detail ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
12590
12609
|
] }, c.id || i)) }) : null
|
|
12591
12610
|
] });
|
|
12592
12611
|
}
|
|
@@ -12597,29 +12616,29 @@ function clampText(text, max) {
|
|
|
12597
12616
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
12598
12617
|
}
|
|
12599
12618
|
function MessageBody({ message: m, ctx }) {
|
|
12600
|
-
const [expanded, setExpanded] =
|
|
12619
|
+
const [expanded, setExpanded] = React65.useState(false);
|
|
12601
12620
|
const isUser = m.role === "user";
|
|
12602
12621
|
const raw = m.text || "";
|
|
12603
12622
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
12604
12623
|
const body = clamped != null ? clamped : raw;
|
|
12605
12624
|
const showMd = ctx.markdown && !isUser;
|
|
12606
|
-
return /* @__PURE__ */ (0,
|
|
12607
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0,
|
|
12608
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0,
|
|
12609
|
-
body ? /* @__PURE__ */ (0,
|
|
12610
|
-
showMd ? /* @__PURE__ */ (0,
|
|
12611
|
-
m.streaming ? /* @__PURE__ */ (0,
|
|
12625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-body", children: [
|
|
12626
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
12627
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
12628
|
+
body ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
12629
|
+
showMd ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-plain", children: body }),
|
|
12630
|
+
m.streaming ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
12612
12631
|
] }) : null,
|
|
12613
|
-
clamped != null ? /* @__PURE__ */ (0,
|
|
12614
|
-
/* @__PURE__ */ (0,
|
|
12632
|
+
clamped != null ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
12633
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
12615
12634
|
"Show more",
|
|
12616
|
-
/* @__PURE__ */ (0,
|
|
12617
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0,
|
|
12618
|
-
/* @__PURE__ */ (0,
|
|
12635
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
12636
|
+
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
12637
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
12619
12638
|
"Show less"
|
|
12620
12639
|
] }) : null,
|
|
12621
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */ (0,
|
|
12622
|
-
m.packet ? /* @__PURE__ */ (0,
|
|
12640
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
12641
|
+
m.packet ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
|
|
12623
12642
|
PacketCard,
|
|
12624
12643
|
{
|
|
12625
12644
|
packet: m.packet,
|
|
@@ -12629,35 +12648,35 @@ function MessageBody({ message: m, ctx }) {
|
|
|
12629
12648
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
12630
12649
|
}
|
|
12631
12650
|
) : null,
|
|
12632
|
-
m.citations && m.citations.length ? /* @__PURE__ */ (0,
|
|
12633
|
-
m.working ? /* @__PURE__ */ (0,
|
|
12634
|
-
/* @__PURE__ */ (0,
|
|
12635
|
-
/* @__PURE__ */ (0,
|
|
12636
|
-
/* @__PURE__ */ (0,
|
|
12637
|
-
/* @__PURE__ */ (0,
|
|
12651
|
+
m.citations && m.citations.length ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
12652
|
+
m.working ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-working", role: "status", children: [
|
|
12653
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
12654
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
|
|
12655
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {}),
|
|
12656
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", {})
|
|
12638
12657
|
] }),
|
|
12639
|
-
/* @__PURE__ */ (0,
|
|
12658
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-label", children: [
|
|
12640
12659
|
m.resumed ? "Resuming" : "Working",
|
|
12641
|
-
m.job && m.job.status ? /* @__PURE__ */ (0,
|
|
12660
|
+
m.job && m.job.status ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-job", children: [
|
|
12642
12661
|
" \xB7 ",
|
|
12643
12662
|
m.job.status
|
|
12644
12663
|
] }) : null,
|
|
12645
|
-
m.job && m.job.detail ? /* @__PURE__ */ (0,
|
|
12664
|
+
m.job && m.job.detail ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-job", children: [
|
|
12646
12665
|
" \xB7 ",
|
|
12647
12666
|
m.job.detail
|
|
12648
12667
|
] }) : null
|
|
12649
12668
|
] }),
|
|
12650
|
-
m.jobId ? /* @__PURE__ */ (0,
|
|
12669
|
+
m.jobId ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
12651
12670
|
] }) : null,
|
|
12652
|
-
m.stopped ? /* @__PURE__ */ (0,
|
|
12653
|
-
/* @__PURE__ */ (0,
|
|
12671
|
+
m.stopped ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-stopped", children: [
|
|
12672
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
12654
12673
|
"Stopped"
|
|
12655
12674
|
] }) : null,
|
|
12656
|
-
m.error ? /* @__PURE__ */ (0,
|
|
12657
|
-
/* @__PURE__ */ (0,
|
|
12658
|
-
/* @__PURE__ */ (0,
|
|
12659
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
12660
|
-
/* @__PURE__ */ (0,
|
|
12675
|
+
m.error ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-error", role: "alert", children: [
|
|
12676
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
12677
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
12678
|
+
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
12679
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
12661
12680
|
"Retry"
|
|
12662
12681
|
] }) : null
|
|
12663
12682
|
] }) : null
|
|
@@ -12670,16 +12689,16 @@ function RunActions({ group, ctx }) {
|
|
|
12670
12689
|
const isAssistant = group.role === "assistant";
|
|
12671
12690
|
const fb = last.feedback;
|
|
12672
12691
|
if (!ctx.messageActions) return null;
|
|
12673
|
-
return /* @__PURE__ */ (0,
|
|
12674
|
-
/* @__PURE__ */ (0,
|
|
12675
|
-
/* @__PURE__ */ (0,
|
|
12676
|
-
/* @__PURE__ */ (0,
|
|
12692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
12693
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
12694
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
12695
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
12677
12696
|
] }),
|
|
12678
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
12679
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0,
|
|
12680
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0,
|
|
12681
|
-
/* @__PURE__ */ (0,
|
|
12682
|
-
/* @__PURE__ */ (0,
|
|
12697
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
12698
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
12699
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(React65.Fragment, { children: [
|
|
12700
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
12701
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
12683
12702
|
] }) : null,
|
|
12684
12703
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
12685
12704
|
] });
|
|
@@ -12689,22 +12708,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
12689
12708
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
12690
12709
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
12691
12710
|
const stamp = group.messages[0].timestamp;
|
|
12692
|
-
return /* @__PURE__ */ (0,
|
|
12693
|
-
/* @__PURE__ */ (0,
|
|
12694
|
-
ctx.showAvatars ? /* @__PURE__ */ (0,
|
|
12695
|
-
/* @__PURE__ */ (0,
|
|
12696
|
-
stamp ? /* @__PURE__ */ (0,
|
|
12697
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0,
|
|
12711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
12712
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-turn-head", children: [
|
|
12713
|
+
ctx.showAvatars ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
12714
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-who", children: name }),
|
|
12715
|
+
stamp ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
12716
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
12698
12717
|
] }),
|
|
12699
|
-
/* @__PURE__ */ (0,
|
|
12700
|
-
group.messages.map((m) => /* @__PURE__ */ (0,
|
|
12701
|
-
/* @__PURE__ */ (0,
|
|
12718
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "fdc-turn-body", children: [
|
|
12719
|
+
group.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(MessageBody, { message: m, ctx }) }, m.id)),
|
|
12720
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)(RunActions, { group, ctx })
|
|
12702
12721
|
] })
|
|
12703
12722
|
] });
|
|
12704
12723
|
}
|
|
12705
12724
|
|
|
12706
12725
|
// src/components/chat/ChatTranscript.tsx
|
|
12707
|
-
var
|
|
12726
|
+
var import_jsx_runtime96 = require("react/jsx-runtime");
|
|
12708
12727
|
var GROUP_WINDOW = 6e4;
|
|
12709
12728
|
var STICK_PX = 100;
|
|
12710
12729
|
function groupMessages(list) {
|
|
@@ -12737,25 +12756,25 @@ function dayLabel(key) {
|
|
|
12737
12756
|
}
|
|
12738
12757
|
function Suggestions({ items = [], onPick }) {
|
|
12739
12758
|
if (!items.length) return null;
|
|
12740
|
-
return /* @__PURE__ */ (0,
|
|
12759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
12741
12760
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
12742
|
-
return /* @__PURE__ */ (0,
|
|
12743
|
-
it.icon ? /* @__PURE__ */ (0,
|
|
12744
|
-
/* @__PURE__ */ (0,
|
|
12745
|
-
/* @__PURE__ */ (0,
|
|
12746
|
-
it.description ? /* @__PURE__ */ (0,
|
|
12761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
12762
|
+
it.icon ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
12763
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("span", { className: "fdc-suggest-text", children: [
|
|
12764
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-suggest-label", children: it.label }),
|
|
12765
|
+
it.description ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
12747
12766
|
] }),
|
|
12748
|
-
/* @__PURE__ */ (0,
|
|
12767
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
12749
12768
|
] }, it.id || i);
|
|
12750
12769
|
}) });
|
|
12751
12770
|
}
|
|
12752
12771
|
function LoadingTurns() {
|
|
12753
|
-
return /* @__PURE__ */ (0,
|
|
12754
|
-
/* @__PURE__ */ (0,
|
|
12755
|
-
/* @__PURE__ */ (0,
|
|
12756
|
-
/* @__PURE__ */ (0,
|
|
12757
|
-
/* @__PURE__ */ (0,
|
|
12758
|
-
/* @__PURE__ */ (0,
|
|
12772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-skel-turn", children: [
|
|
12773
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
12774
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-skel-lines", children: [
|
|
12775
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
12776
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
12777
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
12759
12778
|
] })
|
|
12760
12779
|
] }, i)) });
|
|
12761
12780
|
}
|
|
@@ -12772,10 +12791,10 @@ function ChatTranscript({
|
|
|
12772
12791
|
renderEmpty,
|
|
12773
12792
|
className = ""
|
|
12774
12793
|
}) {
|
|
12775
|
-
const scroller =
|
|
12776
|
-
const stick =
|
|
12777
|
-
const [pill, setPill] =
|
|
12778
|
-
const seen =
|
|
12794
|
+
const scroller = React66.useRef(null);
|
|
12795
|
+
const stick = React66.useRef(true);
|
|
12796
|
+
const [pill, setPill] = React66.useState(0);
|
|
12797
|
+
const seen = React66.useRef(0);
|
|
12779
12798
|
const toBottom = (smooth) => {
|
|
12780
12799
|
const el = scroller.current;
|
|
12781
12800
|
if (!el) return;
|
|
@@ -12794,7 +12813,7 @@ function ChatTranscript({
|
|
|
12794
12813
|
seen.current = messages.length;
|
|
12795
12814
|
}
|
|
12796
12815
|
};
|
|
12797
|
-
|
|
12816
|
+
React66.useLayoutEffect(() => {
|
|
12798
12817
|
const el = scroller.current;
|
|
12799
12818
|
if (!el) return;
|
|
12800
12819
|
if (stick.current) {
|
|
@@ -12802,7 +12821,7 @@ function ChatTranscript({
|
|
|
12802
12821
|
seen.current = messages.length;
|
|
12803
12822
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
12804
12823
|
}, [messages]);
|
|
12805
|
-
|
|
12824
|
+
React66.useEffect(() => {
|
|
12806
12825
|
const el = scroller.current;
|
|
12807
12826
|
const inner = el && el.firstChild;
|
|
12808
12827
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -12812,38 +12831,38 @@ function ChatTranscript({
|
|
|
12812
12831
|
ro.observe(inner);
|
|
12813
12832
|
return () => ro.disconnect();
|
|
12814
12833
|
}, []);
|
|
12815
|
-
const groups =
|
|
12834
|
+
const groups = React66.useMemo(() => groupMessages(messages), [messages]);
|
|
12816
12835
|
const empty = !messages.length && status === "ready";
|
|
12817
|
-
return /* @__PURE__ */ (0,
|
|
12818
|
-
/* @__PURE__ */ (0,
|
|
12819
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0,
|
|
12820
|
-
status === "disconnected" ? /* @__PURE__ */ (0,
|
|
12821
|
-
/* @__PURE__ */ (0,
|
|
12822
|
-
/* @__PURE__ */ (0,
|
|
12823
|
-
/* @__PURE__ */ (0,
|
|
12824
|
-
ctx.onReconnect ? /* @__PURE__ */ (0,
|
|
12825
|
-
/* @__PURE__ */ (0,
|
|
12836
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
12837
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
12838
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(LoadingTurns, {}) : null,
|
|
12839
|
+
status === "disconnected" ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-dead", children: [
|
|
12840
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
12841
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
12842
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "fdc-dead-body", children: fatal === "chat_unavailable" ? "The service reported chat_unavailable. Nothing you type will be lost \u2014 reopen the panel once it\u2019s back." : "The thread couldn\u2019t be resolved" + (fatal ? " (" + fatal + ")" : "") + ". The composer stays disabled until it resolves." }),
|
|
12843
|
+
ctx.onReconnect ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
12844
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
12826
12845
|
"Try again"
|
|
12827
12846
|
] }) : null
|
|
12828
12847
|
] }) : null,
|
|
12829
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0,
|
|
12830
|
-
/* @__PURE__ */ (0,
|
|
12831
|
-
/* @__PURE__ */ (0,
|
|
12832
|
-
emptyDescription ? /* @__PURE__ */ (0,
|
|
12833
|
-
/* @__PURE__ */ (0,
|
|
12848
|
+
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "fdc-empty", children: [
|
|
12849
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
12850
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
12851
|
+
emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
12852
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)(Suggestions, { items: suggestions, onPick })
|
|
12834
12853
|
] }) : null,
|
|
12835
12854
|
groups.map((g, i) => {
|
|
12836
12855
|
const prev = groups[i - 1];
|
|
12837
12856
|
const k = dayKey(g.messages[0].timestamp);
|
|
12838
12857
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
12839
|
-
return /* @__PURE__ */ (0,
|
|
12840
|
-
showDay ? /* @__PURE__ */ (0,
|
|
12841
|
-
/* @__PURE__ */ (0,
|
|
12858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)(React66.Fragment, { children: [
|
|
12859
|
+
showDay ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
12860
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)(ChatTurn, { group: g, ctx })
|
|
12842
12861
|
] }, g.key || i);
|
|
12843
12862
|
})
|
|
12844
12863
|
] }),
|
|
12845
|
-
pill ? /* @__PURE__ */ (0,
|
|
12846
|
-
/* @__PURE__ */ (0,
|
|
12864
|
+
pill ? /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
12865
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
12847
12866
|
pill,
|
|
12848
12867
|
" new message",
|
|
12849
12868
|
pill === 1 ? "" : "s"
|
|
@@ -12853,8 +12872,8 @@ function ChatTranscript({
|
|
|
12853
12872
|
var TranscriptKit = { groupMessages };
|
|
12854
12873
|
|
|
12855
12874
|
// src/components/chat/ChatComposer.tsx
|
|
12856
|
-
var
|
|
12857
|
-
var
|
|
12875
|
+
var React67 = __toESM(require("react"), 1);
|
|
12876
|
+
var import_jsx_runtime97 = require("react/jsx-runtime");
|
|
12858
12877
|
function ChatComposer({
|
|
12859
12878
|
onSubmit,
|
|
12860
12879
|
onStop,
|
|
@@ -12881,17 +12900,17 @@ function ChatComposer({
|
|
|
12881
12900
|
onReject,
|
|
12882
12901
|
onOpenAttachment
|
|
12883
12902
|
}) {
|
|
12884
|
-
const [text, setText] =
|
|
12885
|
-
const [trigger, setTrigger] =
|
|
12886
|
-
const [mentionItems, setMentionItems] =
|
|
12887
|
-
const [listening, setListening] =
|
|
12888
|
-
const [notice, setNotice] =
|
|
12889
|
-
const editor =
|
|
12890
|
-
const wrap =
|
|
12891
|
-
const stopVoice =
|
|
12903
|
+
const [text, setText] = React67.useState(draft || "");
|
|
12904
|
+
const [trigger, setTrigger] = React67.useState(null);
|
|
12905
|
+
const [mentionItems, setMentionItems] = React67.useState([]);
|
|
12906
|
+
const [listening, setListening] = React67.useState(false);
|
|
12907
|
+
const [notice, setNotice] = React67.useState(null);
|
|
12908
|
+
const editor = React67.useRef(null);
|
|
12909
|
+
const wrap = React67.useRef(null);
|
|
12910
|
+
const stopVoice = React67.useRef(null);
|
|
12892
12911
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
12893
12912
|
} });
|
|
12894
|
-
|
|
12913
|
+
React67.useEffect(() => {
|
|
12895
12914
|
if (draft != null && draft !== text) setText(draft);
|
|
12896
12915
|
}, [draft]);
|
|
12897
12916
|
const change = (v) => {
|
|
@@ -12927,7 +12946,7 @@ function ChatComposer({
|
|
|
12927
12946
|
e.preventDefault();
|
|
12928
12947
|
staged.add(found.files);
|
|
12929
12948
|
};
|
|
12930
|
-
|
|
12949
|
+
React67.useEffect(() => {
|
|
12931
12950
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
12932
12951
|
setMentionItems([]);
|
|
12933
12952
|
return;
|
|
@@ -12945,7 +12964,7 @@ function ChatComposer({
|
|
|
12945
12964
|
const q = (trigger.query || "").toLowerCase();
|
|
12946
12965
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
12947
12966
|
}, [trigger, mentionSources]);
|
|
12948
|
-
const slashItems =
|
|
12967
|
+
const slashItems = React67.useMemo(() => {
|
|
12949
12968
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
12950
12969
|
const q = (trigger.query || "").toLowerCase();
|
|
12951
12970
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -12959,7 +12978,7 @@ function ChatComposer({
|
|
|
12959
12978
|
description: it.description,
|
|
12960
12979
|
icon: it.icon,
|
|
12961
12980
|
meta: mention.meta,
|
|
12962
|
-
shortcut: slash.shortcut ? /* @__PURE__ */ (0,
|
|
12981
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
12963
12982
|
onSelect: () => {
|
|
12964
12983
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
12965
12984
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -13018,14 +13037,14 @@ function ChatComposer({
|
|
|
13018
13037
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
13019
13038
|
};
|
|
13020
13039
|
};
|
|
13021
|
-
return /* @__PURE__ */ (0,
|
|
13022
|
-
queue.length ? /* @__PURE__ */ (0,
|
|
13023
|
-
/* @__PURE__ */ (0,
|
|
13024
|
-
/* @__PURE__ */ (0,
|
|
13025
|
-
onRemoveQueued ? /* @__PURE__ */ (0,
|
|
13040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
13041
|
+
queue.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-queue-row", children: [
|
|
13042
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
13043
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-queue-text", title: truncationTitle(q.text || (q.attachments ? q.attachments.length + " file(s)" : "")), children: q.text || (q.attachments ? q.attachments.length + " file(s)" : "") }),
|
|
13044
|
+
onRemoveQueued ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
13026
13045
|
] }, q.id)) }) : null,
|
|
13027
13046
|
sessionBar,
|
|
13028
|
-
/* @__PURE__ */ (0,
|
|
13047
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13029
13048
|
Dropzone,
|
|
13030
13049
|
{
|
|
13031
13050
|
className: "fdc-field",
|
|
@@ -13039,9 +13058,9 @@ function ChatComposer({
|
|
|
13039
13058
|
disabled: !fileUploadHandler || disabled,
|
|
13040
13059
|
label: "Drop to attach",
|
|
13041
13060
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
13042
|
-
children: /* @__PURE__ */ (0,
|
|
13043
|
-
staged.items.length ? /* @__PURE__ */ (0,
|
|
13044
|
-
/* @__PURE__ */ (0,
|
|
13061
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
13062
|
+
staged.items.length ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-staged", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
13063
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13045
13064
|
MarkdownEditor,
|
|
13046
13065
|
{
|
|
13047
13066
|
ref: editor,
|
|
@@ -13060,33 +13079,33 @@ function ChatComposer({
|
|
|
13060
13079
|
ariaLabel: "Message"
|
|
13061
13080
|
}
|
|
13062
13081
|
),
|
|
13063
|
-
/* @__PURE__ */ (0,
|
|
13064
|
-
fileUploadHandler ? /* @__PURE__ */ (0,
|
|
13065
|
-
voiceHandler ? /* @__PURE__ */ (0,
|
|
13082
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-tools", children: [
|
|
13083
|
+
fileUploadHandler ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
13084
|
+
voiceHandler ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
13066
13085
|
toolbarExtras,
|
|
13067
|
-
/* @__PURE__ */ (0,
|
|
13068
|
-
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0,
|
|
13086
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-tools-gap" }),
|
|
13087
|
+
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
13069
13088
|
text.length,
|
|
13070
13089
|
"/",
|
|
13071
13090
|
maxLength
|
|
13072
13091
|
] }) : null,
|
|
13073
|
-
busy ? /* @__PURE__ */ (0,
|
|
13074
|
-
/* @__PURE__ */ (0,
|
|
13075
|
-
/* @__PURE__ */ (0,
|
|
13076
|
-
] }) : /* @__PURE__ */ (0,
|
|
13077
|
-
/* @__PURE__ */ (0,
|
|
13078
|
-
/* @__PURE__ */ (0,
|
|
13092
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
13093
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
13094
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { children: "Stop" })
|
|
13095
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
13096
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
13097
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "fdc-send-label", children: "Send" })
|
|
13079
13098
|
] })
|
|
13080
13099
|
] })
|
|
13081
13100
|
] })
|
|
13082
13101
|
}
|
|
13083
13102
|
),
|
|
13084
|
-
notice ? /* @__PURE__ */ (0,
|
|
13085
|
-
/* @__PURE__ */ (0,
|
|
13103
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "fdc-notice", role: "status", children: [
|
|
13104
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
13086
13105
|
notice
|
|
13087
13106
|
] }) : null,
|
|
13088
|
-
hint && !notice ? /* @__PURE__ */ (0,
|
|
13089
|
-
/* @__PURE__ */ (0,
|
|
13107
|
+
hint && !notice ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fdc-hint", children: hint }) : null,
|
|
13108
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13090
13109
|
Popover,
|
|
13091
13110
|
{
|
|
13092
13111
|
open: menuOpen,
|
|
@@ -13100,12 +13119,12 @@ function ChatComposer({
|
|
|
13100
13119
|
returnFocus: false,
|
|
13101
13120
|
closeOnOutside: true,
|
|
13102
13121
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
13103
|
-
children: /* @__PURE__ */ (0,
|
|
13122
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13104
13123
|
Menu,
|
|
13105
13124
|
{
|
|
13106
13125
|
items: menuItems,
|
|
13107
13126
|
autoFocus: false,
|
|
13108
|
-
header: /* @__PURE__ */ (0,
|
|
13127
|
+
header: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
13109
13128
|
onClose: () => setTrigger(null)
|
|
13110
13129
|
}
|
|
13111
13130
|
)
|
|
@@ -13115,12 +13134,12 @@ function ChatComposer({
|
|
|
13115
13134
|
}
|
|
13116
13135
|
|
|
13117
13136
|
// src/components/chat/ChatSessionBar.tsx
|
|
13118
|
-
var
|
|
13119
|
-
var
|
|
13137
|
+
var React68 = __toESM(require("react"), 1);
|
|
13138
|
+
var import_jsx_runtime98 = require("react/jsx-runtime");
|
|
13120
13139
|
var compact2 = meterFormats.compact;
|
|
13121
13140
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
13122
|
-
const [open2, setOpen] =
|
|
13123
|
-
const anchor =
|
|
13141
|
+
const [open2, setOpen] = React68.useState(false);
|
|
13142
|
+
const anchor = React68.useRef(null);
|
|
13124
13143
|
const stats = sessionStats || null;
|
|
13125
13144
|
const cu = contextUsage || null;
|
|
13126
13145
|
const limits = usageLimits || null;
|
|
@@ -13135,9 +13154,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13135
13154
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
13136
13155
|
if (cu) bits.push(pct + "% context");
|
|
13137
13156
|
const expandable = !!(cu || limits);
|
|
13138
|
-
return /* @__PURE__ */ (0,
|
|
13139
|
-
/* @__PURE__ */ (0,
|
|
13140
|
-
/* @__PURE__ */ (0,
|
|
13157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
|
|
13158
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fdc-bar", children: [
|
|
13159
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(
|
|
13141
13160
|
"button",
|
|
13142
13161
|
{
|
|
13143
13162
|
type: "button",
|
|
@@ -13148,15 +13167,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13148
13167
|
"aria-expanded": expandable ? open2 : void 0,
|
|
13149
13168
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
13150
13169
|
children: [
|
|
13151
|
-
cu ? /* @__PURE__ */ (0,
|
|
13152
|
-
/* @__PURE__ */ (0,
|
|
13153
|
-
expandable ? /* @__PURE__ */ (0,
|
|
13170
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
13171
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
|
|
13172
|
+
expandable ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
13154
13173
|
]
|
|
13155
13174
|
}
|
|
13156
13175
|
),
|
|
13157
13176
|
extras
|
|
13158
13177
|
] }),
|
|
13159
|
-
/* @__PURE__ */ (0,
|
|
13178
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13160
13179
|
Popover,
|
|
13161
13180
|
{
|
|
13162
13181
|
open: open2,
|
|
@@ -13167,15 +13186,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13167
13186
|
maxHeight: 460,
|
|
13168
13187
|
padded: true,
|
|
13169
13188
|
label: "Usage",
|
|
13170
|
-
footer: onClear ? /* @__PURE__ */ (0,
|
|
13189
|
+
footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
13171
13190
|
setOpen(false);
|
|
13172
13191
|
onClear();
|
|
13173
13192
|
}, children: [
|
|
13174
|
-
/* @__PURE__ */ (0,
|
|
13193
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
13175
13194
|
"Clear conversation"
|
|
13176
13195
|
] }) : void 0,
|
|
13177
|
-
children: /* @__PURE__ */ (0,
|
|
13178
|
-
cu ? /* @__PURE__ */ (0,
|
|
13196
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { className: "fdc-usage", children: [
|
|
13197
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13179
13198
|
SegmentedMeter,
|
|
13180
13199
|
{
|
|
13181
13200
|
total,
|
|
@@ -13187,9 +13206,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13187
13206
|
remainderLabel: "Free"
|
|
13188
13207
|
}
|
|
13189
13208
|
) }) : null,
|
|
13190
|
-
limits && limits.length ? /* @__PURE__ */ (0,
|
|
13191
|
-
/* @__PURE__ */ (0,
|
|
13192
|
-
/* @__PURE__ */ (0,
|
|
13209
|
+
limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("section", { className: "fdc-usage-sec", children: [
|
|
13210
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
13211
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13193
13212
|
QuotaRow,
|
|
13194
13213
|
{
|
|
13195
13214
|
label: l.label,
|
|
@@ -13199,25 +13218,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13199
13218
|
l.id
|
|
13200
13219
|
)) })
|
|
13201
13220
|
] }) : null,
|
|
13202
|
-
stats ? /* @__PURE__ */ (0,
|
|
13203
|
-
stats.elapsedMs ? /* @__PURE__ */ (0,
|
|
13204
|
-
/* @__PURE__ */ (0,
|
|
13205
|
-
/* @__PURE__ */ (0,
|
|
13221
|
+
stats ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
13222
|
+
stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
|
|
13223
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Session" }),
|
|
13224
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
13206
13225
|
] }) : null,
|
|
13207
|
-
stats.tokens ? /* @__PURE__ */ (0,
|
|
13208
|
-
/* @__PURE__ */ (0,
|
|
13209
|
-
/* @__PURE__ */ (0,
|
|
13226
|
+
stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
|
|
13227
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Tokens" }),
|
|
13228
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
13210
13229
|
] }) : null,
|
|
13211
|
-
stats.costUsd != null ? /* @__PURE__ */ (0,
|
|
13212
|
-
/* @__PURE__ */ (0,
|
|
13213
|
-
/* @__PURE__ */ (0,
|
|
13230
|
+
stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
|
|
13231
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Cost" }),
|
|
13232
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("b", { className: "fd-tabular", children: [
|
|
13214
13233
|
"$",
|
|
13215
13234
|
Number(stats.costUsd).toFixed(3)
|
|
13216
13235
|
] })
|
|
13217
13236
|
] }) : null,
|
|
13218
|
-
stats.turns ? /* @__PURE__ */ (0,
|
|
13219
|
-
/* @__PURE__ */ (0,
|
|
13220
|
-
/* @__PURE__ */ (0,
|
|
13237
|
+
stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("div", { children: [
|
|
13238
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: "Turns" }),
|
|
13239
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("b", { className: "fd-tabular", children: stats.turns })
|
|
13221
13240
|
] }) : null
|
|
13222
13241
|
] }) : null
|
|
13223
13242
|
] })
|
|
@@ -13256,7 +13275,7 @@ function ModelControls({
|
|
|
13256
13275
|
disabled: m.disabled,
|
|
13257
13276
|
checked: m.id === (current2 && current2.id),
|
|
13258
13277
|
meta: m.meta,
|
|
13259
|
-
shortcut: m.shortcut ? /* @__PURE__ */ (0,
|
|
13278
|
+
shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
13260
13279
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
13261
13280
|
});
|
|
13262
13281
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -13269,15 +13288,15 @@ function ModelControls({
|
|
|
13269
13288
|
items.push({ kind: "section", label: "Fast mode" });
|
|
13270
13289
|
items.push({
|
|
13271
13290
|
kind: "custom",
|
|
13272
|
-
render: () => /* @__PURE__ */ (0,
|
|
13273
|
-
/* @__PURE__ */ (0,
|
|
13274
|
-
/* @__PURE__ */ (0,
|
|
13275
|
-
/* @__PURE__ */ (0,
|
|
13291
|
+
render: () => /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("label", { className: "fdc-switchrow", children: [
|
|
13292
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { children: fastModeLabel }),
|
|
13293
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
13294
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)("span", { className: "fd-switch-thumb" }) })
|
|
13276
13295
|
] })
|
|
13277
13296
|
});
|
|
13278
13297
|
}
|
|
13279
|
-
return /* @__PURE__ */ (0,
|
|
13280
|
-
/* @__PURE__ */ (0,
|
|
13298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
|
|
13299
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13281
13300
|
MenuButton,
|
|
13282
13301
|
{
|
|
13283
13302
|
items,
|
|
@@ -13288,7 +13307,7 @@ function ModelControls({
|
|
|
13288
13307
|
title: "Choose a model"
|
|
13289
13308
|
}
|
|
13290
13309
|
),
|
|
13291
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */ (0,
|
|
13310
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13292
13311
|
MenuButton,
|
|
13293
13312
|
{
|
|
13294
13313
|
placement: "top-end",
|
|
@@ -13309,7 +13328,7 @@ function ModelControls({
|
|
|
13309
13328
|
}
|
|
13310
13329
|
|
|
13311
13330
|
// src/components/chat/AgentChatPanel.tsx
|
|
13312
|
-
var
|
|
13331
|
+
var import_jsx_runtime99 = require("react/jsx-runtime");
|
|
13313
13332
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
13314
13333
|
function AgentChatPanel({
|
|
13315
13334
|
/* required */
|
|
@@ -13393,11 +13412,11 @@ function AgentChatPanel({
|
|
|
13393
13412
|
onFeedback,
|
|
13394
13413
|
onEditMessage
|
|
13395
13414
|
}) {
|
|
13396
|
-
const [panelWidth, setPanelWidth] =
|
|
13397
|
-
const [applied, setApplied] =
|
|
13398
|
-
const [draft, setDraft] =
|
|
13399
|
-
const dragging =
|
|
13400
|
-
|
|
13415
|
+
const [panelWidth, setPanelWidth] = React69.useState(width);
|
|
13416
|
+
const [applied, setApplied] = React69.useState({});
|
|
13417
|
+
const [draft, setDraft] = React69.useState("");
|
|
13418
|
+
const dragging = React69.useRef(null);
|
|
13419
|
+
React69.useEffect(() => setPanelWidth(width), [width]);
|
|
13401
13420
|
const engine = useChatEngine({
|
|
13402
13421
|
contextType,
|
|
13403
13422
|
contextId,
|
|
@@ -13463,7 +13482,7 @@ function AgentChatPanel({
|
|
|
13463
13482
|
onReconnect: engine.reload,
|
|
13464
13483
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
13465
13484
|
};
|
|
13466
|
-
const sessionBar = /* @__PURE__ */ (0,
|
|
13485
|
+
const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13467
13486
|
ChatSessionBar,
|
|
13468
13487
|
{
|
|
13469
13488
|
sessionStats,
|
|
@@ -13472,7 +13491,7 @@ function AgentChatPanel({
|
|
|
13472
13491
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
13473
13492
|
}
|
|
13474
13493
|
);
|
|
13475
|
-
const modelControls = /* @__PURE__ */ (0,
|
|
13494
|
+
const modelControls = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13476
13495
|
ModelControls,
|
|
13477
13496
|
{
|
|
13478
13497
|
models,
|
|
@@ -13487,7 +13506,7 @@ function AgentChatPanel({
|
|
|
13487
13506
|
narrow
|
|
13488
13507
|
}
|
|
13489
13508
|
);
|
|
13490
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0,
|
|
13509
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13491
13510
|
MenuButton,
|
|
13492
13511
|
{
|
|
13493
13512
|
variant: "ghost",
|
|
@@ -13514,7 +13533,7 @@ function AgentChatPanel({
|
|
|
13514
13533
|
})))
|
|
13515
13534
|
}
|
|
13516
13535
|
) : null;
|
|
13517
|
-
return /* @__PURE__ */ (0,
|
|
13536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
|
|
13518
13537
|
"aside",
|
|
13519
13538
|
{
|
|
13520
13539
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -13525,7 +13544,7 @@ function AgentChatPanel({
|
|
|
13525
13544
|
},
|
|
13526
13545
|
"aria-label": title,
|
|
13527
13546
|
children: [
|
|
13528
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */ (0,
|
|
13547
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13529
13548
|
"div",
|
|
13530
13549
|
{
|
|
13531
13550
|
className: "fdc-grip",
|
|
@@ -13540,20 +13559,20 @@ function AgentChatPanel({
|
|
|
13540
13559
|
}
|
|
13541
13560
|
}
|
|
13542
13561
|
) : null,
|
|
13543
|
-
showHeader ? /* @__PURE__ */ (0,
|
|
13544
|
-
/* @__PURE__ */ (0,
|
|
13545
|
-
/* @__PURE__ */ (0,
|
|
13546
|
-
/* @__PURE__ */ (0,
|
|
13547
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
13562
|
+
showHeader ? /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("header", { className: "fdc-head", children: [
|
|
13563
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-" + assistantIcon }) }),
|
|
13564
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-head-titles", children: [
|
|
13565
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
|
|
13566
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
|
|
13548
13567
|
] }),
|
|
13549
|
-
/* @__PURE__ */ (0,
|
|
13568
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-head-acts", children: [
|
|
13550
13569
|
headerActions,
|
|
13551
13570
|
threadMenu,
|
|
13552
|
-
onNewThread ? /* @__PURE__ */ (0,
|
|
13553
|
-
onClose ? /* @__PURE__ */ (0,
|
|
13571
|
+
onNewThread ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
13572
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ (0, import_jsx_runtime99.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
13554
13573
|
] })
|
|
13555
13574
|
] }) : null,
|
|
13556
|
-
/* @__PURE__ */ (0,
|
|
13575
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13557
13576
|
ChatTranscript,
|
|
13558
13577
|
{
|
|
13559
13578
|
messages: engine.visible,
|
|
@@ -13568,7 +13587,7 @@ function AgentChatPanel({
|
|
|
13568
13587
|
renderEmpty
|
|
13569
13588
|
}
|
|
13570
13589
|
),
|
|
13571
|
-
/* @__PURE__ */ (0,
|
|
13590
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13572
13591
|
ChatComposer,
|
|
13573
13592
|
{
|
|
13574
13593
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -13601,8 +13620,8 @@ function AgentChatPanel({
|
|
|
13601
13620
|
}
|
|
13602
13621
|
|
|
13603
13622
|
// src/components/files/FileViewer.tsx
|
|
13604
|
-
var
|
|
13605
|
-
var
|
|
13623
|
+
var React70 = __toESM(require("react"), 1);
|
|
13624
|
+
var import_jsx_runtime100 = require("react/jsx-runtime");
|
|
13606
13625
|
function previewKindOf(file) {
|
|
13607
13626
|
const mime = (file.mime || "").toLowerCase();
|
|
13608
13627
|
const ext = extensionOf(file.name || "");
|
|
@@ -13658,13 +13677,13 @@ function parseDelimited(text, delimiter) {
|
|
|
13658
13677
|
return rows;
|
|
13659
13678
|
}
|
|
13660
13679
|
function usePreview(file, kind, resolveUrl) {
|
|
13661
|
-
const [state, setState] =
|
|
13662
|
-
const [attempt, setAttempt] =
|
|
13663
|
-
const resolveRef =
|
|
13664
|
-
|
|
13680
|
+
const [state, setState] = React70.useState({ status: "loading" });
|
|
13681
|
+
const [attempt, setAttempt] = React70.useState(0);
|
|
13682
|
+
const resolveRef = React70.useRef(resolveUrl);
|
|
13683
|
+
React70.useEffect(() => {
|
|
13665
13684
|
resolveRef.current = resolveUrl;
|
|
13666
13685
|
}, [resolveUrl]);
|
|
13667
|
-
|
|
13686
|
+
React70.useEffect(() => {
|
|
13668
13687
|
if (kind === "none") {
|
|
13669
13688
|
setState({ status: "ready" });
|
|
13670
13689
|
return;
|
|
@@ -13694,19 +13713,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
13694
13713
|
if (ac) ac.abort();
|
|
13695
13714
|
};
|
|
13696
13715
|
}, [file.id, kind, attempt]);
|
|
13697
|
-
return { ...state, retry:
|
|
13716
|
+
return { ...state, retry: React70.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
13698
13717
|
}
|
|
13699
13718
|
function PreviewBody({ file, kind, state }) {
|
|
13700
|
-
if (kind === "image") return /* @__PURE__ */ (0,
|
|
13701
|
-
if (kind === "pdf") return /* @__PURE__ */ (0,
|
|
13702
|
-
if (kind === "markdown") return /* @__PURE__ */ (0,
|
|
13719
|
+
if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
13720
|
+
if (kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
|
|
13721
|
+
if (kind === "markdown") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
|
|
13703
13722
|
if (kind === "json") {
|
|
13704
13723
|
let pretty = state.text || "";
|
|
13705
13724
|
try {
|
|
13706
13725
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
13707
13726
|
} catch {
|
|
13708
13727
|
}
|
|
13709
|
-
return /* @__PURE__ */ (0,
|
|
13728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(CodeBlock, { code: pretty, language: "json" });
|
|
13710
13729
|
}
|
|
13711
13730
|
if (kind === "csv") {
|
|
13712
13731
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -13714,12 +13733,12 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13714
13733
|
const head = rows[0] || [];
|
|
13715
13734
|
const dataRows = rows.slice(1);
|
|
13716
13735
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
13717
|
-
return /* @__PURE__ */ (0,
|
|
13718
|
-
/* @__PURE__ */ (0,
|
|
13719
|
-
/* @__PURE__ */ (0,
|
|
13720
|
-
/* @__PURE__ */ (0,
|
|
13736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-csv", children: [
|
|
13737
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("table", { className: "fd-fv-csv-table", children: [
|
|
13738
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tr", { children: head.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("th", { children: c }, i)) }) }),
|
|
13739
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("tr", { children: head.map((_, ci) => /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
|
|
13721
13740
|
] }),
|
|
13722
|
-
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0,
|
|
13741
|
+
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
|
|
13723
13742
|
"Showing the first ",
|
|
13724
13743
|
FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
|
|
13725
13744
|
" of ",
|
|
@@ -13728,24 +13747,24 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13728
13747
|
] }) : null
|
|
13729
13748
|
] });
|
|
13730
13749
|
}
|
|
13731
|
-
if (kind === "text") return /* @__PURE__ */ (0,
|
|
13732
|
-
return /* @__PURE__ */ (0,
|
|
13733
|
-
/* @__PURE__ */ (0,
|
|
13734
|
-
/* @__PURE__ */ (0,
|
|
13735
|
-
/* @__PURE__ */ (0,
|
|
13750
|
+
if (kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
|
|
13751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-fallback", children: [
|
|
13752
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
13753
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
|
|
13754
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-fallback-meta", children: [
|
|
13736
13755
|
file.mime || "Unknown type",
|
|
13737
13756
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
13738
13757
|
] })
|
|
13739
13758
|
] });
|
|
13740
13759
|
}
|
|
13741
13760
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
13742
|
-
const kind =
|
|
13761
|
+
const kind = React70.useMemo(() => previewKindOf(file), [file]);
|
|
13743
13762
|
const preview = usePreview(file, kind, resolveUrl);
|
|
13744
|
-
const [tab, setTab] =
|
|
13745
|
-
const [downloading, setDownloading] =
|
|
13746
|
-
const [downloadError, setDownloadError] =
|
|
13763
|
+
const [tab, setTab] = React70.useState("preview");
|
|
13764
|
+
const [downloading, setDownloading] = React70.useState(false);
|
|
13765
|
+
const [downloadError, setDownloadError] = React70.useState(null);
|
|
13747
13766
|
const hasSide = sidePanel != null;
|
|
13748
|
-
|
|
13767
|
+
React70.useEffect(() => {
|
|
13749
13768
|
setTab("preview");
|
|
13750
13769
|
}, [file.id]);
|
|
13751
13770
|
const download = () => {
|
|
@@ -13761,29 +13780,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13761
13780
|
a.remove();
|
|
13762
13781
|
}).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
|
|
13763
13782
|
};
|
|
13764
|
-
return /* @__PURE__ */ (0,
|
|
13783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
13765
13784
|
"section",
|
|
13766
13785
|
{
|
|
13767
13786
|
className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
|
|
13768
13787
|
"aria-label": file.name || "File",
|
|
13769
13788
|
children: [
|
|
13770
|
-
/* @__PURE__ */ (0,
|
|
13771
|
-
/* @__PURE__ */ (0,
|
|
13772
|
-
/* @__PURE__ */ (0,
|
|
13773
|
-
/* @__PURE__ */ (0,
|
|
13774
|
-
/* @__PURE__ */ (0,
|
|
13789
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("header", { className: "fd-fv-head", children: [
|
|
13790
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
13791
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-titles", children: [
|
|
13792
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
|
|
13793
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-meta", children: [
|
|
13775
13794
|
file.mime || "Unknown type",
|
|
13776
13795
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
13777
13796
|
] })
|
|
13778
13797
|
] }),
|
|
13779
|
-
/* @__PURE__ */ (0,
|
|
13798
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-actions", children: [
|
|
13780
13799
|
actions,
|
|
13781
|
-
/* @__PURE__ */ (0,
|
|
13782
|
-
onClose ? /* @__PURE__ */ (0,
|
|
13800
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
|
|
13801
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
|
|
13783
13802
|
] })
|
|
13784
13803
|
] }),
|
|
13785
|
-
downloadError ? /* @__PURE__ */ (0,
|
|
13786
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
13804
|
+
downloadError ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
|
|
13805
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
13787
13806
|
Tabs,
|
|
13788
13807
|
{
|
|
13789
13808
|
className: "fd-fv-tabs",
|
|
@@ -13792,19 +13811,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13792
13811
|
onChange: (v) => setTab(v)
|
|
13793
13812
|
}
|
|
13794
13813
|
) : null,
|
|
13795
|
-
/* @__PURE__ */ (0,
|
|
13796
|
-
/* @__PURE__ */ (0,
|
|
13814
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("div", { className: "fd-fv-body", children: [
|
|
13815
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(
|
|
13797
13816
|
LoadingRegion,
|
|
13798
13817
|
{
|
|
13799
13818
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
13800
13819
|
error: preview.error,
|
|
13801
13820
|
label: "Loading preview of " + (file.name || "file"),
|
|
13802
13821
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
13803
|
-
skeleton: /* @__PURE__ */ (0,
|
|
13804
|
-
children: /* @__PURE__ */ (0,
|
|
13822
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(Skeleton, { shape: "card", h: 220 }),
|
|
13823
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(PreviewBody, { file, kind, state: preview })
|
|
13805
13824
|
}
|
|
13806
13825
|
) }),
|
|
13807
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
13826
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
13808
13827
|
] })
|
|
13809
13828
|
]
|
|
13810
13829
|
}
|
|
@@ -13812,8 +13831,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13812
13831
|
}
|
|
13813
13832
|
|
|
13814
13833
|
// src/components/files/FileBrowser.tsx
|
|
13815
|
-
var
|
|
13816
|
-
var
|
|
13834
|
+
var React71 = __toESM(require("react"), 1);
|
|
13835
|
+
var import_jsx_runtime101 = require("react/jsx-runtime");
|
|
13817
13836
|
function childrenOf(folders, parentId) {
|
|
13818
13837
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
13819
13838
|
}
|
|
@@ -13885,8 +13904,8 @@ function FolderPickerMenu({
|
|
|
13885
13904
|
}) {
|
|
13886
13905
|
const panel = useInlinePanel();
|
|
13887
13906
|
const { open: open2, setOpen, ref } = panel;
|
|
13888
|
-
return /* @__PURE__ */ (0,
|
|
13889
|
-
/* @__PURE__ */ (0,
|
|
13907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
13908
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
13890
13909
|
IconButton,
|
|
13891
13910
|
{
|
|
13892
13911
|
icon: "arrows-out-cardinal",
|
|
@@ -13898,9 +13917,9 @@ function FolderPickerMenu({
|
|
|
13898
13917
|
onClick: () => setOpen((v) => !v)
|
|
13899
13918
|
}
|
|
13900
13919
|
),
|
|
13901
|
-
/* @__PURE__ */ (0,
|
|
13902
|
-
/* @__PURE__ */ (0,
|
|
13903
|
-
destinations.map((d) => /* @__PURE__ */ (0,
|
|
13920
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-menu", children: [
|
|
13921
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
13922
|
+
destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(
|
|
13904
13923
|
"button",
|
|
13905
13924
|
{
|
|
13906
13925
|
type: "button",
|
|
@@ -13912,7 +13931,7 @@ function FolderPickerMenu({
|
|
|
13912
13931
|
setOpen(false);
|
|
13913
13932
|
},
|
|
13914
13933
|
children: [
|
|
13915
|
-
/* @__PURE__ */ (0,
|
|
13934
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
13916
13935
|
d.name
|
|
13917
13936
|
]
|
|
13918
13937
|
},
|
|
@@ -13922,8 +13941,8 @@ function FolderPickerMenu({
|
|
|
13922
13941
|
] });
|
|
13923
13942
|
}
|
|
13924
13943
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
13925
|
-
const [over, setOver] =
|
|
13926
|
-
const dragCounter =
|
|
13944
|
+
const [over, setOver] = React71.useState(false);
|
|
13945
|
+
const dragCounter = React71.useRef(0);
|
|
13927
13946
|
const dropHandlers = isDropTarget ? {
|
|
13928
13947
|
onDragEnter: (e) => {
|
|
13929
13948
|
if (!hasInternalPayload(e)) return;
|
|
@@ -13948,8 +13967,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
13948
13967
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
13949
13968
|
}
|
|
13950
13969
|
} : {};
|
|
13951
|
-
return /* @__PURE__ */ (0,
|
|
13952
|
-
/* @__PURE__ */ (0,
|
|
13970
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
13971
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(
|
|
13953
13972
|
"button",
|
|
13954
13973
|
{
|
|
13955
13974
|
type: "button",
|
|
@@ -13958,26 +13977,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
13958
13977
|
draggable: !!draggableId,
|
|
13959
13978
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
13960
13979
|
children: [
|
|
13961
|
-
/* @__PURE__ */ (0,
|
|
13962
|
-
/* @__PURE__ */ (0,
|
|
13963
|
-
/* @__PURE__ */ (0,
|
|
13964
|
-
meta ? /* @__PURE__ */ (0,
|
|
13980
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + icon }) }),
|
|
13981
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-row-text", children: [
|
|
13982
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
13983
|
+
meta ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
13965
13984
|
] })
|
|
13966
13985
|
]
|
|
13967
13986
|
}
|
|
13968
13987
|
),
|
|
13969
|
-
actions ? /* @__PURE__ */ (0,
|
|
13988
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
13970
13989
|
] });
|
|
13971
13990
|
}
|
|
13972
13991
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
13973
13992
|
const kids = childrenOf(folders, folder.id);
|
|
13974
|
-
const [expanded, setExpanded] =
|
|
13975
|
-
|
|
13993
|
+
const [expanded, setExpanded] = React71.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
13994
|
+
React71.useEffect(() => {
|
|
13976
13995
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
13977
13996
|
}, [currentFolderId, folder.id, folders]);
|
|
13978
13997
|
const isCurrent = folder.id === currentFolderId;
|
|
13979
|
-
return /* @__PURE__ */ (0,
|
|
13980
|
-
/* @__PURE__ */ (0,
|
|
13998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-tree-node", children: [
|
|
13999
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
13981
14000
|
RowShell,
|
|
13982
14001
|
{
|
|
13983
14002
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -13987,7 +14006,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13987
14006
|
isDropTarget: canMove,
|
|
13988
14007
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
13989
14008
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
13990
|
-
actions: kids.length ? /* @__PURE__ */ (0,
|
|
14009
|
+
actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
13991
14010
|
IconButton,
|
|
13992
14011
|
{
|
|
13993
14012
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -13999,7 +14018,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13999
14018
|
) : void 0
|
|
14000
14019
|
}
|
|
14001
14020
|
),
|
|
14002
|
-
expanded && kids.length ? /* @__PURE__ */ (0,
|
|
14021
|
+
expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14003
14022
|
TreeNode,
|
|
14004
14023
|
{
|
|
14005
14024
|
folder: k,
|
|
@@ -14038,15 +14057,15 @@ function FileBrowser({
|
|
|
14038
14057
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
14039
14058
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
14040
14059
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
14041
|
-
const [createOpen, setCreateOpen] =
|
|
14042
|
-
const [createName, setCreateName] =
|
|
14043
|
-
const [renameTarget, setRenameTarget] =
|
|
14044
|
-
const [renameValue, setRenameValue] =
|
|
14045
|
-
const [deleteTarget, setDeleteTarget] =
|
|
14046
|
-
const uploadInputRef =
|
|
14047
|
-
const crumbFolders =
|
|
14048
|
-
const subfolders =
|
|
14049
|
-
const currentFiles =
|
|
14060
|
+
const [createOpen, setCreateOpen] = React71.useState(false);
|
|
14061
|
+
const [createName, setCreateName] = React71.useState("");
|
|
14062
|
+
const [renameTarget, setRenameTarget] = React71.useState(null);
|
|
14063
|
+
const [renameValue, setRenameValue] = React71.useState("");
|
|
14064
|
+
const [deleteTarget, setDeleteTarget] = React71.useState(null);
|
|
14065
|
+
const uploadInputRef = React71.useRef(null);
|
|
14066
|
+
const crumbFolders = React71.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
14067
|
+
const subfolders = React71.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
14068
|
+
const currentFiles = React71.useMemo(
|
|
14050
14069
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
14051
14070
|
[files, currentFolderId]
|
|
14052
14071
|
);
|
|
@@ -14085,10 +14104,10 @@ function FileBrowser({
|
|
|
14085
14104
|
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
14086
14105
|
setDeleteTarget(null);
|
|
14087
14106
|
};
|
|
14088
|
-
const content = /* @__PURE__ */ (0,
|
|
14089
|
-
/* @__PURE__ */ (0,
|
|
14090
|
-
/* @__PURE__ */ (0,
|
|
14091
|
-
/* @__PURE__ */ (0,
|
|
14107
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
14108
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-head", children: [
|
|
14109
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
14110
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14092
14111
|
BreadcrumbCrumb,
|
|
14093
14112
|
{
|
|
14094
14113
|
label: "Home",
|
|
@@ -14098,7 +14117,7 @@ function FileBrowser({
|
|
|
14098
14117
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
14099
14118
|
}
|
|
14100
14119
|
),
|
|
14101
|
-
crumbFolders.map((f, i) => /* @__PURE__ */ (0,
|
|
14120
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14102
14121
|
BreadcrumbCrumb,
|
|
14103
14122
|
{
|
|
14104
14123
|
label: f.name,
|
|
@@ -14110,11 +14129,11 @@ function FileBrowser({
|
|
|
14110
14129
|
f.id
|
|
14111
14130
|
))
|
|
14112
14131
|
] }),
|
|
14113
|
-
/* @__PURE__ */ (0,
|
|
14114
|
-
canCreateFolder ? /* @__PURE__ */ (0,
|
|
14115
|
-
canUpload ? /* @__PURE__ */ (0,
|
|
14116
|
-
/* @__PURE__ */ (0,
|
|
14117
|
-
/* @__PURE__ */ (0,
|
|
14132
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("span", { className: "fd-fb-actions", children: [
|
|
14133
|
+
canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
14134
|
+
canUpload ? /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14135
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
14136
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14118
14137
|
"input",
|
|
14119
14138
|
{
|
|
14120
14139
|
ref: uploadInputRef,
|
|
@@ -14132,9 +14151,9 @@ function FileBrowser({
|
|
|
14132
14151
|
] }) : null
|
|
14133
14152
|
] })
|
|
14134
14153
|
] }),
|
|
14135
|
-
/* @__PURE__ */ (0,
|
|
14136
|
-
/* @__PURE__ */ (0,
|
|
14137
|
-
/* @__PURE__ */ (0,
|
|
14154
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-body", children: [
|
|
14155
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
14156
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14138
14157
|
RowShell,
|
|
14139
14158
|
{
|
|
14140
14159
|
icon: "house-simple",
|
|
@@ -14145,7 +14164,7 @@ function FileBrowser({
|
|
|
14145
14164
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
14146
14165
|
}
|
|
14147
14166
|
),
|
|
14148
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0,
|
|
14167
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14149
14168
|
TreeNode,
|
|
14150
14169
|
{
|
|
14151
14170
|
folder: f,
|
|
@@ -14159,18 +14178,18 @@ function FileBrowser({
|
|
|
14159
14178
|
f.id
|
|
14160
14179
|
))
|
|
14161
14180
|
] }),
|
|
14162
|
-
/* @__PURE__ */ (0,
|
|
14181
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14163
14182
|
LoadingRegion,
|
|
14164
14183
|
{
|
|
14165
14184
|
state: loading ? "loading" : "ready",
|
|
14166
14185
|
label: "Loading folder contents",
|
|
14167
|
-
skeleton: /* @__PURE__ */ (0,
|
|
14168
|
-
/* @__PURE__ */ (0,
|
|
14169
|
-
/* @__PURE__ */ (0,
|
|
14170
|
-
/* @__PURE__ */ (0,
|
|
14186
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
14187
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
14188
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
14189
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Skeleton, { h: 44, radius: "10px" })
|
|
14171
14190
|
] }),
|
|
14172
|
-
children: isEmpty ? /* @__PURE__ */ (0,
|
|
14173
|
-
subfolders.map((f) => /* @__PURE__ */ (0,
|
|
14191
|
+
children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-list", children: [
|
|
14192
|
+
subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14174
14193
|
RowShell,
|
|
14175
14194
|
{
|
|
14176
14195
|
icon: "folder-simple",
|
|
@@ -14179,9 +14198,9 @@ function FileBrowser({
|
|
|
14179
14198
|
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
14180
14199
|
isDropTarget: canMove,
|
|
14181
14200
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
14182
|
-
actions: /* @__PURE__ */ (0,
|
|
14183
|
-
canRenameFolder ? /* @__PURE__ */ (0,
|
|
14184
|
-
canMove ? /* @__PURE__ */ (0,
|
|
14201
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14202
|
+
canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
14203
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14185
14204
|
FolderPickerMenu,
|
|
14186
14205
|
{
|
|
14187
14206
|
label: "Move " + f.name,
|
|
@@ -14189,12 +14208,12 @@ function FileBrowser({
|
|
|
14189
14208
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
14190
14209
|
}
|
|
14191
14210
|
) : null,
|
|
14192
|
-
canDeleteFolder ? /* @__PURE__ */ (0,
|
|
14211
|
+
canDeleteFolder ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
14193
14212
|
] })
|
|
14194
14213
|
},
|
|
14195
14214
|
f.id
|
|
14196
14215
|
)),
|
|
14197
|
-
currentFiles.map((file) => /* @__PURE__ */ (0,
|
|
14216
|
+
currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14198
14217
|
RowShell,
|
|
14199
14218
|
{
|
|
14200
14219
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -14202,8 +14221,8 @@ function FileBrowser({
|
|
|
14202
14221
|
meta: file.size ? formatBytes(file.size) : void 0,
|
|
14203
14222
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
14204
14223
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
14205
|
-
actions: /* @__PURE__ */ (0,
|
|
14206
|
-
canMove ? /* @__PURE__ */ (0,
|
|
14224
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14225
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14207
14226
|
FolderPickerMenu,
|
|
14208
14227
|
{
|
|
14209
14228
|
label: "Move " + file.name,
|
|
@@ -14211,7 +14230,7 @@ function FileBrowser({
|
|
|
14211
14230
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
14212
14231
|
}
|
|
14213
14232
|
) : null,
|
|
14214
|
-
canRemoveFile ? /* @__PURE__ */ (0,
|
|
14233
|
+
canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
14215
14234
|
] })
|
|
14216
14235
|
},
|
|
14217
14236
|
file.id
|
|
@@ -14220,10 +14239,10 @@ function FileBrowser({
|
|
|
14220
14239
|
}
|
|
14221
14240
|
) })
|
|
14222
14241
|
] }),
|
|
14223
|
-
/* @__PURE__ */ (0,
|
|
14224
|
-
/* @__PURE__ */ (0,
|
|
14225
|
-
/* @__PURE__ */ (0,
|
|
14226
|
-
] }), children: /* @__PURE__ */ (0,
|
|
14242
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14243
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
14244
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
14245
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14227
14246
|
"input",
|
|
14228
14247
|
{
|
|
14229
14248
|
className: "fd-fb-input",
|
|
@@ -14237,10 +14256,10 @@ function FileBrowser({
|
|
|
14237
14256
|
autoFocus: true
|
|
14238
14257
|
}
|
|
14239
14258
|
) }),
|
|
14240
|
-
/* @__PURE__ */ (0,
|
|
14241
|
-
/* @__PURE__ */ (0,
|
|
14242
|
-
/* @__PURE__ */ (0,
|
|
14243
|
-
] }), children: /* @__PURE__ */ (0,
|
|
14259
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14260
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
14261
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
14262
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14244
14263
|
"input",
|
|
14245
14264
|
{
|
|
14246
14265
|
className: "fd-fb-input",
|
|
@@ -14254,22 +14273,22 @@ function FileBrowser({
|
|
|
14254
14273
|
autoFocus: true
|
|
14255
14274
|
}
|
|
14256
14275
|
) }),
|
|
14257
|
-
/* @__PURE__ */ (0,
|
|
14276
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14258
14277
|
Modal,
|
|
14259
14278
|
{
|
|
14260
14279
|
open: deleteTarget != null,
|
|
14261
14280
|
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
14262
14281
|
description: "This can't be undone. The folder must be empty.",
|
|
14263
14282
|
onClose: () => setDeleteTarget(null),
|
|
14264
|
-
footer: /* @__PURE__ */ (0,
|
|
14265
|
-
/* @__PURE__ */ (0,
|
|
14266
|
-
/* @__PURE__ */ (0,
|
|
14283
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14284
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
14285
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
14267
14286
|
] })
|
|
14268
14287
|
}
|
|
14269
14288
|
)
|
|
14270
14289
|
] });
|
|
14271
14290
|
if (!canUpload) return content;
|
|
14272
|
-
return /* @__PURE__ */ (0,
|
|
14291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
14273
14292
|
}
|
|
14274
14293
|
function BreadcrumbCrumb({
|
|
14275
14294
|
label,
|
|
@@ -14278,8 +14297,8 @@ function BreadcrumbCrumb({
|
|
|
14278
14297
|
isDropTarget,
|
|
14279
14298
|
onDropPayload
|
|
14280
14299
|
}) {
|
|
14281
|
-
const [over, setOver] =
|
|
14282
|
-
const dragCounter =
|
|
14300
|
+
const [over, setOver] = React71.useState(false);
|
|
14301
|
+
const dragCounter = React71.useRef(0);
|
|
14283
14302
|
const dropHandlers = isDropTarget ? {
|
|
14284
14303
|
onDragEnter: (e) => {
|
|
14285
14304
|
if (!hasInternalPayload(e)) return;
|
|
@@ -14304,11 +14323,11 @@ function BreadcrumbCrumb({
|
|
|
14304
14323
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
14305
14324
|
}
|
|
14306
14325
|
} : {};
|
|
14307
|
-
return /* @__PURE__ */ (0,
|
|
14326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
14308
14327
|
}
|
|
14309
14328
|
|
|
14310
14329
|
// src/kits/query.ts
|
|
14311
|
-
var
|
|
14330
|
+
var React72 = __toESM(require("react"), 1);
|
|
14312
14331
|
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
14313
14332
|
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
14314
14333
|
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
@@ -14363,22 +14382,22 @@ function compare(a, b, dir) {
|
|
|
14363
14382
|
var API = null;
|
|
14364
14383
|
var PREFS = null;
|
|
14365
14384
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
14366
|
-
const [query, setQuery] =
|
|
14385
|
+
const [query, setQuery] = React72.useState(() => {
|
|
14367
14386
|
const store = PREFS || window.PlannerPrefs;
|
|
14368
14387
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
14369
14388
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
14370
14389
|
});
|
|
14371
|
-
const savePref =
|
|
14390
|
+
const savePref = React72.useCallback((patch2) => {
|
|
14372
14391
|
const store = PREFS || window.PlannerPrefs;
|
|
14373
14392
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
14374
14393
|
}, [prefsKey]);
|
|
14375
|
-
const [res, setRes] =
|
|
14376
|
-
const [loading, setLoading] =
|
|
14377
|
-
const seq2 =
|
|
14394
|
+
const [res, setRes] = React72.useState(null);
|
|
14395
|
+
const [loading, setLoading] = React72.useState(true);
|
|
14396
|
+
const seq2 = React72.useRef(0);
|
|
14378
14397
|
const depKey = (deps || []).join("|");
|
|
14379
14398
|
const paramKey = JSON.stringify(params || {});
|
|
14380
14399
|
const queryKey = JSON.stringify(query);
|
|
14381
|
-
|
|
14400
|
+
React72.useEffect(() => {
|
|
14382
14401
|
const id = ++seq2.current;
|
|
14383
14402
|
setLoading(true);
|
|
14384
14403
|
const t = setTimeout(() => {
|
|
@@ -14697,12 +14716,12 @@ function createVersionStore(initialState, options) {
|
|
|
14697
14716
|
}
|
|
14698
14717
|
|
|
14699
14718
|
// src/kits/documentTitle.ts
|
|
14700
|
-
var
|
|
14719
|
+
var React73 = __toESM(require("react"), 1);
|
|
14701
14720
|
function formatDocumentTitle(routeTitle, appName) {
|
|
14702
14721
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
14703
14722
|
}
|
|
14704
14723
|
function useDocumentTitle(routeTitle, appName) {
|
|
14705
|
-
|
|
14724
|
+
React73.useEffect(() => {
|
|
14706
14725
|
if (typeof document === "undefined") return;
|
|
14707
14726
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
14708
14727
|
}, [routeTitle, appName]);
|
|
@@ -14717,6 +14736,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14717
14736
|
AppShell,
|
|
14718
14737
|
AppSwitcher,
|
|
14719
14738
|
AppearanceMenu,
|
|
14739
|
+
AppearanceProvider,
|
|
14720
14740
|
Avatar,
|
|
14721
14741
|
AvatarStack,
|
|
14722
14742
|
Badge,
|
|
@@ -14872,6 +14892,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14872
14892
|
__resetLayerStackForTests,
|
|
14873
14893
|
acceptMatches,
|
|
14874
14894
|
anyOfFilter,
|
|
14895
|
+
applyAppearance,
|
|
14875
14896
|
applyPrefs,
|
|
14876
14897
|
channelWeightOf,
|
|
14877
14898
|
computeNeedMore,
|
|
@@ -14917,6 +14938,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14917
14938
|
toAttachment,
|
|
14918
14939
|
tokenize,
|
|
14919
14940
|
useAppearancePrefs,
|
|
14941
|
+
useAppearanceStore,
|
|
14920
14942
|
useChatEngine,
|
|
14921
14943
|
useCopyToClipboard,
|
|
14922
14944
|
useCornerStackSlot,
|
|
@@ -14932,6 +14954,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14932
14954
|
useStagedFiles,
|
|
14933
14955
|
useToast,
|
|
14934
14956
|
validateFilterValue,
|
|
14935
|
-
visibleMessages
|
|
14957
|
+
visibleMessages,
|
|
14958
|
+
watchAppearance
|
|
14936
14959
|
});
|
|
14937
14960
|
//# sourceMappingURL=index.cjs.map
|