@flytedan/flytebot-design-system 0.57.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 +917 -878
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -21
- package/dist/index.d.ts +68 -21
- package/dist/index.js +682 -648
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +7 -0
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,
|
|
@@ -49,6 +50,7 @@ __export(index_exports, {
|
|
|
49
50
|
CHANNEL_WEIGHTS: () => CHANNEL_WEIGHTS,
|
|
50
51
|
CHAT_UNAVAILABLE: () => CHAT_UNAVAILABLE,
|
|
51
52
|
COPIED_FEEDBACK_MS: () => COPIED_FEEDBACK_MS,
|
|
53
|
+
CORNER_STACK_INSET_PROPERTY: () => CORNER_STACK_INSET_PROPERTY,
|
|
52
54
|
Calendar: () => Calendar,
|
|
53
55
|
Card: () => Card,
|
|
54
56
|
CardGrid: () => CardGrid,
|
|
@@ -192,6 +194,7 @@ __export(index_exports, {
|
|
|
192
194
|
__resetLayerStackForTests: () => __resetLayerStackForTests,
|
|
193
195
|
acceptMatches: () => acceptMatches,
|
|
194
196
|
anyOfFilter: () => anyOfFilter,
|
|
197
|
+
applyAppearance: () => applyAppearance,
|
|
195
198
|
applyPrefs: () => applyPrefs,
|
|
196
199
|
channelWeightOf: () => channelWeightOf,
|
|
197
200
|
computeNeedMore: () => computeNeedMore,
|
|
@@ -237,6 +240,7 @@ __export(index_exports, {
|
|
|
237
240
|
toAttachment: () => toAttachment,
|
|
238
241
|
tokenize: () => tokenize,
|
|
239
242
|
useAppearancePrefs: () => useAppearancePrefs,
|
|
243
|
+
useAppearanceStore: () => useAppearanceStore,
|
|
240
244
|
useChatEngine: () => useChatEngine,
|
|
241
245
|
useCopyToClipboard: () => useCopyToClipboard,
|
|
242
246
|
useCornerStackSlot: () => useCornerStackSlot,
|
|
@@ -252,7 +256,8 @@ __export(index_exports, {
|
|
|
252
256
|
useStagedFiles: () => useStagedFiles,
|
|
253
257
|
useToast: () => useToast,
|
|
254
258
|
validateFilterValue: () => validateFilterValue,
|
|
255
|
-
visibleMessages: () => visibleMessages
|
|
259
|
+
visibleMessages: () => visibleMessages,
|
|
260
|
+
watchAppearance: () => watchAppearance
|
|
256
261
|
});
|
|
257
262
|
module.exports = __toCommonJS(index_exports);
|
|
258
263
|
|
|
@@ -1386,9 +1391,11 @@ var React10 = __toESM(require("react"), 1);
|
|
|
1386
1391
|
// src/kits/cornerStack.tsx
|
|
1387
1392
|
var React9 = __toESM(require("react"), 1);
|
|
1388
1393
|
var import_react_dom5 = require("react-dom");
|
|
1394
|
+
var CORNER_STACK_INSET_PROPERTY = "--fd-corner-stack-inset";
|
|
1389
1395
|
var SLOTS = ["jobs", "toasts"];
|
|
1390
1396
|
var references = /* @__PURE__ */ new Map();
|
|
1391
1397
|
var host = null;
|
|
1398
|
+
var hostObserver = null;
|
|
1392
1399
|
var slotElements = /* @__PURE__ */ new Map();
|
|
1393
1400
|
function createHost() {
|
|
1394
1401
|
const stack = document.createElement("div");
|
|
@@ -1402,8 +1409,18 @@ function createHost() {
|
|
|
1402
1409
|
slotElements.set(slot, element);
|
|
1403
1410
|
}
|
|
1404
1411
|
document.body.appendChild(stack);
|
|
1412
|
+
publishInset(stack);
|
|
1413
|
+
if (typeof ResizeObserver === "function") {
|
|
1414
|
+
hostObserver = new ResizeObserver(() => publishInset(stack));
|
|
1415
|
+
hostObserver.observe(stack);
|
|
1416
|
+
}
|
|
1405
1417
|
return stack;
|
|
1406
1418
|
}
|
|
1419
|
+
function publishInset(stack) {
|
|
1420
|
+
const height = stack.offsetHeight;
|
|
1421
|
+
const inset = height > 0 ? height + parseFloat(getComputedStyle(stack).bottom) : 0;
|
|
1422
|
+
document.documentElement.style.setProperty(CORNER_STACK_INSET_PROPERTY, `${inset}px`);
|
|
1423
|
+
}
|
|
1407
1424
|
function acquire(slot) {
|
|
1408
1425
|
host ??= createHost();
|
|
1409
1426
|
references.set(slot, (references.get(slot) ?? 0) + 1);
|
|
@@ -1414,6 +1431,9 @@ function release(slot) {
|
|
|
1414
1431
|
if (remaining > 0) references.set(slot, remaining);
|
|
1415
1432
|
else references.delete(slot);
|
|
1416
1433
|
if (references.size === 0 && host) {
|
|
1434
|
+
hostObserver?.disconnect();
|
|
1435
|
+
hostObserver = null;
|
|
1436
|
+
document.documentElement.style.removeProperty(CORNER_STACK_INSET_PROPERTY);
|
|
1417
1437
|
host.remove();
|
|
1418
1438
|
host = null;
|
|
1419
1439
|
slotElements.clear();
|
|
@@ -1852,7 +1872,7 @@ function AppShell({
|
|
|
1852
1872
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1853
1873
|
"div",
|
|
1854
1874
|
{
|
|
1855
|
-
className: contentClassName,
|
|
1875
|
+
className: ["fd-app-shell-content", contentClassName].filter(Boolean).join(" "),
|
|
1856
1876
|
style: {
|
|
1857
1877
|
flex: 1,
|
|
1858
1878
|
minWidth: 0,
|
|
@@ -1860,7 +1880,6 @@ function AppShell({
|
|
|
1860
1880
|
// table) is contained and clipped by this scroller, never stretching the document.
|
|
1861
1881
|
position: "relative",
|
|
1862
1882
|
overflowY: "auto",
|
|
1863
|
-
padding: 24,
|
|
1864
1883
|
maxWidth: contentMaxWidth,
|
|
1865
1884
|
margin: "0 auto",
|
|
1866
1885
|
width: "100%",
|
|
@@ -8303,7 +8322,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
8303
8322
|
}
|
|
8304
8323
|
|
|
8305
8324
|
// src/components/platform/AppearanceMenu.tsx
|
|
8306
|
-
var
|
|
8325
|
+
var React53 = __toESM(require("react"), 1);
|
|
8307
8326
|
|
|
8308
8327
|
// src/kits/appearance.ts
|
|
8309
8328
|
var React51 = __toESM(require("react"), 1);
|
|
@@ -8400,20 +8419,25 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
8400
8419
|
if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
|
|
8401
8420
|
else root.removeAttribute("data-motion");
|
|
8402
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
|
+
}
|
|
8403
8439
|
function useAppearancePrefs(store) {
|
|
8404
8440
|
const prefs = React51.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
8405
|
-
React51.useEffect(() => {
|
|
8406
|
-
applyPrefs(prefs);
|
|
8407
|
-
}, [prefs]);
|
|
8408
|
-
React51.useEffect(() => {
|
|
8409
|
-
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8410
|
-
return;
|
|
8411
|
-
}
|
|
8412
|
-
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
8413
|
-
const onChange = () => applyPrefs(prefs);
|
|
8414
|
-
mq.addEventListener("change", onChange);
|
|
8415
|
-
return () => mq.removeEventListener("change", onChange);
|
|
8416
|
-
}, [prefs]);
|
|
8417
8441
|
const update = React51.useCallback(
|
|
8418
8442
|
(patch) => {
|
|
8419
8443
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
@@ -8423,8 +8447,22 @@ function useAppearancePrefs(store) {
|
|
|
8423
8447
|
return [prefs, update];
|
|
8424
8448
|
}
|
|
8425
8449
|
|
|
8426
|
-
// src/components/platform/
|
|
8450
|
+
// src/components/platform/AppearanceProvider.tsx
|
|
8451
|
+
var React52 = __toESM(require("react"), 1);
|
|
8427
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");
|
|
8428
8466
|
var THEME_OPTIONS = [
|
|
8429
8467
|
{ value: "light", label: "Light" },
|
|
8430
8468
|
{ value: "dark", label: "Dark" },
|
|
@@ -8436,17 +8474,13 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
8436
8474
|
{ value: "lg", label: "L" },
|
|
8437
8475
|
{ value: "xl", label: "XL" }
|
|
8438
8476
|
];
|
|
8439
|
-
function AppearanceMenu({ className = ""
|
|
8440
|
-
const
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
);
|
|
8444
|
-
const [prefs, update] = useAppearancePrefs(store);
|
|
8445
|
-
const [open2, setOpen] = React52.useState(false);
|
|
8446
|
-
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);
|
|
8447
8481
|
const patch = (p) => update(p);
|
|
8448
|
-
return /* @__PURE__ */ (0,
|
|
8449
|
-
/* @__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)(
|
|
8450
8484
|
IconButton,
|
|
8451
8485
|
{
|
|
8452
8486
|
icon: "circle-half",
|
|
@@ -8454,7 +8488,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8454
8488
|
onClick: () => setOpen((v) => !v)
|
|
8455
8489
|
}
|
|
8456
8490
|
) }),
|
|
8457
|
-
/* @__PURE__ */ (0,
|
|
8491
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8458
8492
|
Popover,
|
|
8459
8493
|
{
|
|
8460
8494
|
open: open2,
|
|
@@ -8464,10 +8498,10 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8464
8498
|
padded: true,
|
|
8465
8499
|
width: 260,
|
|
8466
8500
|
label: "Appearance settings",
|
|
8467
|
-
children: /* @__PURE__ */ (0,
|
|
8468
|
-
/* @__PURE__ */ (0,
|
|
8469
|
-
/* @__PURE__ */ (0,
|
|
8470
|
-
/* @__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)(
|
|
8471
8505
|
SegmentedControl,
|
|
8472
8506
|
{
|
|
8473
8507
|
options: THEME_OPTIONS,
|
|
@@ -8477,9 +8511,9 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8477
8511
|
}
|
|
8478
8512
|
)
|
|
8479
8513
|
] }),
|
|
8480
|
-
/* @__PURE__ */ (0,
|
|
8481
|
-
/* @__PURE__ */ (0,
|
|
8482
|
-
/* @__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)(
|
|
8483
8517
|
SegmentedControl,
|
|
8484
8518
|
{
|
|
8485
8519
|
options: TEXT_SCALE_OPTIONS,
|
|
@@ -8489,7 +8523,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8489
8523
|
}
|
|
8490
8524
|
)
|
|
8491
8525
|
] }),
|
|
8492
|
-
/* @__PURE__ */ (0,
|
|
8526
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8493
8527
|
Switch,
|
|
8494
8528
|
{
|
|
8495
8529
|
label: "High contrast",
|
|
@@ -8498,7 +8532,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8498
8532
|
onChange: (e) => patch({ highContrast: e.target.checked })
|
|
8499
8533
|
}
|
|
8500
8534
|
),
|
|
8501
|
-
/* @__PURE__ */ (0,
|
|
8535
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
8502
8536
|
Switch,
|
|
8503
8537
|
{
|
|
8504
8538
|
label: "Reduce motion",
|
|
@@ -8514,14 +8548,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8514
8548
|
}
|
|
8515
8549
|
|
|
8516
8550
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
8517
|
-
var
|
|
8518
|
-
var
|
|
8551
|
+
var React54 = __toESM(require("react"), 1);
|
|
8552
|
+
var import_jsx_runtime80 = require("react/jsx-runtime");
|
|
8519
8553
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
8520
8554
|
function Json({ obj }) {
|
|
8521
|
-
return /* @__PURE__ */ (0,
|
|
8555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
8522
8556
|
}
|
|
8523
8557
|
function Endpoint({ s, onRequest }) {
|
|
8524
|
-
const [tried, setTried] =
|
|
8558
|
+
const [tried, setTried] = React54.useState(null);
|
|
8525
8559
|
const run = async () => {
|
|
8526
8560
|
setTried("busy");
|
|
8527
8561
|
const t0 = (window.performance || Date).now();
|
|
@@ -8532,50 +8566,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
8532
8566
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
8533
8567
|
}
|
|
8534
8568
|
};
|
|
8535
|
-
return /* @__PURE__ */ (0,
|
|
8536
|
-
/* @__PURE__ */ (0,
|
|
8537
|
-
/* @__PURE__ */ (0,
|
|
8538
|
-
/* @__PURE__ */ (0,
|
|
8539
|
-
s.isList ? /* @__PURE__ */ (0,
|
|
8540
|
-
/* @__PURE__ */ (0,
|
|
8541
|
-
/* @__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: [
|
|
8542
8576
|
s.latency[0],
|
|
8543
8577
|
"\u2013",
|
|
8544
8578
|
s.latency[1],
|
|
8545
8579
|
"ms"
|
|
8546
8580
|
] }),
|
|
8547
|
-
/* @__PURE__ */ (0,
|
|
8581
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
8548
8582
|
] }),
|
|
8549
|
-
/* @__PURE__ */ (0,
|
|
8550
|
-
/* @__PURE__ */ (0,
|
|
8551
|
-
/* @__PURE__ */ (0,
|
|
8552
|
-
/* @__PURE__ */ (0,
|
|
8553
|
-
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
|
|
8554
8588
|
] }),
|
|
8555
|
-
/* @__PURE__ */ (0,
|
|
8556
|
-
s.request ? /* @__PURE__ */ (0,
|
|
8557
|
-
/* @__PURE__ */ (0,
|
|
8558
|
-
/* @__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 })
|
|
8559
8593
|
] }) : null,
|
|
8560
|
-
s.query ? /* @__PURE__ */ (0,
|
|
8561
|
-
/* @__PURE__ */ (0,
|
|
8562
|
-
/* @__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 })
|
|
8563
8597
|
] }) : null,
|
|
8564
|
-
/* @__PURE__ */ (0,
|
|
8565
|
-
/* @__PURE__ */ (0,
|
|
8566
|
-
/* @__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 })
|
|
8567
8601
|
] })
|
|
8568
8602
|
] }),
|
|
8569
|
-
s.notes ? /* @__PURE__ */ (0,
|
|
8570
|
-
tried && tried !== "busy" ? /* @__PURE__ */ (0,
|
|
8571
|
-
/* @__PURE__ */ (0,
|
|
8572
|
-
/* @__PURE__ */ (0,
|
|
8573
|
-
/* @__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: [
|
|
8574
8608
|
tried.ms,
|
|
8575
8609
|
"ms"
|
|
8576
8610
|
] })
|
|
8577
8611
|
] }),
|
|
8578
|
-
/* @__PURE__ */ (0,
|
|
8612
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
8579
8613
|
] }) : null
|
|
8580
8614
|
] })
|
|
8581
8615
|
] }) });
|
|
@@ -8594,58 +8628,58 @@ function ApiSpecBrowser({
|
|
|
8594
8628
|
className = "",
|
|
8595
8629
|
...rest
|
|
8596
8630
|
}) {
|
|
8597
|
-
const [q, setQ] =
|
|
8598
|
-
const [method, setMethod] =
|
|
8599
|
-
const [mod, setMod] =
|
|
8600
|
-
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);
|
|
8601
8635
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
8602
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())));
|
|
8603
8637
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
8604
8638
|
const methods = [...new Set(spec.map((s) => s.method))];
|
|
8605
8639
|
const listCount = spec.filter((s) => s.isList).length;
|
|
8606
|
-
return /* @__PURE__ */ (0,
|
|
8607
|
-
/* @__PURE__ */ (0,
|
|
8608
|
-
kicker ? /* @__PURE__ */ (0,
|
|
8609
|
-
/* @__PURE__ */ (0,
|
|
8610
|
-
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
|
|
8611
8645
|
] }),
|
|
8612
|
-
modules && modules.length ? /* @__PURE__ */ (0,
|
|
8613
|
-
/* @__PURE__ */ (0,
|
|
8614
|
-
/* @__PURE__ */ (0,
|
|
8615
|
-
/* @__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: [
|
|
8616
8650
|
"All screens ",
|
|
8617
|
-
/* @__PURE__ */ (0,
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.length })
|
|
8618
8652
|
] }),
|
|
8619
|
-
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: [
|
|
8620
8654
|
m.label,
|
|
8621
8655
|
" ",
|
|
8622
|
-
/* @__PURE__ */ (0,
|
|
8656
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: m.endpoints.length })
|
|
8623
8657
|
] }, m.id))
|
|
8624
8658
|
] }),
|
|
8625
|
-
activeModule ? /* @__PURE__ */ (0,
|
|
8659
|
+
activeModule ? /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
|
|
8626
8660
|
Flag,
|
|
8627
8661
|
{
|
|
8628
8662
|
tone: "info",
|
|
8629
8663
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
8630
8664
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
8631
|
-
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" })
|
|
8632
8666
|
}
|
|
8633
8667
|
) : null
|
|
8634
8668
|
] }) : null,
|
|
8635
|
-
sourceNote ? /* @__PURE__ */ (0,
|
|
8636
|
-
/* @__PURE__ */ (0,
|
|
8637
|
-
/* @__PURE__ */ (0,
|
|
8638
|
-
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: [
|
|
8639
8673
|
m,
|
|
8640
8674
|
" ",
|
|
8641
|
-
/* @__PURE__ */ (0,
|
|
8675
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
8642
8676
|
] }, m)),
|
|
8643
|
-
listCount ? /* @__PURE__ */ (0,
|
|
8677
|
+
listCount ? /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
8644
8678
|
"Paged lists ",
|
|
8645
|
-
/* @__PURE__ */ (0,
|
|
8679
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "fd-mono", children: listCount })
|
|
8646
8680
|
] }) : null,
|
|
8647
|
-
/* @__PURE__ */ (0,
|
|
8648
|
-
/* @__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: [
|
|
8649
8683
|
hits.length,
|
|
8650
8684
|
" of ",
|
|
8651
8685
|
spec.length,
|
|
@@ -8653,31 +8687,31 @@ function ApiSpecBrowser({
|
|
|
8653
8687
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
8654
8688
|
] })
|
|
8655
8689
|
] }),
|
|
8656
|
-
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]) => {
|
|
8657
8691
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
8658
8692
|
if (!items.length) return null;
|
|
8659
|
-
return /* @__PURE__ */ (0,
|
|
8660
|
-
/* @__PURE__ */ (0,
|
|
8661
|
-
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))
|
|
8662
8696
|
] }, g);
|
|
8663
8697
|
}),
|
|
8664
|
-
conventions && conventions.length ? /* @__PURE__ */ (0,
|
|
8665
|
-
/* @__PURE__ */ (0,
|
|
8666
|
-
/* @__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 })
|
|
8667
8701
|
] }, k)) }) }) : null,
|
|
8668
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */ (0,
|
|
8669
|
-
/* @__PURE__ */ (0,
|
|
8670
|
-
/* @__PURE__ */ (0,
|
|
8671
|
-
/* @__PURE__ */ (0,
|
|
8672
|
-
/* @__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 })
|
|
8673
8707
|
] })
|
|
8674
8708
|
] }, id)) }) }) : null
|
|
8675
8709
|
] });
|
|
8676
8710
|
}
|
|
8677
8711
|
|
|
8678
8712
|
// src/components/platform/ProfilePage.tsx
|
|
8679
|
-
var
|
|
8680
|
-
var
|
|
8713
|
+
var React55 = __toESM(require("react"), 1);
|
|
8714
|
+
var import_jsx_runtime81 = require("react/jsx-runtime");
|
|
8681
8715
|
function fieldInitialValue(field, user) {
|
|
8682
8716
|
if (field.value) return field.value(user);
|
|
8683
8717
|
const raw = user[field.key];
|
|
@@ -8712,21 +8746,21 @@ function ProfilePage({
|
|
|
8712
8746
|
}) {
|
|
8713
8747
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
8714
8748
|
const user = userProp || sessionUser;
|
|
8715
|
-
const initialFieldValues =
|
|
8749
|
+
const initialFieldValues = React55.useMemo(() => {
|
|
8716
8750
|
const values2 = {};
|
|
8717
8751
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
8718
8752
|
return values2;
|
|
8719
8753
|
}, [user.id, fields]);
|
|
8720
|
-
const initialNotify =
|
|
8754
|
+
const initialNotify = React55.useMemo(() => {
|
|
8721
8755
|
const values2 = {};
|
|
8722
8756
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
8723
8757
|
return values2;
|
|
8724
8758
|
}, [user.id, notifications]);
|
|
8725
|
-
const [values, setValues] =
|
|
8726
|
-
const [notify, setNotify] =
|
|
8727
|
-
const [saving, setSaving] =
|
|
8728
|
-
const [saved, setSaved] =
|
|
8729
|
-
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);
|
|
8730
8764
|
if (user.id !== prevUserId) {
|
|
8731
8765
|
setPrevUserId(user.id);
|
|
8732
8766
|
setValues(initialFieldValues);
|
|
@@ -8763,37 +8797,37 @@ function ProfilePage({
|
|
|
8763
8797
|
};
|
|
8764
8798
|
const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
|
|
8765
8799
|
const fieldGroups = groupFields(fields);
|
|
8766
|
-
return /* @__PURE__ */ (0,
|
|
8767
|
-
/* @__PURE__ */ (0,
|
|
8768
|
-
/* @__PURE__ */ (0,
|
|
8769
|
-
/* @__PURE__ */ (0,
|
|
8770
|
-
/* @__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." })
|
|
8771
8805
|
] }),
|
|
8772
|
-
/* @__PURE__ */ (0,
|
|
8773
|
-
/* @__PURE__ */ (0,
|
|
8774
|
-
/* @__PURE__ */ (0,
|
|
8775
|
-
/* @__PURE__ */ (0,
|
|
8776
|
-
/* @__PURE__ */ (0,
|
|
8777
|
-
roles.map((r) => /* @__PURE__ */ (0,
|
|
8778
|
-
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
|
|
8779
8813
|
] })
|
|
8780
8814
|
] }),
|
|
8781
|
-
onChangePhoto ? /* @__PURE__ */ (0,
|
|
8815
|
+
onChangePhoto ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
|
|
8782
8816
|
] }) }),
|
|
8783
|
-
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0,
|
|
8817
|
+
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8784
8818
|
Card,
|
|
8785
8819
|
{
|
|
8786
|
-
title: description ? /* @__PURE__ */ (0,
|
|
8787
|
-
/* @__PURE__ */ (0,
|
|
8788
|
-
/* @__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 })
|
|
8789
8823
|
] }) : group,
|
|
8790
8824
|
elevation: "flat",
|
|
8791
|
-
children: /* @__PURE__ */ (0,
|
|
8792
|
-
/* @__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) => {
|
|
8793
8827
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8794
8828
|
const readOnly = field.readOnly || field.type === "readonly";
|
|
8795
8829
|
if (field.type === "select") {
|
|
8796
|
-
return /* @__PURE__ */ (0,
|
|
8830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8797
8831
|
Select,
|
|
8798
8832
|
{
|
|
8799
8833
|
label: field.label,
|
|
@@ -8807,7 +8841,7 @@ function ProfilePage({
|
|
|
8807
8841
|
field.key
|
|
8808
8842
|
);
|
|
8809
8843
|
}
|
|
8810
|
-
return /* @__PURE__ */ (0,
|
|
8844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8811
8845
|
Input,
|
|
8812
8846
|
{
|
|
8813
8847
|
label: field.label,
|
|
@@ -8823,7 +8857,7 @@ function ProfilePage({
|
|
|
8823
8857
|
}) }),
|
|
8824
8858
|
groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
|
|
8825
8859
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8826
|
-
return /* @__PURE__ */ (0,
|
|
8860
|
+
return /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8827
8861
|
Textarea,
|
|
8828
8862
|
{
|
|
8829
8863
|
label: field.label,
|
|
@@ -8843,16 +8877,16 @@ function ProfilePage({
|
|
|
8843
8877
|
group
|
|
8844
8878
|
)),
|
|
8845
8879
|
extra,
|
|
8846
|
-
notifications.length > 0 ? /* @__PURE__ */ (0,
|
|
8847
|
-
/* @__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)(
|
|
8848
8882
|
Card,
|
|
8849
8883
|
{
|
|
8850
|
-
title: /* @__PURE__ */ (0,
|
|
8851
|
-
/* @__PURE__ */ (0,
|
|
8852
|
-
/* @__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" })
|
|
8853
8887
|
] }),
|
|
8854
8888
|
elevation: "flat",
|
|
8855
|
-
action: /* @__PURE__ */ (0,
|
|
8889
|
+
action: /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8856
8890
|
Button,
|
|
8857
8891
|
{
|
|
8858
8892
|
size: "sm",
|
|
@@ -8863,39 +8897,39 @@ function ProfilePage({
|
|
|
8863
8897
|
}
|
|
8864
8898
|
),
|
|
8865
8899
|
children: [
|
|
8866
|
-
/* @__PURE__ */ (0,
|
|
8867
|
-
/* @__PURE__ */ (0,
|
|
8868
|
-
/* @__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: [
|
|
8869
8903
|
permissions.length,
|
|
8870
8904
|
" granted"
|
|
8871
8905
|
] }),
|
|
8872
|
-
/* @__PURE__ */ (0,
|
|
8906
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsx)(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
8873
8907
|
] }),
|
|
8874
|
-
/* @__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." })
|
|
8875
8909
|
]
|
|
8876
8910
|
}
|
|
8877
8911
|
),
|
|
8878
|
-
sessions ? /* @__PURE__ */ (0,
|
|
8912
|
+
sessions ? /* @__PURE__ */ (0, import_jsx_runtime81.jsx)(
|
|
8879
8913
|
Card,
|
|
8880
8914
|
{
|
|
8881
8915
|
title: "Signed-in devices",
|
|
8882
8916
|
elevation: "flat",
|
|
8883
|
-
action: /* @__PURE__ */ (0,
|
|
8884
|
-
children: /* @__PURE__ */ (0,
|
|
8885
|
-
/* @__PURE__ */ (0,
|
|
8886
|
-
/* @__PURE__ */ (0,
|
|
8887
|
-
/* @__PURE__ */ (0,
|
|
8888
|
-
/* @__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: [
|
|
8889
8923
|
s.where,
|
|
8890
8924
|
" \xB7 ",
|
|
8891
8925
|
s.when
|
|
8892
8926
|
] })
|
|
8893
8927
|
] }),
|
|
8894
|
-
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" })
|
|
8895
8929
|
] }, s.id)) })
|
|
8896
8930
|
}
|
|
8897
8931
|
) : null,
|
|
8898
|
-
/* @__PURE__ */ (0,
|
|
8932
|
+
/* @__PURE__ */ (0, import_jsx_runtime81.jsxs)("div", { className: "fd-row", style: {
|
|
8899
8933
|
gap: 10,
|
|
8900
8934
|
flexWrap: "wrap",
|
|
8901
8935
|
position: "sticky",
|
|
@@ -8906,16 +8940,16 @@ function ProfilePage({
|
|
|
8906
8940
|
border: "1px solid var(--border)",
|
|
8907
8941
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
8908
8942
|
}, children: [
|
|
8909
|
-
/* @__PURE__ */ (0,
|
|
8910
|
-
/* @__PURE__ */ (0,
|
|
8911
|
-
/* @__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" })
|
|
8912
8946
|
] })
|
|
8913
8947
|
] });
|
|
8914
8948
|
}
|
|
8915
8949
|
|
|
8916
8950
|
// src/components/platform/SessionScreen.tsx
|
|
8917
|
-
var
|
|
8918
|
-
var
|
|
8951
|
+
var React56 = __toESM(require("react"), 1);
|
|
8952
|
+
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
8919
8953
|
var COPY = {
|
|
8920
8954
|
"signing-in": { busy: "Signing you in\u2026" },
|
|
8921
8955
|
"session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
|
|
@@ -8928,28 +8962,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8928
8962
|
const copy = COPY[kind];
|
|
8929
8963
|
const busyMessage = "busy" in copy ? copy.busy : null;
|
|
8930
8964
|
const failureTitle = "failure" in copy ? copy.failure : null;
|
|
8931
|
-
const [announced, setAnnounced] =
|
|
8932
|
-
|
|
8965
|
+
const [announced, setAnnounced] = React56.useState("");
|
|
8966
|
+
React56.useEffect(() => {
|
|
8933
8967
|
setAnnounced(busyMessage ?? "");
|
|
8934
8968
|
}, [busyMessage]);
|
|
8935
|
-
const titleRef =
|
|
8969
|
+
const titleRef = React56.useRef(null);
|
|
8936
8970
|
const failed = failureTitle !== null;
|
|
8937
|
-
|
|
8971
|
+
React56.useEffect(() => {
|
|
8938
8972
|
titleRef.current?.focus({ preventScroll: true });
|
|
8939
8973
|
}, [failed]);
|
|
8940
|
-
return /* @__PURE__ */ (0,
|
|
8941
|
-
/* @__PURE__ */ (0,
|
|
8942
|
-
/* @__PURE__ */ (0,
|
|
8943
|
-
/* @__PURE__ */ (0,
|
|
8944
|
-
/* @__PURE__ */ (0,
|
|
8945
|
-
/* @__PURE__ */ (0,
|
|
8946
|
-
/* @__PURE__ */ (0,
|
|
8947
|
-
/* @__PURE__ */ (0,
|
|
8948
|
-
/* @__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 })
|
|
8949
8983
|
] }) : null }),
|
|
8950
|
-
failureTitle !== null ? /* @__PURE__ */ (0,
|
|
8951
|
-
/* @__PURE__ */ (0,
|
|
8952
|
-
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
|
|
8953
8987
|
] }) : null
|
|
8954
8988
|
] }) })
|
|
8955
8989
|
] })
|
|
@@ -8957,10 +8991,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8957
8991
|
}
|
|
8958
8992
|
|
|
8959
8993
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8960
|
-
var
|
|
8994
|
+
var React59 = __toESM(require("react"), 1);
|
|
8961
8995
|
|
|
8962
8996
|
// src/kits/session.ts
|
|
8963
|
-
var
|
|
8997
|
+
var React57 = __toESM(require("react"), 1);
|
|
8964
8998
|
var PERMISSION_CATALOG = [
|
|
8965
8999
|
{ group: "Plans", items: [
|
|
8966
9000
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -10527,8 +10561,8 @@ function roadmap(overrides) {
|
|
|
10527
10561
|
};
|
|
10528
10562
|
}
|
|
10529
10563
|
function useSession() {
|
|
10530
|
-
const [s, setS] =
|
|
10531
|
-
|
|
10564
|
+
const [s, setS] = React57.useState(getSession);
|
|
10565
|
+
React57.useEffect(() => subscribe(setS), []);
|
|
10532
10566
|
return s;
|
|
10533
10567
|
}
|
|
10534
10568
|
var SessionKit = {
|
|
@@ -10561,7 +10595,7 @@ var SessionKit = {
|
|
|
10561
10595
|
};
|
|
10562
10596
|
function DemoSessionProvider({ children }) {
|
|
10563
10597
|
const session = useSession();
|
|
10564
|
-
const value =
|
|
10598
|
+
const value = React57.useMemo(
|
|
10565
10599
|
() => ({
|
|
10566
10600
|
user: session.user,
|
|
10567
10601
|
roles: session.roles,
|
|
@@ -10577,11 +10611,11 @@ function DemoSessionProvider({ children }) {
|
|
|
10577
10611
|
}),
|
|
10578
10612
|
[session]
|
|
10579
10613
|
);
|
|
10580
|
-
return
|
|
10614
|
+
return React57.createElement(SessionProvider, { value }, children);
|
|
10581
10615
|
}
|
|
10582
10616
|
|
|
10583
10617
|
// src/kits/runtime.ts
|
|
10584
|
-
var
|
|
10618
|
+
var React58 = __toESM(require("react"), 1);
|
|
10585
10619
|
var WIRED_ENDPOINTS = [
|
|
10586
10620
|
// Nothing yet. Every id below would come from a real service:
|
|
10587
10621
|
// "plan.get", "placements.list", …
|
|
@@ -10752,8 +10786,8 @@ var RuntimeKit = {
|
|
|
10752
10786
|
};
|
|
10753
10787
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
10754
10788
|
function useRuntimeMode() {
|
|
10755
|
-
const [m, setM] =
|
|
10756
|
-
|
|
10789
|
+
const [m, setM] = React58.useState(RuntimeKit.getMode());
|
|
10790
|
+
React58.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
10757
10791
|
return m;
|
|
10758
10792
|
}
|
|
10759
10793
|
function useFeatureStatus(key) {
|
|
@@ -10772,7 +10806,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
10772
10806
|
var UseFeatureStatus = useFeatureStatus;
|
|
10773
10807
|
|
|
10774
10808
|
// src/components/platform/RoadmapTimeline.tsx
|
|
10775
|
-
var
|
|
10809
|
+
var import_jsx_runtime83 = require("react/jsx-runtime");
|
|
10776
10810
|
var STATUS = {
|
|
10777
10811
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
10778
10812
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -10787,45 +10821,45 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10787
10821
|
const s = STATUS[item.status] || STATUS.planned;
|
|
10788
10822
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
10789
10823
|
const blocking = deps.filter((d) => !d.implemented);
|
|
10790
|
-
return /* @__PURE__ */ (0,
|
|
10791
|
-
/* @__PURE__ */ (0,
|
|
10792
|
-
/* @__PURE__ */ (0,
|
|
10793
|
-
/* @__PURE__ */ (0,
|
|
10794
|
-
/* @__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 })
|
|
10795
10829
|
] }),
|
|
10796
|
-
/* @__PURE__ */ (0,
|
|
10797
|
-
item.backend ? /* @__PURE__ */ (0,
|
|
10798
|
-
/* @__PURE__ */ (0,
|
|
10799
|
-
/* @__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 })
|
|
10800
10834
|
] }) : null,
|
|
10801
|
-
/* @__PURE__ */ (0,
|
|
10802
|
-
item.effort ? /* @__PURE__ */ (0,
|
|
10803
|
-
/* @__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" }),
|
|
10804
10838
|
" ",
|
|
10805
10839
|
item.effort
|
|
10806
10840
|
] }) : null,
|
|
10807
|
-
/* @__PURE__ */ (0,
|
|
10808
|
-
/* @__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" }),
|
|
10809
10843
|
" ",
|
|
10810
10844
|
item.owner
|
|
10811
10845
|
] }),
|
|
10812
|
-
item.screen ? /* @__PURE__ */ (0,
|
|
10813
|
-
/* @__PURE__ */ (0,
|
|
10814
|
-
/* @__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)(
|
|
10815
10849
|
"button",
|
|
10816
10850
|
{
|
|
10817
10851
|
type: "button",
|
|
10818
10852
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
10819
10853
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
10820
|
-
children: /* @__PURE__ */ (0,
|
|
10854
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
10821
10855
|
}
|
|
10822
10856
|
)
|
|
10823
10857
|
] }),
|
|
10824
|
-
deps.length ? /* @__PURE__ */ (0,
|
|
10825
|
-
/* @__PURE__ */ (0,
|
|
10826
|
-
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))
|
|
10827
10861
|
] }) : null,
|
|
10828
|
-
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: [
|
|
10829
10863
|
"Blocked until ",
|
|
10830
10864
|
blocking.map((d) => d.label).join(" and "),
|
|
10831
10865
|
" ",
|
|
@@ -10836,12 +10870,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10836
10870
|
}
|
|
10837
10871
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
10838
10872
|
const session = SessionKit.useSession();
|
|
10839
|
-
const [project, setProject] =
|
|
10840
|
-
const [q, setQ] =
|
|
10841
|
-
const scrollRef =
|
|
10842
|
-
const nowRef =
|
|
10843
|
-
const rm =
|
|
10844
|
-
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(() => {
|
|
10845
10879
|
const m = {};
|
|
10846
10880
|
rm.items.forEach((i) => {
|
|
10847
10881
|
m[i.key] = i;
|
|
@@ -10850,7 +10884,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10850
10884
|
}, [rm]);
|
|
10851
10885
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
10852
10886
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
10853
|
-
|
|
10887
|
+
React59.useEffect(() => {
|
|
10854
10888
|
let raf1 = 0, raf2 = 0;
|
|
10855
10889
|
const place = () => {
|
|
10856
10890
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -10878,23 +10912,23 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10878
10912
|
}, 0);
|
|
10879
10913
|
const nextPhase = items.find((i) => !i.implemented);
|
|
10880
10914
|
let lastPhase = null;
|
|
10881
|
-
return /* @__PURE__ */ (0,
|
|
10882
|
-
/* @__PURE__ */ (0,
|
|
10883
|
-
/* @__PURE__ */ (0,
|
|
10884
|
-
/* @__PURE__ */ (0,
|
|
10885
|
-
/* @__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." })
|
|
10886
10920
|
] }),
|
|
10887
|
-
/* @__PURE__ */ (0,
|
|
10888
|
-
/* @__PURE__ */ (0,
|
|
10889
|
-
/* @__PURE__ */ (0,
|
|
10890
|
-
/* @__PURE__ */ (0,
|
|
10891
|
-
/* @__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" })
|
|
10892
10926
|
] }),
|
|
10893
|
-
/* @__PURE__ */ (0,
|
|
10894
|
-
/* @__PURE__ */ (0,
|
|
10895
|
-
/* @__PURE__ */ (0,
|
|
10896
|
-
/* @__PURE__ */ (0,
|
|
10897
|
-
/* @__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)(
|
|
10898
10932
|
Button,
|
|
10899
10933
|
{
|
|
10900
10934
|
size: "sm",
|
|
@@ -10908,7 +10942,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10908
10942
|
}
|
|
10909
10943
|
)
|
|
10910
10944
|
] }),
|
|
10911
|
-
/* @__PURE__ */ (0,
|
|
10945
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(
|
|
10912
10946
|
Flag,
|
|
10913
10947
|
{
|
|
10914
10948
|
tone: "info",
|
|
@@ -10917,60 +10951,60 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10917
10951
|
actions: null
|
|
10918
10952
|
}
|
|
10919
10953
|
),
|
|
10920
|
-
/* @__PURE__ */ (0,
|
|
10921
|
-
/* @__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%" } }) }),
|
|
10922
10956
|
items.map((item, n) => {
|
|
10923
10957
|
const showPhase = item.phase !== lastPhase;
|
|
10924
10958
|
lastPhase = item.phase;
|
|
10925
10959
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
10926
10960
|
const isBoundary = n === firstPending;
|
|
10927
|
-
return /* @__PURE__ */ (0,
|
|
10928
|
-
showPhase ? /* @__PURE__ */ (0,
|
|
10929
|
-
/* @__PURE__ */ (0,
|
|
10930
|
-
/* @__PURE__ */ (0,
|
|
10931
|
-
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: [
|
|
10932
10966
|
fmtDate(item.phaseStart),
|
|
10933
10967
|
" \u2013 ",
|
|
10934
10968
|
fmtDate(item.date)
|
|
10935
10969
|
] }),
|
|
10936
|
-
/* @__PURE__ */ (0,
|
|
10970
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
10937
10971
|
"\xB7 ",
|
|
10938
10972
|
inPhase,
|
|
10939
10973
|
" feature",
|
|
10940
10974
|
inPhase === 1 ? "" : "s"
|
|
10941
10975
|
] })
|
|
10942
10976
|
] }),
|
|
10943
|
-
item.phaseWhy ? /* @__PURE__ */ (0,
|
|
10977
|
+
item.phaseWhy ? /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
10944
10978
|
] }) : null,
|
|
10945
|
-
isBoundary ? /* @__PURE__ */ (0,
|
|
10946
|
-
/* @__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" }),
|
|
10947
10981
|
" You are here \u2014 everything above is wired"
|
|
10948
10982
|
] }) }) : null,
|
|
10949
|
-
/* @__PURE__ */ (0,
|
|
10950
|
-
/* @__PURE__ */ (0,
|
|
10951
|
-
/* @__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: [
|
|
10952
10986
|
fmtDate(item.date),
|
|
10953
|
-
/* @__PURE__ */ (0,
|
|
10954
|
-
/* @__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 })
|
|
10955
10989
|
] }),
|
|
10956
|
-
/* @__PURE__ */ (0,
|
|
10990
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)(RoadmapCard, { item, byKey, onOpenFlag })
|
|
10957
10991
|
] })
|
|
10958
10992
|
] }, item.key);
|
|
10959
10993
|
}),
|
|
10960
|
-
!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
|
|
10961
10995
|
] }) }) }),
|
|
10962
|
-
/* @__PURE__ */ (0,
|
|
10996
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsxs)("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
10963
10997
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
10964
|
-
/* @__PURE__ */ (0,
|
|
10998
|
+
/* @__PURE__ */ (0, import_jsx_runtime83.jsx)("code", { className: "fd-mono", children: "implemented" }),
|
|
10965
10999
|
" field, so this page cannot drift from what the apps actually do."
|
|
10966
11000
|
] })
|
|
10967
11001
|
] });
|
|
10968
11002
|
}
|
|
10969
11003
|
|
|
10970
11004
|
// src/components/platform/ComingSoon.tsx
|
|
10971
|
-
var
|
|
11005
|
+
var React60 = __toESM(require("react"), 1);
|
|
10972
11006
|
var import_react_dom7 = require("react-dom");
|
|
10973
|
-
var
|
|
11007
|
+
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10974
11008
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
10975
11009
|
function readBypassed() {
|
|
10976
11010
|
try {
|
|
@@ -10986,8 +11020,8 @@ function writeBypassed(list) {
|
|
|
10986
11020
|
}
|
|
10987
11021
|
}
|
|
10988
11022
|
function useBypass(key) {
|
|
10989
|
-
const [on, setOn] =
|
|
10990
|
-
|
|
11023
|
+
const [on, setOn] = React60.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
11024
|
+
React60.useEffect(() => {
|
|
10991
11025
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
10992
11026
|
}, [key]);
|
|
10993
11027
|
const set = (next) => {
|
|
@@ -11000,43 +11034,43 @@ function useBypass(key) {
|
|
|
11000
11034
|
return [on, set];
|
|
11001
11035
|
}
|
|
11002
11036
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
11003
|
-
return /* @__PURE__ */ (0,
|
|
11004
|
-
/* @__PURE__ */ (0,
|
|
11005
|
-
/* @__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" }),
|
|
11006
11040
|
label
|
|
11007
11041
|
] }),
|
|
11008
|
-
detail ? /* @__PURE__ */ (0,
|
|
11009
|
-
backend ? /* @__PURE__ */ (0,
|
|
11010
|
-
/* @__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" }),
|
|
11011
11045
|
" ",
|
|
11012
11046
|
backend
|
|
11013
11047
|
] }) : null,
|
|
11014
|
-
eta || effort || onRoadmap ? /* @__PURE__ */ (0,
|
|
11015
|
-
eta ? /* @__PURE__ */ (0,
|
|
11016
|
-
/* @__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" }),
|
|
11017
11051
|
" ",
|
|
11018
11052
|
eta
|
|
11019
11053
|
] }) : null,
|
|
11020
|
-
effort ? /* @__PURE__ */ (0,
|
|
11021
|
-
/* @__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" }),
|
|
11022
11056
|
" ",
|
|
11023
11057
|
effort
|
|
11024
11058
|
] }) : null,
|
|
11025
|
-
onRoadmap ? /* @__PURE__ */ (0,
|
|
11059
|
+
onRoadmap ? /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
11026
11060
|
"See the roadmap ",
|
|
11027
|
-
/* @__PURE__ */ (0,
|
|
11061
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11028
11062
|
] }) : null
|
|
11029
11063
|
] }) : null,
|
|
11030
|
-
allowed ? /* @__PURE__ */ (0,
|
|
11031
|
-
/* @__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" }),
|
|
11032
11066
|
" View and use it anyway"
|
|
11033
11067
|
] }) : null
|
|
11034
11068
|
] });
|
|
11035
11069
|
}
|
|
11036
11070
|
function useHoverCard(open2) {
|
|
11037
|
-
const anchor =
|
|
11038
|
-
const [pos, setPos] =
|
|
11039
|
-
|
|
11071
|
+
const anchor = React60.useRef(null);
|
|
11072
|
+
const [pos, setPos] = React60.useState(null);
|
|
11073
|
+
React60.useLayoutEffect(() => {
|
|
11040
11074
|
if (!open2 || !anchor.current) {
|
|
11041
11075
|
setPos(null);
|
|
11042
11076
|
return;
|
|
@@ -11088,9 +11122,9 @@ function ComingSoon({
|
|
|
11088
11122
|
const tip = [label, detail, backend ? "Needs " + backend : null, eta ? "ETA " + eta : null, effort].filter(Boolean).join(" \xB7 ");
|
|
11089
11123
|
if (inline) {
|
|
11090
11124
|
if (allowed && bypassed) {
|
|
11091
|
-
return /* @__PURE__ */ (0,
|
|
11125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
11092
11126
|
children,
|
|
11093
|
-
/* @__PURE__ */ (0,
|
|
11127
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11094
11128
|
"button",
|
|
11095
11129
|
{
|
|
11096
11130
|
type: "button",
|
|
@@ -11098,12 +11132,12 @@ function ComingSoon({
|
|
|
11098
11132
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
11099
11133
|
onClick: () => setBypassed(false),
|
|
11100
11134
|
"aria-label": "Re-blur this unwired feature",
|
|
11101
|
-
children: /* @__PURE__ */ (0,
|
|
11135
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
11102
11136
|
}
|
|
11103
11137
|
)
|
|
11104
11138
|
] });
|
|
11105
11139
|
}
|
|
11106
|
-
return /* @__PURE__ */ (0,
|
|
11140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11107
11141
|
InlineSoon,
|
|
11108
11142
|
{
|
|
11109
11143
|
label,
|
|
@@ -11123,20 +11157,20 @@ function ComingSoon({
|
|
|
11123
11157
|
);
|
|
11124
11158
|
}
|
|
11125
11159
|
if (allowed && bypassed) {
|
|
11126
|
-
return /* @__PURE__ */ (0,
|
|
11127
|
-
/* @__PURE__ */ (0,
|
|
11128
|
-
/* @__PURE__ */ (0,
|
|
11129
|
-
/* @__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" }),
|
|
11130
11164
|
"Unwired feature \u2014 you are using it anyway"
|
|
11131
11165
|
] }),
|
|
11132
|
-
/* @__PURE__ */ (0,
|
|
11133
|
-
/* @__PURE__ */ (0,
|
|
11134
|
-
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: [
|
|
11135
11169
|
"Roadmap ",
|
|
11136
|
-
/* @__PURE__ */ (0,
|
|
11170
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11137
11171
|
] }) : null,
|
|
11138
|
-
/* @__PURE__ */ (0,
|
|
11139
|
-
/* @__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" }),
|
|
11140
11174
|
" Re-blur"
|
|
11141
11175
|
] })
|
|
11142
11176
|
] })
|
|
@@ -11144,10 +11178,10 @@ function ComingSoon({
|
|
|
11144
11178
|
children
|
|
11145
11179
|
] });
|
|
11146
11180
|
}
|
|
11147
|
-
return /* @__PURE__ */ (0,
|
|
11148
|
-
/* @__PURE__ */ (0,
|
|
11149
|
-
/* @__PURE__ */ (0,
|
|
11150
|
-
/* @__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)(
|
|
11151
11185
|
SoonCard,
|
|
11152
11186
|
{
|
|
11153
11187
|
label,
|
|
@@ -11163,12 +11197,12 @@ function ComingSoon({
|
|
|
11163
11197
|
] });
|
|
11164
11198
|
}
|
|
11165
11199
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
11166
|
-
const [open2, setOpen] =
|
|
11200
|
+
const [open2, setOpen] = React60.useState(false);
|
|
11167
11201
|
const [anchor, pos] = useHoverCard(open2);
|
|
11168
|
-
const hoverCardRef =
|
|
11202
|
+
const hoverCardRef = React60.useRef(null);
|
|
11169
11203
|
const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
|
|
11170
11204
|
const zIndex = useLayerZIndex(hoverLayer);
|
|
11171
|
-
const close2 =
|
|
11205
|
+
const close2 = React60.useRef(null);
|
|
11172
11206
|
const show = () => {
|
|
11173
11207
|
if (close2.current) {
|
|
11174
11208
|
clearTimeout(close2.current);
|
|
@@ -11184,10 +11218,10 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11184
11218
|
setOpen(false);
|
|
11185
11219
|
}, 140);
|
|
11186
11220
|
};
|
|
11187
|
-
|
|
11221
|
+
React60.useEffect(() => () => {
|
|
11188
11222
|
if (close2.current) clearTimeout(close2.current);
|
|
11189
11223
|
}, []);
|
|
11190
|
-
return /* @__PURE__ */ (0,
|
|
11224
|
+
return /* @__PURE__ */ (0, import_jsx_runtime84.jsxs)(
|
|
11191
11225
|
"span",
|
|
11192
11226
|
{
|
|
11193
11227
|
ref: anchor,
|
|
@@ -11198,8 +11232,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11198
11232
|
onBlur: hide,
|
|
11199
11233
|
...rest,
|
|
11200
11234
|
children: [
|
|
11201
|
-
/* @__PURE__ */ (0,
|
|
11202
|
-
/* @__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)(
|
|
11203
11237
|
"button",
|
|
11204
11238
|
{
|
|
11205
11239
|
type: "button",
|
|
@@ -11210,11 +11244,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11210
11244
|
onFocus: show,
|
|
11211
11245
|
onBlur: hide,
|
|
11212
11246
|
onClick: () => open2 ? setOpen(false) : show(),
|
|
11213
|
-
children: /* @__PURE__ */ (0,
|
|
11247
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
11214
11248
|
}
|
|
11215
11249
|
),
|
|
11216
11250
|
open2 && pos ? (0, import_react_dom7.createPortal)(
|
|
11217
|
-
/* @__PURE__ */ (0,
|
|
11251
|
+
/* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11218
11252
|
"div",
|
|
11219
11253
|
{
|
|
11220
11254
|
ref: hoverCardRef,
|
|
@@ -11223,7 +11257,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
11223
11257
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
11224
11258
|
onMouseEnter: show,
|
|
11225
11259
|
onMouseLeave: hide,
|
|
11226
|
-
children: /* @__PURE__ */ (0,
|
|
11260
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
11227
11261
|
SoonCard,
|
|
11228
11262
|
{
|
|
11229
11263
|
label,
|
|
@@ -11253,10 +11287,10 @@ function formatEta(iso2) {
|
|
|
11253
11287
|
var FormatEta = formatEta;
|
|
11254
11288
|
|
|
11255
11289
|
// src/components/platform/Gate.tsx
|
|
11256
|
-
var
|
|
11290
|
+
var import_jsx_runtime85 = require("react/jsx-runtime");
|
|
11257
11291
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
11258
11292
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
11259
|
-
return /* @__PURE__ */ (0,
|
|
11293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11260
11294
|
"div",
|
|
11261
11295
|
{
|
|
11262
11296
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -11272,14 +11306,14 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
11272
11306
|
},
|
|
11273
11307
|
...rest,
|
|
11274
11308
|
children: [
|
|
11275
|
-
/* @__PURE__ */ (0,
|
|
11276
|
-
/* @__PURE__ */ (0,
|
|
11277
|
-
/* @__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" })
|
|
11278
11312
|
] }),
|
|
11279
|
-
/* @__PURE__ */ (0,
|
|
11280
|
-
need.length ? /* @__PURE__ */ (0,
|
|
11281
|
-
/* @__PURE__ */ (0,
|
|
11282
|
-
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: {
|
|
11283
11317
|
fontSize: 11.5,
|
|
11284
11318
|
padding: "2px 7px",
|
|
11285
11319
|
borderRadius: 5,
|
|
@@ -11292,7 +11326,7 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
11292
11326
|
);
|
|
11293
11327
|
}
|
|
11294
11328
|
function GatePending({ compact: compact3 = false, className = "" }) {
|
|
11295
|
-
return /* @__PURE__ */ (0,
|
|
11329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsxs)(
|
|
11296
11330
|
"div",
|
|
11297
11331
|
{
|
|
11298
11332
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
@@ -11308,11 +11342,11 @@ function GatePending({ compact: compact3 = false, className = "" }) {
|
|
|
11308
11342
|
textAlign: "left"
|
|
11309
11343
|
},
|
|
11310
11344
|
children: [
|
|
11311
|
-
/* @__PURE__ */ (0,
|
|
11312
|
-
/* @__PURE__ */ (0,
|
|
11313
|
-
/* @__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" })
|
|
11314
11348
|
] }),
|
|
11315
|
-
/* @__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." })
|
|
11316
11350
|
]
|
|
11317
11351
|
}
|
|
11318
11352
|
);
|
|
@@ -11322,7 +11356,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11322
11356
|
if (pending) {
|
|
11323
11357
|
if (pendingFallback !== void 0) return pendingFallback;
|
|
11324
11358
|
if (silent) return null;
|
|
11325
|
-
return /* @__PURE__ */ (0,
|
|
11359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(GatePending, { compact: compact3 });
|
|
11326
11360
|
}
|
|
11327
11361
|
let ok = true;
|
|
11328
11362
|
if (perm) ok = ok && can2(perm);
|
|
@@ -11331,7 +11365,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11331
11365
|
if (ok) return children;
|
|
11332
11366
|
if (fallback !== void 0) return fallback;
|
|
11333
11367
|
if (silent) return null;
|
|
11334
|
-
return /* @__PURE__ */ (0,
|
|
11368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
11335
11369
|
}
|
|
11336
11370
|
function FeatureGate({
|
|
11337
11371
|
flag,
|
|
@@ -11354,7 +11388,7 @@ function FeatureGate({
|
|
|
11354
11388
|
const f = SessionKit.findFlag(flag) || {};
|
|
11355
11389
|
const missing = rt.missing || [];
|
|
11356
11390
|
const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
11357
|
-
return /* @__PURE__ */ (0,
|
|
11391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11358
11392
|
ComingSoon,
|
|
11359
11393
|
{
|
|
11360
11394
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -11375,22 +11409,22 @@ function FeatureGate({
|
|
|
11375
11409
|
function PermissionHint({ perm, children }) {
|
|
11376
11410
|
const { can: can2, pending } = useSessionContext();
|
|
11377
11411
|
if (pending) {
|
|
11378
|
-
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 }) });
|
|
11379
11413
|
}
|
|
11380
11414
|
if (can2(perm)) return children;
|
|
11381
|
-
return /* @__PURE__ */ (0,
|
|
11415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime85.jsx)(
|
|
11382
11416
|
"span",
|
|
11383
11417
|
{
|
|
11384
11418
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
11385
11419
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
11386
11420
|
"aria-disabled": "true",
|
|
11387
|
-
children: /* @__PURE__ */ (0,
|
|
11421
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime85.jsx)("span", { style: { pointerEvents: "none" }, children })
|
|
11388
11422
|
}
|
|
11389
11423
|
);
|
|
11390
11424
|
}
|
|
11391
11425
|
|
|
11392
11426
|
// src/components/platform/ModeSwitch.tsx
|
|
11393
|
-
var
|
|
11427
|
+
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
11394
11428
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
11395
11429
|
const mode2 = useRuntimeMode();
|
|
11396
11430
|
const panel = useInlinePanel();
|
|
@@ -11402,8 +11436,8 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11402
11436
|
RuntimeKit.setMode(next);
|
|
11403
11437
|
setOpen(false);
|
|
11404
11438
|
};
|
|
11405
|
-
return /* @__PURE__ */ (0,
|
|
11406
|
-
/* @__PURE__ */ (0,
|
|
11439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { style: { display: "inline-flex" }, ref, children: [
|
|
11440
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
11407
11441
|
"button",
|
|
11408
11442
|
{
|
|
11409
11443
|
type: "button",
|
|
@@ -11413,29 +11447,29 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11413
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.",
|
|
11414
11448
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
|
|
11415
11449
|
children: [
|
|
11416
|
-
/* @__PURE__ */ (0,
|
|
11417
|
-
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
|
|
11418
11452
|
]
|
|
11419
11453
|
}
|
|
11420
11454
|
),
|
|
11421
|
-
/* @__PURE__ */ (0,
|
|
11422
|
-
/* @__PURE__ */ (0,
|
|
11423
|
-
/* @__PURE__ */ (0,
|
|
11424
|
-
/* @__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" }),
|
|
11425
11459
|
test ? "Test mode" : "Live mode"
|
|
11426
11460
|
] }),
|
|
11427
|
-
test ? /* @__PURE__ */ (0,
|
|
11461
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
11428
11462
|
requestCount,
|
|
11429
11463
|
" simulated request",
|
|
11430
11464
|
requestCount === 1 ? "" : "s"
|
|
11431
11465
|
] }) : null,
|
|
11432
|
-
/* @__PURE__ */ (0,
|
|
11433
|
-
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
|
|
11434
11468
|
] }),
|
|
11435
|
-
/* @__PURE__ */ (0,
|
|
11436
|
-
/* @__PURE__ */ (0,
|
|
11437
|
-
/* @__PURE__ */ (0,
|
|
11438
|
-
/* @__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: [
|
|
11439
11473
|
s.endpointsWired,
|
|
11440
11474
|
" endpoint",
|
|
11441
11475
|
s.endpointsWired === 1 ? "" : "s",
|
|
@@ -11445,58 +11479,58 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11445
11479
|
s.total,
|
|
11446
11480
|
" features complete"
|
|
11447
11481
|
] }),
|
|
11448
|
-
onOpenSpec ? /* @__PURE__ */ (0,
|
|
11449
|
-
/* @__PURE__ */ (0,
|
|
11450
|
-
/* @__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: () => {
|
|
11451
11485
|
setOpen(false);
|
|
11452
11486
|
onOpenSpec();
|
|
11453
11487
|
}, children: [
|
|
11454
11488
|
"API spec ",
|
|
11455
|
-
/* @__PURE__ */ (0,
|
|
11489
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11456
11490
|
] })
|
|
11457
11491
|
] }) : null
|
|
11458
11492
|
] })
|
|
11459
11493
|
] }),
|
|
11460
|
-
/* @__PURE__ */ (0,
|
|
11461
|
-
/* @__PURE__ */ (0,
|
|
11462
|
-
/* @__PURE__ */ (0,
|
|
11463
|
-
/* @__PURE__ */ (0,
|
|
11464
|
-
/* @__PURE__ */ (0,
|
|
11465
|
-
/* @__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" })
|
|
11466
11500
|
] }),
|
|
11467
|
-
!test ? /* @__PURE__ */ (0,
|
|
11501
|
+
!test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11468
11502
|
] }),
|
|
11469
|
-
/* @__PURE__ */ (0,
|
|
11470
|
-
/* @__PURE__ */ (0,
|
|
11471
|
-
/* @__PURE__ */ (0,
|
|
11472
|
-
/* @__PURE__ */ (0,
|
|
11473
|
-
/* @__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" })
|
|
11474
11508
|
] }),
|
|
11475
|
-
test ? /* @__PURE__ */ (0,
|
|
11509
|
+
test ? /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11476
11510
|
] })
|
|
11477
11511
|
] }),
|
|
11478
|
-
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
|
|
11479
11513
|
] })
|
|
11480
11514
|
] });
|
|
11481
11515
|
}
|
|
11482
11516
|
function TestModeBar({ onExit }) {
|
|
11483
11517
|
const mode2 = useRuntimeMode();
|
|
11484
11518
|
if (mode2 !== "test") return null;
|
|
11485
|
-
return /* @__PURE__ */ (0,
|
|
11486
|
-
/* @__PURE__ */ (0,
|
|
11487
|
-
/* @__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" }),
|
|
11488
11522
|
"Test mode"
|
|
11489
11523
|
] }),
|
|
11490
|
-
/* @__PURE__ */ (0,
|
|
11491
|
-
/* @__PURE__ */ (0,
|
|
11492
|
-
/* @__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" }),
|
|
11493
11527
|
" Back to live mode"
|
|
11494
11528
|
] })
|
|
11495
11529
|
] });
|
|
11496
11530
|
}
|
|
11497
11531
|
|
|
11498
11532
|
// src/components/planner/ChannelMeta.tsx
|
|
11499
|
-
var
|
|
11533
|
+
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
11500
11534
|
var CHANNEL_WEIGHTS = {
|
|
11501
11535
|
"OOH": 50,
|
|
11502
11536
|
"DOOH": 50,
|
|
@@ -11549,9 +11583,9 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11549
11583
|
const m = ChannelMeta(channel);
|
|
11550
11584
|
const wt = channelWeightOf(channel || "");
|
|
11551
11585
|
if (dot) {
|
|
11552
|
-
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 });
|
|
11553
11587
|
}
|
|
11554
|
-
return /* @__PURE__ */ (0,
|
|
11588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
11555
11589
|
"span",
|
|
11556
11590
|
{
|
|
11557
11591
|
className: ["fd-chan", size === "sm" ? "fd-chan-sm" : "", className].filter(Boolean).join(" "),
|
|
@@ -11559,16 +11593,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11559
11593
|
style: { "--chan": m.color },
|
|
11560
11594
|
...rest,
|
|
11561
11595
|
children: [
|
|
11562
|
-
/* @__PURE__ */ (0,
|
|
11563
|
-
showLabel ? /* @__PURE__ */ (0,
|
|
11564
|
-
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
|
|
11565
11599
|
]
|
|
11566
11600
|
}
|
|
11567
11601
|
);
|
|
11568
11602
|
}
|
|
11569
11603
|
|
|
11570
11604
|
// src/components/planner/SaturationDistribution.tsx
|
|
11571
|
-
var
|
|
11605
|
+
var import_jsx_runtime88 = require("react/jsx-runtime");
|
|
11572
11606
|
var BANDS2 = [
|
|
11573
11607
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
11574
11608
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -11579,24 +11613,24 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11579
11613
|
const grouped = BANDS2.map((b) => ({ ...b, items: campuses.filter((c) => c.band === b.key) }));
|
|
11580
11614
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
11581
11615
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
11582
|
-
return /* @__PURE__ */ (0,
|
|
11583
|
-
/* @__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) => {
|
|
11584
11618
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
11585
11619
|
const active = selectedBand === g.key;
|
|
11586
|
-
return /* @__PURE__ */ (0,
|
|
11620
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
11587
11621
|
"button",
|
|
11588
11622
|
{
|
|
11589
11623
|
type: "button",
|
|
11590
11624
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
11591
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)" },
|
|
11592
11626
|
children: [
|
|
11593
|
-
/* @__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) => (
|
|
11594
11628
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
11595
11629
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
11596
11630
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
11597
11631
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
11598
11632
|
// is still one hover away via `title`.
|
|
11599
|
-
/* @__PURE__ */ (0,
|
|
11633
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
11600
11634
|
"span",
|
|
11601
11635
|
{
|
|
11602
11636
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -11606,13 +11640,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11606
11640
|
c.name
|
|
11607
11641
|
)
|
|
11608
11642
|
)) }),
|
|
11609
|
-
/* @__PURE__ */ (0,
|
|
11610
|
-
/* @__PURE__ */ (0,
|
|
11611
|
-
/* @__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)) })
|
|
11612
11646
|
] }),
|
|
11613
|
-
/* @__PURE__ */ (0,
|
|
11614
|
-
/* @__PURE__ */ (0,
|
|
11615
|
-
/* @__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: [
|
|
11616
11650
|
"CRP ",
|
|
11617
11651
|
g.range
|
|
11618
11652
|
] })
|
|
@@ -11622,10 +11656,10 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11622
11656
|
g.key
|
|
11623
11657
|
);
|
|
11624
11658
|
}) }),
|
|
11625
|
-
floorBand ? /* @__PURE__ */ (0,
|
|
11626
|
-
/* @__PURE__ */ (0,
|
|
11627
|
-
/* @__PURE__ */ (0,
|
|
11628
|
-
/* @__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: [
|
|
11629
11663
|
"Plan floor ",
|
|
11630
11664
|
floorScore
|
|
11631
11665
|
] }),
|
|
@@ -11636,8 +11670,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11636
11670
|
}
|
|
11637
11671
|
|
|
11638
11672
|
// src/components/planner/MixGap.tsx
|
|
11639
|
-
var
|
|
11640
|
-
var
|
|
11673
|
+
var React61 = __toESM(require("react"), 1);
|
|
11674
|
+
var import_jsx_runtime89 = require("react/jsx-runtime");
|
|
11641
11675
|
var MIX_GAP_LAYOUT = {
|
|
11642
11676
|
trackHeight: 30,
|
|
11643
11677
|
barHeight: 20,
|
|
@@ -11651,19 +11685,19 @@ function mixGapOffset(value, max) {
|
|
|
11651
11685
|
}
|
|
11652
11686
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
11653
11687
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
11654
|
-
const [hover, setHover] =
|
|
11688
|
+
const [hover, setHover] = React61.useState(null);
|
|
11655
11689
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
11656
11690
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
11657
11691
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
11658
11692
|
const barTop = (trackHeight - barHeight) / 2;
|
|
11659
|
-
return /* @__PURE__ */ (0,
|
|
11660
|
-
/* @__PURE__ */ (0,
|
|
11661
|
-
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ (0,
|
|
11662
|
-
/* @__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 } }),
|
|
11663
11697
|
l
|
|
11664
11698
|
] }, l)),
|
|
11665
|
-
/* @__PURE__ */ (0,
|
|
11666
|
-
/* @__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 } }),
|
|
11667
11701
|
"Target"
|
|
11668
11702
|
] })
|
|
11669
11703
|
] }),
|
|
@@ -11672,7 +11706,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11672
11706
|
const tone = toneOf(gap);
|
|
11673
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 : "");
|
|
11674
11708
|
const labelLeft = r.realized > r.target ? `calc(${mixGapOffset(r.realized, max)} + ${labelGap}px)` : `calc(${mixGapOffset(r.target, max)} + ${targetWidth / 2 + labelGap}px)`;
|
|
11675
|
-
return /* @__PURE__ */ (0,
|
|
11709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
|
|
11676
11710
|
"div",
|
|
11677
11711
|
{
|
|
11678
11712
|
className: "fd-row",
|
|
@@ -11680,15 +11714,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11680
11714
|
onMouseEnter: () => setHover(r.channel),
|
|
11681
11715
|
onMouseLeave: () => setHover(null),
|
|
11682
11716
|
children: [
|
|
11683
|
-
/* @__PURE__ */ (0,
|
|
11684
|
-
/* @__PURE__ */ (0,
|
|
11685
|
-
/* @__PURE__ */ (0,
|
|
11686
|
-
/* @__PURE__ */ (0,
|
|
11687
|
-
/* @__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: [
|
|
11688
11722
|
r.realized,
|
|
11689
11723
|
"%"
|
|
11690
11724
|
] }),
|
|
11691
|
-
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
|
|
11692
11726
|
] }) })
|
|
11693
11727
|
]
|
|
11694
11728
|
},
|
|
@@ -11699,7 +11733,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11699
11733
|
}
|
|
11700
11734
|
|
|
11701
11735
|
// src/components/planner/ChannelContribution.tsx
|
|
11702
|
-
var
|
|
11736
|
+
var import_jsx_runtime90 = require("react/jsx-runtime");
|
|
11703
11737
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
11704
11738
|
function ChannelContribution({
|
|
11705
11739
|
channels = [],
|
|
@@ -11715,9 +11749,9 @@ function ChannelContribution({
|
|
|
11715
11749
|
const grand = total !== void 0 ? total : base + bonus;
|
|
11716
11750
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
11717
11751
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
11718
|
-
return /* @__PURE__ */ (0,
|
|
11719
|
-
loading ? /* @__PURE__ */ (0,
|
|
11720
|
-
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)(
|
|
11721
11755
|
"span",
|
|
11722
11756
|
{
|
|
11723
11757
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -11726,7 +11760,7 @@ function ChannelContribution({
|
|
|
11726
11760
|
},
|
|
11727
11761
|
c.name
|
|
11728
11762
|
)),
|
|
11729
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
11763
|
+
bonus > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
11730
11764
|
"span",
|
|
11731
11765
|
{
|
|
11732
11766
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -11735,18 +11769,18 @@ function ChannelContribution({
|
|
|
11735
11769
|
}
|
|
11736
11770
|
) : null
|
|
11737
11771
|
] }),
|
|
11738
|
-
showTable ? /* @__PURE__ */ (0,
|
|
11739
|
-
/* @__PURE__ */ (0,
|
|
11740
|
-
/* @__PURE__ */ (0,
|
|
11741
|
-
/* @__PURE__ */ (0,
|
|
11742
|
-
/* @__PURE__ */ (0,
|
|
11743
|
-
/* @__PURE__ */ (0,
|
|
11744
|
-
/* @__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" })
|
|
11745
11779
|
] }) }),
|
|
11746
|
-
/* @__PURE__ */ (0,
|
|
11747
|
-
channels.map((c) => /* @__PURE__ */ (0,
|
|
11748
|
-
/* @__PURE__ */ (0,
|
|
11749
|
-
/* @__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)(
|
|
11750
11784
|
"span",
|
|
11751
11785
|
{
|
|
11752
11786
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -11755,38 +11789,38 @@ function ChannelContribution({
|
|
|
11755
11789
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
11756
11790
|
}
|
|
11757
11791
|
) }),
|
|
11758
|
-
/* @__PURE__ */ (0,
|
|
11759
|
-
/* @__PURE__ */ (0,
|
|
11760
|
-
/* @__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: [
|
|
11761
11795
|
pct(c.crp).toFixed(0),
|
|
11762
11796
|
"%"
|
|
11763
11797
|
] })
|
|
11764
11798
|
] }, c.name)),
|
|
11765
|
-
bonus > 0 ? /* @__PURE__ */ (0,
|
|
11766
|
-
/* @__PURE__ */ (0,
|
|
11767
|
-
/* @__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" } }),
|
|
11768
11802
|
"Surround-sound bonus"
|
|
11769
11803
|
] }) }),
|
|
11770
|
-
/* @__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: [
|
|
11771
11805
|
"+",
|
|
11772
11806
|
bonusPct,
|
|
11773
11807
|
"% of +",
|
|
11774
11808
|
bonusMax,
|
|
11775
11809
|
"%"
|
|
11776
11810
|
] }) }),
|
|
11777
|
-
/* @__PURE__ */ (0,
|
|
11778
|
-
/* @__PURE__ */ (0,
|
|
11779
|
-
/* @__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: [
|
|
11780
11814
|
pct(bonus).toFixed(0),
|
|
11781
11815
|
"%"
|
|
11782
11816
|
] })
|
|
11783
11817
|
] }) : null,
|
|
11784
|
-
/* @__PURE__ */ (0,
|
|
11785
|
-
/* @__PURE__ */ (0,
|
|
11786
|
-
/* @__PURE__ */ (0,
|
|
11787
|
-
/* @__PURE__ */ (0,
|
|
11788
|
-
/* @__PURE__ */ (0,
|
|
11789
|
-
/* @__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%" })
|
|
11790
11824
|
] })
|
|
11791
11825
|
] })
|
|
11792
11826
|
] }) : null
|
|
@@ -11794,8 +11828,8 @@ function ChannelContribution({
|
|
|
11794
11828
|
}
|
|
11795
11829
|
|
|
11796
11830
|
// src/components/planner/BudgetReallocator.tsx
|
|
11797
|
-
var
|
|
11798
|
-
var
|
|
11831
|
+
var React62 = __toESM(require("react"), 1);
|
|
11832
|
+
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
11799
11833
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
11800
11834
|
function BudgetReallocator({
|
|
11801
11835
|
campus,
|
|
@@ -11810,8 +11844,8 @@ function BudgetReallocator({
|
|
|
11810
11844
|
onCancel,
|
|
11811
11845
|
className = ""
|
|
11812
11846
|
}) {
|
|
11813
|
-
const [draft, setDraft] =
|
|
11814
|
-
|
|
11847
|
+
const [draft, setDraft] = React62.useState(spend);
|
|
11848
|
+
React62.useEffect(() => setDraft(spend), [spend]);
|
|
11815
11849
|
const dirty = draft !== spend;
|
|
11816
11850
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
11817
11851
|
const nextBand = bandFor(nextCrp);
|
|
@@ -11826,10 +11860,10 @@ function BudgetReallocator({
|
|
|
11826
11860
|
setDraft(spend);
|
|
11827
11861
|
if (onCancel) onCancel();
|
|
11828
11862
|
};
|
|
11829
|
-
const trackRef =
|
|
11830
|
-
const chipRef =
|
|
11831
|
-
const [chipLeft, setChipLeft] =
|
|
11832
|
-
|
|
11863
|
+
const trackRef = React62.useRef(null);
|
|
11864
|
+
const chipRef = React62.useRef(null);
|
|
11865
|
+
const [chipLeft, setChipLeft] = React62.useState(null);
|
|
11866
|
+
React62.useLayoutEffect(() => {
|
|
11833
11867
|
const track = trackRef.current;
|
|
11834
11868
|
if (!dirty || !track) {
|
|
11835
11869
|
setChipLeft(null);
|
|
@@ -11850,23 +11884,23 @@ function BudgetReallocator({
|
|
|
11850
11884
|
ro.observe(track);
|
|
11851
11885
|
return () => ro.disconnect();
|
|
11852
11886
|
}, [dirty, pct]);
|
|
11853
|
-
return /* @__PURE__ */ (0,
|
|
11887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
11854
11888
|
"div",
|
|
11855
11889
|
{
|
|
11856
11890
|
className: ["fd-stack", className].filter(Boolean).join(" "),
|
|
11857
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)" },
|
|
11858
11892
|
children: [
|
|
11859
|
-
/* @__PURE__ */ (0,
|
|
11860
|
-
/* @__PURE__ */ (0,
|
|
11861
|
-
/* @__PURE__ */ (0,
|
|
11862
|
-
dirty ? /* @__PURE__ */ (0,
|
|
11863
|
-
/* @__PURE__ */ (0,
|
|
11864
|
-
/* @__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 })
|
|
11865
11899
|
] }) : null
|
|
11866
11900
|
] }),
|
|
11867
|
-
/* @__PURE__ */ (0,
|
|
11868
|
-
/* @__PURE__ */ (0,
|
|
11869
|
-
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)(
|
|
11870
11904
|
"span",
|
|
11871
11905
|
{
|
|
11872
11906
|
ref: chipRef,
|
|
@@ -11878,7 +11912,7 @@ function BudgetReallocator({
|
|
|
11878
11912
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
11879
11913
|
}
|
|
11880
11914
|
) : null,
|
|
11881
|
-
/* @__PURE__ */ (0,
|
|
11915
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
11882
11916
|
"input",
|
|
11883
11917
|
{
|
|
11884
11918
|
type: "range",
|
|
@@ -11894,13 +11928,13 @@ function BudgetReallocator({
|
|
|
11894
11928
|
}
|
|
11895
11929
|
)
|
|
11896
11930
|
] }),
|
|
11897
|
-
/* @__PURE__ */ (0,
|
|
11898
|
-
/* @__PURE__ */ (0,
|
|
11899
|
-
/* @__PURE__ */ (0,
|
|
11900
|
-
/* @__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." })
|
|
11901
11935
|
] }),
|
|
11902
|
-
/* @__PURE__ */ (0,
|
|
11903
|
-
/* @__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)(
|
|
11904
11938
|
"button",
|
|
11905
11939
|
{
|
|
11906
11940
|
type: "button",
|
|
@@ -11919,7 +11953,7 @@ function BudgetReallocator({
|
|
|
11919
11953
|
}
|
|
11920
11954
|
|
|
11921
11955
|
// src/components/planner/SurroundSound.tsx
|
|
11922
|
-
var
|
|
11956
|
+
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
11923
11957
|
var CATEGORIES = [
|
|
11924
11958
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
11925
11959
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -11931,26 +11965,26 @@ var CATEGORIES = [
|
|
|
11931
11965
|
function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost, className = "" }) {
|
|
11932
11966
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
11933
11967
|
const single = present.length <= 2;
|
|
11934
|
-
return /* @__PURE__ */ (0,
|
|
11935
|
-
/* @__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) => {
|
|
11936
11970
|
const on = present.includes(c.key);
|
|
11937
|
-
return /* @__PURE__ */ (0,
|
|
11971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
|
|
11938
11972
|
"span",
|
|
11939
11973
|
{
|
|
11940
11974
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
11941
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)" },
|
|
11942
11976
|
children: [
|
|
11943
|
-
/* @__PURE__ */ (0,
|
|
11944
|
-
/* @__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 })
|
|
11945
11979
|
]
|
|
11946
11980
|
},
|
|
11947
11981
|
c.key
|
|
11948
11982
|
);
|
|
11949
11983
|
}) }),
|
|
11950
|
-
/* @__PURE__ */ (0,
|
|
11951
|
-
/* @__PURE__ */ (0,
|
|
11952
|
-
/* @__PURE__ */ (0,
|
|
11953
|
-
/* @__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: [
|
|
11954
11988
|
"+",
|
|
11955
11989
|
bonusPct,
|
|
11956
11990
|
"% of +",
|
|
@@ -11958,8 +11992,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11958
11992
|
"%"
|
|
11959
11993
|
] })
|
|
11960
11994
|
] }),
|
|
11961
|
-
/* @__PURE__ */ (0,
|
|
11962
|
-
/* @__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: [
|
|
11963
11997
|
present.length,
|
|
11964
11998
|
" of 6 channel categories present.",
|
|
11965
11999
|
" ",
|
|
@@ -11971,7 +12005,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11971
12005
|
}
|
|
11972
12006
|
|
|
11973
12007
|
// src/components/planner/Importance.tsx
|
|
11974
|
-
var
|
|
12008
|
+
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
11975
12009
|
var IMPORTANCE_LEVELS = [
|
|
11976
12010
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
11977
12011
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -12001,7 +12035,7 @@ function importanceTokens(id) {
|
|
|
12001
12035
|
function ImportanceTag({ level, showLabel = true, size = "sm", className = "", disabled = false }) {
|
|
12002
12036
|
const lvl = importanceLevel(level);
|
|
12003
12037
|
const t = importanceTokens(level);
|
|
12004
|
-
return /* @__PURE__ */ (0,
|
|
12038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
|
|
12005
12039
|
"span",
|
|
12006
12040
|
{
|
|
12007
12041
|
className: ["fd-imp-tag", size === "md" ? "is-md" : "", disabled ? "is-disabled" : "", className].filter(Boolean).join(" "),
|
|
@@ -12009,16 +12043,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
|
|
|
12009
12043
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
12010
12044
|
"aria-disabled": disabled ? "true" : void 0,
|
|
12011
12045
|
children: [
|
|
12012
|
-
/* @__PURE__ */ (0,
|
|
12013
|
-
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 })
|
|
12014
12048
|
]
|
|
12015
12049
|
}
|
|
12016
12050
|
);
|
|
12017
12051
|
}
|
|
12018
12052
|
|
|
12019
12053
|
// src/components/planner/PreferenceMeter.tsx
|
|
12020
|
-
var
|
|
12021
|
-
var
|
|
12054
|
+
var React63 = __toESM(require("react"), 1);
|
|
12055
|
+
var import_jsx_runtime94 = require("react/jsx-runtime");
|
|
12022
12056
|
function preferenceScore(criteria) {
|
|
12023
12057
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
12024
12058
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -12047,8 +12081,8 @@ function PreferenceMeter({
|
|
|
12047
12081
|
className = ""
|
|
12048
12082
|
}) {
|
|
12049
12083
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
12050
|
-
const segments =
|
|
12051
|
-
return /* @__PURE__ */ (0,
|
|
12084
|
+
const segments = React63.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
12085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
|
|
12052
12086
|
ScoreMeter,
|
|
12053
12087
|
{
|
|
12054
12088
|
score: value,
|
|
@@ -12060,22 +12094,22 @@ function PreferenceMeter({
|
|
|
12060
12094
|
placement,
|
|
12061
12095
|
className,
|
|
12062
12096
|
breakdownLabel: breakdownTitle,
|
|
12063
|
-
breakdown: /* @__PURE__ */ (0,
|
|
12064
|
-
/* @__PURE__ */ (0,
|
|
12065
|
-
/* @__PURE__ */ (0,
|
|
12066
|
-
/* @__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) })
|
|
12067
12101
|
] }),
|
|
12068
|
-
/* @__PURE__ */ (0,
|
|
12102
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
12069
12103
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
12070
|
-
return /* @__PURE__ */ (0,
|
|
12071
|
-
/* @__PURE__ */ (0,
|
|
12072
|
-
/* @__PURE__ */ (0,
|
|
12073
|
-
/* @__PURE__ */ (0,
|
|
12074
|
-
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
|
|
12075
12109
|
] }),
|
|
12076
|
-
/* @__PURE__ */ (0,
|
|
12110
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsxs)("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
12077
12111
|
Math.round(Number(c.earned) || 0),
|
|
12078
|
-
/* @__PURE__ */ (0,
|
|
12112
|
+
/* @__PURE__ */ (0, import_jsx_runtime94.jsx)("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
12079
12113
|
Math.round(c.weight)
|
|
12080
12114
|
] })
|
|
12081
12115
|
] }, c.id);
|
|
@@ -12086,10 +12120,10 @@ function PreferenceMeter({
|
|
|
12086
12120
|
}
|
|
12087
12121
|
|
|
12088
12122
|
// src/components/chat/AgentChatPanel.tsx
|
|
12089
|
-
var
|
|
12123
|
+
var React69 = __toESM(require("react"), 1);
|
|
12090
12124
|
|
|
12091
12125
|
// src/components/chat/chatEngine.ts
|
|
12092
|
-
var
|
|
12126
|
+
var React64 = __toESM(require("react"), 1);
|
|
12093
12127
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
12094
12128
|
var JOB_PENDING = ["queued", "running"];
|
|
12095
12129
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -12143,22 +12177,22 @@ function useChatEngine(opts) {
|
|
|
12143
12177
|
onClear,
|
|
12144
12178
|
onFeedback
|
|
12145
12179
|
} = opts || {};
|
|
12146
|
-
const [status, setStatus] =
|
|
12147
|
-
const [threadId, setThreadId] =
|
|
12148
|
-
const [messages, setMessages] =
|
|
12149
|
-
const [queue, setQueue] =
|
|
12150
|
-
const [fatal, setFatal] =
|
|
12151
|
-
const [busy, setBusy] =
|
|
12152
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
12153
|
-
const listRef =
|
|
12154
|
-
const queueRef =
|
|
12155
|
-
const busyRef =
|
|
12156
|
-
const stoppedRef =
|
|
12157
|
-
const abortRef =
|
|
12158
|
-
const serverCount =
|
|
12159
|
-
const threadRef =
|
|
12160
|
-
const mounted =
|
|
12161
|
-
|
|
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(() => {
|
|
12162
12196
|
mounted.current = true;
|
|
12163
12197
|
return () => {
|
|
12164
12198
|
mounted.current = false;
|
|
@@ -12180,14 +12214,14 @@ function useChatEngine(opts) {
|
|
|
12180
12214
|
}
|
|
12181
12215
|
return false;
|
|
12182
12216
|
};
|
|
12183
|
-
const loadThread =
|
|
12217
|
+
const loadThread = React64.useCallback(async (id) => {
|
|
12184
12218
|
const data = await apiAdapter.getThread(id);
|
|
12185
12219
|
const list = [...data && data.messages || []];
|
|
12186
12220
|
serverCount.current = list.length;
|
|
12187
12221
|
commit(list);
|
|
12188
12222
|
return list;
|
|
12189
12223
|
}, [apiAdapter]);
|
|
12190
|
-
|
|
12224
|
+
React64.useEffect(() => {
|
|
12191
12225
|
if (!apiAdapter) {
|
|
12192
12226
|
setStatus("idle");
|
|
12193
12227
|
setFatal(null);
|
|
@@ -12400,7 +12434,7 @@ function useChatEngine(opts) {
|
|
|
12400
12434
|
await dispatchTurn(turn);
|
|
12401
12435
|
}
|
|
12402
12436
|
}
|
|
12403
|
-
const send =
|
|
12437
|
+
const send = React64.useCallback((text, attachments) => {
|
|
12404
12438
|
const body = (text || "").trim();
|
|
12405
12439
|
if (!body && !(attachments && attachments.length)) return;
|
|
12406
12440
|
if (status === "disconnected") return;
|
|
@@ -12410,7 +12444,7 @@ function useChatEngine(opts) {
|
|
|
12410
12444
|
stoppedRef.current = false;
|
|
12411
12445
|
drain();
|
|
12412
12446
|
}, [status]);
|
|
12413
|
-
const stop =
|
|
12447
|
+
const stop = React64.useCallback(() => {
|
|
12414
12448
|
stoppedRef.current = true;
|
|
12415
12449
|
const ac = abortRef.current;
|
|
12416
12450
|
if (ac) {
|
|
@@ -12429,11 +12463,11 @@ function useChatEngine(opts) {
|
|
|
12429
12463
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
12430
12464
|
}
|
|
12431
12465
|
}, [apiAdapter]);
|
|
12432
|
-
const removeQueued =
|
|
12466
|
+
const removeQueued = React64.useCallback((id) => {
|
|
12433
12467
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
12434
12468
|
setQueue(queueRef.current.slice());
|
|
12435
12469
|
}, []);
|
|
12436
|
-
const retry =
|
|
12470
|
+
const retry = React64.useCallback(() => {
|
|
12437
12471
|
const list = listRef.current;
|
|
12438
12472
|
let at = -1;
|
|
12439
12473
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -12449,19 +12483,19 @@ function useChatEngine(opts) {
|
|
|
12449
12483
|
setQueue(queueRef.current.slice());
|
|
12450
12484
|
drain();
|
|
12451
12485
|
}, []);
|
|
12452
|
-
const clear =
|
|
12486
|
+
const clear = React64.useCallback(() => {
|
|
12453
12487
|
commit([]);
|
|
12454
12488
|
serverCount.current = 0;
|
|
12455
12489
|
queueRef.current = [];
|
|
12456
12490
|
setQueue([]);
|
|
12457
12491
|
onClear && onClear();
|
|
12458
12492
|
}, [onClear]);
|
|
12459
|
-
const setFeedback =
|
|
12493
|
+
const setFeedback = React64.useCallback((id, value) => {
|
|
12460
12494
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
12461
12495
|
const msg = listRef.current.find((m) => m.id === id);
|
|
12462
12496
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
12463
12497
|
}, [onFeedback]);
|
|
12464
|
-
const reload =
|
|
12498
|
+
const reload = React64.useCallback(async () => {
|
|
12465
12499
|
if (!threadRef.current) return;
|
|
12466
12500
|
setStatus("loading");
|
|
12467
12501
|
try {
|
|
@@ -12499,11 +12533,11 @@ var ChatKit = {
|
|
|
12499
12533
|
};
|
|
12500
12534
|
|
|
12501
12535
|
// src/components/chat/ChatTranscript.tsx
|
|
12502
|
-
var
|
|
12536
|
+
var React66 = __toESM(require("react"), 1);
|
|
12503
12537
|
|
|
12504
12538
|
// src/components/chat/ChatTurn.tsx
|
|
12505
|
-
var
|
|
12506
|
-
var
|
|
12539
|
+
var React65 = __toESM(require("react"), 1);
|
|
12540
|
+
var import_jsx_runtime95 = require("react/jsx-runtime");
|
|
12507
12541
|
function JsonView({ value }) {
|
|
12508
12542
|
let text;
|
|
12509
12543
|
try {
|
|
@@ -12511,67 +12545,67 @@ function JsonView({ value }) {
|
|
|
12511
12545
|
} catch (e) {
|
|
12512
12546
|
text = String(value);
|
|
12513
12547
|
}
|
|
12514
|
-
return /* @__PURE__ */ (0,
|
|
12548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
12515
12549
|
}
|
|
12516
12550
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
12517
12551
|
if (!packet) return null;
|
|
12518
12552
|
const s = schema || {};
|
|
12519
12553
|
const invalid = packet.valid === false;
|
|
12520
12554
|
const title = s.heading || packet.type;
|
|
12521
|
-
return /* @__PURE__ */ (0,
|
|
12522
|
-
/* @__PURE__ */ (0,
|
|
12523
|
-
/* @__PURE__ */ (0,
|
|
12524
|
-
/* @__PURE__ */ (0,
|
|
12525
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
12526
|
-
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
|
|
12527
12561
|
] }),
|
|
12528
|
-
invalid ? /* @__PURE__ */ (0,
|
|
12529
|
-
/* @__PURE__ */ (0,
|
|
12530
|
-
/* @__PURE__ */ (0,
|
|
12531
|
-
] }) : /* @__PURE__ */ (0,
|
|
12532
|
-
!invalid && onApply ? /* @__PURE__ */ (0,
|
|
12533
|
-
packet.repaired ? /* @__PURE__ */ (0,
|
|
12534
|
-
/* @__PURE__ */ (0,
|
|
12535
|
-
/* @__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" }),
|
|
12536
12570
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
12537
12571
|
] })
|
|
12538
12572
|
] }) : null
|
|
12539
12573
|
] });
|
|
12540
12574
|
}
|
|
12541
12575
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
12542
|
-
const [open2, setOpen] =
|
|
12576
|
+
const [open2, setOpen] = React65.useState(defaultOpen);
|
|
12543
12577
|
if (!text) return null;
|
|
12544
|
-
return /* @__PURE__ */ (0,
|
|
12545
|
-
/* @__PURE__ */ (0,
|
|
12546
|
-
/* @__PURE__ */ (0,
|
|
12547
|
-
/* @__PURE__ */ (0,
|
|
12548
|
-
streaming ? /* @__PURE__ */ (0,
|
|
12549
|
-
/* @__PURE__ */ (0,
|
|
12550
|
-
/* @__PURE__ */ (0,
|
|
12551
|
-
/* @__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", {})
|
|
12552
12586
|
] }) : null,
|
|
12553
|
-
/* @__PURE__ */ (0,
|
|
12587
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12554
12588
|
] }),
|
|
12555
|
-
open2 ? /* @__PURE__ */ (0,
|
|
12589
|
+
open2 ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "fdc-think-body", children: text }) : null
|
|
12556
12590
|
] });
|
|
12557
12591
|
}
|
|
12558
12592
|
function Citations({ items = [], onOpen }) {
|
|
12559
|
-
const [open2, setOpen] =
|
|
12593
|
+
const [open2, setOpen] = React65.useState(false);
|
|
12560
12594
|
if (!items.length) return null;
|
|
12561
|
-
return /* @__PURE__ */ (0,
|
|
12562
|
-
/* @__PURE__ */ (0,
|
|
12563
|
-
/* @__PURE__ */ (0,
|
|
12564
|
-
/* @__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: [
|
|
12565
12599
|
items.length,
|
|
12566
12600
|
" source",
|
|
12567
12601
|
items.length === 1 ? "" : "s"
|
|
12568
12602
|
] }),
|
|
12569
|
-
/* @__PURE__ */ (0,
|
|
12603
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsx)("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12570
12604
|
] }),
|
|
12571
|
-
open2 ? /* @__PURE__ */ (0,
|
|
12572
|
-
/* @__PURE__ */ (0,
|
|
12573
|
-
c.url ? /* @__PURE__ */ (0,
|
|
12574
|
-
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
|
|
12575
12609
|
] }, c.id || i)) }) : null
|
|
12576
12610
|
] });
|
|
12577
12611
|
}
|
|
@@ -12582,29 +12616,29 @@ function clampText(text, max) {
|
|
|
12582
12616
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
12583
12617
|
}
|
|
12584
12618
|
function MessageBody({ message: m, ctx }) {
|
|
12585
|
-
const [expanded, setExpanded] =
|
|
12619
|
+
const [expanded, setExpanded] = React65.useState(false);
|
|
12586
12620
|
const isUser = m.role === "user";
|
|
12587
12621
|
const raw = m.text || "";
|
|
12588
12622
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
12589
12623
|
const body = clamped != null ? clamped : raw;
|
|
12590
12624
|
const showMd = ctx.markdown && !isUser;
|
|
12591
|
-
return /* @__PURE__ */ (0,
|
|
12592
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */ (0,
|
|
12593
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ (0,
|
|
12594
|
-
body ? /* @__PURE__ */ (0,
|
|
12595
|
-
showMd ? /* @__PURE__ */ (0,
|
|
12596
|
-
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
|
|
12597
12631
|
] }) : null,
|
|
12598
|
-
clamped != null ? /* @__PURE__ */ (0,
|
|
12599
|
-
/* @__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" }),
|
|
12600
12634
|
"Show more",
|
|
12601
|
-
/* @__PURE__ */ (0,
|
|
12602
|
-
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ (0,
|
|
12603
|
-
/* @__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" }),
|
|
12604
12638
|
"Show less"
|
|
12605
12639
|
] }) : null,
|
|
12606
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */ (0,
|
|
12607
|
-
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)(
|
|
12608
12642
|
PacketCard,
|
|
12609
12643
|
{
|
|
12610
12644
|
packet: m.packet,
|
|
@@ -12614,35 +12648,35 @@ function MessageBody({ message: m, ctx }) {
|
|
|
12614
12648
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
12615
12649
|
}
|
|
12616
12650
|
) : null,
|
|
12617
|
-
m.citations && m.citations.length ? /* @__PURE__ */ (0,
|
|
12618
|
-
m.working ? /* @__PURE__ */ (0,
|
|
12619
|
-
/* @__PURE__ */ (0,
|
|
12620
|
-
/* @__PURE__ */ (0,
|
|
12621
|
-
/* @__PURE__ */ (0,
|
|
12622
|
-
/* @__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", {})
|
|
12623
12657
|
] }),
|
|
12624
|
-
/* @__PURE__ */ (0,
|
|
12658
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("span", { className: "fdc-working-label", children: [
|
|
12625
12659
|
m.resumed ? "Resuming" : "Working",
|
|
12626
|
-
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: [
|
|
12627
12661
|
" \xB7 ",
|
|
12628
12662
|
m.job.status
|
|
12629
12663
|
] }) : null,
|
|
12630
|
-
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: [
|
|
12631
12665
|
" \xB7 ",
|
|
12632
12666
|
m.job.detail
|
|
12633
12667
|
] }) : null
|
|
12634
12668
|
] }),
|
|
12635
|
-
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
|
|
12636
12670
|
] }) : null,
|
|
12637
|
-
m.stopped ? /* @__PURE__ */ (0,
|
|
12638
|
-
/* @__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" }),
|
|
12639
12673
|
"Stopped"
|
|
12640
12674
|
] }) : null,
|
|
12641
|
-
m.error ? /* @__PURE__ */ (0,
|
|
12642
|
-
/* @__PURE__ */ (0,
|
|
12643
|
-
/* @__PURE__ */ (0,
|
|
12644
|
-
m.retryable && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
12645
|
-
/* @__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" }),
|
|
12646
12680
|
"Retry"
|
|
12647
12681
|
] }) : null
|
|
12648
12682
|
] }) : null
|
|
@@ -12655,16 +12689,16 @@ function RunActions({ group, ctx }) {
|
|
|
12655
12689
|
const isAssistant = group.role === "assistant";
|
|
12656
12690
|
const fb = last.feedback;
|
|
12657
12691
|
if (!ctx.messageActions) return null;
|
|
12658
|
-
return /* @__PURE__ */ (0,
|
|
12659
|
-
/* @__PURE__ */ (0,
|
|
12660
|
-
/* @__PURE__ */ (0,
|
|
12661
|
-
/* @__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" })
|
|
12662
12696
|
] }),
|
|
12663
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0,
|
|
12664
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0,
|
|
12665
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0,
|
|
12666
|
-
/* @__PURE__ */ (0,
|
|
12667
|
-
/* @__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" }) })
|
|
12668
12702
|
] }) : null,
|
|
12669
12703
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
12670
12704
|
] });
|
|
@@ -12674,22 +12708,22 @@ function ChatTurn({ group, ctx }) {
|
|
|
12674
12708
|
const name = isUser ? ctx.userName : group.author || ctx.assistantName;
|
|
12675
12709
|
const avatar = isUser ? ctx.userAvatar : ctx.assistantAvatar;
|
|
12676
12710
|
const stamp = group.messages[0].timestamp;
|
|
12677
|
-
return /* @__PURE__ */ (0,
|
|
12678
|
-
/* @__PURE__ */ (0,
|
|
12679
|
-
ctx.showAvatars ? /* @__PURE__ */ (0,
|
|
12680
|
-
/* @__PURE__ */ (0,
|
|
12681
|
-
stamp ? /* @__PURE__ */ (0,
|
|
12682
|
-
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
|
|
12683
12717
|
] }),
|
|
12684
|
-
/* @__PURE__ */ (0,
|
|
12685
|
-
group.messages.map((m) => /* @__PURE__ */ (0,
|
|
12686
|
-
/* @__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 })
|
|
12687
12721
|
] })
|
|
12688
12722
|
] });
|
|
12689
12723
|
}
|
|
12690
12724
|
|
|
12691
12725
|
// src/components/chat/ChatTranscript.tsx
|
|
12692
|
-
var
|
|
12726
|
+
var import_jsx_runtime96 = require("react/jsx-runtime");
|
|
12693
12727
|
var GROUP_WINDOW = 6e4;
|
|
12694
12728
|
var STICK_PX = 100;
|
|
12695
12729
|
function groupMessages(list) {
|
|
@@ -12722,25 +12756,25 @@ function dayLabel(key) {
|
|
|
12722
12756
|
}
|
|
12723
12757
|
function Suggestions({ items = [], onPick }) {
|
|
12724
12758
|
if (!items.length) return null;
|
|
12725
|
-
return /* @__PURE__ */ (0,
|
|
12759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
12726
12760
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
12727
|
-
return /* @__PURE__ */ (0,
|
|
12728
|
-
it.icon ? /* @__PURE__ */ (0,
|
|
12729
|
-
/* @__PURE__ */ (0,
|
|
12730
|
-
/* @__PURE__ */ (0,
|
|
12731
|
-
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
|
|
12732
12766
|
] }),
|
|
12733
|
-
/* @__PURE__ */ (0,
|
|
12767
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
12734
12768
|
] }, it.id || i);
|
|
12735
12769
|
}) });
|
|
12736
12770
|
}
|
|
12737
12771
|
function LoadingTurns() {
|
|
12738
|
-
return /* @__PURE__ */ (0,
|
|
12739
|
-
/* @__PURE__ */ (0,
|
|
12740
|
-
/* @__PURE__ */ (0,
|
|
12741
|
-
/* @__PURE__ */ (0,
|
|
12742
|
-
/* @__PURE__ */ (0,
|
|
12743
|
-
/* @__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 } })
|
|
12744
12778
|
] })
|
|
12745
12779
|
] }, i)) });
|
|
12746
12780
|
}
|
|
@@ -12757,10 +12791,10 @@ function ChatTranscript({
|
|
|
12757
12791
|
renderEmpty,
|
|
12758
12792
|
className = ""
|
|
12759
12793
|
}) {
|
|
12760
|
-
const scroller =
|
|
12761
|
-
const stick =
|
|
12762
|
-
const [pill, setPill] =
|
|
12763
|
-
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);
|
|
12764
12798
|
const toBottom = (smooth) => {
|
|
12765
12799
|
const el = scroller.current;
|
|
12766
12800
|
if (!el) return;
|
|
@@ -12779,7 +12813,7 @@ function ChatTranscript({
|
|
|
12779
12813
|
seen.current = messages.length;
|
|
12780
12814
|
}
|
|
12781
12815
|
};
|
|
12782
|
-
|
|
12816
|
+
React66.useLayoutEffect(() => {
|
|
12783
12817
|
const el = scroller.current;
|
|
12784
12818
|
if (!el) return;
|
|
12785
12819
|
if (stick.current) {
|
|
@@ -12787,7 +12821,7 @@ function ChatTranscript({
|
|
|
12787
12821
|
seen.current = messages.length;
|
|
12788
12822
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
12789
12823
|
}, [messages]);
|
|
12790
|
-
|
|
12824
|
+
React66.useEffect(() => {
|
|
12791
12825
|
const el = scroller.current;
|
|
12792
12826
|
const inner = el && el.firstChild;
|
|
12793
12827
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -12797,38 +12831,38 @@ function ChatTranscript({
|
|
|
12797
12831
|
ro.observe(inner);
|
|
12798
12832
|
return () => ro.disconnect();
|
|
12799
12833
|
}, []);
|
|
12800
|
-
const groups =
|
|
12834
|
+
const groups = React66.useMemo(() => groupMessages(messages), [messages]);
|
|
12801
12835
|
const empty = !messages.length && status === "ready";
|
|
12802
|
-
return /* @__PURE__ */ (0,
|
|
12803
|
-
/* @__PURE__ */ (0,
|
|
12804
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */ (0,
|
|
12805
|
-
status === "disconnected" ? /* @__PURE__ */ (0,
|
|
12806
|
-
/* @__PURE__ */ (0,
|
|
12807
|
-
/* @__PURE__ */ (0,
|
|
12808
|
-
/* @__PURE__ */ (0,
|
|
12809
|
-
ctx.onReconnect ? /* @__PURE__ */ (0,
|
|
12810
|
-
/* @__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" }),
|
|
12811
12845
|
"Try again"
|
|
12812
12846
|
] }) : null
|
|
12813
12847
|
] }) : null,
|
|
12814
|
-
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ (0,
|
|
12815
|
-
/* @__PURE__ */ (0,
|
|
12816
|
-
/* @__PURE__ */ (0,
|
|
12817
|
-
emptyDescription ? /* @__PURE__ */ (0,
|
|
12818
|
-
/* @__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 })
|
|
12819
12853
|
] }) : null,
|
|
12820
12854
|
groups.map((g, i) => {
|
|
12821
12855
|
const prev = groups[i - 1];
|
|
12822
12856
|
const k = dayKey(g.messages[0].timestamp);
|
|
12823
12857
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
12824
|
-
return /* @__PURE__ */ (0,
|
|
12825
|
-
showDay ? /* @__PURE__ */ (0,
|
|
12826
|
-
/* @__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 })
|
|
12827
12861
|
] }, g.key || i);
|
|
12828
12862
|
})
|
|
12829
12863
|
] }),
|
|
12830
|
-
pill ? /* @__PURE__ */ (0,
|
|
12831
|
-
/* @__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" }),
|
|
12832
12866
|
pill,
|
|
12833
12867
|
" new message",
|
|
12834
12868
|
pill === 1 ? "" : "s"
|
|
@@ -12838,8 +12872,8 @@ function ChatTranscript({
|
|
|
12838
12872
|
var TranscriptKit = { groupMessages };
|
|
12839
12873
|
|
|
12840
12874
|
// src/components/chat/ChatComposer.tsx
|
|
12841
|
-
var
|
|
12842
|
-
var
|
|
12875
|
+
var React67 = __toESM(require("react"), 1);
|
|
12876
|
+
var import_jsx_runtime97 = require("react/jsx-runtime");
|
|
12843
12877
|
function ChatComposer({
|
|
12844
12878
|
onSubmit,
|
|
12845
12879
|
onStop,
|
|
@@ -12866,17 +12900,17 @@ function ChatComposer({
|
|
|
12866
12900
|
onReject,
|
|
12867
12901
|
onOpenAttachment
|
|
12868
12902
|
}) {
|
|
12869
|
-
const [text, setText] =
|
|
12870
|
-
const [trigger, setTrigger] =
|
|
12871
|
-
const [mentionItems, setMentionItems] =
|
|
12872
|
-
const [listening, setListening] =
|
|
12873
|
-
const [notice, setNotice] =
|
|
12874
|
-
const editor =
|
|
12875
|
-
const wrap =
|
|
12876
|
-
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);
|
|
12877
12911
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
12878
12912
|
} });
|
|
12879
|
-
|
|
12913
|
+
React67.useEffect(() => {
|
|
12880
12914
|
if (draft != null && draft !== text) setText(draft);
|
|
12881
12915
|
}, [draft]);
|
|
12882
12916
|
const change = (v) => {
|
|
@@ -12912,7 +12946,7 @@ function ChatComposer({
|
|
|
12912
12946
|
e.preventDefault();
|
|
12913
12947
|
staged.add(found.files);
|
|
12914
12948
|
};
|
|
12915
|
-
|
|
12949
|
+
React67.useEffect(() => {
|
|
12916
12950
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
12917
12951
|
setMentionItems([]);
|
|
12918
12952
|
return;
|
|
@@ -12930,7 +12964,7 @@ function ChatComposer({
|
|
|
12930
12964
|
const q = (trigger.query || "").toLowerCase();
|
|
12931
12965
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
12932
12966
|
}, [trigger, mentionSources]);
|
|
12933
|
-
const slashItems =
|
|
12967
|
+
const slashItems = React67.useMemo(() => {
|
|
12934
12968
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
12935
12969
|
const q = (trigger.query || "").toLowerCase();
|
|
12936
12970
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -12944,7 +12978,7 @@ function ChatComposer({
|
|
|
12944
12978
|
description: it.description,
|
|
12945
12979
|
icon: it.icon,
|
|
12946
12980
|
meta: mention.meta,
|
|
12947
|
-
shortcut: slash.shortcut ? /* @__PURE__ */ (0,
|
|
12981
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
12948
12982
|
onSelect: () => {
|
|
12949
12983
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
12950
12984
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -13003,14 +13037,14 @@ function ChatComposer({
|
|
|
13003
13037
|
stopVoice.current = typeof res === "function" ? res : () => {
|
|
13004
13038
|
};
|
|
13005
13039
|
};
|
|
13006
|
-
return /* @__PURE__ */ (0,
|
|
13007
|
-
queue.length ? /* @__PURE__ */ (0,
|
|
13008
|
-
/* @__PURE__ */ (0,
|
|
13009
|
-
/* @__PURE__ */ (0,
|
|
13010
|
-
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
|
|
13011
13045
|
] }, q.id)) }) : null,
|
|
13012
13046
|
sessionBar,
|
|
13013
|
-
/* @__PURE__ */ (0,
|
|
13047
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13014
13048
|
Dropzone,
|
|
13015
13049
|
{
|
|
13016
13050
|
className: "fdc-field",
|
|
@@ -13024,9 +13058,9 @@ function ChatComposer({
|
|
|
13024
13058
|
disabled: !fileUploadHandler || disabled,
|
|
13025
13059
|
label: "Drop to attach",
|
|
13026
13060
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
13027
|
-
children: /* @__PURE__ */ (0,
|
|
13028
|
-
staged.items.length ? /* @__PURE__ */ (0,
|
|
13029
|
-
/* @__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)(
|
|
13030
13064
|
MarkdownEditor,
|
|
13031
13065
|
{
|
|
13032
13066
|
ref: editor,
|
|
@@ -13045,33 +13079,33 @@ function ChatComposer({
|
|
|
13045
13079
|
ariaLabel: "Message"
|
|
13046
13080
|
}
|
|
13047
13081
|
),
|
|
13048
|
-
/* @__PURE__ */ (0,
|
|
13049
|
-
fileUploadHandler ? /* @__PURE__ */ (0,
|
|
13050
|
-
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,
|
|
13051
13085
|
toolbarExtras,
|
|
13052
|
-
/* @__PURE__ */ (0,
|
|
13053
|
-
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: [
|
|
13054
13088
|
text.length,
|
|
13055
13089
|
"/",
|
|
13056
13090
|
maxLength
|
|
13057
13091
|
] }) : null,
|
|
13058
|
-
busy ? /* @__PURE__ */ (0,
|
|
13059
|
-
/* @__PURE__ */ (0,
|
|
13060
|
-
/* @__PURE__ */ (0,
|
|
13061
|
-
] }) : /* @__PURE__ */ (0,
|
|
13062
|
-
/* @__PURE__ */ (0,
|
|
13063
|
-
/* @__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" })
|
|
13064
13098
|
] })
|
|
13065
13099
|
] })
|
|
13066
13100
|
] })
|
|
13067
13101
|
}
|
|
13068
13102
|
),
|
|
13069
|
-
notice ? /* @__PURE__ */ (0,
|
|
13070
|
-
/* @__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" }),
|
|
13071
13105
|
notice
|
|
13072
13106
|
] }) : null,
|
|
13073
|
-
hint && !notice ? /* @__PURE__ */ (0,
|
|
13074
|
-
/* @__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)(
|
|
13075
13109
|
Popover,
|
|
13076
13110
|
{
|
|
13077
13111
|
open: menuOpen,
|
|
@@ -13085,12 +13119,12 @@ function ChatComposer({
|
|
|
13085
13119
|
returnFocus: false,
|
|
13086
13120
|
closeOnOutside: true,
|
|
13087
13121
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
13088
|
-
children: /* @__PURE__ */ (0,
|
|
13122
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
13089
13123
|
Menu,
|
|
13090
13124
|
{
|
|
13091
13125
|
items: menuItems,
|
|
13092
13126
|
autoFocus: false,
|
|
13093
|
-
header: /* @__PURE__ */ (0,
|
|
13127
|
+
header: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
13094
13128
|
onClose: () => setTrigger(null)
|
|
13095
13129
|
}
|
|
13096
13130
|
)
|
|
@@ -13100,12 +13134,12 @@ function ChatComposer({
|
|
|
13100
13134
|
}
|
|
13101
13135
|
|
|
13102
13136
|
// src/components/chat/ChatSessionBar.tsx
|
|
13103
|
-
var
|
|
13104
|
-
var
|
|
13137
|
+
var React68 = __toESM(require("react"), 1);
|
|
13138
|
+
var import_jsx_runtime98 = require("react/jsx-runtime");
|
|
13105
13139
|
var compact2 = meterFormats.compact;
|
|
13106
13140
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
13107
|
-
const [open2, setOpen] =
|
|
13108
|
-
const anchor =
|
|
13141
|
+
const [open2, setOpen] = React68.useState(false);
|
|
13142
|
+
const anchor = React68.useRef(null);
|
|
13109
13143
|
const stats = sessionStats || null;
|
|
13110
13144
|
const cu = contextUsage || null;
|
|
13111
13145
|
const limits = usageLimits || null;
|
|
@@ -13120,9 +13154,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13120
13154
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
13121
13155
|
if (cu) bits.push(pct + "% context");
|
|
13122
13156
|
const expandable = !!(cu || limits);
|
|
13123
|
-
return /* @__PURE__ */ (0,
|
|
13124
|
-
/* @__PURE__ */ (0,
|
|
13125
|
-
/* @__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)(
|
|
13126
13160
|
"button",
|
|
13127
13161
|
{
|
|
13128
13162
|
type: "button",
|
|
@@ -13133,15 +13167,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13133
13167
|
"aria-expanded": expandable ? open2 : void 0,
|
|
13134
13168
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
13135
13169
|
children: [
|
|
13136
|
-
cu ? /* @__PURE__ */ (0,
|
|
13137
|
-
/* @__PURE__ */ (0,
|
|
13138
|
-
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
|
|
13139
13173
|
]
|
|
13140
13174
|
}
|
|
13141
13175
|
),
|
|
13142
13176
|
extras
|
|
13143
13177
|
] }),
|
|
13144
|
-
/* @__PURE__ */ (0,
|
|
13178
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13145
13179
|
Popover,
|
|
13146
13180
|
{
|
|
13147
13181
|
open: open2,
|
|
@@ -13152,15 +13186,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13152
13186
|
maxHeight: 460,
|
|
13153
13187
|
padded: true,
|
|
13154
13188
|
label: "Usage",
|
|
13155
|
-
footer: onClear ? /* @__PURE__ */ (0,
|
|
13189
|
+
footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
13156
13190
|
setOpen(false);
|
|
13157
13191
|
onClear();
|
|
13158
13192
|
}, children: [
|
|
13159
|
-
/* @__PURE__ */ (0,
|
|
13193
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
13160
13194
|
"Clear conversation"
|
|
13161
13195
|
] }) : void 0,
|
|
13162
|
-
children: /* @__PURE__ */ (0,
|
|
13163
|
-
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)(
|
|
13164
13198
|
SegmentedMeter,
|
|
13165
13199
|
{
|
|
13166
13200
|
total,
|
|
@@ -13172,9 +13206,9 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13172
13206
|
remainderLabel: "Free"
|
|
13173
13207
|
}
|
|
13174
13208
|
) }) : null,
|
|
13175
|
-
limits && limits.length ? /* @__PURE__ */ (0,
|
|
13176
|
-
/* @__PURE__ */ (0,
|
|
13177
|
-
/* @__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)(
|
|
13178
13212
|
QuotaRow,
|
|
13179
13213
|
{
|
|
13180
13214
|
label: l.label,
|
|
@@ -13184,25 +13218,25 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
13184
13218
|
l.id
|
|
13185
13219
|
)) })
|
|
13186
13220
|
] }) : null,
|
|
13187
|
-
stats ? /* @__PURE__ */ (0,
|
|
13188
|
-
stats.elapsedMs ? /* @__PURE__ */ (0,
|
|
13189
|
-
/* @__PURE__ */ (0,
|
|
13190
|
-
/* @__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) })
|
|
13191
13225
|
] }) : null,
|
|
13192
|
-
stats.tokens ? /* @__PURE__ */ (0,
|
|
13193
|
-
/* @__PURE__ */ (0,
|
|
13194
|
-
/* @__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() })
|
|
13195
13229
|
] }) : null,
|
|
13196
|
-
stats.costUsd != null ? /* @__PURE__ */ (0,
|
|
13197
|
-
/* @__PURE__ */ (0,
|
|
13198
|
-
/* @__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: [
|
|
13199
13233
|
"$",
|
|
13200
13234
|
Number(stats.costUsd).toFixed(3)
|
|
13201
13235
|
] })
|
|
13202
13236
|
] }) : null,
|
|
13203
|
-
stats.turns ? /* @__PURE__ */ (0,
|
|
13204
|
-
/* @__PURE__ */ (0,
|
|
13205
|
-
/* @__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 })
|
|
13206
13240
|
] }) : null
|
|
13207
13241
|
] }) : null
|
|
13208
13242
|
] })
|
|
@@ -13241,7 +13275,7 @@ function ModelControls({
|
|
|
13241
13275
|
disabled: m.disabled,
|
|
13242
13276
|
checked: m.id === (current2 && current2.id),
|
|
13243
13277
|
meta: m.meta,
|
|
13244
|
-
shortcut: m.shortcut ? /* @__PURE__ */ (0,
|
|
13278
|
+
shortcut: m.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
13245
13279
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
13246
13280
|
});
|
|
13247
13281
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -13254,15 +13288,15 @@ function ModelControls({
|
|
|
13254
13288
|
items.push({ kind: "section", label: "Fast mode" });
|
|
13255
13289
|
items.push({
|
|
13256
13290
|
kind: "custom",
|
|
13257
|
-
render: () => /* @__PURE__ */ (0,
|
|
13258
|
-
/* @__PURE__ */ (0,
|
|
13259
|
-
/* @__PURE__ */ (0,
|
|
13260
|
-
/* @__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" }) })
|
|
13261
13295
|
] })
|
|
13262
13296
|
});
|
|
13263
13297
|
}
|
|
13264
|
-
return /* @__PURE__ */ (0,
|
|
13265
|
-
/* @__PURE__ */ (0,
|
|
13298
|
+
return /* @__PURE__ */ (0, import_jsx_runtime98.jsxs)(React68.Fragment, { children: [
|
|
13299
|
+
/* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13266
13300
|
MenuButton,
|
|
13267
13301
|
{
|
|
13268
13302
|
items,
|
|
@@ -13273,7 +13307,7 @@ function ModelControls({
|
|
|
13273
13307
|
title: "Choose a model"
|
|
13274
13308
|
}
|
|
13275
13309
|
),
|
|
13276
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */ (0,
|
|
13310
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
13277
13311
|
MenuButton,
|
|
13278
13312
|
{
|
|
13279
13313
|
placement: "top-end",
|
|
@@ -13294,7 +13328,7 @@ function ModelControls({
|
|
|
13294
13328
|
}
|
|
13295
13329
|
|
|
13296
13330
|
// src/components/chat/AgentChatPanel.tsx
|
|
13297
|
-
var
|
|
13331
|
+
var import_jsx_runtime99 = require("react/jsx-runtime");
|
|
13298
13332
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
13299
13333
|
function AgentChatPanel({
|
|
13300
13334
|
/* required */
|
|
@@ -13378,11 +13412,11 @@ function AgentChatPanel({
|
|
|
13378
13412
|
onFeedback,
|
|
13379
13413
|
onEditMessage
|
|
13380
13414
|
}) {
|
|
13381
|
-
const [panelWidth, setPanelWidth] =
|
|
13382
|
-
const [applied, setApplied] =
|
|
13383
|
-
const [draft, setDraft] =
|
|
13384
|
-
const dragging =
|
|
13385
|
-
|
|
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]);
|
|
13386
13420
|
const engine = useChatEngine({
|
|
13387
13421
|
contextType,
|
|
13388
13422
|
contextId,
|
|
@@ -13448,7 +13482,7 @@ function AgentChatPanel({
|
|
|
13448
13482
|
onReconnect: engine.reload,
|
|
13449
13483
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
13450
13484
|
};
|
|
13451
|
-
const sessionBar = /* @__PURE__ */ (0,
|
|
13485
|
+
const sessionBar = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13452
13486
|
ChatSessionBar,
|
|
13453
13487
|
{
|
|
13454
13488
|
sessionStats,
|
|
@@ -13457,7 +13491,7 @@ function AgentChatPanel({
|
|
|
13457
13491
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
13458
13492
|
}
|
|
13459
13493
|
);
|
|
13460
|
-
const modelControls = /* @__PURE__ */ (0,
|
|
13494
|
+
const modelControls = /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13461
13495
|
ModelControls,
|
|
13462
13496
|
{
|
|
13463
13497
|
models,
|
|
@@ -13472,7 +13506,7 @@ function AgentChatPanel({
|
|
|
13472
13506
|
narrow
|
|
13473
13507
|
}
|
|
13474
13508
|
);
|
|
13475
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0,
|
|
13509
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13476
13510
|
MenuButton,
|
|
13477
13511
|
{
|
|
13478
13512
|
variant: "ghost",
|
|
@@ -13499,7 +13533,7 @@ function AgentChatPanel({
|
|
|
13499
13533
|
})))
|
|
13500
13534
|
}
|
|
13501
13535
|
) : null;
|
|
13502
|
-
return /* @__PURE__ */ (0,
|
|
13536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime99.jsxs)(
|
|
13503
13537
|
"aside",
|
|
13504
13538
|
{
|
|
13505
13539
|
className: ["fdc-panel", SURFACES[surface] || SURFACES.sidebar, narrow ? "is-narrow" : "", className].filter(Boolean).join(" "),
|
|
@@ -13510,7 +13544,7 @@ function AgentChatPanel({
|
|
|
13510
13544
|
},
|
|
13511
13545
|
"aria-label": title,
|
|
13512
13546
|
children: [
|
|
13513
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */ (0,
|
|
13547
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13514
13548
|
"div",
|
|
13515
13549
|
{
|
|
13516
13550
|
className: "fdc-grip",
|
|
@@ -13525,20 +13559,20 @@ function AgentChatPanel({
|
|
|
13525
13559
|
}
|
|
13526
13560
|
}
|
|
13527
13561
|
) : null,
|
|
13528
|
-
showHeader ? /* @__PURE__ */ (0,
|
|
13529
|
-
/* @__PURE__ */ (0,
|
|
13530
|
-
/* @__PURE__ */ (0,
|
|
13531
|
-
/* @__PURE__ */ (0,
|
|
13532
|
-
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
|
|
13533
13567
|
] }),
|
|
13534
|
-
/* @__PURE__ */ (0,
|
|
13568
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsxs)("span", { className: "fdc-head-acts", children: [
|
|
13535
13569
|
headerActions,
|
|
13536
13570
|
threadMenu,
|
|
13537
|
-
onNewThread ? /* @__PURE__ */ (0,
|
|
13538
|
-
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
|
|
13539
13573
|
] })
|
|
13540
13574
|
] }) : null,
|
|
13541
|
-
/* @__PURE__ */ (0,
|
|
13575
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13542
13576
|
ChatTranscript,
|
|
13543
13577
|
{
|
|
13544
13578
|
messages: engine.visible,
|
|
@@ -13553,7 +13587,7 @@ function AgentChatPanel({
|
|
|
13553
13587
|
renderEmpty
|
|
13554
13588
|
}
|
|
13555
13589
|
),
|
|
13556
|
-
/* @__PURE__ */ (0,
|
|
13590
|
+
/* @__PURE__ */ (0, import_jsx_runtime99.jsx)(
|
|
13557
13591
|
ChatComposer,
|
|
13558
13592
|
{
|
|
13559
13593
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -13586,8 +13620,8 @@ function AgentChatPanel({
|
|
|
13586
13620
|
}
|
|
13587
13621
|
|
|
13588
13622
|
// src/components/files/FileViewer.tsx
|
|
13589
|
-
var
|
|
13590
|
-
var
|
|
13623
|
+
var React70 = __toESM(require("react"), 1);
|
|
13624
|
+
var import_jsx_runtime100 = require("react/jsx-runtime");
|
|
13591
13625
|
function previewKindOf(file) {
|
|
13592
13626
|
const mime = (file.mime || "").toLowerCase();
|
|
13593
13627
|
const ext = extensionOf(file.name || "");
|
|
@@ -13643,13 +13677,13 @@ function parseDelimited(text, delimiter) {
|
|
|
13643
13677
|
return rows;
|
|
13644
13678
|
}
|
|
13645
13679
|
function usePreview(file, kind, resolveUrl) {
|
|
13646
|
-
const [state, setState] =
|
|
13647
|
-
const [attempt, setAttempt] =
|
|
13648
|
-
const resolveRef =
|
|
13649
|
-
|
|
13680
|
+
const [state, setState] = React70.useState({ status: "loading" });
|
|
13681
|
+
const [attempt, setAttempt] = React70.useState(0);
|
|
13682
|
+
const resolveRef = React70.useRef(resolveUrl);
|
|
13683
|
+
React70.useEffect(() => {
|
|
13650
13684
|
resolveRef.current = resolveUrl;
|
|
13651
13685
|
}, [resolveUrl]);
|
|
13652
|
-
|
|
13686
|
+
React70.useEffect(() => {
|
|
13653
13687
|
if (kind === "none") {
|
|
13654
13688
|
setState({ status: "ready" });
|
|
13655
13689
|
return;
|
|
@@ -13679,19 +13713,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
13679
13713
|
if (ac) ac.abort();
|
|
13680
13714
|
};
|
|
13681
13715
|
}, [file.id, kind, attempt]);
|
|
13682
|
-
return { ...state, retry:
|
|
13716
|
+
return { ...state, retry: React70.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
13683
13717
|
}
|
|
13684
13718
|
function PreviewBody({ file, kind, state }) {
|
|
13685
|
-
if (kind === "image") return /* @__PURE__ */ (0,
|
|
13686
|
-
if (kind === "pdf") return /* @__PURE__ */ (0,
|
|
13687
|
-
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 || "" });
|
|
13688
13722
|
if (kind === "json") {
|
|
13689
13723
|
let pretty = state.text || "";
|
|
13690
13724
|
try {
|
|
13691
13725
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
13692
13726
|
} catch {
|
|
13693
13727
|
}
|
|
13694
|
-
return /* @__PURE__ */ (0,
|
|
13728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsx)(CodeBlock, { code: pretty, language: "json" });
|
|
13695
13729
|
}
|
|
13696
13730
|
if (kind === "csv") {
|
|
13697
13731
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -13699,12 +13733,12 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13699
13733
|
const head = rows[0] || [];
|
|
13700
13734
|
const dataRows = rows.slice(1);
|
|
13701
13735
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
13702
|
-
return /* @__PURE__ */ (0,
|
|
13703
|
-
/* @__PURE__ */ (0,
|
|
13704
|
-
/* @__PURE__ */ (0,
|
|
13705
|
-
/* @__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)) })
|
|
13706
13740
|
] }),
|
|
13707
|
-
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: [
|
|
13708
13742
|
"Showing the first ",
|
|
13709
13743
|
FILE_VIEWER_CSV_ROW_LIMIT.toLocaleString(),
|
|
13710
13744
|
" of ",
|
|
@@ -13713,24 +13747,24 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13713
13747
|
] }) : null
|
|
13714
13748
|
] });
|
|
13715
13749
|
}
|
|
13716
|
-
if (kind === "text") return /* @__PURE__ */ (0,
|
|
13717
|
-
return /* @__PURE__ */ (0,
|
|
13718
|
-
/* @__PURE__ */ (0,
|
|
13719
|
-
/* @__PURE__ */ (0,
|
|
13720
|
-
/* @__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: [
|
|
13721
13755
|
file.mime || "Unknown type",
|
|
13722
13756
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
13723
13757
|
] })
|
|
13724
13758
|
] });
|
|
13725
13759
|
}
|
|
13726
13760
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
13727
|
-
const kind =
|
|
13761
|
+
const kind = React70.useMemo(() => previewKindOf(file), [file]);
|
|
13728
13762
|
const preview = usePreview(file, kind, resolveUrl);
|
|
13729
|
-
const [tab, setTab] =
|
|
13730
|
-
const [downloading, setDownloading] =
|
|
13731
|
-
const [downloadError, setDownloadError] =
|
|
13763
|
+
const [tab, setTab] = React70.useState("preview");
|
|
13764
|
+
const [downloading, setDownloading] = React70.useState(false);
|
|
13765
|
+
const [downloadError, setDownloadError] = React70.useState(null);
|
|
13732
13766
|
const hasSide = sidePanel != null;
|
|
13733
|
-
|
|
13767
|
+
React70.useEffect(() => {
|
|
13734
13768
|
setTab("preview");
|
|
13735
13769
|
}, [file.id]);
|
|
13736
13770
|
const download = () => {
|
|
@@ -13746,29 +13780,29 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13746
13780
|
a.remove();
|
|
13747
13781
|
}).catch((err) => setDownloadError(err && err.message || "Download failed.")).finally(() => setDownloading(false));
|
|
13748
13782
|
};
|
|
13749
|
-
return /* @__PURE__ */ (0,
|
|
13783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime100.jsxs)(
|
|
13750
13784
|
"section",
|
|
13751
13785
|
{
|
|
13752
13786
|
className: ["fd-fv", hasSide && tab === "side" ? "is-tab-side" : "is-tab-preview", className].filter(Boolean).join(" "),
|
|
13753
13787
|
"aria-label": file.name || "File",
|
|
13754
13788
|
children: [
|
|
13755
|
-
/* @__PURE__ */ (0,
|
|
13756
|
-
/* @__PURE__ */ (0,
|
|
13757
|
-
/* @__PURE__ */ (0,
|
|
13758
|
-
/* @__PURE__ */ (0,
|
|
13759
|
-
/* @__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: [
|
|
13760
13794
|
file.mime || "Unknown type",
|
|
13761
13795
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
13762
13796
|
] })
|
|
13763
13797
|
] }),
|
|
13764
|
-
/* @__PURE__ */ (0,
|
|
13798
|
+
/* @__PURE__ */ (0, import_jsx_runtime100.jsxs)("span", { className: "fd-fv-head-actions", children: [
|
|
13765
13799
|
actions,
|
|
13766
|
-
/* @__PURE__ */ (0,
|
|
13767
|
-
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
|
|
13768
13802
|
] })
|
|
13769
13803
|
] }),
|
|
13770
|
-
downloadError ? /* @__PURE__ */ (0,
|
|
13771
|
-
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)(
|
|
13772
13806
|
Tabs,
|
|
13773
13807
|
{
|
|
13774
13808
|
className: "fd-fv-tabs",
|
|
@@ -13777,19 +13811,19 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13777
13811
|
onChange: (v) => setTab(v)
|
|
13778
13812
|
}
|
|
13779
13813
|
) : null,
|
|
13780
|
-
/* @__PURE__ */ (0,
|
|
13781
|
-
/* @__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)(
|
|
13782
13816
|
LoadingRegion,
|
|
13783
13817
|
{
|
|
13784
13818
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
13785
13819
|
error: preview.error,
|
|
13786
13820
|
label: "Loading preview of " + (file.name || "file"),
|
|
13787
13821
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
13788
|
-
skeleton: /* @__PURE__ */ (0,
|
|
13789
|
-
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 })
|
|
13790
13824
|
}
|
|
13791
13825
|
) }),
|
|
13792
|
-
hasSide ? /* @__PURE__ */ (0,
|
|
13826
|
+
hasSide ? /* @__PURE__ */ (0, import_jsx_runtime100.jsx)("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
13793
13827
|
] })
|
|
13794
13828
|
]
|
|
13795
13829
|
}
|
|
@@ -13797,8 +13831,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13797
13831
|
}
|
|
13798
13832
|
|
|
13799
13833
|
// src/components/files/FileBrowser.tsx
|
|
13800
|
-
var
|
|
13801
|
-
var
|
|
13834
|
+
var React71 = __toESM(require("react"), 1);
|
|
13835
|
+
var import_jsx_runtime101 = require("react/jsx-runtime");
|
|
13802
13836
|
function childrenOf(folders, parentId) {
|
|
13803
13837
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
13804
13838
|
}
|
|
@@ -13870,8 +13904,8 @@ function FolderPickerMenu({
|
|
|
13870
13904
|
}) {
|
|
13871
13905
|
const panel = useInlinePanel();
|
|
13872
13906
|
const { open: open2, setOpen, ref } = panel;
|
|
13873
|
-
return /* @__PURE__ */ (0,
|
|
13874
|
-
/* @__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)(
|
|
13875
13909
|
IconButton,
|
|
13876
13910
|
{
|
|
13877
13911
|
icon: "arrows-out-cardinal",
|
|
@@ -13883,9 +13917,9 @@ function FolderPickerMenu({
|
|
|
13883
13917
|
onClick: () => setOpen((v) => !v)
|
|
13884
13918
|
}
|
|
13885
13919
|
),
|
|
13886
|
-
/* @__PURE__ */ (0,
|
|
13887
|
-
/* @__PURE__ */ (0,
|
|
13888
|
-
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)(
|
|
13889
13923
|
"button",
|
|
13890
13924
|
{
|
|
13891
13925
|
type: "button",
|
|
@@ -13897,7 +13931,7 @@ function FolderPickerMenu({
|
|
|
13897
13931
|
setOpen(false);
|
|
13898
13932
|
},
|
|
13899
13933
|
children: [
|
|
13900
|
-
/* @__PURE__ */ (0,
|
|
13934
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
13901
13935
|
d.name
|
|
13902
13936
|
]
|
|
13903
13937
|
},
|
|
@@ -13907,8 +13941,8 @@ function FolderPickerMenu({
|
|
|
13907
13941
|
] });
|
|
13908
13942
|
}
|
|
13909
13943
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
13910
|
-
const [over, setOver] =
|
|
13911
|
-
const dragCounter =
|
|
13944
|
+
const [over, setOver] = React71.useState(false);
|
|
13945
|
+
const dragCounter = React71.useRef(0);
|
|
13912
13946
|
const dropHandlers = isDropTarget ? {
|
|
13913
13947
|
onDragEnter: (e) => {
|
|
13914
13948
|
if (!hasInternalPayload(e)) return;
|
|
@@ -13933,8 +13967,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
13933
13967
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
13934
13968
|
}
|
|
13935
13969
|
} : {};
|
|
13936
|
-
return /* @__PURE__ */ (0,
|
|
13937
|
-
/* @__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)(
|
|
13938
13972
|
"button",
|
|
13939
13973
|
{
|
|
13940
13974
|
type: "button",
|
|
@@ -13943,26 +13977,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
13943
13977
|
draggable: !!draggableId,
|
|
13944
13978
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
13945
13979
|
children: [
|
|
13946
|
-
/* @__PURE__ */ (0,
|
|
13947
|
-
/* @__PURE__ */ (0,
|
|
13948
|
-
/* @__PURE__ */ (0,
|
|
13949
|
-
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
|
|
13950
13984
|
] })
|
|
13951
13985
|
]
|
|
13952
13986
|
}
|
|
13953
13987
|
),
|
|
13954
|
-
actions ? /* @__PURE__ */ (0,
|
|
13988
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
13955
13989
|
] });
|
|
13956
13990
|
}
|
|
13957
13991
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
13958
13992
|
const kids = childrenOf(folders, folder.id);
|
|
13959
|
-
const [expanded, setExpanded] =
|
|
13960
|
-
|
|
13993
|
+
const [expanded, setExpanded] = React71.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
13994
|
+
React71.useEffect(() => {
|
|
13961
13995
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
13962
13996
|
}, [currentFolderId, folder.id, folders]);
|
|
13963
13997
|
const isCurrent = folder.id === currentFolderId;
|
|
13964
|
-
return /* @__PURE__ */ (0,
|
|
13965
|
-
/* @__PURE__ */ (0,
|
|
13998
|
+
return /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)("div", { className: "fd-fb-tree-node", children: [
|
|
13999
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
13966
14000
|
RowShell,
|
|
13967
14001
|
{
|
|
13968
14002
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -13972,7 +14006,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13972
14006
|
isDropTarget: canMove,
|
|
13973
14007
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
13974
14008
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
13975
|
-
actions: kids.length ? /* @__PURE__ */ (0,
|
|
14009
|
+
actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
13976
14010
|
IconButton,
|
|
13977
14011
|
{
|
|
13978
14012
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -13984,7 +14018,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13984
14018
|
) : void 0
|
|
13985
14019
|
}
|
|
13986
14020
|
),
|
|
13987
|
-
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)(
|
|
13988
14022
|
TreeNode,
|
|
13989
14023
|
{
|
|
13990
14024
|
folder: k,
|
|
@@ -14023,15 +14057,15 @@ function FileBrowser({
|
|
|
14023
14057
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
14024
14058
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
14025
14059
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
14026
|
-
const [createOpen, setCreateOpen] =
|
|
14027
|
-
const [createName, setCreateName] =
|
|
14028
|
-
const [renameTarget, setRenameTarget] =
|
|
14029
|
-
const [renameValue, setRenameValue] =
|
|
14030
|
-
const [deleteTarget, setDeleteTarget] =
|
|
14031
|
-
const uploadInputRef =
|
|
14032
|
-
const crumbFolders =
|
|
14033
|
-
const subfolders =
|
|
14034
|
-
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(
|
|
14035
14069
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
14036
14070
|
[files, currentFolderId]
|
|
14037
14071
|
);
|
|
@@ -14070,10 +14104,10 @@ function FileBrowser({
|
|
|
14070
14104
|
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
14071
14105
|
setDeleteTarget(null);
|
|
14072
14106
|
};
|
|
14073
|
-
const content = /* @__PURE__ */ (0,
|
|
14074
|
-
/* @__PURE__ */ (0,
|
|
14075
|
-
/* @__PURE__ */ (0,
|
|
14076
|
-
/* @__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)(
|
|
14077
14111
|
BreadcrumbCrumb,
|
|
14078
14112
|
{
|
|
14079
14113
|
label: "Home",
|
|
@@ -14083,7 +14117,7 @@ function FileBrowser({
|
|
|
14083
14117
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
14084
14118
|
}
|
|
14085
14119
|
),
|
|
14086
|
-
crumbFolders.map((f, i) => /* @__PURE__ */ (0,
|
|
14120
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14087
14121
|
BreadcrumbCrumb,
|
|
14088
14122
|
{
|
|
14089
14123
|
label: f.name,
|
|
@@ -14095,11 +14129,11 @@ function FileBrowser({
|
|
|
14095
14129
|
f.id
|
|
14096
14130
|
))
|
|
14097
14131
|
] }),
|
|
14098
|
-
/* @__PURE__ */ (0,
|
|
14099
|
-
canCreateFolder ? /* @__PURE__ */ (0,
|
|
14100
|
-
canUpload ? /* @__PURE__ */ (0,
|
|
14101
|
-
/* @__PURE__ */ (0,
|
|
14102
|
-
/* @__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)(
|
|
14103
14137
|
"input",
|
|
14104
14138
|
{
|
|
14105
14139
|
ref: uploadInputRef,
|
|
@@ -14117,9 +14151,9 @@ function FileBrowser({
|
|
|
14117
14151
|
] }) : null
|
|
14118
14152
|
] })
|
|
14119
14153
|
] }),
|
|
14120
|
-
/* @__PURE__ */ (0,
|
|
14121
|
-
/* @__PURE__ */ (0,
|
|
14122
|
-
/* @__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)(
|
|
14123
14157
|
RowShell,
|
|
14124
14158
|
{
|
|
14125
14159
|
icon: "house-simple",
|
|
@@ -14130,7 +14164,7 @@ function FileBrowser({
|
|
|
14130
14164
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
14131
14165
|
}
|
|
14132
14166
|
),
|
|
14133
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0,
|
|
14167
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14134
14168
|
TreeNode,
|
|
14135
14169
|
{
|
|
14136
14170
|
folder: f,
|
|
@@ -14144,18 +14178,18 @@ function FileBrowser({
|
|
|
14144
14178
|
f.id
|
|
14145
14179
|
))
|
|
14146
14180
|
] }),
|
|
14147
|
-
/* @__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)(
|
|
14148
14182
|
LoadingRegion,
|
|
14149
14183
|
{
|
|
14150
14184
|
state: loading ? "loading" : "ready",
|
|
14151
14185
|
label: "Loading folder contents",
|
|
14152
|
-
skeleton: /* @__PURE__ */ (0,
|
|
14153
|
-
/* @__PURE__ */ (0,
|
|
14154
|
-
/* @__PURE__ */ (0,
|
|
14155
|
-
/* @__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" })
|
|
14156
14190
|
] }),
|
|
14157
|
-
children: isEmpty ? /* @__PURE__ */ (0,
|
|
14158
|
-
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)(
|
|
14159
14193
|
RowShell,
|
|
14160
14194
|
{
|
|
14161
14195
|
icon: "folder-simple",
|
|
@@ -14164,9 +14198,9 @@ function FileBrowser({
|
|
|
14164
14198
|
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
14165
14199
|
isDropTarget: canMove,
|
|
14166
14200
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
14167
|
-
actions: /* @__PURE__ */ (0,
|
|
14168
|
-
canRenameFolder ? /* @__PURE__ */ (0,
|
|
14169
|
-
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)(
|
|
14170
14204
|
FolderPickerMenu,
|
|
14171
14205
|
{
|
|
14172
14206
|
label: "Move " + f.name,
|
|
@@ -14174,12 +14208,12 @@ function FileBrowser({
|
|
|
14174
14208
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
14175
14209
|
}
|
|
14176
14210
|
) : null,
|
|
14177
|
-
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
|
|
14178
14212
|
] })
|
|
14179
14213
|
},
|
|
14180
14214
|
f.id
|
|
14181
14215
|
)),
|
|
14182
|
-
currentFiles.map((file) => /* @__PURE__ */ (0,
|
|
14216
|
+
currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14183
14217
|
RowShell,
|
|
14184
14218
|
{
|
|
14185
14219
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -14187,8 +14221,8 @@ function FileBrowser({
|
|
|
14187
14221
|
meta: file.size ? formatBytes(file.size) : void 0,
|
|
14188
14222
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
14189
14223
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
14190
|
-
actions: /* @__PURE__ */ (0,
|
|
14191
|
-
canMove ? /* @__PURE__ */ (0,
|
|
14224
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime101.jsxs)(import_jsx_runtime101.Fragment, { children: [
|
|
14225
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14192
14226
|
FolderPickerMenu,
|
|
14193
14227
|
{
|
|
14194
14228
|
label: "Move " + file.name,
|
|
@@ -14196,7 +14230,7 @@ function FileBrowser({
|
|
|
14196
14230
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
14197
14231
|
}
|
|
14198
14232
|
) : null,
|
|
14199
|
-
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
|
|
14200
14234
|
] })
|
|
14201
14235
|
},
|
|
14202
14236
|
file.id
|
|
@@ -14205,10 +14239,10 @@ function FileBrowser({
|
|
|
14205
14239
|
}
|
|
14206
14240
|
) })
|
|
14207
14241
|
] }),
|
|
14208
|
-
/* @__PURE__ */ (0,
|
|
14209
|
-
/* @__PURE__ */ (0,
|
|
14210
|
-
/* @__PURE__ */ (0,
|
|
14211
|
-
] }), 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)(
|
|
14212
14246
|
"input",
|
|
14213
14247
|
{
|
|
14214
14248
|
className: "fd-fb-input",
|
|
@@ -14222,10 +14256,10 @@ function FileBrowser({
|
|
|
14222
14256
|
autoFocus: true
|
|
14223
14257
|
}
|
|
14224
14258
|
) }),
|
|
14225
|
-
/* @__PURE__ */ (0,
|
|
14226
|
-
/* @__PURE__ */ (0,
|
|
14227
|
-
/* @__PURE__ */ (0,
|
|
14228
|
-
] }), 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)(
|
|
14229
14263
|
"input",
|
|
14230
14264
|
{
|
|
14231
14265
|
className: "fd-fb-input",
|
|
@@ -14239,22 +14273,22 @@ function FileBrowser({
|
|
|
14239
14273
|
autoFocus: true
|
|
14240
14274
|
}
|
|
14241
14275
|
) }),
|
|
14242
|
-
/* @__PURE__ */ (0,
|
|
14276
|
+
/* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
14243
14277
|
Modal,
|
|
14244
14278
|
{
|
|
14245
14279
|
open: deleteTarget != null,
|
|
14246
14280
|
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
14247
14281
|
description: "This can't be undone. The folder must be empty.",
|
|
14248
14282
|
onClose: () => setDeleteTarget(null),
|
|
14249
|
-
footer: /* @__PURE__ */ (0,
|
|
14250
|
-
/* @__PURE__ */ (0,
|
|
14251
|
-
/* @__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" })
|
|
14252
14286
|
] })
|
|
14253
14287
|
}
|
|
14254
14288
|
)
|
|
14255
14289
|
] });
|
|
14256
14290
|
if (!canUpload) return content;
|
|
14257
|
-
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 });
|
|
14258
14292
|
}
|
|
14259
14293
|
function BreadcrumbCrumb({
|
|
14260
14294
|
label,
|
|
@@ -14263,8 +14297,8 @@ function BreadcrumbCrumb({
|
|
|
14263
14297
|
isDropTarget,
|
|
14264
14298
|
onDropPayload
|
|
14265
14299
|
}) {
|
|
14266
|
-
const [over, setOver] =
|
|
14267
|
-
const dragCounter =
|
|
14300
|
+
const [over, setOver] = React71.useState(false);
|
|
14301
|
+
const dragCounter = React71.useRef(0);
|
|
14268
14302
|
const dropHandlers = isDropTarget ? {
|
|
14269
14303
|
onDragEnter: (e) => {
|
|
14270
14304
|
if (!hasInternalPayload(e)) return;
|
|
@@ -14289,11 +14323,11 @@ function BreadcrumbCrumb({
|
|
|
14289
14323
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
14290
14324
|
}
|
|
14291
14325
|
} : {};
|
|
14292
|
-
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 }) });
|
|
14293
14327
|
}
|
|
14294
14328
|
|
|
14295
14329
|
// src/kits/query.ts
|
|
14296
|
-
var
|
|
14330
|
+
var React72 = __toESM(require("react"), 1);
|
|
14297
14331
|
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
14298
14332
|
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
14299
14333
|
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
@@ -14348,22 +14382,22 @@ function compare(a, b, dir) {
|
|
|
14348
14382
|
var API = null;
|
|
14349
14383
|
var PREFS = null;
|
|
14350
14384
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
14351
|
-
const [query, setQuery] =
|
|
14385
|
+
const [query, setQuery] = React72.useState(() => {
|
|
14352
14386
|
const store = PREFS || window.PlannerPrefs;
|
|
14353
14387
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
14354
14388
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
14355
14389
|
});
|
|
14356
|
-
const savePref =
|
|
14390
|
+
const savePref = React72.useCallback((patch2) => {
|
|
14357
14391
|
const store = PREFS || window.PlannerPrefs;
|
|
14358
14392
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
14359
14393
|
}, [prefsKey]);
|
|
14360
|
-
const [res, setRes] =
|
|
14361
|
-
const [loading, setLoading] =
|
|
14362
|
-
const seq2 =
|
|
14394
|
+
const [res, setRes] = React72.useState(null);
|
|
14395
|
+
const [loading, setLoading] = React72.useState(true);
|
|
14396
|
+
const seq2 = React72.useRef(0);
|
|
14363
14397
|
const depKey = (deps || []).join("|");
|
|
14364
14398
|
const paramKey = JSON.stringify(params || {});
|
|
14365
14399
|
const queryKey = JSON.stringify(query);
|
|
14366
|
-
|
|
14400
|
+
React72.useEffect(() => {
|
|
14367
14401
|
const id = ++seq2.current;
|
|
14368
14402
|
setLoading(true);
|
|
14369
14403
|
const t = setTimeout(() => {
|
|
@@ -14682,12 +14716,12 @@ function createVersionStore(initialState, options) {
|
|
|
14682
14716
|
}
|
|
14683
14717
|
|
|
14684
14718
|
// src/kits/documentTitle.ts
|
|
14685
|
-
var
|
|
14719
|
+
var React73 = __toESM(require("react"), 1);
|
|
14686
14720
|
function formatDocumentTitle(routeTitle, appName) {
|
|
14687
14721
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
14688
14722
|
}
|
|
14689
14723
|
function useDocumentTitle(routeTitle, appName) {
|
|
14690
|
-
|
|
14724
|
+
React73.useEffect(() => {
|
|
14691
14725
|
if (typeof document === "undefined") return;
|
|
14692
14726
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
14693
14727
|
}, [routeTitle, appName]);
|
|
@@ -14702,6 +14736,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14702
14736
|
AppShell,
|
|
14703
14737
|
AppSwitcher,
|
|
14704
14738
|
AppearanceMenu,
|
|
14739
|
+
AppearanceProvider,
|
|
14705
14740
|
Avatar,
|
|
14706
14741
|
AvatarStack,
|
|
14707
14742
|
Badge,
|
|
@@ -14713,6 +14748,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14713
14748
|
CHANNEL_WEIGHTS,
|
|
14714
14749
|
CHAT_UNAVAILABLE,
|
|
14715
14750
|
COPIED_FEEDBACK_MS,
|
|
14751
|
+
CORNER_STACK_INSET_PROPERTY,
|
|
14716
14752
|
Calendar,
|
|
14717
14753
|
Card,
|
|
14718
14754
|
CardGrid,
|
|
@@ -14856,6 +14892,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14856
14892
|
__resetLayerStackForTests,
|
|
14857
14893
|
acceptMatches,
|
|
14858
14894
|
anyOfFilter,
|
|
14895
|
+
applyAppearance,
|
|
14859
14896
|
applyPrefs,
|
|
14860
14897
|
channelWeightOf,
|
|
14861
14898
|
computeNeedMore,
|
|
@@ -14901,6 +14938,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14901
14938
|
toAttachment,
|
|
14902
14939
|
tokenize,
|
|
14903
14940
|
useAppearancePrefs,
|
|
14941
|
+
useAppearanceStore,
|
|
14904
14942
|
useChatEngine,
|
|
14905
14943
|
useCopyToClipboard,
|
|
14906
14944
|
useCornerStackSlot,
|
|
@@ -14916,6 +14954,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
14916
14954
|
useStagedFiles,
|
|
14917
14955
|
useToast,
|
|
14918
14956
|
validateFilterValue,
|
|
14919
|
-
visibleMessages
|
|
14957
|
+
visibleMessages,
|
|
14958
|
+
watchAppearance
|
|
14920
14959
|
});
|
|
14921
14960
|
//# sourceMappingURL=index.cjs.map
|