@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.js
CHANGED
|
@@ -1128,9 +1128,11 @@ import * as React10 from "react";
|
|
|
1128
1128
|
// src/kits/cornerStack.tsx
|
|
1129
1129
|
import * as React9 from "react";
|
|
1130
1130
|
import { createPortal as createPortal4 } from "react-dom";
|
|
1131
|
+
var CORNER_STACK_INSET_PROPERTY = "--fd-corner-stack-inset";
|
|
1131
1132
|
var SLOTS = ["jobs", "toasts"];
|
|
1132
1133
|
var references = /* @__PURE__ */ new Map();
|
|
1133
1134
|
var host = null;
|
|
1135
|
+
var hostObserver = null;
|
|
1134
1136
|
var slotElements = /* @__PURE__ */ new Map();
|
|
1135
1137
|
function createHost() {
|
|
1136
1138
|
const stack = document.createElement("div");
|
|
@@ -1144,8 +1146,18 @@ function createHost() {
|
|
|
1144
1146
|
slotElements.set(slot, element);
|
|
1145
1147
|
}
|
|
1146
1148
|
document.body.appendChild(stack);
|
|
1149
|
+
publishInset(stack);
|
|
1150
|
+
if (typeof ResizeObserver === "function") {
|
|
1151
|
+
hostObserver = new ResizeObserver(() => publishInset(stack));
|
|
1152
|
+
hostObserver.observe(stack);
|
|
1153
|
+
}
|
|
1147
1154
|
return stack;
|
|
1148
1155
|
}
|
|
1156
|
+
function publishInset(stack) {
|
|
1157
|
+
const height = stack.offsetHeight;
|
|
1158
|
+
const inset = height > 0 ? height + parseFloat(getComputedStyle(stack).bottom) : 0;
|
|
1159
|
+
document.documentElement.style.setProperty(CORNER_STACK_INSET_PROPERTY, `${inset}px`);
|
|
1160
|
+
}
|
|
1149
1161
|
function acquire(slot) {
|
|
1150
1162
|
host ??= createHost();
|
|
1151
1163
|
references.set(slot, (references.get(slot) ?? 0) + 1);
|
|
@@ -1156,6 +1168,9 @@ function release(slot) {
|
|
|
1156
1168
|
if (remaining > 0) references.set(slot, remaining);
|
|
1157
1169
|
else references.delete(slot);
|
|
1158
1170
|
if (references.size === 0 && host) {
|
|
1171
|
+
hostObserver?.disconnect();
|
|
1172
|
+
hostObserver = null;
|
|
1173
|
+
document.documentElement.style.removeProperty(CORNER_STACK_INSET_PROPERTY);
|
|
1159
1174
|
host.remove();
|
|
1160
1175
|
host = null;
|
|
1161
1176
|
slotElements.clear();
|
|
@@ -1594,7 +1609,7 @@ function AppShell({
|
|
|
1594
1609
|
/* @__PURE__ */ jsx21(
|
|
1595
1610
|
"div",
|
|
1596
1611
|
{
|
|
1597
|
-
className: contentClassName,
|
|
1612
|
+
className: ["fd-app-shell-content", contentClassName].filter(Boolean).join(" "),
|
|
1598
1613
|
style: {
|
|
1599
1614
|
flex: 1,
|
|
1600
1615
|
minWidth: 0,
|
|
@@ -1602,7 +1617,6 @@ function AppShell({
|
|
|
1602
1617
|
// table) is contained and clipped by this scroller, never stretching the document.
|
|
1603
1618
|
position: "relative",
|
|
1604
1619
|
overflowY: "auto",
|
|
1605
|
-
padding: 24,
|
|
1606
1620
|
maxWidth: contentMaxWidth,
|
|
1607
1621
|
margin: "0 auto",
|
|
1608
1622
|
width: "100%",
|
|
@@ -8045,7 +8059,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
8045
8059
|
}
|
|
8046
8060
|
|
|
8047
8061
|
// src/components/platform/AppearanceMenu.tsx
|
|
8048
|
-
import * as
|
|
8062
|
+
import * as React53 from "react";
|
|
8049
8063
|
|
|
8050
8064
|
// src/kits/appearance.ts
|
|
8051
8065
|
import * as React51 from "react";
|
|
@@ -8142,20 +8156,25 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
8142
8156
|
if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
|
|
8143
8157
|
else root.removeAttribute("data-motion");
|
|
8144
8158
|
}
|
|
8159
|
+
function applyAppearance(store, root = document.documentElement) {
|
|
8160
|
+
applyPrefs(store.getSnapshot(), root);
|
|
8161
|
+
}
|
|
8162
|
+
function watchAppearance(store, root = document.documentElement) {
|
|
8163
|
+
const apply = () => applyAppearance(store, root);
|
|
8164
|
+
apply();
|
|
8165
|
+
const unsubscribe = store.subscribe(apply);
|
|
8166
|
+
const mq = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
8167
|
+
const onSchemeChange = () => {
|
|
8168
|
+
if (store.getSnapshot().theme === "system") apply();
|
|
8169
|
+
};
|
|
8170
|
+
mq?.addEventListener("change", onSchemeChange);
|
|
8171
|
+
return () => {
|
|
8172
|
+
unsubscribe();
|
|
8173
|
+
mq?.removeEventListener("change", onSchemeChange);
|
|
8174
|
+
};
|
|
8175
|
+
}
|
|
8145
8176
|
function useAppearancePrefs(store) {
|
|
8146
8177
|
const prefs = React51.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
8147
|
-
React51.useEffect(() => {
|
|
8148
|
-
applyPrefs(prefs);
|
|
8149
|
-
}, [prefs]);
|
|
8150
|
-
React51.useEffect(() => {
|
|
8151
|
-
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
8152
|
-
return;
|
|
8153
|
-
}
|
|
8154
|
-
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
8155
|
-
const onChange = () => applyPrefs(prefs);
|
|
8156
|
-
mq.addEventListener("change", onChange);
|
|
8157
|
-
return () => mq.removeEventListener("change", onChange);
|
|
8158
|
-
}, [prefs]);
|
|
8159
8178
|
const update = React51.useCallback(
|
|
8160
8179
|
(patch) => {
|
|
8161
8180
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
@@ -8165,8 +8184,22 @@ function useAppearancePrefs(store) {
|
|
|
8165
8184
|
return [prefs, update];
|
|
8166
8185
|
}
|
|
8167
8186
|
|
|
8187
|
+
// src/components/platform/AppearanceProvider.tsx
|
|
8188
|
+
import * as React52 from "react";
|
|
8189
|
+
import { jsx as jsx77 } from "react/jsx-runtime";
|
|
8190
|
+
var AppearanceStoreContext = React52.createContext(null);
|
|
8191
|
+
function AppearanceProvider({ store, children }) {
|
|
8192
|
+
React52.useLayoutEffect(() => watchAppearance(store), [store]);
|
|
8193
|
+
return /* @__PURE__ */ jsx77(AppearanceStoreContext.Provider, { value: store, children });
|
|
8194
|
+
}
|
|
8195
|
+
function useAppearanceStore() {
|
|
8196
|
+
const store = React52.useContext(AppearanceStoreContext);
|
|
8197
|
+
if (!store) throw new Error("AppearanceMenu and useAppearanceStore must be rendered inside an <AppearanceProvider>.");
|
|
8198
|
+
return store;
|
|
8199
|
+
}
|
|
8200
|
+
|
|
8168
8201
|
// src/components/platform/AppearanceMenu.tsx
|
|
8169
|
-
import { jsx as
|
|
8202
|
+
import { jsx as jsx78, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
8170
8203
|
var THEME_OPTIONS = [
|
|
8171
8204
|
{ value: "light", label: "Light" },
|
|
8172
8205
|
{ value: "dark", label: "Dark" },
|
|
@@ -8178,17 +8211,13 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
8178
8211
|
{ value: "lg", label: "L" },
|
|
8179
8212
|
{ value: "xl", label: "XL" }
|
|
8180
8213
|
];
|
|
8181
|
-
function AppearanceMenu({ className = ""
|
|
8182
|
-
const
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
);
|
|
8186
|
-
const [prefs, update] = useAppearancePrefs(store);
|
|
8187
|
-
const [open2, setOpen] = React52.useState(false);
|
|
8188
|
-
const anchorRef = React52.useRef(null);
|
|
8214
|
+
function AppearanceMenu({ className = "" }) {
|
|
8215
|
+
const [prefs, update] = useAppearancePrefs(useAppearanceStore());
|
|
8216
|
+
const [open2, setOpen] = React53.useState(false);
|
|
8217
|
+
const anchorRef = React53.useRef(null);
|
|
8189
8218
|
const patch = (p) => update(p);
|
|
8190
|
-
return /* @__PURE__ */ jsxs68(
|
|
8191
|
-
/* @__PURE__ */
|
|
8219
|
+
return /* @__PURE__ */ jsxs68(React53.Fragment, { children: [
|
|
8220
|
+
/* @__PURE__ */ jsx78("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx78(
|
|
8192
8221
|
IconButton,
|
|
8193
8222
|
{
|
|
8194
8223
|
icon: "circle-half",
|
|
@@ -8196,7 +8225,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8196
8225
|
onClick: () => setOpen((v) => !v)
|
|
8197
8226
|
}
|
|
8198
8227
|
) }),
|
|
8199
|
-
/* @__PURE__ */
|
|
8228
|
+
/* @__PURE__ */ jsx78(
|
|
8200
8229
|
Popover,
|
|
8201
8230
|
{
|
|
8202
8231
|
open: open2,
|
|
@@ -8208,8 +8237,8 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8208
8237
|
label: "Appearance settings",
|
|
8209
8238
|
children: /* @__PURE__ */ jsxs68("div", { className: "fd-stack", style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
|
|
8210
8239
|
/* @__PURE__ */ jsxs68("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
8211
|
-
/* @__PURE__ */
|
|
8212
|
-
/* @__PURE__ */
|
|
8240
|
+
/* @__PURE__ */ jsx78("span", { className: "fd-field-label", children: "Theme" }),
|
|
8241
|
+
/* @__PURE__ */ jsx78(
|
|
8213
8242
|
SegmentedControl,
|
|
8214
8243
|
{
|
|
8215
8244
|
options: THEME_OPTIONS,
|
|
@@ -8220,8 +8249,8 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8220
8249
|
)
|
|
8221
8250
|
] }),
|
|
8222
8251
|
/* @__PURE__ */ jsxs68("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
8223
|
-
/* @__PURE__ */
|
|
8224
|
-
/* @__PURE__ */
|
|
8252
|
+
/* @__PURE__ */ jsx78("span", { className: "fd-field-label", children: "Text size" }),
|
|
8253
|
+
/* @__PURE__ */ jsx78(
|
|
8225
8254
|
SegmentedControl,
|
|
8226
8255
|
{
|
|
8227
8256
|
options: TEXT_SCALE_OPTIONS,
|
|
@@ -8231,7 +8260,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8231
8260
|
}
|
|
8232
8261
|
)
|
|
8233
8262
|
] }),
|
|
8234
|
-
/* @__PURE__ */
|
|
8263
|
+
/* @__PURE__ */ jsx78(
|
|
8235
8264
|
Switch,
|
|
8236
8265
|
{
|
|
8237
8266
|
label: "High contrast",
|
|
@@ -8240,7 +8269,7 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8240
8269
|
onChange: (e) => patch({ highContrast: e.target.checked })
|
|
8241
8270
|
}
|
|
8242
8271
|
),
|
|
8243
|
-
/* @__PURE__ */
|
|
8272
|
+
/* @__PURE__ */ jsx78(
|
|
8244
8273
|
Switch,
|
|
8245
8274
|
{
|
|
8246
8275
|
label: "Reduce motion",
|
|
@@ -8256,14 +8285,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
8256
8285
|
}
|
|
8257
8286
|
|
|
8258
8287
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
8259
|
-
import * as
|
|
8260
|
-
import { jsx as
|
|
8288
|
+
import * as React54 from "react";
|
|
8289
|
+
import { jsx as jsx79, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
8261
8290
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
8262
8291
|
function Json({ obj }) {
|
|
8263
|
-
return /* @__PURE__ */
|
|
8292
|
+
return /* @__PURE__ */ jsx79("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
8264
8293
|
}
|
|
8265
8294
|
function Endpoint({ s, onRequest }) {
|
|
8266
|
-
const [tried, setTried] =
|
|
8295
|
+
const [tried, setTried] = React54.useState(null);
|
|
8267
8296
|
const run = async () => {
|
|
8268
8297
|
setTried("busy");
|
|
8269
8298
|
const t0 = (window.performance || Date).now();
|
|
@@ -8274,50 +8303,50 @@ function Endpoint({ s, onRequest }) {
|
|
|
8274
8303
|
setTried({ ms: Math.round((window.performance || Date).now() - t0), error: String(e && e.message || e) });
|
|
8275
8304
|
}
|
|
8276
8305
|
};
|
|
8277
|
-
return /* @__PURE__ */
|
|
8306
|
+
return /* @__PURE__ */ jsx79(Card, { elevation: "flat", padded: false, children: /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
8278
8307
|
/* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { gap: 10, padding: "14px 18px", flexWrap: "wrap" }, children: [
|
|
8279
|
-
/* @__PURE__ */
|
|
8280
|
-
/* @__PURE__ */
|
|
8281
|
-
s.isList ? /* @__PURE__ */
|
|
8282
|
-
/* @__PURE__ */
|
|
8308
|
+
/* @__PURE__ */ jsx79(Badge, { tone: METHOD_TONE[s.method] || "neutral", children: s.method }),
|
|
8309
|
+
/* @__PURE__ */ jsx79("code", { className: "fd-mono", style: { fontSize: 12.5, fontWeight: 600, color: "var(--text)", wordBreak: "break-all" }, children: s.path }),
|
|
8310
|
+
s.isList ? /* @__PURE__ */ jsx79(Badge, { tone: "neutral", icon: "rows", children: "Paged list" }) : null,
|
|
8311
|
+
/* @__PURE__ */ jsx79("span", { style: { flex: 1 } }),
|
|
8283
8312
|
/* @__PURE__ */ jsxs69("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
8284
8313
|
s.latency[0],
|
|
8285
8314
|
"\u2013",
|
|
8286
8315
|
s.latency[1],
|
|
8287
8316
|
"ms"
|
|
8288
8317
|
] }),
|
|
8289
|
-
/* @__PURE__ */
|
|
8318
|
+
/* @__PURE__ */ jsx79(Button, { size: "sm", variant: "secondary", icon: "play", loading: tried === "busy", onClick: run, children: "Try it" })
|
|
8290
8319
|
] }),
|
|
8291
8320
|
/* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 14, padding: "0 18px 16px" }, children: [
|
|
8292
8321
|
/* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8293
|
-
/* @__PURE__ */
|
|
8294
|
-
/* @__PURE__ */
|
|
8295
|
-
s.usedBy && s.usedBy.length ? /* @__PURE__ */
|
|
8322
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-body-sm", style: { fontWeight: 700 }, children: s.title }),
|
|
8323
|
+
/* @__PURE__ */ jsx79("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: s.purpose }),
|
|
8324
|
+
s.usedBy && s.usedBy.length ? /* @__PURE__ */ jsx79("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: s.usedBy.map((u) => /* @__PURE__ */ jsx79(Tag, { children: u }, u)) }) : null
|
|
8296
8325
|
] }),
|
|
8297
8326
|
/* @__PURE__ */ jsxs69("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(280px,1fr))", gap: 12, alignItems: "start" }, children: [
|
|
8298
8327
|
s.request ? /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8299
|
-
/* @__PURE__ */
|
|
8300
|
-
/* @__PURE__ */
|
|
8328
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: "Request body" }),
|
|
8329
|
+
/* @__PURE__ */ jsx79(Json, { obj: s.request })
|
|
8301
8330
|
] }) : null,
|
|
8302
8331
|
s.query ? /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8303
|
-
/* @__PURE__ */
|
|
8304
|
-
/* @__PURE__ */
|
|
8332
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: "Query" }),
|
|
8333
|
+
/* @__PURE__ */ jsx79(Json, { obj: s.query })
|
|
8305
8334
|
] }) : null,
|
|
8306
8335
|
/* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8307
|
-
/* @__PURE__ */
|
|
8308
|
-
/* @__PURE__ */
|
|
8336
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: "Response 200" }),
|
|
8337
|
+
/* @__PURE__ */ jsx79(Json, { obj: s.response })
|
|
8309
8338
|
] })
|
|
8310
8339
|
] }),
|
|
8311
|
-
s.notes ? /* @__PURE__ */
|
|
8340
|
+
s.notes ? /* @__PURE__ */ jsx79(Flag, { tone: "info", statement: "Implementation note", cost: s.notes, actions: null }) : null,
|
|
8312
8341
|
tried && tried !== "busy" ? /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 6 }, children: [
|
|
8313
8342
|
/* @__PURE__ */ jsxs69("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
8314
|
-
/* @__PURE__ */
|
|
8343
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: "Simulated response" }),
|
|
8315
8344
|
/* @__PURE__ */ jsxs69(Badge, { tone: tried.error ? "danger" : "success", icon: "timer", children: [
|
|
8316
8345
|
tried.ms,
|
|
8317
8346
|
"ms"
|
|
8318
8347
|
] })
|
|
8319
8348
|
] }),
|
|
8320
|
-
/* @__PURE__ */
|
|
8349
|
+
/* @__PURE__ */ jsx79(Json, { obj: tried.error ? { error: tried.error } : tried.data })
|
|
8321
8350
|
] }) : null
|
|
8322
8351
|
] })
|
|
8323
8352
|
] }) });
|
|
@@ -8336,10 +8365,10 @@ function ApiSpecBrowser({
|
|
|
8336
8365
|
className = "",
|
|
8337
8366
|
...rest
|
|
8338
8367
|
}) {
|
|
8339
|
-
const [q, setQ] =
|
|
8340
|
-
const [method, setMethod] =
|
|
8341
|
-
const [mod, setMod] =
|
|
8342
|
-
const [listOnly, setListOnly] =
|
|
8368
|
+
const [q, setQ] = React54.useState("");
|
|
8369
|
+
const [method, setMethod] = React54.useState(null);
|
|
8370
|
+
const [mod, setMod] = React54.useState(null);
|
|
8371
|
+
const [listOnly, setListOnly] = React54.useState(false);
|
|
8343
8372
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
8344
8373
|
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())));
|
|
8345
8374
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -8347,46 +8376,46 @@ function ApiSpecBrowser({
|
|
|
8347
8376
|
const listCount = spec.filter((s) => s.isList).length;
|
|
8348
8377
|
return /* @__PURE__ */ jsxs69("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 1100 }, ...rest, children: [
|
|
8349
8378
|
/* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8350
|
-
kicker ? /* @__PURE__ */
|
|
8351
|
-
/* @__PURE__ */
|
|
8352
|
-
lede ? /* @__PURE__ */
|
|
8379
|
+
kicker ? /* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: kicker }) : null,
|
|
8380
|
+
/* @__PURE__ */ jsx79("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
8381
|
+
lede ? /* @__PURE__ */ jsx79("p", { className: "fd-body fd-secondary fd-prose", style: { margin: 0 }, children: lede }) : null
|
|
8353
8382
|
] }),
|
|
8354
8383
|
modules && modules.length ? /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
8355
|
-
/* @__PURE__ */
|
|
8384
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", children: "Filter by screen \u2014 every endpoint that screen depends on" }),
|
|
8356
8385
|
/* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
8357
8386
|
/* @__PURE__ */ jsxs69(Tag, { icon: "stack", selected: !mod, onClick: () => setMod(null), children: [
|
|
8358
8387
|
"All screens ",
|
|
8359
|
-
/* @__PURE__ */
|
|
8388
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-mono", children: spec.length })
|
|
8360
8389
|
] }),
|
|
8361
8390
|
modules.map((m) => /* @__PURE__ */ jsxs69(Tag, { icon: m.icon, selected: mod === m.id, onClick: () => setMod(mod === m.id ? null : m.id), children: [
|
|
8362
8391
|
m.label,
|
|
8363
8392
|
" ",
|
|
8364
|
-
/* @__PURE__ */
|
|
8393
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-mono", children: m.endpoints.length })
|
|
8365
8394
|
] }, m.id))
|
|
8366
8395
|
] }),
|
|
8367
|
-
activeModule ? /* @__PURE__ */
|
|
8396
|
+
activeModule ? /* @__PURE__ */ jsx79(
|
|
8368
8397
|
Flag,
|
|
8369
8398
|
{
|
|
8370
8399
|
tone: "info",
|
|
8371
8400
|
statement: activeModule.label + " calls " + activeModule.endpoints.length + " endpoints.",
|
|
8372
8401
|
cost: "Integration checklist for this screen: " + activeModule.endpoints.join(", ") + ". Wire these and the screen is done.",
|
|
8373
|
-
actions: /* @__PURE__ */
|
|
8402
|
+
actions: /* @__PURE__ */ jsx79(Button, { size: "sm", variant: "ghost", icon: "x", onClick: () => setMod(null), children: "Show all screens" })
|
|
8374
8403
|
}
|
|
8375
8404
|
) : null
|
|
8376
8405
|
] }) : null,
|
|
8377
|
-
sourceNote ? /* @__PURE__ */
|
|
8406
|
+
sourceNote ? /* @__PURE__ */ jsx79(Flag, { tone: "info", statement: "Design-first: this page is the spec.", cost: sourceNote, actions: null }) : null,
|
|
8378
8407
|
/* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
8379
|
-
/* @__PURE__ */
|
|
8408
|
+
/* @__PURE__ */ jsx79(Input, { icon: "magnifying-glass", placeholder: "Find an endpoint, screen, or behavior", value: q, onChange: (e) => setQ(e.target.value), style: { width: 300 } }),
|
|
8380
8409
|
methods.map((m) => /* @__PURE__ */ jsxs69(Tag, { selected: method === m, onClick: () => setMethod(method === m ? null : m), children: [
|
|
8381
8410
|
m,
|
|
8382
8411
|
" ",
|
|
8383
|
-
/* @__PURE__ */
|
|
8412
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-mono", children: spec.filter((s) => s.method === m).length })
|
|
8384
8413
|
] }, m)),
|
|
8385
8414
|
listCount ? /* @__PURE__ */ jsxs69(Tag, { icon: "rows", selected: listOnly, onClick: () => setListOnly(!listOnly), children: [
|
|
8386
8415
|
"Paged lists ",
|
|
8387
|
-
/* @__PURE__ */
|
|
8416
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-mono", children: listCount })
|
|
8388
8417
|
] }) : null,
|
|
8389
|
-
/* @__PURE__ */
|
|
8418
|
+
/* @__PURE__ */ jsx79("span", { style: { flex: 1 } }),
|
|
8390
8419
|
/* @__PURE__ */ jsxs69("span", { className: "fd-body-sm fd-muted", children: [
|
|
8391
8420
|
hits.length,
|
|
8392
8421
|
" of ",
|
|
@@ -8395,31 +8424,31 @@ function ApiSpecBrowser({
|
|
|
8395
8424
|
listCount ? " \xB7 " + listCount + " paged" : ""
|
|
8396
8425
|
] })
|
|
8397
8426
|
] }),
|
|
8398
|
-
hits.length === 0 ? /* @__PURE__ */
|
|
8427
|
+
hits.length === 0 ? /* @__PURE__ */ jsx79(Card, { elevation: "flat", children: /* @__PURE__ */ jsx79("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No endpoint matches those filters." }) }) : effGroups.map(([g, ids]) => {
|
|
8399
8428
|
const items = hits.filter((s) => ids.indexOf(s.id) >= 0);
|
|
8400
8429
|
if (!items.length) return null;
|
|
8401
8430
|
return /* @__PURE__ */ jsxs69("div", { className: "fd-stack", style: { gap: 12 }, children: [
|
|
8402
|
-
/* @__PURE__ */
|
|
8403
|
-
items.map((s) => /* @__PURE__ */
|
|
8431
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-label-lg", children: g }),
|
|
8432
|
+
items.map((s) => /* @__PURE__ */ jsx79(Endpoint, { s, onRequest }, s.id))
|
|
8404
8433
|
] }, g);
|
|
8405
8434
|
}),
|
|
8406
|
-
conventions && conventions.length ? /* @__PURE__ */
|
|
8407
|
-
/* @__PURE__ */
|
|
8408
|
-
/* @__PURE__ */
|
|
8435
|
+
conventions && conventions.length ? /* @__PURE__ */ jsx79(Card, { title: "Cross-cutting conventions", elevation: "flat", children: /* @__PURE__ */ jsx79("div", { className: "fd-stack", style: { gap: 10 }, children: conventions.map(([k, v]) => /* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { gap: 12, alignItems: "flex-start" }, children: [
|
|
8436
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-overline fd-muted", style: { width: 110, flex: "none", paddingTop: 2 }, children: k }),
|
|
8437
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: v })
|
|
8409
8438
|
] }, k)) }) }) : null,
|
|
8410
|
-
openQuestions && openQuestions.length ? /* @__PURE__ */
|
|
8411
|
-
/* @__PURE__ */
|
|
8439
|
+
openQuestions && openQuestions.length ? /* @__PURE__ */ jsx79(Collapsible, { icon: "list-checks", title: "Open questions before implementation", subtitle: openQuestions.length + " unresolved", children: /* @__PURE__ */ jsx79("div", { className: "fd-stack", style: { gap: 8 }, children: openQuestions.map(([id, question, why]) => /* @__PURE__ */ jsxs69("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start", padding: "8px 0", borderTop: "1px solid var(--border)" }, children: [
|
|
8440
|
+
/* @__PURE__ */ jsx79(Badge, { tone: "danger", children: id }),
|
|
8412
8441
|
/* @__PURE__ */ jsxs69("span", { className: "fd-stack", style: { gap: 2, flex: 1 }, children: [
|
|
8413
|
-
/* @__PURE__ */
|
|
8414
|
-
/* @__PURE__ */
|
|
8442
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: question }),
|
|
8443
|
+
/* @__PURE__ */ jsx79("span", { className: "fd-body-sm fd-muted", children: why })
|
|
8415
8444
|
] })
|
|
8416
8445
|
] }, id)) }) }) : null
|
|
8417
8446
|
] });
|
|
8418
8447
|
}
|
|
8419
8448
|
|
|
8420
8449
|
// src/components/platform/ProfilePage.tsx
|
|
8421
|
-
import * as
|
|
8422
|
-
import { jsx as
|
|
8450
|
+
import * as React55 from "react";
|
|
8451
|
+
import { jsx as jsx80, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
8423
8452
|
function fieldInitialValue(field, user) {
|
|
8424
8453
|
if (field.value) return field.value(user);
|
|
8425
8454
|
const raw = user[field.key];
|
|
@@ -8454,21 +8483,21 @@ function ProfilePage({
|
|
|
8454
8483
|
}) {
|
|
8455
8484
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
8456
8485
|
const user = userProp || sessionUser;
|
|
8457
|
-
const initialFieldValues =
|
|
8486
|
+
const initialFieldValues = React55.useMemo(() => {
|
|
8458
8487
|
const values2 = {};
|
|
8459
8488
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
8460
8489
|
return values2;
|
|
8461
8490
|
}, [user.id, fields]);
|
|
8462
|
-
const initialNotify =
|
|
8491
|
+
const initialNotify = React55.useMemo(() => {
|
|
8463
8492
|
const values2 = {};
|
|
8464
8493
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
8465
8494
|
return values2;
|
|
8466
8495
|
}, [user.id, notifications]);
|
|
8467
|
-
const [values, setValues] =
|
|
8468
|
-
const [notify, setNotify] =
|
|
8469
|
-
const [saving, setSaving] =
|
|
8470
|
-
const [saved, setSaved] =
|
|
8471
|
-
const [prevUserId, setPrevUserId] =
|
|
8496
|
+
const [values, setValues] = React55.useState(initialFieldValues);
|
|
8497
|
+
const [notify, setNotify] = React55.useState(initialNotify);
|
|
8498
|
+
const [saving, setSaving] = React55.useState(false);
|
|
8499
|
+
const [saved, setSaved] = React55.useState(false);
|
|
8500
|
+
const [prevUserId, setPrevUserId] = React55.useState(user.id);
|
|
8472
8501
|
if (user.id !== prevUserId) {
|
|
8473
8502
|
setPrevUserId(user.id);
|
|
8474
8503
|
setValues(initialFieldValues);
|
|
@@ -8507,35 +8536,35 @@ function ProfilePage({
|
|
|
8507
8536
|
const fieldGroups = groupFields(fields);
|
|
8508
8537
|
return /* @__PURE__ */ jsxs70("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
|
|
8509
8538
|
/* @__PURE__ */ jsxs70("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
8510
|
-
/* @__PURE__ */
|
|
8511
|
-
/* @__PURE__ */
|
|
8512
|
-
/* @__PURE__ */
|
|
8539
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-overline fd-muted", children: "Account" }),
|
|
8540
|
+
/* @__PURE__ */ jsx80("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
|
|
8541
|
+
/* @__PURE__ */ jsx80("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." })
|
|
8513
8542
|
] }),
|
|
8514
|
-
/* @__PURE__ */
|
|
8515
|
-
/* @__PURE__ */
|
|
8543
|
+
/* @__PURE__ */ jsx80(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs70("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
|
|
8544
|
+
/* @__PURE__ */ jsx80(Avatar, { name: displayName, size: "lg" }),
|
|
8516
8545
|
/* @__PURE__ */ jsxs70("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
|
|
8517
|
-
/* @__PURE__ */
|
|
8546
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
|
|
8518
8547
|
/* @__PURE__ */ jsxs70("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
|
|
8519
|
-
roles.map((r) => /* @__PURE__ */
|
|
8520
|
-
user.sso ? /* @__PURE__ */
|
|
8548
|
+
roles.map((r) => /* @__PURE__ */ jsx80(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
|
|
8549
|
+
user.sso ? /* @__PURE__ */ jsx80(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
|
|
8521
8550
|
] })
|
|
8522
8551
|
] }),
|
|
8523
|
-
onChangePhoto ? /* @__PURE__ */
|
|
8552
|
+
onChangePhoto ? /* @__PURE__ */ jsx80(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
|
|
8524
8553
|
] }) }),
|
|
8525
|
-
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */
|
|
8554
|
+
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ jsx80(
|
|
8526
8555
|
Card,
|
|
8527
8556
|
{
|
|
8528
8557
|
title: description ? /* @__PURE__ */ jsxs70("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
8529
|
-
/* @__PURE__ */
|
|
8530
|
-
/* @__PURE__ */
|
|
8558
|
+
/* @__PURE__ */ jsx80("span", { children: group }),
|
|
8559
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
|
|
8531
8560
|
] }) : group,
|
|
8532
8561
|
elevation: "flat",
|
|
8533
8562
|
children: /* @__PURE__ */ jsxs70("div", { className: "fd-stack", style: { gap: 14 }, children: [
|
|
8534
|
-
/* @__PURE__ */
|
|
8563
|
+
/* @__PURE__ */ jsx80("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
|
|
8535
8564
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8536
8565
|
const readOnly = field.readOnly || field.type === "readonly";
|
|
8537
8566
|
if (field.type === "select") {
|
|
8538
|
-
return /* @__PURE__ */
|
|
8567
|
+
return /* @__PURE__ */ jsx80(
|
|
8539
8568
|
Select,
|
|
8540
8569
|
{
|
|
8541
8570
|
label: field.label,
|
|
@@ -8549,7 +8578,7 @@ function ProfilePage({
|
|
|
8549
8578
|
field.key
|
|
8550
8579
|
);
|
|
8551
8580
|
}
|
|
8552
|
-
return /* @__PURE__ */
|
|
8581
|
+
return /* @__PURE__ */ jsx80(
|
|
8553
8582
|
Input,
|
|
8554
8583
|
{
|
|
8555
8584
|
label: field.label,
|
|
@@ -8565,7 +8594,7 @@ function ProfilePage({
|
|
|
8565
8594
|
}) }),
|
|
8566
8595
|
groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
|
|
8567
8596
|
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
8568
|
-
return /* @__PURE__ */
|
|
8597
|
+
return /* @__PURE__ */ jsx80(
|
|
8569
8598
|
Textarea,
|
|
8570
8599
|
{
|
|
8571
8600
|
label: field.label,
|
|
@@ -8585,16 +8614,16 @@ function ProfilePage({
|
|
|
8585
8614
|
group
|
|
8586
8615
|
)),
|
|
8587
8616
|
extra,
|
|
8588
|
-
notifications.length > 0 ? /* @__PURE__ */
|
|
8617
|
+
notifications.length > 0 ? /* @__PURE__ */ jsx80(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ jsx80("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ jsx80(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
|
|
8589
8618
|
/* @__PURE__ */ jsxs70(
|
|
8590
8619
|
Card,
|
|
8591
8620
|
{
|
|
8592
8621
|
title: /* @__PURE__ */ jsxs70("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
8593
|
-
/* @__PURE__ */
|
|
8594
|
-
/* @__PURE__ */
|
|
8622
|
+
/* @__PURE__ */ jsx80("span", { children: "Access" }),
|
|
8623
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "What your roles grant you" })
|
|
8595
8624
|
] }),
|
|
8596
8625
|
elevation: "flat",
|
|
8597
|
-
action: /* @__PURE__ */
|
|
8626
|
+
action: /* @__PURE__ */ jsx80(
|
|
8598
8627
|
Button,
|
|
8599
8628
|
{
|
|
8600
8629
|
size: "sm",
|
|
@@ -8606,34 +8635,34 @@ function ProfilePage({
|
|
|
8606
8635
|
),
|
|
8607
8636
|
children: [
|
|
8608
8637
|
/* @__PURE__ */ jsxs70("div", { className: "fd-stack", style: { gap: 0 }, children: [
|
|
8609
|
-
/* @__PURE__ */
|
|
8638
|
+
/* @__PURE__ */ jsx80(CardRow, { label: "Roles", children: roles.map((r) => r.name).join(", ") || "None" }),
|
|
8610
8639
|
/* @__PURE__ */ jsxs70(CardRow, { label: "Permissions", children: [
|
|
8611
8640
|
permissions.length,
|
|
8612
8641
|
" granted"
|
|
8613
8642
|
] }),
|
|
8614
|
-
/* @__PURE__ */
|
|
8643
|
+
/* @__PURE__ */ jsx80(CardRow, { label: "Member since", children: user.joined || "\u2014" })
|
|
8615
8644
|
] }),
|
|
8616
|
-
/* @__PURE__ */
|
|
8645
|
+
/* @__PURE__ */ jsx80("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." })
|
|
8617
8646
|
]
|
|
8618
8647
|
}
|
|
8619
8648
|
),
|
|
8620
|
-
sessions ? /* @__PURE__ */
|
|
8649
|
+
sessions ? /* @__PURE__ */ jsx80(
|
|
8621
8650
|
Card,
|
|
8622
8651
|
{
|
|
8623
8652
|
title: "Signed-in devices",
|
|
8624
8653
|
elevation: "flat",
|
|
8625
|
-
action: /* @__PURE__ */
|
|
8626
|
-
children: /* @__PURE__ */
|
|
8627
|
-
/* @__PURE__ */
|
|
8654
|
+
action: /* @__PURE__ */ jsx80(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
|
|
8655
|
+
children: /* @__PURE__ */ jsx80("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ jsx80("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ jsxs70("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
8656
|
+
/* @__PURE__ */ jsx80("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
8628
8657
|
/* @__PURE__ */ jsxs70("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
|
|
8629
|
-
/* @__PURE__ */
|
|
8658
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
|
|
8630
8659
|
/* @__PURE__ */ jsxs70("span", { className: "fd-body-sm fd-muted", children: [
|
|
8631
8660
|
s.where,
|
|
8632
8661
|
" \xB7 ",
|
|
8633
8662
|
s.when
|
|
8634
8663
|
] })
|
|
8635
8664
|
] }),
|
|
8636
|
-
s.current ? /* @__PURE__ */
|
|
8665
|
+
s.current ? /* @__PURE__ */ jsx80(Badge, { tone: "success", dot: true, children: "This device" }) : /* @__PURE__ */ jsx80(Button, { size: "sm", variant: "ghost", children: "Revoke" })
|
|
8637
8666
|
] }, s.id)) })
|
|
8638
8667
|
}
|
|
8639
8668
|
) : null,
|
|
@@ -8648,16 +8677,16 @@ function ProfilePage({
|
|
|
8648
8677
|
border: "1px solid var(--border)",
|
|
8649
8678
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
8650
8679
|
}, children: [
|
|
8651
|
-
/* @__PURE__ */
|
|
8652
|
-
/* @__PURE__ */
|
|
8653
|
-
/* @__PURE__ */
|
|
8680
|
+
/* @__PURE__ */ jsx80("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
|
|
8681
|
+
/* @__PURE__ */ jsx80(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
|
|
8682
|
+
/* @__PURE__ */ jsx80(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
|
|
8654
8683
|
] })
|
|
8655
8684
|
] });
|
|
8656
8685
|
}
|
|
8657
8686
|
|
|
8658
8687
|
// src/components/platform/SessionScreen.tsx
|
|
8659
|
-
import * as
|
|
8660
|
-
import { Fragment as Fragment20, jsx as
|
|
8688
|
+
import * as React56 from "react";
|
|
8689
|
+
import { Fragment as Fragment20, jsx as jsx81, jsxs as jsxs71 } from "react/jsx-runtime";
|
|
8661
8690
|
var COPY = {
|
|
8662
8691
|
"signing-in": { busy: "Signing you in\u2026" },
|
|
8663
8692
|
"session-expired": { busy: "Your session expired \u2014 signing you back in\u2026" },
|
|
@@ -8670,28 +8699,28 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8670
8699
|
const copy = COPY[kind];
|
|
8671
8700
|
const busyMessage = "busy" in copy ? copy.busy : null;
|
|
8672
8701
|
const failureTitle = "failure" in copy ? copy.failure : null;
|
|
8673
|
-
const [announced, setAnnounced] =
|
|
8674
|
-
|
|
8702
|
+
const [announced, setAnnounced] = React56.useState("");
|
|
8703
|
+
React56.useEffect(() => {
|
|
8675
8704
|
setAnnounced(busyMessage ?? "");
|
|
8676
8705
|
}, [busyMessage]);
|
|
8677
|
-
const titleRef =
|
|
8706
|
+
const titleRef = React56.useRef(null);
|
|
8678
8707
|
const failed = failureTitle !== null;
|
|
8679
|
-
|
|
8708
|
+
React56.useEffect(() => {
|
|
8680
8709
|
titleRef.current?.focus({ preventScroll: true });
|
|
8681
8710
|
}, [failed]);
|
|
8682
|
-
return /* @__PURE__ */
|
|
8683
|
-
/* @__PURE__ */
|
|
8711
|
+
return /* @__PURE__ */ jsx81("main", { className: "fd-session-screen", children: /* @__PURE__ */ jsxs71("div", { className: "fd-session-screen-inner", children: [
|
|
8712
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-session-screen-mark", "data-theme": "dark", children: /* @__PURE__ */ jsx81(FlytedeskMark, { size: "lg" }) }),
|
|
8684
8713
|
/* @__PURE__ */ jsxs71("div", { className: "fd-session-screen-frame", children: [
|
|
8685
|
-
/* @__PURE__ */
|
|
8686
|
-
/* @__PURE__ */
|
|
8687
|
-
/* @__PURE__ */
|
|
8688
|
-
/* @__PURE__ */
|
|
8689
|
-
/* @__PURE__ */
|
|
8690
|
-
/* @__PURE__ */
|
|
8714
|
+
/* @__PURE__ */ jsx81("div", { className: "fd-session-screen-stripe" }),
|
|
8715
|
+
/* @__PURE__ */ jsx81(Card, { children: /* @__PURE__ */ jsxs71("div", { className: "fd-session-screen-body", children: [
|
|
8716
|
+
/* @__PURE__ */ jsx81("h1", { ref: titleRef, tabIndex: -1, className: "fd-h3 fd-session-screen-title", children: productName }),
|
|
8717
|
+
/* @__PURE__ */ jsx81("div", { role: "status", "aria-live": "polite", className: "fd-session-screen-status", children: busyMessage !== null ? /* @__PURE__ */ jsxs71(Fragment20, { children: [
|
|
8718
|
+
/* @__PURE__ */ jsx81("span", { className: "fd-spinner fd-spinner-lg fd-session-screen-spinner", "aria-hidden": "true" }),
|
|
8719
|
+
/* @__PURE__ */ jsx81("p", { className: "fd-body fd-session-screen-message", children: announced })
|
|
8691
8720
|
] }) : null }),
|
|
8692
8721
|
failureTitle !== null ? /* @__PURE__ */ jsxs71("div", { className: "fd-session-screen-failure", children: [
|
|
8693
|
-
/* @__PURE__ */
|
|
8694
|
-
onRetry !== null ? /* @__PURE__ */
|
|
8722
|
+
/* @__PURE__ */ jsx81(Banner, { tone: "danger", title: failureTitle, detail: error ?? void 0 }),
|
|
8723
|
+
onRetry !== null ? /* @__PURE__ */ jsx81(Button, { variant: "primary", block: true, onClick: onRetry, children: "Try again" }) : null
|
|
8695
8724
|
] }) : null
|
|
8696
8725
|
] }) })
|
|
8697
8726
|
] })
|
|
@@ -8699,10 +8728,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
|
|
|
8699
8728
|
}
|
|
8700
8729
|
|
|
8701
8730
|
// src/components/platform/RoadmapTimeline.tsx
|
|
8702
|
-
import * as
|
|
8731
|
+
import * as React59 from "react";
|
|
8703
8732
|
|
|
8704
8733
|
// src/kits/session.ts
|
|
8705
|
-
import * as
|
|
8734
|
+
import * as React57 from "react";
|
|
8706
8735
|
var PERMISSION_CATALOG = [
|
|
8707
8736
|
{ group: "Plans", items: [
|
|
8708
8737
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -10269,8 +10298,8 @@ function roadmap(overrides) {
|
|
|
10269
10298
|
};
|
|
10270
10299
|
}
|
|
10271
10300
|
function useSession() {
|
|
10272
|
-
const [s, setS] =
|
|
10273
|
-
|
|
10301
|
+
const [s, setS] = React57.useState(getSession);
|
|
10302
|
+
React57.useEffect(() => subscribe(setS), []);
|
|
10274
10303
|
return s;
|
|
10275
10304
|
}
|
|
10276
10305
|
var SessionKit = {
|
|
@@ -10303,7 +10332,7 @@ var SessionKit = {
|
|
|
10303
10332
|
};
|
|
10304
10333
|
function DemoSessionProvider({ children }) {
|
|
10305
10334
|
const session = useSession();
|
|
10306
|
-
const value =
|
|
10335
|
+
const value = React57.useMemo(
|
|
10307
10336
|
() => ({
|
|
10308
10337
|
user: session.user,
|
|
10309
10338
|
roles: session.roles,
|
|
@@ -10319,11 +10348,11 @@ function DemoSessionProvider({ children }) {
|
|
|
10319
10348
|
}),
|
|
10320
10349
|
[session]
|
|
10321
10350
|
);
|
|
10322
|
-
return
|
|
10351
|
+
return React57.createElement(SessionProvider, { value }, children);
|
|
10323
10352
|
}
|
|
10324
10353
|
|
|
10325
10354
|
// src/kits/runtime.ts
|
|
10326
|
-
import * as
|
|
10355
|
+
import * as React58 from "react";
|
|
10327
10356
|
var WIRED_ENDPOINTS = [
|
|
10328
10357
|
// Nothing yet. Every id below would come from a real service:
|
|
10329
10358
|
// "plan.get", "placements.list", …
|
|
@@ -10494,8 +10523,8 @@ var RuntimeKit = {
|
|
|
10494
10523
|
};
|
|
10495
10524
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
10496
10525
|
function useRuntimeMode() {
|
|
10497
|
-
const [m, setM] =
|
|
10498
|
-
|
|
10526
|
+
const [m, setM] = React58.useState(RuntimeKit.getMode());
|
|
10527
|
+
React58.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
10499
10528
|
return m;
|
|
10500
10529
|
}
|
|
10501
10530
|
function useFeatureStatus(key) {
|
|
@@ -10514,7 +10543,7 @@ var UseRuntimeMode = useRuntimeMode;
|
|
|
10514
10543
|
var UseFeatureStatus = useFeatureStatus;
|
|
10515
10544
|
|
|
10516
10545
|
// src/components/platform/RoadmapTimeline.tsx
|
|
10517
|
-
import { jsx as
|
|
10546
|
+
import { jsx as jsx82, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
10518
10547
|
var STATUS = {
|
|
10519
10548
|
shipped: { tone: "success", icon: "check-circle", label: "Wired" },
|
|
10520
10549
|
next: { tone: "warning", icon: "traffic-cone", label: "Not wired" },
|
|
@@ -10529,43 +10558,43 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10529
10558
|
const s = STATUS[item.status] || STATUS.planned;
|
|
10530
10559
|
const deps = (item.dependsOn || []).map((k) => byKey[k]).filter(Boolean);
|
|
10531
10560
|
const blocking = deps.filter((d) => !d.implemented);
|
|
10532
|
-
return /* @__PURE__ */
|
|
10561
|
+
return /* @__PURE__ */ jsx82(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs72("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
10533
10562
|
/* @__PURE__ */ jsxs72("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: [
|
|
10534
|
-
/* @__PURE__ */
|
|
10535
|
-
/* @__PURE__ */
|
|
10536
|
-
/* @__PURE__ */
|
|
10563
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-body", style: { fontWeight: 700, flex: 1, minWidth: 140 }, children: item.label }),
|
|
10564
|
+
/* @__PURE__ */ jsx82(Badge, { tone: "neutral", icon: PROJECT_ICON[item.project] || "squares-four", children: item.project }),
|
|
10565
|
+
/* @__PURE__ */ jsx82(Badge, { tone: s.tone, icon: s.icon, children: s.label })
|
|
10537
10566
|
] }),
|
|
10538
|
-
/* @__PURE__ */
|
|
10567
|
+
/* @__PURE__ */ jsx82("p", { className: "fd-body-sm fd-secondary", style: { margin: 0, textWrap: "pretty" }, children: item.description }),
|
|
10539
10568
|
item.backend ? /* @__PURE__ */ jsxs72("div", { className: "fd-row", style: { gap: 10, alignItems: "flex-start" }, children: [
|
|
10540
|
-
/* @__PURE__ */
|
|
10541
|
-
/* @__PURE__ */
|
|
10569
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-overline fd-muted", style: { width: 62, flex: "none", paddingTop: 2 }, children: "Backend" }),
|
|
10570
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-body-sm", style: { flex: 1, textWrap: "pretty" }, children: item.backend })
|
|
10542
10571
|
] }) : null,
|
|
10543
10572
|
/* @__PURE__ */ jsxs72("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
10544
10573
|
item.effort ? /* @__PURE__ */ jsxs72("span", { className: "fd-body-sm fd-muted", children: [
|
|
10545
|
-
/* @__PURE__ */
|
|
10574
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-hourglass-medium" }),
|
|
10546
10575
|
" ",
|
|
10547
10576
|
item.effort
|
|
10548
10577
|
] }) : null,
|
|
10549
10578
|
/* @__PURE__ */ jsxs72("span", { className: "fd-body-sm fd-muted", children: [
|
|
10550
|
-
/* @__PURE__ */
|
|
10579
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-user" }),
|
|
10551
10580
|
" ",
|
|
10552
10581
|
item.owner
|
|
10553
10582
|
] }),
|
|
10554
|
-
item.screen ? /* @__PURE__ */
|
|
10555
|
-
/* @__PURE__ */
|
|
10556
|
-
/* @__PURE__ */
|
|
10583
|
+
item.screen ? /* @__PURE__ */ jsx82(Badge, { tone: "neutral", icon: "browser", children: "screen" }) : null,
|
|
10584
|
+
/* @__PURE__ */ jsx82("span", { style: { flex: 1 } }),
|
|
10585
|
+
/* @__PURE__ */ jsx82(
|
|
10557
10586
|
"button",
|
|
10558
10587
|
{
|
|
10559
10588
|
type: "button",
|
|
10560
10589
|
onClick: () => onOpenFlag && onOpenFlag(item.key),
|
|
10561
10590
|
style: { all: "unset", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: 5 },
|
|
10562
|
-
children: /* @__PURE__ */
|
|
10591
|
+
children: /* @__PURE__ */ jsx82("code", { className: "fd-mono", style: { fontSize: 11, color: "var(--brand)" }, children: item.key })
|
|
10563
10592
|
}
|
|
10564
10593
|
)
|
|
10565
10594
|
] }),
|
|
10566
10595
|
deps.length ? /* @__PURE__ */ jsxs72("div", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 6, borderTop: "1px solid var(--border)" }, children: [
|
|
10567
|
-
/* @__PURE__ */
|
|
10568
|
-
deps.map((d) => /* @__PURE__ */
|
|
10596
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-overline fd-muted", style: { paddingTop: 3 }, children: "After" }),
|
|
10597
|
+
deps.map((d) => /* @__PURE__ */ jsx82(Tag, { icon: d.implemented ? "check" : "clock", children: d.label }, d.key))
|
|
10569
10598
|
] }) : null,
|
|
10570
10599
|
blocking.length && !item.implemented ? /* @__PURE__ */ jsxs72("span", { className: "fd-body-sm", style: { color: "var(--warn-text)" }, children: [
|
|
10571
10600
|
"Blocked until ",
|
|
@@ -10578,12 +10607,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
10578
10607
|
}
|
|
10579
10608
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
10580
10609
|
const session = SessionKit.useSession();
|
|
10581
|
-
const [project, setProject] =
|
|
10582
|
-
const [q, setQ] =
|
|
10583
|
-
const scrollRef =
|
|
10584
|
-
const nowRef =
|
|
10585
|
-
const rm =
|
|
10586
|
-
const byKey =
|
|
10610
|
+
const [project, setProject] = React59.useState("");
|
|
10611
|
+
const [q, setQ] = React59.useState("");
|
|
10612
|
+
const scrollRef = React59.useRef(null);
|
|
10613
|
+
const nowRef = React59.useRef(null);
|
|
10614
|
+
const rm = React59.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
10615
|
+
const byKey = React59.useMemo(() => {
|
|
10587
10616
|
const m = {};
|
|
10588
10617
|
rm.items.forEach((i) => {
|
|
10589
10618
|
m[i.key] = i;
|
|
@@ -10592,7 +10621,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10592
10621
|
}, [rm]);
|
|
10593
10622
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
10594
10623
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
10595
|
-
|
|
10624
|
+
React59.useEffect(() => {
|
|
10596
10625
|
let raf1 = 0, raf2 = 0;
|
|
10597
10626
|
const place = () => {
|
|
10598
10627
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -10622,21 +10651,21 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10622
10651
|
let lastPhase = null;
|
|
10623
10652
|
return /* @__PURE__ */ jsxs72("div", { className: "fd-stack", style: { gap: 16, maxWidth: 1e3 }, children: [
|
|
10624
10653
|
/* @__PURE__ */ jsxs72("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
10625
|
-
/* @__PURE__ */
|
|
10626
|
-
/* @__PURE__ */
|
|
10627
|
-
/* @__PURE__ */
|
|
10654
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-overline fd-muted", children: "Architecture" }),
|
|
10655
|
+
/* @__PURE__ */ jsx82("h1", { className: "fd-h1", style: { margin: 0 }, children: title }),
|
|
10656
|
+
/* @__PURE__ */ jsx82("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." })
|
|
10628
10657
|
] }),
|
|
10629
10658
|
/* @__PURE__ */ jsxs72("div", { className: "fd-grid-stats is-thin", children: [
|
|
10630
|
-
/* @__PURE__ */
|
|
10631
|
-
/* @__PURE__ */
|
|
10632
|
-
/* @__PURE__ */
|
|
10633
|
-
/* @__PURE__ */
|
|
10659
|
+
/* @__PURE__ */ jsx82(StatTile, { compact: true, label: "Wired", value: String(rm.shipped), sub: "of " + rm.items.length + " features" }),
|
|
10660
|
+
/* @__PURE__ */ jsx82(StatTile, { compact: true, label: "Remaining", value: String(rm.remaining), sub: "backend work" }),
|
|
10661
|
+
/* @__PURE__ */ jsx82(StatTile, { compact: true, label: "Est. effort", value: days ? days + " days" : "\u2014", sub: "sum of estimates, not calendar" }),
|
|
10662
|
+
/* @__PURE__ */ jsx82(StatTile, { compact: true, label: "Up next", value: nextPhase ? "Phase " + nextPhase.phase : "\u2014", sub: nextPhase ? nextPhase.phaseName : "all wired" })
|
|
10634
10663
|
] }),
|
|
10635
10664
|
/* @__PURE__ */ jsxs72("div", { className: "fd-row", style: { gap: 10, flexWrap: "wrap" }, children: [
|
|
10636
|
-
/* @__PURE__ */
|
|
10637
|
-
/* @__PURE__ */
|
|
10638
|
-
/* @__PURE__ */
|
|
10639
|
-
/* @__PURE__ */
|
|
10665
|
+
/* @__PURE__ */ jsx82(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 } }),
|
|
10666
|
+
/* @__PURE__ */ jsx82(Select, { placeholder: "All projects", value: project, onChange: (e) => setProject(e.target.value), options: projects, style: { width: 190 } }),
|
|
10667
|
+
/* @__PURE__ */ jsx82("span", { style: { flex: 1 } }),
|
|
10668
|
+
/* @__PURE__ */ jsx82(
|
|
10640
10669
|
Button,
|
|
10641
10670
|
{
|
|
10642
10671
|
size: "sm",
|
|
@@ -10650,7 +10679,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10650
10679
|
}
|
|
10651
10680
|
)
|
|
10652
10681
|
] }),
|
|
10653
|
-
/* @__PURE__ */
|
|
10682
|
+
/* @__PURE__ */ jsx82(
|
|
10654
10683
|
Flag,
|
|
10655
10684
|
{
|
|
10656
10685
|
tone: "info",
|
|
@@ -10659,17 +10688,17 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10659
10688
|
actions: null
|
|
10660
10689
|
}
|
|
10661
10690
|
),
|
|
10662
|
-
/* @__PURE__ */
|
|
10663
|
-
/* @__PURE__ */
|
|
10691
|
+
/* @__PURE__ */ jsx82("div", { className: "fd-rm", children: /* @__PURE__ */ jsx82("div", { className: "fd-rm-scroll", ref: scrollRef, children: /* @__PURE__ */ jsxs72("div", { className: "fd-rm-track", children: [
|
|
10692
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-rm-spine", children: /* @__PURE__ */ jsx82("span", { className: "fd-rm-spine-done", style: { height: items.length ? 100 * shippedShown / items.length + "%" : "0%" } }) }),
|
|
10664
10693
|
items.map((item, n) => {
|
|
10665
10694
|
const showPhase = item.phase !== lastPhase;
|
|
10666
10695
|
lastPhase = item.phase;
|
|
10667
10696
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
10668
10697
|
const isBoundary = n === firstPending;
|
|
10669
|
-
return /* @__PURE__ */ jsxs72(
|
|
10698
|
+
return /* @__PURE__ */ jsxs72(React59.Fragment, { children: [
|
|
10670
10699
|
showPhase ? /* @__PURE__ */ jsxs72("div", { className: "fd-rm-era", children: [
|
|
10671
10700
|
/* @__PURE__ */ jsxs72("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
10672
|
-
/* @__PURE__ */
|
|
10701
|
+
/* @__PURE__ */ jsx82("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
10673
10702
|
item.phase === 0 ? null : /* @__PURE__ */ jsxs72("span", { className: "fd-mono", style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
10674
10703
|
fmtDate(item.phaseStart),
|
|
10675
10704
|
" \u2013 ",
|
|
@@ -10682,37 +10711,37 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
10682
10711
|
inPhase === 1 ? "" : "s"
|
|
10683
10712
|
] })
|
|
10684
10713
|
] }),
|
|
10685
|
-
item.phaseWhy ? /* @__PURE__ */
|
|
10714
|
+
item.phaseWhy ? /* @__PURE__ */ jsx82("p", { className: "fd-rm-era-why", children: item.phaseWhy }) : null
|
|
10686
10715
|
] }) : null,
|
|
10687
|
-
isBoundary ? /* @__PURE__ */
|
|
10688
|
-
/* @__PURE__ */
|
|
10716
|
+
isBoundary ? /* @__PURE__ */ jsx82("div", { className: "fd-rm-now", ref: nowRef, children: /* @__PURE__ */ jsxs72("span", { className: "fd-rm-now-pill", children: [
|
|
10717
|
+
/* @__PURE__ */ jsx82("i", { className: "ph ph-map-pin" }),
|
|
10689
10718
|
" You are here \u2014 everything above is wired"
|
|
10690
10719
|
] }) }) : null,
|
|
10691
10720
|
/* @__PURE__ */ jsxs72("div", { className: "fd-rm-row", children: [
|
|
10692
|
-
/* @__PURE__ */
|
|
10721
|
+
/* @__PURE__ */ jsx82("span", { className: "fd-rm-dot " + (item.implemented ? "is-shipped" : item.status === "next" ? "is-next" : "") }),
|
|
10693
10722
|
/* @__PURE__ */ jsxs72("div", { className: "fd-rm-date", children: [
|
|
10694
10723
|
fmtDate(item.date),
|
|
10695
|
-
/* @__PURE__ */
|
|
10696
|
-
/* @__PURE__ */
|
|
10724
|
+
/* @__PURE__ */ jsx82("br", {}),
|
|
10725
|
+
/* @__PURE__ */ jsx82("span", { style: { opacity: 0.75 }, children: item.implemented ? "shipped" : "phase " + item.phase })
|
|
10697
10726
|
] }),
|
|
10698
|
-
/* @__PURE__ */
|
|
10727
|
+
/* @__PURE__ */ jsx82(RoadmapCard, { item, byKey, onOpenFlag })
|
|
10699
10728
|
] })
|
|
10700
10729
|
] }, item.key);
|
|
10701
10730
|
}),
|
|
10702
|
-
!items.length ? /* @__PURE__ */
|
|
10731
|
+
!items.length ? /* @__PURE__ */ jsx82("p", { className: "fd-body-sm fd-muted", children: "Nothing matches that filter." }) : null
|
|
10703
10732
|
] }) }) }),
|
|
10704
10733
|
/* @__PURE__ */ jsxs72("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: [
|
|
10705
10734
|
"Derived from the feature-flag registry \u2014 each entry's status is its flag's ",
|
|
10706
|
-
/* @__PURE__ */
|
|
10735
|
+
/* @__PURE__ */ jsx82("code", { className: "fd-mono", children: "implemented" }),
|
|
10707
10736
|
" field, so this page cannot drift from what the apps actually do."
|
|
10708
10737
|
] })
|
|
10709
10738
|
] });
|
|
10710
10739
|
}
|
|
10711
10740
|
|
|
10712
10741
|
// src/components/platform/ComingSoon.tsx
|
|
10713
|
-
import * as
|
|
10742
|
+
import * as React60 from "react";
|
|
10714
10743
|
import { createPortal as createPortal6 } from "react-dom";
|
|
10715
|
-
import { Fragment as Fragment22, jsx as
|
|
10744
|
+
import { Fragment as Fragment22, jsx as jsx83, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
10716
10745
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
10717
10746
|
function readBypassed() {
|
|
10718
10747
|
try {
|
|
@@ -10728,8 +10757,8 @@ function writeBypassed(list) {
|
|
|
10728
10757
|
}
|
|
10729
10758
|
}
|
|
10730
10759
|
function useBypass(key) {
|
|
10731
|
-
const [on, setOn] =
|
|
10732
|
-
|
|
10760
|
+
const [on, setOn] = React60.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
10761
|
+
React60.useEffect(() => {
|
|
10733
10762
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
10734
10763
|
}, [key]);
|
|
10735
10764
|
const set = (next) => {
|
|
@@ -10744,41 +10773,41 @@ function useBypass(key) {
|
|
|
10744
10773
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
10745
10774
|
return /* @__PURE__ */ jsxs73(Fragment22, { children: [
|
|
10746
10775
|
/* @__PURE__ */ jsxs73("span", { className: "fd-soon-badge", children: [
|
|
10747
|
-
/* @__PURE__ */
|
|
10776
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
10748
10777
|
label
|
|
10749
10778
|
] }),
|
|
10750
|
-
detail ? /* @__PURE__ */
|
|
10779
|
+
detail ? /* @__PURE__ */ jsx83("span", { className: "fd-soon-detail", children: detail }) : null,
|
|
10751
10780
|
backend ? /* @__PURE__ */ jsxs73("span", { className: "fd-soon-backend", children: [
|
|
10752
|
-
/* @__PURE__ */
|
|
10781
|
+
/* @__PURE__ */ jsx83("span", { className: "fd-overline", children: "Needs" }),
|
|
10753
10782
|
" ",
|
|
10754
10783
|
backend
|
|
10755
10784
|
] }) : null,
|
|
10756
10785
|
eta || effort || onRoadmap ? /* @__PURE__ */ jsxs73("span", { className: "fd-soon-meta", children: [
|
|
10757
10786
|
eta ? /* @__PURE__ */ jsxs73("span", { children: [
|
|
10758
|
-
/* @__PURE__ */
|
|
10787
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }),
|
|
10759
10788
|
" ",
|
|
10760
10789
|
eta
|
|
10761
10790
|
] }) : null,
|
|
10762
10791
|
effort ? /* @__PURE__ */ jsxs73("span", { children: [
|
|
10763
|
-
/* @__PURE__ */
|
|
10792
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-hourglass-medium", "aria-hidden": "true" }),
|
|
10764
10793
|
" ",
|
|
10765
10794
|
effort
|
|
10766
10795
|
] }) : null,
|
|
10767
10796
|
onRoadmap ? /* @__PURE__ */ jsxs73("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
10768
10797
|
"See the roadmap ",
|
|
10769
|
-
/* @__PURE__ */
|
|
10798
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
10770
10799
|
] }) : null
|
|
10771
10800
|
] }) : null,
|
|
10772
10801
|
allowed ? /* @__PURE__ */ jsxs73("button", { type: "button", className: "fd-soon-view", onClick: onBypass, children: [
|
|
10773
|
-
/* @__PURE__ */
|
|
10802
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-eye", "aria-hidden": "true" }),
|
|
10774
10803
|
" View and use it anyway"
|
|
10775
10804
|
] }) : null
|
|
10776
10805
|
] });
|
|
10777
10806
|
}
|
|
10778
10807
|
function useHoverCard(open2) {
|
|
10779
|
-
const anchor =
|
|
10780
|
-
const [pos, setPos] =
|
|
10781
|
-
|
|
10808
|
+
const anchor = React60.useRef(null);
|
|
10809
|
+
const [pos, setPos] = React60.useState(null);
|
|
10810
|
+
React60.useLayoutEffect(() => {
|
|
10782
10811
|
if (!open2 || !anchor.current) {
|
|
10783
10812
|
setPos(null);
|
|
10784
10813
|
return;
|
|
@@ -10832,7 +10861,7 @@ function ComingSoon({
|
|
|
10832
10861
|
if (allowed && bypassed) {
|
|
10833
10862
|
return /* @__PURE__ */ jsxs73("span", { className: ["fd-soon-inline-on", className].filter(Boolean).join(" "), ...rest, children: [
|
|
10834
10863
|
children,
|
|
10835
|
-
/* @__PURE__ */
|
|
10864
|
+
/* @__PURE__ */ jsx83(
|
|
10836
10865
|
"button",
|
|
10837
10866
|
{
|
|
10838
10867
|
type: "button",
|
|
@@ -10840,12 +10869,12 @@ function ComingSoon({
|
|
|
10840
10869
|
title: "Unwired \u2014 writes go to the simulated backend. " + tip + " Click to re-blur.",
|
|
10841
10870
|
onClick: () => setBypassed(false),
|
|
10842
10871
|
"aria-label": "Re-blur this unwired feature",
|
|
10843
|
-
children: /* @__PURE__ */
|
|
10872
|
+
children: /* @__PURE__ */ jsx83("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
10844
10873
|
}
|
|
10845
10874
|
)
|
|
10846
10875
|
] });
|
|
10847
10876
|
}
|
|
10848
|
-
return /* @__PURE__ */
|
|
10877
|
+
return /* @__PURE__ */ jsx83(
|
|
10849
10878
|
InlineSoon,
|
|
10850
10879
|
{
|
|
10851
10880
|
label,
|
|
@@ -10868,17 +10897,17 @@ function ComingSoon({
|
|
|
10868
10897
|
return /* @__PURE__ */ jsxs73("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, ...rest, children: [
|
|
10869
10898
|
/* @__PURE__ */ jsxs73("div", { className: "fd-soon-bar", role: "status", children: [
|
|
10870
10899
|
/* @__PURE__ */ jsxs73("span", { className: "fd-soon-badge", children: [
|
|
10871
|
-
/* @__PURE__ */
|
|
10900
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
10872
10901
|
"Unwired feature \u2014 you are using it anyway"
|
|
10873
10902
|
] }),
|
|
10874
|
-
/* @__PURE__ */
|
|
10903
|
+
/* @__PURE__ */ jsx83("span", { className: "fd-soon-bar-detail", children: "Every action here writes to the simulated backend, so nothing you do persists beyond this session." }),
|
|
10875
10904
|
/* @__PURE__ */ jsxs73("span", { className: "fd-soon-bar-actions", children: [
|
|
10876
10905
|
onRoadmap ? /* @__PURE__ */ jsxs73("button", { type: "button", className: "fd-soon-link", onClick: onRoadmap, children: [
|
|
10877
10906
|
"Roadmap ",
|
|
10878
|
-
/* @__PURE__ */
|
|
10907
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
10879
10908
|
] }) : null,
|
|
10880
10909
|
/* @__PURE__ */ jsxs73("button", { type: "button", className: "fd-soon-link", onClick: () => setBypassed(false), children: [
|
|
10881
|
-
/* @__PURE__ */
|
|
10910
|
+
/* @__PURE__ */ jsx83("i", { className: "ph ph-eye-slash", "aria-hidden": "true" }),
|
|
10882
10911
|
" Re-blur"
|
|
10883
10912
|
] })
|
|
10884
10913
|
] })
|
|
@@ -10887,9 +10916,9 @@ function ComingSoon({
|
|
|
10887
10916
|
] });
|
|
10888
10917
|
}
|
|
10889
10918
|
return /* @__PURE__ */ jsxs73("div", { className: ["fd-soon", className].filter(Boolean).join(" "), style: minHeight ? { minHeight } : void 0, ...rest, children: [
|
|
10890
|
-
/* @__PURE__ */
|
|
10891
|
-
/* @__PURE__ */
|
|
10892
|
-
/* @__PURE__ */
|
|
10919
|
+
/* @__PURE__ */ jsx83("div", { className: "fd-soon-under", style: { filter: "blur(" + blur + "px) saturate(.62)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
10920
|
+
/* @__PURE__ */ jsx83("div", { className: "fd-soon-veil" }),
|
|
10921
|
+
/* @__PURE__ */ jsx83("div", { className: "fd-soon-note", role: "note", children: /* @__PURE__ */ jsx83(
|
|
10893
10922
|
SoonCard,
|
|
10894
10923
|
{
|
|
10895
10924
|
label,
|
|
@@ -10905,12 +10934,12 @@ function ComingSoon({
|
|
|
10905
10934
|
] });
|
|
10906
10935
|
}
|
|
10907
10936
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
10908
|
-
const [open2, setOpen] =
|
|
10937
|
+
const [open2, setOpen] = React60.useState(false);
|
|
10909
10938
|
const [anchor, pos] = useHoverCard(open2);
|
|
10910
|
-
const hoverCardRef =
|
|
10939
|
+
const hoverCardRef = React60.useRef(null);
|
|
10911
10940
|
const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
|
|
10912
10941
|
const zIndex = useLayerZIndex(hoverLayer);
|
|
10913
|
-
const close2 =
|
|
10942
|
+
const close2 = React60.useRef(null);
|
|
10914
10943
|
const show = () => {
|
|
10915
10944
|
if (close2.current) {
|
|
10916
10945
|
clearTimeout(close2.current);
|
|
@@ -10926,7 +10955,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10926
10955
|
setOpen(false);
|
|
10927
10956
|
}, 140);
|
|
10928
10957
|
};
|
|
10929
|
-
|
|
10958
|
+
React60.useEffect(() => () => {
|
|
10930
10959
|
if (close2.current) clearTimeout(close2.current);
|
|
10931
10960
|
}, []);
|
|
10932
10961
|
return /* @__PURE__ */ jsxs73(
|
|
@@ -10940,8 +10969,8 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10940
10969
|
onBlur: hide,
|
|
10941
10970
|
...rest,
|
|
10942
10971
|
children: [
|
|
10943
|
-
/* @__PURE__ */
|
|
10944
|
-
/* @__PURE__ */
|
|
10972
|
+
/* @__PURE__ */ jsx83("span", { className: "fd-soon-under", style: { filter: "blur(" + Math.min(blur, 1.1) + "px) saturate(.66)" }, ...{ inert: "" }, "aria-hidden": "true", children }),
|
|
10973
|
+
/* @__PURE__ */ jsx83(
|
|
10945
10974
|
"button",
|
|
10946
10975
|
{
|
|
10947
10976
|
type: "button",
|
|
@@ -10952,11 +10981,11 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10952
10981
|
onFocus: show,
|
|
10953
10982
|
onBlur: hide,
|
|
10954
10983
|
onClick: () => open2 ? setOpen(false) : show(),
|
|
10955
|
-
children: /* @__PURE__ */
|
|
10984
|
+
children: /* @__PURE__ */ jsx83("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
10956
10985
|
}
|
|
10957
10986
|
),
|
|
10958
10987
|
open2 && pos ? createPortal6(
|
|
10959
|
-
/* @__PURE__ */
|
|
10988
|
+
/* @__PURE__ */ jsx83(
|
|
10960
10989
|
"div",
|
|
10961
10990
|
{
|
|
10962
10991
|
ref: hoverCardRef,
|
|
@@ -10965,7 +10994,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10965
10994
|
style: { position: "fixed", left: pos.left, top: pos.top, bottom: pos.bottom, width: pos.width, zIndex },
|
|
10966
10995
|
onMouseEnter: show,
|
|
10967
10996
|
onMouseLeave: hide,
|
|
10968
|
-
children: /* @__PURE__ */
|
|
10997
|
+
children: /* @__PURE__ */ jsx83(
|
|
10969
10998
|
SoonCard,
|
|
10970
10999
|
{
|
|
10971
11000
|
label,
|
|
@@ -10995,7 +11024,7 @@ function formatEta(iso2) {
|
|
|
10995
11024
|
var FormatEta = formatEta;
|
|
10996
11025
|
|
|
10997
11026
|
// src/components/platform/Gate.tsx
|
|
10998
|
-
import { jsx as
|
|
11027
|
+
import { jsx as jsx84, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
10999
11028
|
function PermissionDenied({ permission, title, detail, compact: compact3 = false, className = "", ...rest }) {
|
|
11000
11029
|
const need = Array.isArray(permission) ? permission : [permission].filter(Boolean);
|
|
11001
11030
|
return /* @__PURE__ */ jsxs74(
|
|
@@ -11015,13 +11044,13 @@ function PermissionDenied({ permission, title, detail, compact: compact3 = false
|
|
|
11015
11044
|
...rest,
|
|
11016
11045
|
children: [
|
|
11017
11046
|
/* @__PURE__ */ jsxs74("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
11018
|
-
/* @__PURE__ */
|
|
11019
|
-
/* @__PURE__ */
|
|
11047
|
+
/* @__PURE__ */ jsx84("i", { className: "ph ph-lock-simple", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11048
|
+
/* @__PURE__ */ jsx84("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: title || "You do not have access to this" })
|
|
11020
11049
|
] }),
|
|
11021
|
-
/* @__PURE__ */
|
|
11050
|
+
/* @__PURE__ */ jsx84("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." }),
|
|
11022
11051
|
need.length ? /* @__PURE__ */ jsxs74("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap" }, children: [
|
|
11023
|
-
/* @__PURE__ */
|
|
11024
|
-
need.map((p) => /* @__PURE__ */
|
|
11052
|
+
/* @__PURE__ */ jsx84("span", { className: "fd-overline fd-muted", children: "Requires" }),
|
|
11053
|
+
need.map((p) => /* @__PURE__ */ jsx84("code", { className: "fd-mono", style: {
|
|
11025
11054
|
fontSize: 11.5,
|
|
11026
11055
|
padding: "2px 7px",
|
|
11027
11056
|
borderRadius: 5,
|
|
@@ -11051,10 +11080,10 @@ function GatePending({ compact: compact3 = false, className = "" }) {
|
|
|
11051
11080
|
},
|
|
11052
11081
|
children: [
|
|
11053
11082
|
/* @__PURE__ */ jsxs74("span", { className: "fd-row", style: { gap: 8 }, children: [
|
|
11054
|
-
/* @__PURE__ */
|
|
11055
|
-
/* @__PURE__ */
|
|
11083
|
+
/* @__PURE__ */ jsx84("i", { className: "ph ph-arrows-clockwise", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11084
|
+
/* @__PURE__ */ jsx84("span", { className: compact3 ? "fd-label-lg" : "fd-h3", children: "Reconnecting\u2026" })
|
|
11056
11085
|
] }),
|
|
11057
|
-
/* @__PURE__ */
|
|
11086
|
+
/* @__PURE__ */ jsx84("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." })
|
|
11058
11087
|
]
|
|
11059
11088
|
}
|
|
11060
11089
|
);
|
|
@@ -11064,7 +11093,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11064
11093
|
if (pending) {
|
|
11065
11094
|
if (pendingFallback !== void 0) return pendingFallback;
|
|
11066
11095
|
if (silent) return null;
|
|
11067
|
-
return /* @__PURE__ */
|
|
11096
|
+
return /* @__PURE__ */ jsx84(GatePending, { compact: compact3 });
|
|
11068
11097
|
}
|
|
11069
11098
|
let ok = true;
|
|
11070
11099
|
if (perm) ok = ok && can2(perm);
|
|
@@ -11073,7 +11102,7 @@ function Gate({ perm, anyOf, role, silent = false, fallback, pendingFallback, co
|
|
|
11073
11102
|
if (ok) return children;
|
|
11074
11103
|
if (fallback !== void 0) return fallback;
|
|
11075
11104
|
if (silent) return null;
|
|
11076
|
-
return /* @__PURE__ */
|
|
11105
|
+
return /* @__PURE__ */ jsx84(PermissionDenied, { permission: perm || anyOf, compact: compact3 });
|
|
11077
11106
|
}
|
|
11078
11107
|
function FeatureGate({
|
|
11079
11108
|
flag,
|
|
@@ -11096,7 +11125,7 @@ function FeatureGate({
|
|
|
11096
11125
|
const f = SessionKit.findFlag(flag) || {};
|
|
11097
11126
|
const missing = rt.missing || [];
|
|
11098
11127
|
const canBypass = pending ? false : bypassPerm === null ? false : !bypassPerm || can2(bypassPerm);
|
|
11099
|
-
return /* @__PURE__ */
|
|
11128
|
+
return /* @__PURE__ */ jsx84(
|
|
11100
11129
|
ComingSoon,
|
|
11101
11130
|
{
|
|
11102
11131
|
label: label || (variant === "inline" ? f.label || "Not wired yet" : "Designed \u2014 backend not wired yet"),
|
|
@@ -11117,22 +11146,22 @@ function FeatureGate({
|
|
|
11117
11146
|
function PermissionHint({ perm, children }) {
|
|
11118
11147
|
const { can: can2, pending } = useSessionContext();
|
|
11119
11148
|
if (pending) {
|
|
11120
|
-
return /* @__PURE__ */
|
|
11149
|
+
return /* @__PURE__ */ jsx84("span", { title: "Access can't be verified right now", style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" }, "aria-disabled": "true", children: /* @__PURE__ */ jsx84("span", { style: { pointerEvents: "none" }, children }) });
|
|
11121
11150
|
}
|
|
11122
11151
|
if (can2(perm)) return children;
|
|
11123
|
-
return /* @__PURE__ */
|
|
11152
|
+
return /* @__PURE__ */ jsx84(
|
|
11124
11153
|
"span",
|
|
11125
11154
|
{
|
|
11126
11155
|
title: "Requires " + (Array.isArray(perm) ? perm.join(", ") : perm),
|
|
11127
11156
|
style: { display: "inline-flex", opacity: 0.45, cursor: "not-allowed" },
|
|
11128
11157
|
"aria-disabled": "true",
|
|
11129
|
-
children: /* @__PURE__ */
|
|
11158
|
+
children: /* @__PURE__ */ jsx84("span", { style: { pointerEvents: "none" }, children })
|
|
11130
11159
|
}
|
|
11131
11160
|
);
|
|
11132
11161
|
}
|
|
11133
11162
|
|
|
11134
11163
|
// src/components/platform/ModeSwitch.tsx
|
|
11135
|
-
import { Fragment as Fragment23, jsx as
|
|
11164
|
+
import { Fragment as Fragment23, jsx as jsx85, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
11136
11165
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
11137
11166
|
const mode2 = useRuntimeMode();
|
|
11138
11167
|
const panel = useInlinePanel();
|
|
@@ -11155,15 +11184,15 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11155
11184
|
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.",
|
|
11156
11185
|
className: "fd-mode-btn" + (test ? " is-test" : "") + (open2 ? " is-open" : ""),
|
|
11157
11186
|
children: [
|
|
11158
|
-
/* @__PURE__ */
|
|
11159
|
-
test && requestCount ? /* @__PURE__ */
|
|
11187
|
+
/* @__PURE__ */ jsx85("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), style: { fontSize: 17 } }),
|
|
11188
|
+
test && requestCount ? /* @__PURE__ */ jsx85("span", { className: "fd-mono fd-mode-count", children: requestCount > 99 ? "99+" : requestCount }, requestCount) : null
|
|
11160
11189
|
]
|
|
11161
11190
|
}
|
|
11162
11191
|
),
|
|
11163
11192
|
/* @__PURE__ */ jsxs75(InlinePanelSurface, { panel, align: "right", offset: 8, width: 400, className: "fd-mode-pop", label: test ? "Test mode" : "Live mode", children: [
|
|
11164
11193
|
/* @__PURE__ */ jsxs75("span", { className: "fd-row", style: { gap: 10, padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
11165
11194
|
/* @__PURE__ */ jsxs75("span", { className: "fd-badge " + (test ? "fd-badge-warning" : "fd-badge-neutral"), children: [
|
|
11166
|
-
/* @__PURE__ */
|
|
11195
|
+
/* @__PURE__ */ jsx85("i", { className: "ph " + (test ? "ph-flask" : "ph-lightning"), "aria-hidden": "true" }),
|
|
11167
11196
|
test ? "Test mode" : "Live mode"
|
|
11168
11197
|
] }),
|
|
11169
11198
|
test ? /* @__PURE__ */ jsxs75("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
@@ -11171,11 +11200,11 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11171
11200
|
" simulated request",
|
|
11172
11201
|
requestCount === 1 ? "" : "s"
|
|
11173
11202
|
] }) : null,
|
|
11174
|
-
/* @__PURE__ */
|
|
11175
|
-
test && onClearLog ? /* @__PURE__ */
|
|
11203
|
+
/* @__PURE__ */ jsx85("span", { style: { flex: 1 } }),
|
|
11204
|
+
test && onClearLog ? /* @__PURE__ */ jsx85("button", { type: "button", className: "fd-soon-link", onClick: onClearLog, children: "Clear" }) : null
|
|
11176
11205
|
] }),
|
|
11177
11206
|
/* @__PURE__ */ jsxs75("span", { style: { display: "block", padding: "12px 14px", borderBottom: "1px solid var(--border)" }, children: [
|
|
11178
|
-
/* @__PURE__ */
|
|
11207
|
+
/* @__PURE__ */ jsx85("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." }),
|
|
11179
11208
|
/* @__PURE__ */ jsxs75("span", { className: "fd-row", style: { gap: 8, marginTop: 10, flexWrap: "wrap" }, children: [
|
|
11180
11209
|
/* @__PURE__ */ jsxs75("span", { className: "fd-body-sm fd-muted fd-mono", children: [
|
|
11181
11210
|
s.endpointsWired,
|
|
@@ -11188,36 +11217,36 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
11188
11217
|
" features complete"
|
|
11189
11218
|
] }),
|
|
11190
11219
|
onOpenSpec ? /* @__PURE__ */ jsxs75(Fragment23, { children: [
|
|
11191
|
-
/* @__PURE__ */
|
|
11220
|
+
/* @__PURE__ */ jsx85("span", { style: { flex: 1 } }),
|
|
11192
11221
|
/* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
11193
11222
|
setOpen(false);
|
|
11194
11223
|
onOpenSpec();
|
|
11195
11224
|
}, children: [
|
|
11196
11225
|
"API spec ",
|
|
11197
|
-
/* @__PURE__ */
|
|
11226
|
+
/* @__PURE__ */ jsx85("i", { className: "ph ph-arrow-right", "aria-hidden": "true" })
|
|
11198
11227
|
] })
|
|
11199
11228
|
] }) : null
|
|
11200
11229
|
] })
|
|
11201
11230
|
] }),
|
|
11202
11231
|
/* @__PURE__ */ jsxs75("span", { className: "fd-mode-choice", children: [
|
|
11203
11232
|
/* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-mode-opt" + (!test ? " is-on" : ""), onClick: () => go("live"), children: [
|
|
11204
|
-
/* @__PURE__ */
|
|
11233
|
+
/* @__PURE__ */ jsx85("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
11205
11234
|
/* @__PURE__ */ jsxs75("span", { className: "fd-mode-opt-text", children: [
|
|
11206
|
-
/* @__PURE__ */
|
|
11207
|
-
/* @__PURE__ */
|
|
11235
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-mode-opt-title", children: "Live mode" }),
|
|
11236
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-mode-opt-desc", children: "Incomplete features under construction" })
|
|
11208
11237
|
] }),
|
|
11209
|
-
!test ? /* @__PURE__ */
|
|
11238
|
+
!test ? /* @__PURE__ */ jsx85("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11210
11239
|
] }),
|
|
11211
11240
|
/* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-mode-opt" + (test ? " is-on" : ""), onClick: () => go("test"), children: [
|
|
11212
|
-
/* @__PURE__ */
|
|
11241
|
+
/* @__PURE__ */ jsx85("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
11213
11242
|
/* @__PURE__ */ jsxs75("span", { className: "fd-mode-opt-text", children: [
|
|
11214
|
-
/* @__PURE__ */
|
|
11215
|
-
/* @__PURE__ */
|
|
11243
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-mode-opt-title", children: "Test mode" }),
|
|
11244
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-mode-opt-desc", children: "Everything usable, all data simulated" })
|
|
11216
11245
|
] }),
|
|
11217
|
-
test ? /* @__PURE__ */
|
|
11246
|
+
test ? /* @__PURE__ */ jsx85("i", { className: "ph ph-check", "aria-hidden": "true" }) : null
|
|
11218
11247
|
] })
|
|
11219
11248
|
] }),
|
|
11220
|
-
test && renderLog ? /* @__PURE__ */
|
|
11249
|
+
test && renderLog ? /* @__PURE__ */ jsx85("span", { style: { display: "block", maxHeight: 340, overflowY: "auto", borderTop: "1px solid var(--border)" }, children: renderLog() }) : null
|
|
11221
11250
|
] })
|
|
11222
11251
|
] });
|
|
11223
11252
|
}
|
|
@@ -11226,19 +11255,19 @@ function TestModeBar({ onExit }) {
|
|
|
11226
11255
|
if (mode2 !== "test") return null;
|
|
11227
11256
|
return /* @__PURE__ */ jsxs75("div", { className: "fd-testbar", role: "status", children: [
|
|
11228
11257
|
/* @__PURE__ */ jsxs75("span", { className: "fd-badge fd-badge-warning", children: [
|
|
11229
|
-
/* @__PURE__ */
|
|
11258
|
+
/* @__PURE__ */ jsx85("i", { className: "ph ph-flask", "aria-hidden": "true" }),
|
|
11230
11259
|
"Test mode"
|
|
11231
11260
|
] }),
|
|
11232
|
-
/* @__PURE__ */
|
|
11261
|
+
/* @__PURE__ */ jsx85("span", { className: "fd-testbar-detail", children: "Every feature is unlocked and every response is simulated \u2014 nothing here persists." }),
|
|
11233
11262
|
/* @__PURE__ */ jsxs75("button", { type: "button", className: "fd-soon-link", onClick: () => onExit ? onExit() : RuntimeKit.setMode("live"), children: [
|
|
11234
|
-
/* @__PURE__ */
|
|
11263
|
+
/* @__PURE__ */ jsx85("i", { className: "ph ph-lightning", "aria-hidden": "true" }),
|
|
11235
11264
|
" Back to live mode"
|
|
11236
11265
|
] })
|
|
11237
11266
|
] });
|
|
11238
11267
|
}
|
|
11239
11268
|
|
|
11240
11269
|
// src/components/planner/ChannelMeta.tsx
|
|
11241
|
-
import { jsx as
|
|
11270
|
+
import { jsx as jsx86, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
11242
11271
|
var CHANNEL_WEIGHTS = {
|
|
11243
11272
|
"OOH": 50,
|
|
11244
11273
|
"DOOH": 50,
|
|
@@ -11291,7 +11320,7 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11291
11320
|
const m = ChannelMeta(channel);
|
|
11292
11321
|
const wt = channelWeightOf(channel || "");
|
|
11293
11322
|
if (dot) {
|
|
11294
|
-
return /* @__PURE__ */
|
|
11323
|
+
return /* @__PURE__ */ jsx86("span", { className: ["fd-chan-dot", className].filter(Boolean).join(" "), title: m.name, style: { background: m.color }, ...rest });
|
|
11295
11324
|
}
|
|
11296
11325
|
return /* @__PURE__ */ jsxs76(
|
|
11297
11326
|
"span",
|
|
@@ -11301,16 +11330,16 @@ function ChannelTag({ channel, size = "md", showLabel = true, dot = false, weigh
|
|
|
11301
11330
|
style: { "--chan": m.color },
|
|
11302
11331
|
...rest,
|
|
11303
11332
|
children: [
|
|
11304
|
-
/* @__PURE__ */
|
|
11305
|
-
showLabel ? /* @__PURE__ */
|
|
11306
|
-
weight ? /* @__PURE__ */
|
|
11333
|
+
/* @__PURE__ */ jsx86("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }),
|
|
11334
|
+
showLabel ? /* @__PURE__ */ jsx86("span", { className: "fd-chan-label", children: m.label }) : null,
|
|
11335
|
+
weight ? /* @__PURE__ */ jsx86("span", { className: "fd-chan-weight", children: wt || 0 }) : null
|
|
11307
11336
|
]
|
|
11308
11337
|
}
|
|
11309
11338
|
);
|
|
11310
11339
|
}
|
|
11311
11340
|
|
|
11312
11341
|
// src/components/planner/SaturationDistribution.tsx
|
|
11313
|
-
import { jsx as
|
|
11342
|
+
import { jsx as jsx87, jsxs as jsxs77 } from "react/jsx-runtime";
|
|
11314
11343
|
var BANDS2 = [
|
|
11315
11344
|
{ key: "weak", label: "Weak", n: 1, range: "< 50" },
|
|
11316
11345
|
{ key: "adequate", label: "Adequate", n: 2, range: "50\u2013100" },
|
|
@@ -11322,7 +11351,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11322
11351
|
const tallest = Math.max(1, ...grouped.map((g) => g.items.length));
|
|
11323
11352
|
const floor = BANDS2.find((b) => b.key === floorBand) || BANDS2[0];
|
|
11324
11353
|
return /* @__PURE__ */ jsxs77("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
11325
|
-
/* @__PURE__ */
|
|
11354
|
+
/* @__PURE__ */ jsx87("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,minmax(0,1fr))", gap: 12, alignItems: "end" }, children: grouped.map((g) => {
|
|
11326
11355
|
const mark = "var(--csi-" + g.n + "-mark)";
|
|
11327
11356
|
const active = selectedBand === g.key;
|
|
11328
11357
|
return /* @__PURE__ */ jsxs77(
|
|
@@ -11332,13 +11361,13 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11332
11361
|
onClick: onSelectBand ? () => onSelectBand(active ? null : g.key) : void 0,
|
|
11333
11362
|
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)" },
|
|
11334
11363
|
children: [
|
|
11335
|
-
/* @__PURE__ */
|
|
11364
|
+
/* @__PURE__ */ jsx87("span", { style: { display: "flex", flexDirection: "column-reverse", gap: 4, minHeight: tallest * 24, minWidth: 0 }, children: loading ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx87("span", { className: "fd-skel", style: { height: 16, borderRadius: 4 } }, i)) : g.items.map((c) => (
|
|
11336
11365
|
// `overflow: hidden` + `white-space: nowrap` only clips once the span
|
|
11337
11366
|
// actually HAS a bounded width to clip against (see the grid/flex
|
|
11338
11367
|
// `minWidth: 0` chain above) — `textOverflow: ellipsis` then makes
|
|
11339
11368
|
// that clip readable instead of a hard cut mid-letter; the full name
|
|
11340
11369
|
// is still one hover away via `title`.
|
|
11341
|
-
/* @__PURE__ */
|
|
11370
|
+
/* @__PURE__ */ jsx87(
|
|
11342
11371
|
"span",
|
|
11343
11372
|
{
|
|
11344
11373
|
title: c.name + " \xB7 " + c.crp,
|
|
@@ -11349,11 +11378,11 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11349
11378
|
)
|
|
11350
11379
|
)) }),
|
|
11351
11380
|
/* @__PURE__ */ jsxs77("span", { className: "fd-row", style: { gap: 8, alignItems: "baseline" }, children: [
|
|
11352
|
-
/* @__PURE__ */
|
|
11353
|
-
/* @__PURE__ */
|
|
11381
|
+
/* @__PURE__ */ jsx87("span", { className: "fd-num-hero", style: { fontSize: 30, color: g.items.length ? "var(--text)" : "var(--text-disabled)" }, children: loading ? "\u2013" : g.items.length }),
|
|
11382
|
+
/* @__PURE__ */ jsx87("span", { className: "fd-meter", style: { gap: 2, color: mark }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx87("span", { className: "fd-meter-seg" + (i <= g.n ? " is-on" : ""), style: { width: 4, height: 9 } }, i)) })
|
|
11354
11383
|
] }),
|
|
11355
11384
|
/* @__PURE__ */ jsxs77("span", { className: "fd-stack", style: { gap: 1 }, children: [
|
|
11356
|
-
/* @__PURE__ */
|
|
11385
|
+
/* @__PURE__ */ jsx87("span", { className: "fd-label-lg", children: g.label }),
|
|
11357
11386
|
/* @__PURE__ */ jsxs77("span", { className: "fd-body-sm fd-muted", style: { fontSize: 11.5 }, children: [
|
|
11358
11387
|
"CRP ",
|
|
11359
11388
|
g.range
|
|
@@ -11365,7 +11394,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11365
11394
|
);
|
|
11366
11395
|
}) }),
|
|
11367
11396
|
floorBand ? /* @__PURE__ */ jsxs77("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: [
|
|
11368
|
-
/* @__PURE__ */
|
|
11397
|
+
/* @__PURE__ */ jsx87("span", { className: "fd-meter", style: { gap: 2, color: "var(--csi-" + floor.n + "-mark)" }, "aria-hidden": "true", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx87("span", { className: "fd-meter-seg" + (i <= floor.n ? " is-on" : ""), style: { width: 5, height: 12 } }, i)) }),
|
|
11369
11398
|
/* @__PURE__ */ jsxs77("span", { className: "fd-body-sm fd-secondary", style: { flex: 1, minWidth: 240 }, children: [
|
|
11370
11399
|
/* @__PURE__ */ jsxs77("strong", { style: { color: "var(--text)" }, children: [
|
|
11371
11400
|
"Plan floor ",
|
|
@@ -11378,8 +11407,8 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
11378
11407
|
}
|
|
11379
11408
|
|
|
11380
11409
|
// src/components/planner/MixGap.tsx
|
|
11381
|
-
import * as
|
|
11382
|
-
import { Fragment as Fragment24, jsx as
|
|
11410
|
+
import * as React61 from "react";
|
|
11411
|
+
import { Fragment as Fragment24, jsx as jsx88, jsxs as jsxs78 } from "react/jsx-runtime";
|
|
11383
11412
|
var MIX_GAP_LAYOUT = {
|
|
11384
11413
|
trackHeight: 30,
|
|
11385
11414
|
barHeight: 20,
|
|
@@ -11393,7 +11422,7 @@ function mixGapOffset(value, max) {
|
|
|
11393
11422
|
}
|
|
11394
11423
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
11395
11424
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
11396
|
-
const [hover, setHover] =
|
|
11425
|
+
const [hover, setHover] = React61.useState(null);
|
|
11397
11426
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
11398
11427
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
11399
11428
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
@@ -11401,11 +11430,11 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11401
11430
|
return /* @__PURE__ */ jsxs78("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
11402
11431
|
/* @__PURE__ */ jsxs78("div", { className: "fd-row", style: { gap: 16, justifyContent: "flex-end", paddingBottom: 6, flexWrap: "wrap" }, children: [
|
|
11403
11432
|
[["On target", TONE.ok], ["Close", TONE.warn], ["Short", TONE.danger]].map(([l, c]) => /* @__PURE__ */ jsxs78("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
11404
|
-
/* @__PURE__ */
|
|
11433
|
+
/* @__PURE__ */ jsx88("span", { style: { width: 14, height: 9, borderRadius: 2, background: c } }),
|
|
11405
11434
|
l
|
|
11406
11435
|
] }, l)),
|
|
11407
11436
|
/* @__PURE__ */ jsxs78("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: 6 }, children: [
|
|
11408
|
-
/* @__PURE__ */
|
|
11437
|
+
/* @__PURE__ */ jsx88("span", { "data-mixgap-legend-target": "", style: { width: targetWidth, height: 16, borderRadius: 1, background: MIX_GAP_TARGET_STRIPE } }),
|
|
11409
11438
|
"Target"
|
|
11410
11439
|
] })
|
|
11411
11440
|
] }),
|
|
@@ -11422,15 +11451,15 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11422
11451
|
onMouseEnter: () => setHover(r.channel),
|
|
11423
11452
|
onMouseLeave: () => setHover(null),
|
|
11424
11453
|
children: [
|
|
11425
|
-
/* @__PURE__ */
|
|
11426
|
-
/* @__PURE__ */
|
|
11427
|
-
/* @__PURE__ */
|
|
11428
|
-
/* @__PURE__ */
|
|
11454
|
+
/* @__PURE__ */ jsx88("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx88(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
11455
|
+
/* @__PURE__ */ jsx88("span", { style: { position: "relative", flex: 1, height: trackHeight, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx88("span", { className: "fd-skel", style: { position: "absolute", left: 0, right: 0, top: barTop, height: barHeight, borderRadius: 3 } }) : /* @__PURE__ */ jsxs78(Fragment24, { children: [
|
|
11456
|
+
/* @__PURE__ */ jsx88("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)" } }),
|
|
11457
|
+
/* @__PURE__ */ jsx88("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 } }),
|
|
11429
11458
|
/* @__PURE__ */ jsxs78("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: [
|
|
11430
11459
|
r.realized,
|
|
11431
11460
|
"%"
|
|
11432
11461
|
] }),
|
|
11433
|
-
hover === r.channel ? /* @__PURE__ */
|
|
11462
|
+
hover === r.channel ? /* @__PURE__ */ jsx88("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
|
|
11434
11463
|
] }) })
|
|
11435
11464
|
]
|
|
11436
11465
|
},
|
|
@@ -11441,7 +11470,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
11441
11470
|
}
|
|
11442
11471
|
|
|
11443
11472
|
// src/components/planner/ChannelContribution.tsx
|
|
11444
|
-
import { jsx as
|
|
11473
|
+
import { jsx as jsx89, jsxs as jsxs79 } from "react/jsx-runtime";
|
|
11445
11474
|
var money = (n) => "$" + Math.round(n).toLocaleString();
|
|
11446
11475
|
function ChannelContribution({
|
|
11447
11476
|
channels = [],
|
|
@@ -11458,8 +11487,8 @@ function ChannelContribution({
|
|
|
11458
11487
|
const pct = (v) => grand ? v / grand * 100 : 0;
|
|
11459
11488
|
const spendTotal = channels.reduce((s, c) => s + Number(String(c.spend || 0).replace(/[^0-9.]/g, "")), 0);
|
|
11460
11489
|
return /* @__PURE__ */ jsxs79("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 16 }, children: [
|
|
11461
|
-
loading ? /* @__PURE__ */
|
|
11462
|
-
channels.map((c) => /* @__PURE__ */
|
|
11490
|
+
loading ? /* @__PURE__ */ jsx89("span", { className: "fd-skel", style: { height: 34, borderRadius: "var(--r-sm)" } }) : /* @__PURE__ */ jsxs79("div", { className: "fd-row", style: { height: 34, borderRadius: "var(--r-sm)", overflow: "hidden", gap: 2, background: "var(--surface-3)" }, children: [
|
|
11491
|
+
channels.map((c) => /* @__PURE__ */ jsx89(
|
|
11463
11492
|
"span",
|
|
11464
11493
|
{
|
|
11465
11494
|
title: c.name + " \xB7 " + c.crp.toFixed(1) + " CRP",
|
|
@@ -11468,7 +11497,7 @@ function ChannelContribution({
|
|
|
11468
11497
|
},
|
|
11469
11498
|
c.name
|
|
11470
11499
|
)),
|
|
11471
|
-
bonus > 0 ? /* @__PURE__ */
|
|
11500
|
+
bonus > 0 ? /* @__PURE__ */ jsx89(
|
|
11472
11501
|
"span",
|
|
11473
11502
|
{
|
|
11474
11503
|
title: "Surround-sound bonus +" + bonusPct + "%",
|
|
@@ -11478,17 +11507,17 @@ function ChannelContribution({
|
|
|
11478
11507
|
) : null
|
|
11479
11508
|
] }),
|
|
11480
11509
|
showTable ? /* @__PURE__ */ jsxs79("table", { className: "fd-table", style: { fontSize: "var(--body-sm-size)" }, children: [
|
|
11481
|
-
/* @__PURE__ */
|
|
11482
|
-
/* @__PURE__ */
|
|
11483
|
-
/* @__PURE__ */
|
|
11484
|
-
/* @__PURE__ */
|
|
11485
|
-
/* @__PURE__ */
|
|
11486
|
-
/* @__PURE__ */
|
|
11510
|
+
/* @__PURE__ */ jsx89("thead", { children: /* @__PURE__ */ jsxs79("tr", { children: [
|
|
11511
|
+
/* @__PURE__ */ jsx89("th", { style: { width: "34%" }, children: "Channel" }),
|
|
11512
|
+
/* @__PURE__ */ jsx89("th", { style: { width: "16%" }, children: "Weight" }),
|
|
11513
|
+
/* @__PURE__ */ jsx89("th", { className: "is-num", style: { width: "16%" }, children: "Spend" }),
|
|
11514
|
+
/* @__PURE__ */ jsx89("th", { className: "is-num", style: { width: "17%" }, children: "CRP" }),
|
|
11515
|
+
/* @__PURE__ */ jsx89("th", { className: "is-num", style: { width: "17%" }, children: "Share" })
|
|
11487
11516
|
] }) }),
|
|
11488
11517
|
/* @__PURE__ */ jsxs79("tbody", { children: [
|
|
11489
11518
|
channels.map((c) => /* @__PURE__ */ jsxs79("tr", { children: [
|
|
11490
|
-
/* @__PURE__ */
|
|
11491
|
-
/* @__PURE__ */
|
|
11519
|
+
/* @__PURE__ */ jsx89("td", { children: /* @__PURE__ */ jsx89(ChannelTag, { channel: c.name, size: "sm" }) }),
|
|
11520
|
+
/* @__PURE__ */ jsx89("td", { children: /* @__PURE__ */ jsx89(
|
|
11492
11521
|
"span",
|
|
11493
11522
|
{
|
|
11494
11523
|
className: "fd-badge fd-badge-neutral",
|
|
@@ -11497,38 +11526,38 @@ function ChannelContribution({
|
|
|
11497
11526
|
children: "weight " + (channelWeightOf(c.name) || 0)
|
|
11498
11527
|
}
|
|
11499
11528
|
) }),
|
|
11500
|
-
/* @__PURE__ */
|
|
11501
|
-
/* @__PURE__ */
|
|
11529
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", children: c.spend }),
|
|
11530
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", children: c.crp.toFixed(1) }),
|
|
11502
11531
|
/* @__PURE__ */ jsxs79("td", { className: "is-num", children: [
|
|
11503
11532
|
pct(c.crp).toFixed(0),
|
|
11504
11533
|
"%"
|
|
11505
11534
|
] })
|
|
11506
11535
|
] }, c.name)),
|
|
11507
11536
|
bonus > 0 ? /* @__PURE__ */ jsxs79("tr", { children: [
|
|
11508
|
-
/* @__PURE__ */
|
|
11509
|
-
/* @__PURE__ */
|
|
11537
|
+
/* @__PURE__ */ jsx89("td", { children: /* @__PURE__ */ jsxs79("span", { className: "fd-row", style: { gap: 9, fontWeight: 600 }, children: [
|
|
11538
|
+
/* @__PURE__ */ jsx89("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" } }),
|
|
11510
11539
|
"Surround-sound bonus"
|
|
11511
11540
|
] }) }),
|
|
11512
|
-
/* @__PURE__ */
|
|
11541
|
+
/* @__PURE__ */ jsx89("td", { children: /* @__PURE__ */ jsxs79("span", { className: "fd-badge fd-badge-success", style: { height: 20, fontSize: 11 }, children: [
|
|
11513
11542
|
"+",
|
|
11514
11543
|
bonusPct,
|
|
11515
11544
|
"% of +",
|
|
11516
11545
|
bonusMax,
|
|
11517
11546
|
"%"
|
|
11518
11547
|
] }) }),
|
|
11519
|
-
/* @__PURE__ */
|
|
11520
|
-
/* @__PURE__ */
|
|
11548
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num fd-muted", children: "\u2014" }),
|
|
11549
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", children: bonus.toFixed(1) }),
|
|
11521
11550
|
/* @__PURE__ */ jsxs79("td", { className: "is-num", children: [
|
|
11522
11551
|
pct(bonus).toFixed(0),
|
|
11523
11552
|
"%"
|
|
11524
11553
|
] })
|
|
11525
11554
|
] }) : null,
|
|
11526
11555
|
/* @__PURE__ */ jsxs79("tr", { style: { background: "var(--surface-2)" }, children: [
|
|
11527
|
-
/* @__PURE__ */
|
|
11528
|
-
/* @__PURE__ */
|
|
11529
|
-
/* @__PURE__ */
|
|
11530
|
-
/* @__PURE__ */
|
|
11531
|
-
/* @__PURE__ */
|
|
11556
|
+
/* @__PURE__ */ jsx89("td", { style: { fontWeight: 700 }, children: "Campus total" }),
|
|
11557
|
+
/* @__PURE__ */ jsx89("td", {}),
|
|
11558
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", style: { fontWeight: 700 }, children: money(spendTotal) }),
|
|
11559
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", style: { fontWeight: 700 }, children: grand.toFixed(1) }),
|
|
11560
|
+
/* @__PURE__ */ jsx89("td", { className: "is-num", style: { fontWeight: 700 }, children: "100%" })
|
|
11532
11561
|
] })
|
|
11533
11562
|
] })
|
|
11534
11563
|
] }) : null
|
|
@@ -11536,8 +11565,8 @@ function ChannelContribution({
|
|
|
11536
11565
|
}
|
|
11537
11566
|
|
|
11538
11567
|
// src/components/planner/BudgetReallocator.tsx
|
|
11539
|
-
import * as
|
|
11540
|
-
import { Fragment as Fragment25, jsx as
|
|
11568
|
+
import * as React62 from "react";
|
|
11569
|
+
import { Fragment as Fragment25, jsx as jsx90, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
11541
11570
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
11542
11571
|
function BudgetReallocator({
|
|
11543
11572
|
campus,
|
|
@@ -11552,8 +11581,8 @@ function BudgetReallocator({
|
|
|
11552
11581
|
onCancel,
|
|
11553
11582
|
className = ""
|
|
11554
11583
|
}) {
|
|
11555
|
-
const [draft, setDraft] =
|
|
11556
|
-
|
|
11584
|
+
const [draft, setDraft] = React62.useState(spend);
|
|
11585
|
+
React62.useEffect(() => setDraft(spend), [spend]);
|
|
11557
11586
|
const dirty = draft !== spend;
|
|
11558
11587
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
11559
11588
|
const nextBand = bandFor(nextCrp);
|
|
@@ -11568,10 +11597,10 @@ function BudgetReallocator({
|
|
|
11568
11597
|
setDraft(spend);
|
|
11569
11598
|
if (onCancel) onCancel();
|
|
11570
11599
|
};
|
|
11571
|
-
const trackRef =
|
|
11572
|
-
const chipRef =
|
|
11573
|
-
const [chipLeft, setChipLeft] =
|
|
11574
|
-
|
|
11600
|
+
const trackRef = React62.useRef(null);
|
|
11601
|
+
const chipRef = React62.useRef(null);
|
|
11602
|
+
const [chipLeft, setChipLeft] = React62.useState(null);
|
|
11603
|
+
React62.useLayoutEffect(() => {
|
|
11575
11604
|
const track = trackRef.current;
|
|
11576
11605
|
if (!dirty || !track) {
|
|
11577
11606
|
setChipLeft(null);
|
|
@@ -11599,16 +11628,16 @@ function BudgetReallocator({
|
|
|
11599
11628
|
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)" },
|
|
11600
11629
|
children: [
|
|
11601
11630
|
/* @__PURE__ */ jsxs80("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
11602
|
-
/* @__PURE__ */
|
|
11603
|
-
/* @__PURE__ */
|
|
11631
|
+
/* @__PURE__ */ jsx90("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
11632
|
+
/* @__PURE__ */ jsx90(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
11604
11633
|
dirty ? /* @__PURE__ */ jsxs80(Fragment25, { children: [
|
|
11605
|
-
/* @__PURE__ */
|
|
11606
|
-
/* @__PURE__ */
|
|
11634
|
+
/* @__PURE__ */ jsx90("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
11635
|
+
/* @__PURE__ */ jsx90(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
11607
11636
|
] }) : null
|
|
11608
11637
|
] }),
|
|
11609
11638
|
/* @__PURE__ */ jsxs80("div", { className: "fd-slider", ref: trackRef, children: [
|
|
11610
|
-
/* @__PURE__ */
|
|
11611
|
-
dirty ? /* @__PURE__ */
|
|
11639
|
+
/* @__PURE__ */ jsx90("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
11640
|
+
dirty ? /* @__PURE__ */ jsx90(
|
|
11612
11641
|
"span",
|
|
11613
11642
|
{
|
|
11614
11643
|
ref: chipRef,
|
|
@@ -11620,7 +11649,7 @@ function BudgetReallocator({
|
|
|
11620
11649
|
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
11621
11650
|
}
|
|
11622
11651
|
) : null,
|
|
11623
|
-
/* @__PURE__ */
|
|
11652
|
+
/* @__PURE__ */ jsx90(
|
|
11624
11653
|
"input",
|
|
11625
11654
|
{
|
|
11626
11655
|
type: "range",
|
|
@@ -11638,11 +11667,11 @@ function BudgetReallocator({
|
|
|
11638
11667
|
] }),
|
|
11639
11668
|
/* @__PURE__ */ jsxs80("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
11640
11669
|
/* @__PURE__ */ jsxs80("span", { className: "fd-stack", style: { gap: 2, flex: 1, minWidth: 150 }, children: [
|
|
11641
|
-
/* @__PURE__ */
|
|
11642
|
-
/* @__PURE__ */
|
|
11670
|
+
/* @__PURE__ */ jsx90("span", { className: "fd-num", style: { fontSize: 19, fontWeight: 700 }, children: "$" + draft.toLocaleString() }),
|
|
11671
|
+
/* @__PURE__ */ jsx90("span", { className: "fd-body-sm fd-muted", children: "Arrow keys step $100, shift+arrow $1,000. Escape reverts." })
|
|
11643
11672
|
] }),
|
|
11644
|
-
/* @__PURE__ */
|
|
11645
|
-
/* @__PURE__ */
|
|
11673
|
+
/* @__PURE__ */ jsx90("button", { type: "button", className: "fd-btn fd-btn-ghost", disabled: !dirty, onClick: revert, children: "Cancel" }),
|
|
11674
|
+
/* @__PURE__ */ jsx90(
|
|
11646
11675
|
"button",
|
|
11647
11676
|
{
|
|
11648
11677
|
type: "button",
|
|
@@ -11661,7 +11690,7 @@ function BudgetReallocator({
|
|
|
11661
11690
|
}
|
|
11662
11691
|
|
|
11663
11692
|
// src/components/planner/SurroundSound.tsx
|
|
11664
|
-
import { jsx as
|
|
11693
|
+
import { jsx as jsx91, jsxs as jsxs81 } from "react/jsx-runtime";
|
|
11665
11694
|
var CATEGORIES = [
|
|
11666
11695
|
{ key: "ooh", label: "OOH", icon: "flag-banner", color: "var(--ch-ooh)" },
|
|
11667
11696
|
{ key: "transit", label: "Transit", icon: "bus", color: "var(--ch-transit)" },
|
|
@@ -11674,7 +11703,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11674
11703
|
const earned = Math.max(0, Math.min(1, bonusPct / bonusMax));
|
|
11675
11704
|
const single = present.length <= 2;
|
|
11676
11705
|
return /* @__PURE__ */ jsxs81("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 14 }, children: [
|
|
11677
|
-
/* @__PURE__ */
|
|
11706
|
+
/* @__PURE__ */ jsx91("div", { className: "fd-row", style: { gap: 8, flexWrap: "wrap" }, children: CATEGORIES.map((c) => {
|
|
11678
11707
|
const on = present.includes(c.key);
|
|
11679
11708
|
return /* @__PURE__ */ jsxs81(
|
|
11680
11709
|
"span",
|
|
@@ -11682,8 +11711,8 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11682
11711
|
title: c.label + (on ? " \u2014 present" : " \u2014 not bought"),
|
|
11683
11712
|
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)" },
|
|
11684
11713
|
children: [
|
|
11685
|
-
/* @__PURE__ */
|
|
11686
|
-
/* @__PURE__ */
|
|
11714
|
+
/* @__PURE__ */ jsx91("i", { className: "ph ph-" + c.icon, style: { fontSize: 19, color: on ? c.color : "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
11715
|
+
/* @__PURE__ */ jsx91("span", { style: { fontSize: 10.5, fontWeight: 700 }, children: c.label })
|
|
11687
11716
|
]
|
|
11688
11717
|
},
|
|
11689
11718
|
c.key
|
|
@@ -11691,7 +11720,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11691
11720
|
}) }),
|
|
11692
11721
|
/* @__PURE__ */ jsxs81("div", { className: "fd-stack", style: { gap: 8 }, children: [
|
|
11693
11722
|
/* @__PURE__ */ jsxs81("div", { className: "fd-row", style: { justifyContent: "space-between", gap: 12 }, children: [
|
|
11694
|
-
/* @__PURE__ */
|
|
11723
|
+
/* @__PURE__ */ jsx91("span", { className: "fd-label-lg", children: "Surround-sound bonus earned" }),
|
|
11695
11724
|
/* @__PURE__ */ jsxs81("span", { className: "fd-num", style: { color: single ? "var(--warn-text)" : "var(--csi-3-mark)", fontWeight: 700 }, children: [
|
|
11696
11725
|
"+",
|
|
11697
11726
|
bonusPct,
|
|
@@ -11700,7 +11729,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11700
11729
|
"%"
|
|
11701
11730
|
] })
|
|
11702
11731
|
] }),
|
|
11703
|
-
/* @__PURE__ */
|
|
11732
|
+
/* @__PURE__ */ jsx91("div", { style: { height: 8, borderRadius: "var(--r-xs)", background: "var(--surface-3)", overflow: "hidden" }, children: /* @__PURE__ */ jsx91("div", { style: { height: "100%", width: earned * 100 + "%", background: "var(--csi-3-mark)", borderRadius: "inherit", transition: "width var(--dur-slow) var(--ease)" } }) }),
|
|
11704
11733
|
/* @__PURE__ */ jsxs81("span", { className: "fd-body-sm fd-secondary", style: { textWrap: "pretty" }, children: [
|
|
11705
11734
|
present.length,
|
|
11706
11735
|
" of 6 channel categories present.",
|
|
@@ -11713,7 +11742,7 @@ function SurroundSound({ present = [], bonusPct = 0, bonusMax = 40, missedCost,
|
|
|
11713
11742
|
}
|
|
11714
11743
|
|
|
11715
11744
|
// src/components/planner/Importance.tsx
|
|
11716
|
-
import { jsx as
|
|
11745
|
+
import { jsx as jsx92, jsxs as jsxs82 } from "react/jsx-runtime";
|
|
11717
11746
|
var IMPORTANCE_LEVELS = [
|
|
11718
11747
|
{ id: "nudge", rank: 1, label: "Nudge", icon: "feather", description: "Breaks a tie, nothing more." },
|
|
11719
11748
|
{ id: "lean", rank: 2, label: "Lean", icon: "arrow-bend-up-right", description: "A mild preference between otherwise equal options." },
|
|
@@ -11751,16 +11780,16 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
|
|
|
11751
11780
|
title: lvl.label + " \u2014 " + lvl.description,
|
|
11752
11781
|
"aria-disabled": disabled ? "true" : void 0,
|
|
11753
11782
|
children: [
|
|
11754
|
-
/* @__PURE__ */
|
|
11755
|
-
showLabel ? lvl.label : /* @__PURE__ */
|
|
11783
|
+
/* @__PURE__ */ jsx92("i", { className: "ph ph-" + lvl.icon, "aria-hidden": "true" }),
|
|
11784
|
+
showLabel ? lvl.label : /* @__PURE__ */ jsx92("span", { className: "fd-sr", children: lvl.label })
|
|
11756
11785
|
]
|
|
11757
11786
|
}
|
|
11758
11787
|
);
|
|
11759
11788
|
}
|
|
11760
11789
|
|
|
11761
11790
|
// src/components/planner/PreferenceMeter.tsx
|
|
11762
|
-
import * as
|
|
11763
|
-
import { jsx as
|
|
11791
|
+
import * as React63 from "react";
|
|
11792
|
+
import { jsx as jsx93, jsxs as jsxs83 } from "react/jsx-runtime";
|
|
11764
11793
|
function preferenceScore(criteria) {
|
|
11765
11794
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
11766
11795
|
const weight = criteria.reduce((n, c) => n + (Number(c.weight) || 0), 0);
|
|
@@ -11789,8 +11818,8 @@ function PreferenceMeter({
|
|
|
11789
11818
|
className = ""
|
|
11790
11819
|
}) {
|
|
11791
11820
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
11792
|
-
const segments =
|
|
11793
|
-
return /* @__PURE__ */
|
|
11821
|
+
const segments = React63.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
11822
|
+
return /* @__PURE__ */ jsx93(
|
|
11794
11823
|
ScoreMeter,
|
|
11795
11824
|
{
|
|
11796
11825
|
score: value,
|
|
@@ -11804,20 +11833,20 @@ function PreferenceMeter({
|
|
|
11804
11833
|
breakdownLabel: breakdownTitle,
|
|
11805
11834
|
breakdown: /* @__PURE__ */ jsxs83("div", { className: "fd-prefbreak", children: [
|
|
11806
11835
|
/* @__PURE__ */ jsxs83("div", { className: "fd-prefbreak-head", children: [
|
|
11807
|
-
/* @__PURE__ */
|
|
11808
|
-
/* @__PURE__ */
|
|
11836
|
+
/* @__PURE__ */ jsx93("span", { className: "fd-label-lg", children: breakdownTitle }),
|
|
11837
|
+
/* @__PURE__ */ jsx93("span", { className: "fd-prefbreak-score fd-tabular", children: Math.round(value) })
|
|
11809
11838
|
] }),
|
|
11810
|
-
/* @__PURE__ */
|
|
11839
|
+
/* @__PURE__ */ jsx93("ul", { className: "fd-prefbreak-list", children: criteria.map((c) => {
|
|
11811
11840
|
const pct = c.weight > 0 ? Math.round((Number(c.earned) || 0) / c.weight * 100) : 0;
|
|
11812
11841
|
return /* @__PURE__ */ jsxs83("li", { className: pct === 0 ? "fd-prefbreak-item is-unmet" : "fd-prefbreak-item", children: [
|
|
11813
|
-
/* @__PURE__ */
|
|
11842
|
+
/* @__PURE__ */ jsx93(ImportanceTag, { level: c.importance }),
|
|
11814
11843
|
/* @__PURE__ */ jsxs83("span", { className: "fd-prefbreak-text", children: [
|
|
11815
|
-
/* @__PURE__ */
|
|
11816
|
-
c.note ? /* @__PURE__ */
|
|
11844
|
+
/* @__PURE__ */ jsx93("span", { className: "fd-prefbreak-label", children: c.label }),
|
|
11845
|
+
c.note ? /* @__PURE__ */ jsx93("span", { className: "fd-prefbreak-note", children: c.note }) : null
|
|
11817
11846
|
] }),
|
|
11818
11847
|
/* @__PURE__ */ jsxs83("span", { className: "fd-prefbreak-val fd-tabular", children: [
|
|
11819
11848
|
Math.round(Number(c.earned) || 0),
|
|
11820
|
-
/* @__PURE__ */
|
|
11849
|
+
/* @__PURE__ */ jsx93("span", { className: "fd-prefbreak-sep", children: "/" }),
|
|
11821
11850
|
Math.round(c.weight)
|
|
11822
11851
|
] })
|
|
11823
11852
|
] }, c.id);
|
|
@@ -11828,10 +11857,10 @@ function PreferenceMeter({
|
|
|
11828
11857
|
}
|
|
11829
11858
|
|
|
11830
11859
|
// src/components/chat/AgentChatPanel.tsx
|
|
11831
|
-
import * as
|
|
11860
|
+
import * as React69 from "react";
|
|
11832
11861
|
|
|
11833
11862
|
// src/components/chat/chatEngine.ts
|
|
11834
|
-
import * as
|
|
11863
|
+
import * as React64 from "react";
|
|
11835
11864
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
11836
11865
|
var JOB_PENDING = ["queued", "running"];
|
|
11837
11866
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -11885,22 +11914,22 @@ function useChatEngine(opts) {
|
|
|
11885
11914
|
onClear,
|
|
11886
11915
|
onFeedback
|
|
11887
11916
|
} = opts || {};
|
|
11888
|
-
const [status, setStatus] =
|
|
11889
|
-
const [threadId, setThreadId] =
|
|
11890
|
-
const [messages, setMessages] =
|
|
11891
|
-
const [queue, setQueue] =
|
|
11892
|
-
const [fatal, setFatal] =
|
|
11893
|
-
const [busy, setBusy] =
|
|
11894
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
11895
|
-
const listRef =
|
|
11896
|
-
const queueRef =
|
|
11897
|
-
const busyRef =
|
|
11898
|
-
const stoppedRef =
|
|
11899
|
-
const abortRef =
|
|
11900
|
-
const serverCount =
|
|
11901
|
-
const threadRef =
|
|
11902
|
-
const mounted =
|
|
11903
|
-
|
|
11917
|
+
const [status, setStatus] = React64.useState("idle");
|
|
11918
|
+
const [threadId, setThreadId] = React64.useState(null);
|
|
11919
|
+
const [messages, setMessages] = React64.useState([]);
|
|
11920
|
+
const [queue, setQueue] = React64.useState([]);
|
|
11921
|
+
const [fatal, setFatal] = React64.useState(null);
|
|
11922
|
+
const [busy, setBusy] = React64.useState(false);
|
|
11923
|
+
const [turnStartedAt, setTurnStartedAt] = React64.useState(null);
|
|
11924
|
+
const listRef = React64.useRef([]);
|
|
11925
|
+
const queueRef = React64.useRef([]);
|
|
11926
|
+
const busyRef = React64.useRef(false);
|
|
11927
|
+
const stoppedRef = React64.useRef(false);
|
|
11928
|
+
const abortRef = React64.useRef(null);
|
|
11929
|
+
const serverCount = React64.useRef(0);
|
|
11930
|
+
const threadRef = React64.useRef(null);
|
|
11931
|
+
const mounted = React64.useRef(true);
|
|
11932
|
+
React64.useEffect(() => {
|
|
11904
11933
|
mounted.current = true;
|
|
11905
11934
|
return () => {
|
|
11906
11935
|
mounted.current = false;
|
|
@@ -11922,14 +11951,14 @@ function useChatEngine(opts) {
|
|
|
11922
11951
|
}
|
|
11923
11952
|
return false;
|
|
11924
11953
|
};
|
|
11925
|
-
const loadThread =
|
|
11954
|
+
const loadThread = React64.useCallback(async (id) => {
|
|
11926
11955
|
const data = await apiAdapter.getThread(id);
|
|
11927
11956
|
const list = [...data && data.messages || []];
|
|
11928
11957
|
serverCount.current = list.length;
|
|
11929
11958
|
commit(list);
|
|
11930
11959
|
return list;
|
|
11931
11960
|
}, [apiAdapter]);
|
|
11932
|
-
|
|
11961
|
+
React64.useEffect(() => {
|
|
11933
11962
|
if (!apiAdapter) {
|
|
11934
11963
|
setStatus("idle");
|
|
11935
11964
|
setFatal(null);
|
|
@@ -12142,7 +12171,7 @@ function useChatEngine(opts) {
|
|
|
12142
12171
|
await dispatchTurn(turn);
|
|
12143
12172
|
}
|
|
12144
12173
|
}
|
|
12145
|
-
const send =
|
|
12174
|
+
const send = React64.useCallback((text, attachments) => {
|
|
12146
12175
|
const body = (text || "").trim();
|
|
12147
12176
|
if (!body && !(attachments && attachments.length)) return;
|
|
12148
12177
|
if (status === "disconnected") return;
|
|
@@ -12152,7 +12181,7 @@ function useChatEngine(opts) {
|
|
|
12152
12181
|
stoppedRef.current = false;
|
|
12153
12182
|
drain();
|
|
12154
12183
|
}, [status]);
|
|
12155
|
-
const stop =
|
|
12184
|
+
const stop = React64.useCallback(() => {
|
|
12156
12185
|
stoppedRef.current = true;
|
|
12157
12186
|
const ac = abortRef.current;
|
|
12158
12187
|
if (ac) {
|
|
@@ -12171,11 +12200,11 @@ function useChatEngine(opts) {
|
|
|
12171
12200
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
12172
12201
|
}
|
|
12173
12202
|
}, [apiAdapter]);
|
|
12174
|
-
const removeQueued =
|
|
12203
|
+
const removeQueued = React64.useCallback((id) => {
|
|
12175
12204
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
12176
12205
|
setQueue(queueRef.current.slice());
|
|
12177
12206
|
}, []);
|
|
12178
|
-
const retry =
|
|
12207
|
+
const retry = React64.useCallback(() => {
|
|
12179
12208
|
const list = listRef.current;
|
|
12180
12209
|
let at = -1;
|
|
12181
12210
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -12191,19 +12220,19 @@ function useChatEngine(opts) {
|
|
|
12191
12220
|
setQueue(queueRef.current.slice());
|
|
12192
12221
|
drain();
|
|
12193
12222
|
}, []);
|
|
12194
|
-
const clear =
|
|
12223
|
+
const clear = React64.useCallback(() => {
|
|
12195
12224
|
commit([]);
|
|
12196
12225
|
serverCount.current = 0;
|
|
12197
12226
|
queueRef.current = [];
|
|
12198
12227
|
setQueue([]);
|
|
12199
12228
|
onClear && onClear();
|
|
12200
12229
|
}, [onClear]);
|
|
12201
|
-
const setFeedback =
|
|
12230
|
+
const setFeedback = React64.useCallback((id, value) => {
|
|
12202
12231
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
12203
12232
|
const msg = listRef.current.find((m) => m.id === id);
|
|
12204
12233
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
12205
12234
|
}, [onFeedback]);
|
|
12206
|
-
const reload =
|
|
12235
|
+
const reload = React64.useCallback(async () => {
|
|
12207
12236
|
if (!threadRef.current) return;
|
|
12208
12237
|
setStatus("loading");
|
|
12209
12238
|
try {
|
|
@@ -12241,11 +12270,11 @@ var ChatKit = {
|
|
|
12241
12270
|
};
|
|
12242
12271
|
|
|
12243
12272
|
// src/components/chat/ChatTranscript.tsx
|
|
12244
|
-
import * as
|
|
12273
|
+
import * as React66 from "react";
|
|
12245
12274
|
|
|
12246
12275
|
// src/components/chat/ChatTurn.tsx
|
|
12247
|
-
import * as
|
|
12248
|
-
import { jsx as
|
|
12276
|
+
import * as React65 from "react";
|
|
12277
|
+
import { jsx as jsx94, jsxs as jsxs84 } from "react/jsx-runtime";
|
|
12249
12278
|
function JsonView({ value }) {
|
|
12250
12279
|
let text;
|
|
12251
12280
|
try {
|
|
@@ -12253,7 +12282,7 @@ function JsonView({ value }) {
|
|
|
12253
12282
|
} catch (e) {
|
|
12254
12283
|
text = String(value);
|
|
12255
12284
|
}
|
|
12256
|
-
return /* @__PURE__ */
|
|
12285
|
+
return /* @__PURE__ */ jsx94(CodeBlock, { code: text, language: "json", collapseAfter: 18 });
|
|
12257
12286
|
}
|
|
12258
12287
|
function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
12259
12288
|
if (!packet) return null;
|
|
@@ -12262,58 +12291,58 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
12262
12291
|
const title = s.heading || packet.type;
|
|
12263
12292
|
return /* @__PURE__ */ jsxs84("section", { className: "fdc-packet" + (invalid ? " is-invalid" : ""), "aria-label": title, children: [
|
|
12264
12293
|
/* @__PURE__ */ jsxs84("header", { className: "fdc-packet-head", children: [
|
|
12265
|
-
/* @__PURE__ */
|
|
12266
|
-
/* @__PURE__ */
|
|
12267
|
-
packet.repaired ? /* @__PURE__ */
|
|
12268
|
-
invalid ? /* @__PURE__ */
|
|
12294
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-" + (s.icon || "package"), "aria-hidden": "true" }),
|
|
12295
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-packet-title", title: truncationTitle(title), children: title }),
|
|
12296
|
+
packet.repaired ? /* @__PURE__ */ jsx94("span", { className: "fdc-packet-badge", children: "Repaired" }) : null,
|
|
12297
|
+
invalid ? /* @__PURE__ */ jsx94("span", { className: "fdc-packet-badge is-danger", children: "Invalid" }) : null
|
|
12269
12298
|
] }),
|
|
12270
12299
|
invalid ? /* @__PURE__ */ jsxs84("div", { className: "fdc-packet-alert", role: "alert", children: [
|
|
12271
|
-
/* @__PURE__ */
|
|
12272
|
-
/* @__PURE__ */
|
|
12273
|
-
] }) : /* @__PURE__ */
|
|
12300
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
12301
|
+
/* @__PURE__ */ jsx94("span", { children: packet.error || "This result failed validation and can\u2019t be applied." })
|
|
12302
|
+
] }) : /* @__PURE__ */ jsx94("div", { className: "fdc-packet-body", children: render ? render(packet) : /* @__PURE__ */ jsx94(JsonView, { value: packet.payload }) }),
|
|
12274
12303
|
!invalid && onApply ? /* @__PURE__ */ jsxs84("footer", { className: "fdc-packet-foot", children: [
|
|
12275
|
-
packet.repaired ? /* @__PURE__ */
|
|
12304
|
+
packet.repaired ? /* @__PURE__ */ jsx94("span", { className: "fdc-packet-note", children: "Corrected by the backend after a first attempt." }) : /* @__PURE__ */ jsx94("span", {}),
|
|
12276
12305
|
/* @__PURE__ */ jsxs84("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", disabled: applied, onClick: () => onApply(packet), children: [
|
|
12277
|
-
/* @__PURE__ */
|
|
12306
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-" + (applied ? "check" : "arrow-square-in"), "aria-hidden": "true" }),
|
|
12278
12307
|
applied ? "Applied" : s.applyLabel || "Apply"
|
|
12279
12308
|
] })
|
|
12280
12309
|
] }) : null
|
|
12281
12310
|
] });
|
|
12282
12311
|
}
|
|
12283
12312
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
12284
|
-
const [open2, setOpen] =
|
|
12313
|
+
const [open2, setOpen] = React65.useState(defaultOpen);
|
|
12285
12314
|
if (!text) return null;
|
|
12286
12315
|
return /* @__PURE__ */ jsxs84("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
|
|
12287
12316
|
/* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
|
|
12288
|
-
/* @__PURE__ */
|
|
12289
|
-
/* @__PURE__ */
|
|
12317
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-brain", "aria-hidden": "true" }),
|
|
12318
|
+
/* @__PURE__ */ jsx94("span", { children: streaming ? "Thinking" : durationMs ? "Thought for " + formatDuration(durationMs) : "Thought process" }),
|
|
12290
12319
|
streaming ? /* @__PURE__ */ jsxs84("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
12291
|
-
/* @__PURE__ */
|
|
12292
|
-
/* @__PURE__ */
|
|
12293
|
-
/* @__PURE__ */
|
|
12320
|
+
/* @__PURE__ */ jsx94("span", {}),
|
|
12321
|
+
/* @__PURE__ */ jsx94("span", {}),
|
|
12322
|
+
/* @__PURE__ */ jsx94("span", {})
|
|
12294
12323
|
] }) : null,
|
|
12295
|
-
/* @__PURE__ */
|
|
12324
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12296
12325
|
] }),
|
|
12297
|
-
open2 ? /* @__PURE__ */
|
|
12326
|
+
open2 ? /* @__PURE__ */ jsx94("div", { className: "fdc-think-body", children: text }) : null
|
|
12298
12327
|
] });
|
|
12299
12328
|
}
|
|
12300
12329
|
function Citations({ items = [], onOpen }) {
|
|
12301
|
-
const [open2, setOpen] =
|
|
12330
|
+
const [open2, setOpen] = React65.useState(false);
|
|
12302
12331
|
if (!items.length) return null;
|
|
12303
12332
|
return /* @__PURE__ */ jsxs84("div", { className: "fdc-cites", children: [
|
|
12304
12333
|
/* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
|
|
12305
|
-
/* @__PURE__ */
|
|
12334
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-quotes", "aria-hidden": "true" }),
|
|
12306
12335
|
/* @__PURE__ */ jsxs84("span", { children: [
|
|
12307
12336
|
items.length,
|
|
12308
12337
|
" source",
|
|
12309
12338
|
items.length === 1 ? "" : "s"
|
|
12310
12339
|
] }),
|
|
12311
|
-
/* @__PURE__ */
|
|
12340
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-caret-" + (open2 ? "up" : "down"), "aria-hidden": "true" })
|
|
12312
12341
|
] }),
|
|
12313
|
-
open2 ? /* @__PURE__ */
|
|
12314
|
-
/* @__PURE__ */
|
|
12315
|
-
c.url ? /* @__PURE__ */
|
|
12316
|
-
c.detail ? /* @__PURE__ */
|
|
12342
|
+
open2 ? /* @__PURE__ */ jsx94("ol", { className: "fdc-cites-list", children: items.map((c, i) => /* @__PURE__ */ jsxs84("li", { children: [
|
|
12343
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-cite-n fd-tabular", children: c.marker || i + 1 }),
|
|
12344
|
+
c.url ? /* @__PURE__ */ jsx94("a", { href: c.url, target: "_blank", rel: "noopener noreferrer", onClick: onOpen ? (e) => onOpen(c, e) : void 0, children: c.title || c.url }) : /* @__PURE__ */ jsx94("span", { children: c.title || "Source" }),
|
|
12345
|
+
c.detail ? /* @__PURE__ */ jsx94("span", { className: "fdc-cite-detail", children: c.detail }) : null
|
|
12317
12346
|
] }, c.id || i)) }) : null
|
|
12318
12347
|
] });
|
|
12319
12348
|
}
|
|
@@ -12324,29 +12353,29 @@ function clampText(text, max) {
|
|
|
12324
12353
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
12325
12354
|
}
|
|
12326
12355
|
function MessageBody({ message: m, ctx }) {
|
|
12327
|
-
const [expanded, setExpanded] =
|
|
12356
|
+
const [expanded, setExpanded] = React65.useState(false);
|
|
12328
12357
|
const isUser = m.role === "user";
|
|
12329
12358
|
const raw = m.text || "";
|
|
12330
12359
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
12331
12360
|
const body = clamped != null ? clamped : raw;
|
|
12332
12361
|
const showMd = ctx.markdown && !isUser;
|
|
12333
12362
|
return /* @__PURE__ */ jsxs84("div", { className: "fdc-body", children: [
|
|
12334
|
-
m.thinking && ctx.showThinking ? /* @__PURE__ */
|
|
12335
|
-
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */
|
|
12363
|
+
m.thinking && ctx.showThinking ? /* @__PURE__ */ jsx94(ThinkingBlock, { text: m.thinking, durationMs: m.thinkingMs, streaming: m.streaming && !m.text }) : null,
|
|
12364
|
+
m.steps && m.steps.length && ctx.showSteps ? /* @__PURE__ */ jsx94(StepList, { steps: m.steps, defaultOpen: m.steps.some((s) => s.status === "running"), dense: true }) : null,
|
|
12336
12365
|
body ? /* @__PURE__ */ jsxs84("div", { className: "fdc-text" + (isUser ? " is-user" : ""), children: [
|
|
12337
|
-
showMd ? /* @__PURE__ */
|
|
12338
|
-
m.streaming ? /* @__PURE__ */
|
|
12366
|
+
showMd ? /* @__PURE__ */ jsx94(Markdown, { source: body, headingOffset: 2, codeProps: { collapseAfter: 22 }, renderCitation: ctx.renderCitation }) : /* @__PURE__ */ jsx94("div", { className: "fdc-plain", children: body }),
|
|
12367
|
+
m.streaming ? /* @__PURE__ */ jsx94("span", { className: "fdc-caret", "aria-hidden": "true" }) : null
|
|
12339
12368
|
] }) : null,
|
|
12340
12369
|
clamped != null ? /* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(true), children: [
|
|
12341
|
-
/* @__PURE__ */
|
|
12370
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-caret-down", "aria-hidden": "true" }),
|
|
12342
12371
|
"Show more",
|
|
12343
|
-
/* @__PURE__ */
|
|
12372
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-more-len fd-tabular", children: raw.length < 2e3 ? raw.length.toLocaleString() + " characters" : Math.round(raw.length / 100) / 10 + "k characters" })
|
|
12344
12373
|
] }) : expanded && ctx.maxVisibleChars && raw.length > ctx.maxVisibleChars ? /* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-more", onClick: () => setExpanded(false), children: [
|
|
12345
|
-
/* @__PURE__ */
|
|
12374
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-caret-up", "aria-hidden": "true" }),
|
|
12346
12375
|
"Show less"
|
|
12347
12376
|
] }) : null,
|
|
12348
|
-
m.attachments && m.attachments.length ? /* @__PURE__ */
|
|
12349
|
-
m.packet ? /* @__PURE__ */
|
|
12377
|
+
m.attachments && m.attachments.length ? /* @__PURE__ */ jsx94(FileGrid, { files: m.attachments, onOpen: ctx.onOpenAttachment, tiles: true, maxHeight: ctx.attachmentHeight || 220, compact: ctx.narrow }) : null,
|
|
12378
|
+
m.packet ? /* @__PURE__ */ jsx94(
|
|
12350
12379
|
PacketCard,
|
|
12351
12380
|
{
|
|
12352
12381
|
packet: m.packet,
|
|
@@ -12356,12 +12385,12 @@ function MessageBody({ message: m, ctx }) {
|
|
|
12356
12385
|
applied: ctx.appliedPackets && ctx.appliedPackets[m.id]
|
|
12357
12386
|
}
|
|
12358
12387
|
) : null,
|
|
12359
|
-
m.citations && m.citations.length ? /* @__PURE__ */
|
|
12388
|
+
m.citations && m.citations.length ? /* @__PURE__ */ jsx94(Citations, { items: m.citations, onOpen: ctx.onOpenCitation }) : null,
|
|
12360
12389
|
m.working ? /* @__PURE__ */ jsxs84("div", { className: "fdc-working", role: "status", children: [
|
|
12361
12390
|
/* @__PURE__ */ jsxs84("span", { className: "fdc-dots", "aria-hidden": "true", children: [
|
|
12362
|
-
/* @__PURE__ */
|
|
12363
|
-
/* @__PURE__ */
|
|
12364
|
-
/* @__PURE__ */
|
|
12391
|
+
/* @__PURE__ */ jsx94("span", {}),
|
|
12392
|
+
/* @__PURE__ */ jsx94("span", {}),
|
|
12393
|
+
/* @__PURE__ */ jsx94("span", {})
|
|
12365
12394
|
] }),
|
|
12366
12395
|
/* @__PURE__ */ jsxs84("span", { className: "fdc-working-label", children: [
|
|
12367
12396
|
m.resumed ? "Resuming" : "Working",
|
|
@@ -12374,17 +12403,17 @@ function MessageBody({ message: m, ctx }) {
|
|
|
12374
12403
|
m.job.detail
|
|
12375
12404
|
] }) : null
|
|
12376
12405
|
] }),
|
|
12377
|
-
m.jobId ? /* @__PURE__ */
|
|
12406
|
+
m.jobId ? /* @__PURE__ */ jsx94("span", { className: "fdc-working-id fd-mono", children: String(m.jobId).slice(0, 12) }) : null
|
|
12378
12407
|
] }) : null,
|
|
12379
12408
|
m.stopped ? /* @__PURE__ */ jsxs84("div", { className: "fdc-stopped", children: [
|
|
12380
|
-
/* @__PURE__ */
|
|
12409
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
12381
12410
|
"Stopped"
|
|
12382
12411
|
] }) : null,
|
|
12383
12412
|
m.error ? /* @__PURE__ */ jsxs84("div", { className: "fdc-error", role: "alert", children: [
|
|
12384
|
-
/* @__PURE__ */
|
|
12385
|
-
/* @__PURE__ */
|
|
12413
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
12414
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-error-text", children: ctx.errorCopy ? ctx.errorCopy(m.error) : m.error }),
|
|
12386
12415
|
m.retryable && ctx.onRetry ? /* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-error-retry", onClick: ctx.onRetry, children: [
|
|
12387
|
-
/* @__PURE__ */
|
|
12416
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
12388
12417
|
"Retry"
|
|
12389
12418
|
] }) : null
|
|
12390
12419
|
] }) : null
|
|
@@ -12399,14 +12428,14 @@ function RunActions({ group, ctx }) {
|
|
|
12399
12428
|
if (!ctx.messageActions) return null;
|
|
12400
12429
|
return /* @__PURE__ */ jsxs84("div", { className: "fdc-actions", role: "group", "aria-label": "Message actions", children: [
|
|
12401
12430
|
/* @__PURE__ */ jsxs84("button", { type: "button", className: "fdc-act" + (copied ? " is-done" : ""), onClick: () => copy(markdownToText(text)), "aria-label": "Copy message", children: [
|
|
12402
|
-
/* @__PURE__ */
|
|
12403
|
-
/* @__PURE__ */
|
|
12431
|
+
/* @__PURE__ */ jsx94("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
|
|
12432
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-act-label", children: copied ? "Copied" : "Copy" })
|
|
12404
12433
|
] }),
|
|
12405
|
-
isAssistant && ctx.onRetry ? /* @__PURE__ */
|
|
12406
|
-
group.role === "user" && ctx.onEdit ? /* @__PURE__ */
|
|
12407
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs84(
|
|
12408
|
-
/* @__PURE__ */
|
|
12409
|
-
/* @__PURE__ */
|
|
12434
|
+
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx94("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx94("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
12435
|
+
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx94("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx94("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
12436
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs84(React65.Fragment, { children: [
|
|
12437
|
+
/* @__PURE__ */ jsx94("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__ */ jsx94("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
12438
|
+
/* @__PURE__ */ jsx94("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__ */ jsx94("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
12410
12439
|
] }) : null,
|
|
12411
12440
|
ctx.extraActions ? ctx.extraActions(group) : null
|
|
12412
12441
|
] });
|
|
@@ -12418,20 +12447,20 @@ function ChatTurn({ group, ctx }) {
|
|
|
12418
12447
|
const stamp = group.messages[0].timestamp;
|
|
12419
12448
|
return /* @__PURE__ */ jsxs84("article", { className: "fdc-turn is-" + group.role, "aria-label": String(name) + (stamp ? " at " + formatClock(stamp) : ""), children: [
|
|
12420
12449
|
/* @__PURE__ */ jsxs84("div", { className: "fdc-turn-head", children: [
|
|
12421
|
-
ctx.showAvatars ? /* @__PURE__ */
|
|
12422
|
-
/* @__PURE__ */
|
|
12423
|
-
stamp ? /* @__PURE__ */
|
|
12424
|
-
group.messages.some((m) => m.model) ? /* @__PURE__ */
|
|
12450
|
+
ctx.showAvatars ? /* @__PURE__ */ jsx94("span", { className: "fdc-avatar is-" + group.role, "aria-hidden": "true", children: avatar ? /* @__PURE__ */ jsx94("img", { src: avatar, alt: "" }) : isUser ? /* @__PURE__ */ jsx94("span", { className: "fdc-avatar-txt", children: (name || "You").slice(0, 1).toUpperCase() }) : /* @__PURE__ */ jsx94("i", { className: "ph ph-" + (ctx.assistantIcon || "sparkle") }) }) : null,
|
|
12451
|
+
/* @__PURE__ */ jsx94("span", { className: "fdc-who", children: name }),
|
|
12452
|
+
stamp ? /* @__PURE__ */ jsx94(RelativeTime, { className: "fdc-when", value: stamp }) : null,
|
|
12453
|
+
group.messages.some((m) => m.model) ? /* @__PURE__ */ jsx94("span", { className: "fdc-turn-model", children: group.messages.find((m) => m.model).model }) : null
|
|
12425
12454
|
] }),
|
|
12426
12455
|
/* @__PURE__ */ jsxs84("div", { className: "fdc-turn-body", children: [
|
|
12427
|
-
group.messages.map((m) => /* @__PURE__ */
|
|
12428
|
-
/* @__PURE__ */
|
|
12456
|
+
group.messages.map((m) => /* @__PURE__ */ jsx94("div", { className: "fdc-msg" + (m.pending ? " is-pending" : ""), children: /* @__PURE__ */ jsx94(MessageBody, { message: m, ctx }) }, m.id)),
|
|
12457
|
+
/* @__PURE__ */ jsx94(RunActions, { group, ctx })
|
|
12429
12458
|
] })
|
|
12430
12459
|
] });
|
|
12431
12460
|
}
|
|
12432
12461
|
|
|
12433
12462
|
// src/components/chat/ChatTranscript.tsx
|
|
12434
|
-
import { jsx as
|
|
12463
|
+
import { jsx as jsx95, jsxs as jsxs85 } from "react/jsx-runtime";
|
|
12435
12464
|
var GROUP_WINDOW = 6e4;
|
|
12436
12465
|
var STICK_PX = 100;
|
|
12437
12466
|
function groupMessages(list) {
|
|
@@ -12464,25 +12493,25 @@ function dayLabel(key) {
|
|
|
12464
12493
|
}
|
|
12465
12494
|
function Suggestions({ items = [], onPick }) {
|
|
12466
12495
|
if (!items.length) return null;
|
|
12467
|
-
return /* @__PURE__ */
|
|
12496
|
+
return /* @__PURE__ */ jsx95("div", { className: "fdc-suggest", children: items.map((s, i) => {
|
|
12468
12497
|
const it = typeof s === "string" ? { label: s, text: s } : s;
|
|
12469
12498
|
return /* @__PURE__ */ jsxs85("button", { type: "button", className: "fdc-suggest-item", onClick: () => onPick && onPick(it.text || it.label), children: [
|
|
12470
|
-
it.icon ? /* @__PURE__ */
|
|
12499
|
+
it.icon ? /* @__PURE__ */ jsx95("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) : null,
|
|
12471
12500
|
/* @__PURE__ */ jsxs85("span", { className: "fdc-suggest-text", children: [
|
|
12472
|
-
/* @__PURE__ */
|
|
12473
|
-
it.description ? /* @__PURE__ */
|
|
12501
|
+
/* @__PURE__ */ jsx95("span", { className: "fdc-suggest-label", children: it.label }),
|
|
12502
|
+
it.description ? /* @__PURE__ */ jsx95("span", { className: "fdc-suggest-desc", children: it.description }) : null
|
|
12474
12503
|
] }),
|
|
12475
|
-
/* @__PURE__ */
|
|
12504
|
+
/* @__PURE__ */ jsx95("i", { className: "ph ph-arrow-up-right fdc-suggest-go", "aria-hidden": "true" })
|
|
12476
12505
|
] }, it.id || i);
|
|
12477
12506
|
}) });
|
|
12478
12507
|
}
|
|
12479
12508
|
function LoadingTurns() {
|
|
12480
|
-
return /* @__PURE__ */
|
|
12481
|
-
/* @__PURE__ */
|
|
12509
|
+
return /* @__PURE__ */ jsx95("div", { className: "fdc-skel", "aria-hidden": "true", children: [0, 1].map((i) => /* @__PURE__ */ jsxs85("div", { className: "fdc-skel-turn", children: [
|
|
12510
|
+
/* @__PURE__ */ jsx95("div", { className: "fd-skel fd-skel-circle", style: { width: 22, height: 22 } }),
|
|
12482
12511
|
/* @__PURE__ */ jsxs85("div", { className: "fdc-skel-lines", children: [
|
|
12483
|
-
/* @__PURE__ */
|
|
12484
|
-
/* @__PURE__ */
|
|
12485
|
-
/* @__PURE__ */
|
|
12512
|
+
/* @__PURE__ */ jsx95("div", { className: "fd-skel", style: { width: i ? "62%" : "44%", height: 11 } }),
|
|
12513
|
+
/* @__PURE__ */ jsx95("div", { className: "fd-skel", style: { width: i ? "94%" : "78%", height: 11 } }),
|
|
12514
|
+
/* @__PURE__ */ jsx95("div", { className: "fd-skel", style: { width: i ? "71%" : "56%", height: 11 } })
|
|
12486
12515
|
] })
|
|
12487
12516
|
] }, i)) });
|
|
12488
12517
|
}
|
|
@@ -12499,10 +12528,10 @@ function ChatTranscript({
|
|
|
12499
12528
|
renderEmpty,
|
|
12500
12529
|
className = ""
|
|
12501
12530
|
}) {
|
|
12502
|
-
const scroller =
|
|
12503
|
-
const stick =
|
|
12504
|
-
const [pill, setPill] =
|
|
12505
|
-
const seen =
|
|
12531
|
+
const scroller = React66.useRef(null);
|
|
12532
|
+
const stick = React66.useRef(true);
|
|
12533
|
+
const [pill, setPill] = React66.useState(0);
|
|
12534
|
+
const seen = React66.useRef(0);
|
|
12506
12535
|
const toBottom = (smooth) => {
|
|
12507
12536
|
const el = scroller.current;
|
|
12508
12537
|
if (!el) return;
|
|
@@ -12521,7 +12550,7 @@ function ChatTranscript({
|
|
|
12521
12550
|
seen.current = messages.length;
|
|
12522
12551
|
}
|
|
12523
12552
|
};
|
|
12524
|
-
|
|
12553
|
+
React66.useLayoutEffect(() => {
|
|
12525
12554
|
const el = scroller.current;
|
|
12526
12555
|
if (!el) return;
|
|
12527
12556
|
if (stick.current) {
|
|
@@ -12529,7 +12558,7 @@ function ChatTranscript({
|
|
|
12529
12558
|
seen.current = messages.length;
|
|
12530
12559
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
12531
12560
|
}, [messages]);
|
|
12532
|
-
|
|
12561
|
+
React66.useEffect(() => {
|
|
12533
12562
|
const el = scroller.current;
|
|
12534
12563
|
const inner = el && el.firstChild;
|
|
12535
12564
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -12539,38 +12568,38 @@ function ChatTranscript({
|
|
|
12539
12568
|
ro.observe(inner);
|
|
12540
12569
|
return () => ro.disconnect();
|
|
12541
12570
|
}, []);
|
|
12542
|
-
const groups =
|
|
12571
|
+
const groups = React66.useMemo(() => groupMessages(messages), [messages]);
|
|
12543
12572
|
const empty = !messages.length && status === "ready";
|
|
12544
12573
|
return /* @__PURE__ */ jsxs85("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
12545
12574
|
/* @__PURE__ */ jsxs85("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
12546
|
-
status === "loading" || status === "resolving" ? /* @__PURE__ */
|
|
12575
|
+
status === "loading" || status === "resolving" ? /* @__PURE__ */ jsx95(LoadingTurns, {}) : null,
|
|
12547
12576
|
status === "disconnected" ? /* @__PURE__ */ jsxs85("div", { className: "fdc-dead", children: [
|
|
12548
|
-
/* @__PURE__ */
|
|
12549
|
-
/* @__PURE__ */
|
|
12550
|
-
/* @__PURE__ */
|
|
12577
|
+
/* @__PURE__ */ jsx95("span", { className: "fdc-dead-icon", children: /* @__PURE__ */ jsx95("i", { className: "ph ph-plugs", "aria-hidden": "true" }) }),
|
|
12578
|
+
/* @__PURE__ */ jsx95("h3", { className: "fdc-dead-title", children: ctx.deadTitle || "The assistant isn\u2019t reachable" }),
|
|
12579
|
+
/* @__PURE__ */ jsx95("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." }),
|
|
12551
12580
|
ctx.onReconnect ? /* @__PURE__ */ jsxs85("button", { type: "button", className: "fd-btn fd-btn-secondary fd-btn-sm", onClick: ctx.onReconnect, children: [
|
|
12552
|
-
/* @__PURE__ */
|
|
12581
|
+
/* @__PURE__ */ jsx95("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }),
|
|
12553
12582
|
"Try again"
|
|
12554
12583
|
] }) : null
|
|
12555
12584
|
] }) : null,
|
|
12556
12585
|
empty ? renderEmpty ? renderEmpty() : /* @__PURE__ */ jsxs85("div", { className: "fdc-empty", children: [
|
|
12557
|
-
/* @__PURE__ */
|
|
12558
|
-
/* @__PURE__ */
|
|
12559
|
-
emptyDescription ? /* @__PURE__ */
|
|
12560
|
-
/* @__PURE__ */
|
|
12586
|
+
/* @__PURE__ */ jsx95("span", { className: "fdc-empty-icon", children: /* @__PURE__ */ jsx95("i", { className: "ph ph-" + emptyIcon, "aria-hidden": "true" }) }),
|
|
12587
|
+
/* @__PURE__ */ jsx95("h3", { className: "fdc-empty-title", children: emptyTitle }),
|
|
12588
|
+
emptyDescription ? /* @__PURE__ */ jsx95("p", { className: "fdc-empty-body", children: emptyDescription }) : null,
|
|
12589
|
+
/* @__PURE__ */ jsx95(Suggestions, { items: suggestions, onPick })
|
|
12561
12590
|
] }) : null,
|
|
12562
12591
|
groups.map((g, i) => {
|
|
12563
12592
|
const prev = groups[i - 1];
|
|
12564
12593
|
const k = dayKey(g.messages[0].timestamp);
|
|
12565
12594
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
12566
|
-
return /* @__PURE__ */ jsxs85(
|
|
12567
|
-
showDay ? /* @__PURE__ */
|
|
12568
|
-
/* @__PURE__ */
|
|
12595
|
+
return /* @__PURE__ */ jsxs85(React66.Fragment, { children: [
|
|
12596
|
+
showDay ? /* @__PURE__ */ jsx95("div", { className: "fdc-day", children: /* @__PURE__ */ jsx95("span", { children: dayLabel(k) }) }) : null,
|
|
12597
|
+
/* @__PURE__ */ jsx95(ChatTurn, { group: g, ctx })
|
|
12569
12598
|
] }, g.key || i);
|
|
12570
12599
|
})
|
|
12571
12600
|
] }),
|
|
12572
12601
|
pill ? /* @__PURE__ */ jsxs85("button", { type: "button", className: "fdc-pill", onClick: () => toBottom(true), children: [
|
|
12573
|
-
/* @__PURE__ */
|
|
12602
|
+
/* @__PURE__ */ jsx95("i", { className: "ph ph-arrow-down", "aria-hidden": "true" }),
|
|
12574
12603
|
pill,
|
|
12575
12604
|
" new message",
|
|
12576
12605
|
pill === 1 ? "" : "s"
|
|
@@ -12580,8 +12609,8 @@ function ChatTranscript({
|
|
|
12580
12609
|
var TranscriptKit = { groupMessages };
|
|
12581
12610
|
|
|
12582
12611
|
// src/components/chat/ChatComposer.tsx
|
|
12583
|
-
import * as
|
|
12584
|
-
import { jsx as
|
|
12612
|
+
import * as React67 from "react";
|
|
12613
|
+
import { jsx as jsx96, jsxs as jsxs86 } from "react/jsx-runtime";
|
|
12585
12614
|
function ChatComposer({
|
|
12586
12615
|
onSubmit,
|
|
12587
12616
|
onStop,
|
|
@@ -12608,17 +12637,17 @@ function ChatComposer({
|
|
|
12608
12637
|
onReject,
|
|
12609
12638
|
onOpenAttachment
|
|
12610
12639
|
}) {
|
|
12611
|
-
const [text, setText] =
|
|
12612
|
-
const [trigger, setTrigger] =
|
|
12613
|
-
const [mentionItems, setMentionItems] =
|
|
12614
|
-
const [listening, setListening] =
|
|
12615
|
-
const [notice, setNotice] =
|
|
12616
|
-
const editor =
|
|
12617
|
-
const wrap =
|
|
12618
|
-
const stopVoice =
|
|
12640
|
+
const [text, setText] = React67.useState(draft || "");
|
|
12641
|
+
const [trigger, setTrigger] = React67.useState(null);
|
|
12642
|
+
const [mentionItems, setMentionItems] = React67.useState([]);
|
|
12643
|
+
const [listening, setListening] = React67.useState(false);
|
|
12644
|
+
const [notice, setNotice] = React67.useState(null);
|
|
12645
|
+
const editor = React67.useRef(null);
|
|
12646
|
+
const wrap = React67.useRef(null);
|
|
12647
|
+
const stopVoice = React67.useRef(null);
|
|
12619
12648
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
12620
12649
|
} });
|
|
12621
|
-
|
|
12650
|
+
React67.useEffect(() => {
|
|
12622
12651
|
if (draft != null && draft !== text) setText(draft);
|
|
12623
12652
|
}, [draft]);
|
|
12624
12653
|
const change = (v) => {
|
|
@@ -12654,7 +12683,7 @@ function ChatComposer({
|
|
|
12654
12683
|
e.preventDefault();
|
|
12655
12684
|
staged.add(found.files);
|
|
12656
12685
|
};
|
|
12657
|
-
|
|
12686
|
+
React67.useEffect(() => {
|
|
12658
12687
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
12659
12688
|
setMentionItems([]);
|
|
12660
12689
|
return;
|
|
@@ -12672,7 +12701,7 @@ function ChatComposer({
|
|
|
12672
12701
|
const q = (trigger.query || "").toLowerCase();
|
|
12673
12702
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
12674
12703
|
}, [trigger, mentionSources]);
|
|
12675
|
-
const slashItems =
|
|
12704
|
+
const slashItems = React67.useMemo(() => {
|
|
12676
12705
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
12677
12706
|
const q = (trigger.query || "").toLowerCase();
|
|
12678
12707
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -12686,7 +12715,7 @@ function ChatComposer({
|
|
|
12686
12715
|
description: it.description,
|
|
12687
12716
|
icon: it.icon,
|
|
12688
12717
|
meta: mention.meta,
|
|
12689
|
-
shortcut: slash.shortcut ? /* @__PURE__ */
|
|
12718
|
+
shortcut: slash.shortcut ? /* @__PURE__ */ jsx96(KeyHint, { keys: slash.shortcut, size: "sm" }) : void 0,
|
|
12690
12719
|
onSelect: () => {
|
|
12691
12720
|
const insert = trigger.type === "slash" ? slash.immediate ? "/" + slash.id : "/" + slash.id + " " : "@" + (mention.value || mention.label) + " ";
|
|
12692
12721
|
editor.current && editor.current.replaceRange(trigger.from, trigger.to, insert);
|
|
@@ -12746,13 +12775,13 @@ function ChatComposer({
|
|
|
12746
12775
|
};
|
|
12747
12776
|
};
|
|
12748
12777
|
return /* @__PURE__ */ jsxs86("div", { className: "fdc-composer" + (disabled ? " is-disabled" : "") + (narrow ? " is-narrow" : ""), children: [
|
|
12749
|
-
queue.length ? /* @__PURE__ */
|
|
12750
|
-
/* @__PURE__ */
|
|
12751
|
-
/* @__PURE__ */
|
|
12752
|
-
onRemoveQueued ? /* @__PURE__ */
|
|
12778
|
+
queue.length ? /* @__PURE__ */ jsx96("div", { className: "fdc-queue", "aria-label": "Queued messages", children: queue.map((q) => /* @__PURE__ */ jsxs86("div", { className: "fdc-queue-row", children: [
|
|
12779
|
+
/* @__PURE__ */ jsx96("i", { className: "ph ph-clock-countdown", "aria-hidden": "true" }),
|
|
12780
|
+
/* @__PURE__ */ jsx96("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)" : "") }),
|
|
12781
|
+
onRemoveQueued ? /* @__PURE__ */ jsx96("button", { type: "button", className: "fdc-queue-x", onClick: () => onRemoveQueued(q.id), "aria-label": "Remove queued message", children: /* @__PURE__ */ jsx96("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
12753
12782
|
] }, q.id)) }) : null,
|
|
12754
12783
|
sessionBar,
|
|
12755
|
-
/* @__PURE__ */
|
|
12784
|
+
/* @__PURE__ */ jsx96(
|
|
12756
12785
|
Dropzone,
|
|
12757
12786
|
{
|
|
12758
12787
|
className: "fdc-field",
|
|
@@ -12767,8 +12796,8 @@ function ChatComposer({
|
|
|
12767
12796
|
label: "Drop to attach",
|
|
12768
12797
|
hint: acceptFiles ? acceptFiles.replace(/,/g, " \xB7 ") : void 0,
|
|
12769
12798
|
children: /* @__PURE__ */ jsxs86("div", { ref: wrap, className: "fdc-field-inner", children: [
|
|
12770
|
-
staged.items.length ? /* @__PURE__ */
|
|
12771
|
-
/* @__PURE__ */
|
|
12799
|
+
staged.items.length ? /* @__PURE__ */ jsx96("div", { className: "fdc-staged", children: /* @__PURE__ */ jsx96(FileStrip, { files: staged.items, size: narrow ? 60 : 68, onRemove: staged.remove, onRetry: staged.retry, onOpen: onOpenAttachment }) }) : null,
|
|
12800
|
+
/* @__PURE__ */ jsx96(
|
|
12772
12801
|
MarkdownEditor,
|
|
12773
12802
|
{
|
|
12774
12803
|
ref: editor,
|
|
@@ -12788,32 +12817,32 @@ function ChatComposer({
|
|
|
12788
12817
|
}
|
|
12789
12818
|
),
|
|
12790
12819
|
/* @__PURE__ */ jsxs86("div", { className: "fdc-tools", children: [
|
|
12791
|
-
fileUploadHandler ? /* @__PURE__ */
|
|
12792
|
-
voiceHandler ? /* @__PURE__ */
|
|
12820
|
+
fileUploadHandler ? /* @__PURE__ */ jsx96(FilePickButton, { onFiles: staged.add, onReject: (r) => flash(r[0].message), accept: acceptFiles, maxFileSize, label: "Attach files", icon: "plus" }) : null,
|
|
12821
|
+
voiceHandler ? /* @__PURE__ */ jsx96("button", { type: "button", className: "fd-attachbtn" + (listening ? " is-live" : ""), onClick: voice, "aria-pressed": listening, "aria-label": listening ? "Stop dictation" : "Dictate", children: /* @__PURE__ */ jsx96("i", { className: "ph ph-" + (listening ? "waveform" : "microphone"), "aria-hidden": "true" }) }) : null,
|
|
12793
12822
|
toolbarExtras,
|
|
12794
|
-
/* @__PURE__ */
|
|
12823
|
+
/* @__PURE__ */ jsx96("span", { className: "fdc-tools-gap" }),
|
|
12795
12824
|
maxLength && text.length > maxLength * 0.6 ? /* @__PURE__ */ jsxs86("span", { className: "fdc-count fd-tabular" + (text.length > maxLength * 0.95 ? " is-hot" : ""), children: [
|
|
12796
12825
|
text.length,
|
|
12797
12826
|
"/",
|
|
12798
12827
|
maxLength
|
|
12799
12828
|
] }) : null,
|
|
12800
12829
|
busy ? /* @__PURE__ */ jsxs86("button", { type: "button", className: "fdc-stop", onClick: onStop, "aria-label": "Stop generating", children: [
|
|
12801
|
-
/* @__PURE__ */
|
|
12802
|
-
/* @__PURE__ */
|
|
12830
|
+
/* @__PURE__ */ jsx96("i", { className: "ph ph-stop-circle", "aria-hidden": "true" }),
|
|
12831
|
+
/* @__PURE__ */ jsx96("span", { children: "Stop" })
|
|
12803
12832
|
] }) : /* @__PURE__ */ jsxs86("button", { type: "button", className: "fdc-send", onClick: submit, disabled: !canSend, "aria-label": "Send message", children: [
|
|
12804
|
-
/* @__PURE__ */
|
|
12805
|
-
/* @__PURE__ */
|
|
12833
|
+
/* @__PURE__ */ jsx96("i", { className: "ph ph-paper-plane-right", "aria-hidden": "true" }),
|
|
12834
|
+
/* @__PURE__ */ jsx96("span", { className: "fdc-send-label", children: "Send" })
|
|
12806
12835
|
] })
|
|
12807
12836
|
] })
|
|
12808
12837
|
] })
|
|
12809
12838
|
}
|
|
12810
12839
|
),
|
|
12811
12840
|
notice ? /* @__PURE__ */ jsxs86("div", { className: "fdc-notice", role: "status", children: [
|
|
12812
|
-
/* @__PURE__ */
|
|
12841
|
+
/* @__PURE__ */ jsx96("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
12813
12842
|
notice
|
|
12814
12843
|
] }) : null,
|
|
12815
|
-
hint && !notice ? /* @__PURE__ */
|
|
12816
|
-
/* @__PURE__ */
|
|
12844
|
+
hint && !notice ? /* @__PURE__ */ jsx96("div", { className: "fdc-hint", children: hint }) : null,
|
|
12845
|
+
/* @__PURE__ */ jsx96(
|
|
12817
12846
|
Popover,
|
|
12818
12847
|
{
|
|
12819
12848
|
open: menuOpen,
|
|
@@ -12827,12 +12856,12 @@ function ChatComposer({
|
|
|
12827
12856
|
returnFocus: false,
|
|
12828
12857
|
closeOnOutside: true,
|
|
12829
12858
|
label: trigger && trigger.type === "slash" ? "Commands" : "Mentions",
|
|
12830
|
-
children: /* @__PURE__ */
|
|
12859
|
+
children: /* @__PURE__ */ jsx96(
|
|
12831
12860
|
Menu,
|
|
12832
12861
|
{
|
|
12833
12862
|
items: menuItems,
|
|
12834
12863
|
autoFocus: false,
|
|
12835
|
-
header: /* @__PURE__ */
|
|
12864
|
+
header: /* @__PURE__ */ jsx96("div", { className: "fd-pop-group", children: trigger && trigger.type === "slash" ? "Commands" : "Attach context" }),
|
|
12836
12865
|
onClose: () => setTrigger(null)
|
|
12837
12866
|
}
|
|
12838
12867
|
)
|
|
@@ -12842,12 +12871,12 @@ function ChatComposer({
|
|
|
12842
12871
|
}
|
|
12843
12872
|
|
|
12844
12873
|
// src/components/chat/ChatSessionBar.tsx
|
|
12845
|
-
import * as
|
|
12846
|
-
import { jsx as
|
|
12874
|
+
import * as React68 from "react";
|
|
12875
|
+
import { jsx as jsx97, jsxs as jsxs87 } from "react/jsx-runtime";
|
|
12847
12876
|
var compact2 = meterFormats.compact;
|
|
12848
12877
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
12849
|
-
const [open2, setOpen] =
|
|
12850
|
-
const anchor =
|
|
12878
|
+
const [open2, setOpen] = React68.useState(false);
|
|
12879
|
+
const anchor = React68.useRef(null);
|
|
12851
12880
|
const stats = sessionStats || null;
|
|
12852
12881
|
const cu = contextUsage || null;
|
|
12853
12882
|
const limits = usageLimits || null;
|
|
@@ -12862,7 +12891,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
12862
12891
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
12863
12892
|
if (cu) bits.push(pct + "% context");
|
|
12864
12893
|
const expandable = !!(cu || limits);
|
|
12865
|
-
return /* @__PURE__ */ jsxs87(
|
|
12894
|
+
return /* @__PURE__ */ jsxs87(React68.Fragment, { children: [
|
|
12866
12895
|
/* @__PURE__ */ jsxs87("div", { className: "fdc-bar", children: [
|
|
12867
12896
|
/* @__PURE__ */ jsxs87(
|
|
12868
12897
|
"button",
|
|
@@ -12875,15 +12904,15 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
12875
12904
|
"aria-expanded": expandable ? open2 : void 0,
|
|
12876
12905
|
"aria-label": expandable ? "Usage details" : void 0,
|
|
12877
12906
|
children: [
|
|
12878
|
-
cu ? /* @__PURE__ */
|
|
12879
|
-
/* @__PURE__ */
|
|
12880
|
-
expandable ? /* @__PURE__ */
|
|
12907
|
+
cu ? /* @__PURE__ */ jsx97("span", { className: "fdc-bar-mini", "aria-hidden": "true", children: /* @__PURE__ */ jsx97(SegmentedMeter, { total, segments: cu.segments, height: 4, showTotal: false }) }) : null,
|
|
12908
|
+
/* @__PURE__ */ jsx97("span", { className: "fdc-bar-text", title: truncationTitle(bits.join(" \xB7 ")), children: bits.join(" \xB7 ") }),
|
|
12909
|
+
expandable ? /* @__PURE__ */ jsx97("i", { className: "ph ph-caret-right fdc-bar-caret", "aria-hidden": "true" }) : null
|
|
12881
12910
|
]
|
|
12882
12911
|
}
|
|
12883
12912
|
),
|
|
12884
12913
|
extras
|
|
12885
12914
|
] }),
|
|
12886
|
-
/* @__PURE__ */
|
|
12915
|
+
/* @__PURE__ */ jsx97(
|
|
12887
12916
|
Popover,
|
|
12888
12917
|
{
|
|
12889
12918
|
open: open2,
|
|
@@ -12898,11 +12927,11 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
12898
12927
|
setOpen(false);
|
|
12899
12928
|
onClear();
|
|
12900
12929
|
}, children: [
|
|
12901
|
-
/* @__PURE__ */
|
|
12930
|
+
/* @__PURE__ */ jsx97("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
12902
12931
|
"Clear conversation"
|
|
12903
12932
|
] }) : void 0,
|
|
12904
12933
|
children: /* @__PURE__ */ jsxs87("div", { className: "fdc-usage", children: [
|
|
12905
|
-
cu ? /* @__PURE__ */
|
|
12934
|
+
cu ? /* @__PURE__ */ jsx97("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx97(
|
|
12906
12935
|
SegmentedMeter,
|
|
12907
12936
|
{
|
|
12908
12937
|
total,
|
|
@@ -12915,8 +12944,8 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
12915
12944
|
}
|
|
12916
12945
|
) }) : null,
|
|
12917
12946
|
limits && limits.length ? /* @__PURE__ */ jsxs87("section", { className: "fdc-usage-sec", children: [
|
|
12918
|
-
/* @__PURE__ */
|
|
12919
|
-
/* @__PURE__ */
|
|
12947
|
+
/* @__PURE__ */ jsx97("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
12948
|
+
/* @__PURE__ */ jsx97("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx97(
|
|
12920
12949
|
QuotaRow,
|
|
12921
12950
|
{
|
|
12922
12951
|
label: l.label,
|
|
@@ -12928,23 +12957,23 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
12928
12957
|
] }) : null,
|
|
12929
12958
|
stats ? /* @__PURE__ */ jsxs87("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
12930
12959
|
stats.elapsedMs ? /* @__PURE__ */ jsxs87("div", { children: [
|
|
12931
|
-
/* @__PURE__ */
|
|
12932
|
-
/* @__PURE__ */
|
|
12960
|
+
/* @__PURE__ */ jsx97("span", { children: "Session" }),
|
|
12961
|
+
/* @__PURE__ */ jsx97("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
12933
12962
|
] }) : null,
|
|
12934
12963
|
stats.tokens ? /* @__PURE__ */ jsxs87("div", { children: [
|
|
12935
|
-
/* @__PURE__ */
|
|
12936
|
-
/* @__PURE__ */
|
|
12964
|
+
/* @__PURE__ */ jsx97("span", { children: "Tokens" }),
|
|
12965
|
+
/* @__PURE__ */ jsx97("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
12937
12966
|
] }) : null,
|
|
12938
12967
|
stats.costUsd != null ? /* @__PURE__ */ jsxs87("div", { children: [
|
|
12939
|
-
/* @__PURE__ */
|
|
12968
|
+
/* @__PURE__ */ jsx97("span", { children: "Cost" }),
|
|
12940
12969
|
/* @__PURE__ */ jsxs87("b", { className: "fd-tabular", children: [
|
|
12941
12970
|
"$",
|
|
12942
12971
|
Number(stats.costUsd).toFixed(3)
|
|
12943
12972
|
] })
|
|
12944
12973
|
] }) : null,
|
|
12945
12974
|
stats.turns ? /* @__PURE__ */ jsxs87("div", { children: [
|
|
12946
|
-
/* @__PURE__ */
|
|
12947
|
-
/* @__PURE__ */
|
|
12975
|
+
/* @__PURE__ */ jsx97("span", { children: "Turns" }),
|
|
12976
|
+
/* @__PURE__ */ jsx97("b", { className: "fd-tabular", children: stats.turns })
|
|
12948
12977
|
] }) : null
|
|
12949
12978
|
] }) : null
|
|
12950
12979
|
] })
|
|
@@ -12983,7 +13012,7 @@ function ModelControls({
|
|
|
12983
13012
|
disabled: m.disabled,
|
|
12984
13013
|
checked: m.id === (current2 && current2.id),
|
|
12985
13014
|
meta: m.meta,
|
|
12986
|
-
shortcut: m.shortcut ? /* @__PURE__ */
|
|
13015
|
+
shortcut: m.shortcut ? /* @__PURE__ */ jsx97(KeyHint, { keys: m.shortcut, size: "sm" }) : void 0,
|
|
12987
13016
|
onSelect: () => onModelChange && onModelChange(m.id)
|
|
12988
13017
|
});
|
|
12989
13018
|
const items = [{ kind: "section", label: "Models" }].concat(flat.map(item));
|
|
@@ -12997,14 +13026,14 @@ function ModelControls({
|
|
|
12997
13026
|
items.push({
|
|
12998
13027
|
kind: "custom",
|
|
12999
13028
|
render: () => /* @__PURE__ */ jsxs87("label", { className: "fdc-switchrow", children: [
|
|
13000
|
-
/* @__PURE__ */
|
|
13001
|
-
/* @__PURE__ */
|
|
13002
|
-
/* @__PURE__ */
|
|
13029
|
+
/* @__PURE__ */ jsx97("span", { children: fastModeLabel }),
|
|
13030
|
+
/* @__PURE__ */ jsx97("input", { type: "checkbox", className: "fd-sr", checked: !!fastMode, onChange: (e) => onFastModeChange(e.target.checked) }),
|
|
13031
|
+
/* @__PURE__ */ jsx97("span", { className: "fd-switch-track" + (fastMode ? " is-on" : ""), "aria-hidden": "true", children: /* @__PURE__ */ jsx97("span", { className: "fd-switch-thumb" }) })
|
|
13003
13032
|
] })
|
|
13004
13033
|
});
|
|
13005
13034
|
}
|
|
13006
|
-
return /* @__PURE__ */ jsxs87(
|
|
13007
|
-
/* @__PURE__ */
|
|
13035
|
+
return /* @__PURE__ */ jsxs87(React68.Fragment, { children: [
|
|
13036
|
+
/* @__PURE__ */ jsx97(
|
|
13008
13037
|
MenuButton,
|
|
13009
13038
|
{
|
|
13010
13039
|
items,
|
|
@@ -13015,7 +13044,7 @@ function ModelControls({
|
|
|
13015
13044
|
title: "Choose a model"
|
|
13016
13045
|
}
|
|
13017
13046
|
),
|
|
13018
|
-
effortLevels && effortLevels.length ? /* @__PURE__ */
|
|
13047
|
+
effortLevels && effortLevels.length ? /* @__PURE__ */ jsx97(
|
|
13019
13048
|
MenuButton,
|
|
13020
13049
|
{
|
|
13021
13050
|
placement: "top-end",
|
|
@@ -13036,7 +13065,7 @@ function ModelControls({
|
|
|
13036
13065
|
}
|
|
13037
13066
|
|
|
13038
13067
|
// src/components/chat/AgentChatPanel.tsx
|
|
13039
|
-
import { jsx as
|
|
13068
|
+
import { jsx as jsx98, jsxs as jsxs88 } from "react/jsx-runtime";
|
|
13040
13069
|
var SURFACES = { sidebar: "is-sidebar", inline: "is-inline", page: "is-page", modal: "is-modal", sheet: "is-sheet" };
|
|
13041
13070
|
function AgentChatPanel({
|
|
13042
13071
|
/* required */
|
|
@@ -13120,11 +13149,11 @@ function AgentChatPanel({
|
|
|
13120
13149
|
onFeedback,
|
|
13121
13150
|
onEditMessage
|
|
13122
13151
|
}) {
|
|
13123
|
-
const [panelWidth, setPanelWidth] =
|
|
13124
|
-
const [applied, setApplied] =
|
|
13125
|
-
const [draft, setDraft] =
|
|
13126
|
-
const dragging =
|
|
13127
|
-
|
|
13152
|
+
const [panelWidth, setPanelWidth] = React69.useState(width);
|
|
13153
|
+
const [applied, setApplied] = React69.useState({});
|
|
13154
|
+
const [draft, setDraft] = React69.useState("");
|
|
13155
|
+
const dragging = React69.useRef(null);
|
|
13156
|
+
React69.useEffect(() => setPanelWidth(width), [width]);
|
|
13128
13157
|
const engine = useChatEngine({
|
|
13129
13158
|
contextType,
|
|
13130
13159
|
contextId,
|
|
@@ -13190,7 +13219,7 @@ function AgentChatPanel({
|
|
|
13190
13219
|
onReconnect: engine.reload,
|
|
13191
13220
|
deadTitle: "The assistant isn\u2019t reachable"
|
|
13192
13221
|
};
|
|
13193
|
-
const sessionBar = /* @__PURE__ */
|
|
13222
|
+
const sessionBar = /* @__PURE__ */ jsx98(
|
|
13194
13223
|
ChatSessionBar,
|
|
13195
13224
|
{
|
|
13196
13225
|
sessionStats,
|
|
@@ -13199,7 +13228,7 @@ function AgentChatPanel({
|
|
|
13199
13228
|
onClear: engine.visible.length ? engine.clear : void 0
|
|
13200
13229
|
}
|
|
13201
13230
|
);
|
|
13202
|
-
const modelControls = /* @__PURE__ */
|
|
13231
|
+
const modelControls = /* @__PURE__ */ jsx98(
|
|
13203
13232
|
ModelControls,
|
|
13204
13233
|
{
|
|
13205
13234
|
models,
|
|
@@ -13214,7 +13243,7 @@ function AgentChatPanel({
|
|
|
13214
13243
|
narrow
|
|
13215
13244
|
}
|
|
13216
13245
|
);
|
|
13217
|
-
const threadMenu = threads && threads.length ? /* @__PURE__ */
|
|
13246
|
+
const threadMenu = threads && threads.length ? /* @__PURE__ */ jsx98(
|
|
13218
13247
|
MenuButton,
|
|
13219
13248
|
{
|
|
13220
13249
|
variant: "ghost",
|
|
@@ -13252,7 +13281,7 @@ function AgentChatPanel({
|
|
|
13252
13281
|
},
|
|
13253
13282
|
"aria-label": title,
|
|
13254
13283
|
children: [
|
|
13255
|
-
surface === "sidebar" && resizable ? /* @__PURE__ */
|
|
13284
|
+
surface === "sidebar" && resizable ? /* @__PURE__ */ jsx98(
|
|
13256
13285
|
"div",
|
|
13257
13286
|
{
|
|
13258
13287
|
className: "fdc-grip",
|
|
@@ -13268,19 +13297,19 @@ function AgentChatPanel({
|
|
|
13268
13297
|
}
|
|
13269
13298
|
) : null,
|
|
13270
13299
|
showHeader ? /* @__PURE__ */ jsxs88("header", { className: "fdc-head", children: [
|
|
13271
|
-
/* @__PURE__ */
|
|
13300
|
+
/* @__PURE__ */ jsx98("span", { className: "fdc-head-mark", "aria-hidden": "true", children: /* @__PURE__ */ jsx98("i", { className: "ph ph-" + assistantIcon }) }),
|
|
13272
13301
|
/* @__PURE__ */ jsxs88("span", { className: "fdc-head-titles", children: [
|
|
13273
|
-
/* @__PURE__ */
|
|
13274
|
-
subtitle ? /* @__PURE__ */
|
|
13302
|
+
/* @__PURE__ */ jsx98("span", { className: "fdc-head-title", title: truncationTitle(title), children: title }),
|
|
13303
|
+
subtitle ? /* @__PURE__ */ jsx98("span", { className: "fdc-head-sub", title: truncationTitle(subtitle), children: subtitle }) : null
|
|
13275
13304
|
] }),
|
|
13276
13305
|
/* @__PURE__ */ jsxs88("span", { className: "fdc-head-acts", children: [
|
|
13277
13306
|
headerActions,
|
|
13278
13307
|
threadMenu,
|
|
13279
|
-
onNewThread ? /* @__PURE__ */
|
|
13280
|
-
onClose ? /* @__PURE__ */
|
|
13308
|
+
onNewThread ? /* @__PURE__ */ jsx98("button", { type: "button", className: "fdc-iconbtn", onClick: onNewThread, "aria-label": "New conversation", title: "New conversation", children: /* @__PURE__ */ jsx98("i", { className: "ph ph-plus", "aria-hidden": "true" }) }) : null,
|
|
13309
|
+
onClose ? /* @__PURE__ */ jsx98("button", { type: "button", className: "fdc-iconbtn", onClick: onClose, "aria-label": "Close panel", title: "Close", children: /* @__PURE__ */ jsx98("i", { className: "ph ph-x", "aria-hidden": "true" }) }) : null
|
|
13281
13310
|
] })
|
|
13282
13311
|
] }) : null,
|
|
13283
|
-
/* @__PURE__ */
|
|
13312
|
+
/* @__PURE__ */ jsx98(
|
|
13284
13313
|
ChatTranscript,
|
|
13285
13314
|
{
|
|
13286
13315
|
messages: engine.visible,
|
|
@@ -13295,7 +13324,7 @@ function AgentChatPanel({
|
|
|
13295
13324
|
renderEmpty
|
|
13296
13325
|
}
|
|
13297
13326
|
),
|
|
13298
|
-
/* @__PURE__ */
|
|
13327
|
+
/* @__PURE__ */ jsx98(
|
|
13299
13328
|
ChatComposer,
|
|
13300
13329
|
{
|
|
13301
13330
|
onSubmit: (text, atts) => engine.send(text, atts),
|
|
@@ -13328,8 +13357,8 @@ function AgentChatPanel({
|
|
|
13328
13357
|
}
|
|
13329
13358
|
|
|
13330
13359
|
// src/components/files/FileViewer.tsx
|
|
13331
|
-
import * as
|
|
13332
|
-
import { jsx as
|
|
13360
|
+
import * as React70 from "react";
|
|
13361
|
+
import { jsx as jsx99, jsxs as jsxs89 } from "react/jsx-runtime";
|
|
13333
13362
|
function previewKindOf(file) {
|
|
13334
13363
|
const mime = (file.mime || "").toLowerCase();
|
|
13335
13364
|
const ext = extensionOf(file.name || "");
|
|
@@ -13385,13 +13414,13 @@ function parseDelimited(text, delimiter) {
|
|
|
13385
13414
|
return rows;
|
|
13386
13415
|
}
|
|
13387
13416
|
function usePreview(file, kind, resolveUrl) {
|
|
13388
|
-
const [state, setState] =
|
|
13389
|
-
const [attempt, setAttempt] =
|
|
13390
|
-
const resolveRef =
|
|
13391
|
-
|
|
13417
|
+
const [state, setState] = React70.useState({ status: "loading" });
|
|
13418
|
+
const [attempt, setAttempt] = React70.useState(0);
|
|
13419
|
+
const resolveRef = React70.useRef(resolveUrl);
|
|
13420
|
+
React70.useEffect(() => {
|
|
13392
13421
|
resolveRef.current = resolveUrl;
|
|
13393
13422
|
}, [resolveUrl]);
|
|
13394
|
-
|
|
13423
|
+
React70.useEffect(() => {
|
|
13395
13424
|
if (kind === "none") {
|
|
13396
13425
|
setState({ status: "ready" });
|
|
13397
13426
|
return;
|
|
@@ -13421,19 +13450,19 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
13421
13450
|
if (ac) ac.abort();
|
|
13422
13451
|
};
|
|
13423
13452
|
}, [file.id, kind, attempt]);
|
|
13424
|
-
return { ...state, retry:
|
|
13453
|
+
return { ...state, retry: React70.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
13425
13454
|
}
|
|
13426
13455
|
function PreviewBody({ file, kind, state }) {
|
|
13427
|
-
if (kind === "image") return /* @__PURE__ */
|
|
13428
|
-
if (kind === "pdf") return /* @__PURE__ */
|
|
13429
|
-
if (kind === "markdown") return /* @__PURE__ */
|
|
13456
|
+
if (kind === "image") return /* @__PURE__ */ jsx99("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
13457
|
+
if (kind === "pdf") return /* @__PURE__ */ jsx99("iframe", { className: "fd-fv-pdf", src: state.url, title: file.name || "PDF preview" });
|
|
13458
|
+
if (kind === "markdown") return /* @__PURE__ */ jsx99(Markdown, { className: "fd-fv-markdown", source: state.text || "" });
|
|
13430
13459
|
if (kind === "json") {
|
|
13431
13460
|
let pretty = state.text || "";
|
|
13432
13461
|
try {
|
|
13433
13462
|
pretty = JSON.stringify(JSON.parse(pretty), null, 2);
|
|
13434
13463
|
} catch {
|
|
13435
13464
|
}
|
|
13436
|
-
return /* @__PURE__ */
|
|
13465
|
+
return /* @__PURE__ */ jsx99(CodeBlock, { code: pretty, language: "json" });
|
|
13437
13466
|
}
|
|
13438
13467
|
if (kind === "csv") {
|
|
13439
13468
|
const tsv = extensionOf(file.name || "") === "tsv" || (file.mime || "").toLowerCase().includes("tab-separated");
|
|
@@ -13443,8 +13472,8 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13443
13472
|
const shown = dataRows.slice(0, FILE_VIEWER_CSV_ROW_LIMIT);
|
|
13444
13473
|
return /* @__PURE__ */ jsxs89("div", { className: "fd-fv-csv", children: [
|
|
13445
13474
|
/* @__PURE__ */ jsxs89("table", { className: "fd-fv-csv-table", children: [
|
|
13446
|
-
/* @__PURE__ */
|
|
13447
|
-
/* @__PURE__ */
|
|
13475
|
+
/* @__PURE__ */ jsx99("thead", { children: /* @__PURE__ */ jsx99("tr", { children: head.map((c, i) => /* @__PURE__ */ jsx99("th", { children: c }, i)) }) }),
|
|
13476
|
+
/* @__PURE__ */ jsx99("tbody", { children: shown.map((r, ri) => /* @__PURE__ */ jsx99("tr", { children: head.map((_, ci) => /* @__PURE__ */ jsx99("td", { children: r[ci] ?? "" }, ci)) }, ri)) })
|
|
13448
13477
|
] }),
|
|
13449
13478
|
dataRows.length > FILE_VIEWER_CSV_ROW_LIMIT ? /* @__PURE__ */ jsxs89("p", { className: "fd-fv-csv-note fd-body-sm fd-muted", children: [
|
|
13450
13479
|
"Showing the first ",
|
|
@@ -13455,10 +13484,10 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13455
13484
|
] }) : null
|
|
13456
13485
|
] });
|
|
13457
13486
|
}
|
|
13458
|
-
if (kind === "text") return /* @__PURE__ */
|
|
13487
|
+
if (kind === "text") return /* @__PURE__ */ jsx99(CodeBlock, { code: state.text || "", language: extensionOf(file.name || "") || void 0 });
|
|
13459
13488
|
return /* @__PURE__ */ jsxs89("div", { className: "fd-fv-fallback", children: [
|
|
13460
|
-
/* @__PURE__ */
|
|
13461
|
-
/* @__PURE__ */
|
|
13489
|
+
/* @__PURE__ */ jsx99("span", { className: "fd-fv-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx99("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
13490
|
+
/* @__PURE__ */ jsx99("span", { className: "fd-fv-fallback-title", children: "No preview available" }),
|
|
13462
13491
|
/* @__PURE__ */ jsxs89("span", { className: "fd-fv-fallback-meta", children: [
|
|
13463
13492
|
file.mime || "Unknown type",
|
|
13464
13493
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
@@ -13466,13 +13495,13 @@ function PreviewBody({ file, kind, state }) {
|
|
|
13466
13495
|
] });
|
|
13467
13496
|
}
|
|
13468
13497
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
13469
|
-
const kind =
|
|
13498
|
+
const kind = React70.useMemo(() => previewKindOf(file), [file]);
|
|
13470
13499
|
const preview = usePreview(file, kind, resolveUrl);
|
|
13471
|
-
const [tab, setTab] =
|
|
13472
|
-
const [downloading, setDownloading] =
|
|
13473
|
-
const [downloadError, setDownloadError] =
|
|
13500
|
+
const [tab, setTab] = React70.useState("preview");
|
|
13501
|
+
const [downloading, setDownloading] = React70.useState(false);
|
|
13502
|
+
const [downloadError, setDownloadError] = React70.useState(null);
|
|
13474
13503
|
const hasSide = sidePanel != null;
|
|
13475
|
-
|
|
13504
|
+
React70.useEffect(() => {
|
|
13476
13505
|
setTab("preview");
|
|
13477
13506
|
}, [file.id]);
|
|
13478
13507
|
const download = () => {
|
|
@@ -13495,9 +13524,9 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13495
13524
|
"aria-label": file.name || "File",
|
|
13496
13525
|
children: [
|
|
13497
13526
|
/* @__PURE__ */ jsxs89("header", { className: "fd-fv-head", children: [
|
|
13498
|
-
/* @__PURE__ */
|
|
13527
|
+
/* @__PURE__ */ jsx99("span", { className: "fd-fv-head-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx99("i", { className: "ph ph-" + iconForMime(file.mime, file.name) }) }),
|
|
13499
13528
|
/* @__PURE__ */ jsxs89("span", { className: "fd-fv-head-titles", children: [
|
|
13500
|
-
/* @__PURE__ */
|
|
13529
|
+
/* @__PURE__ */ jsx99("span", { className: "fd-fv-head-title", title: file.name, children: file.name }),
|
|
13501
13530
|
/* @__PURE__ */ jsxs89("span", { className: "fd-fv-head-meta", children: [
|
|
13502
13531
|
file.mime || "Unknown type",
|
|
13503
13532
|
file.size ? " \xB7 " + formatBytes(file.size) : ""
|
|
@@ -13505,12 +13534,12 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13505
13534
|
] }),
|
|
13506
13535
|
/* @__PURE__ */ jsxs89("span", { className: "fd-fv-head-actions", children: [
|
|
13507
13536
|
actions,
|
|
13508
|
-
/* @__PURE__ */
|
|
13509
|
-
onClose ? /* @__PURE__ */
|
|
13537
|
+
/* @__PURE__ */ jsx99(Button, { variant: "secondary", size: "sm", icon: "download-simple", loading: downloading, onClick: download, children: "Download" }),
|
|
13538
|
+
onClose ? /* @__PURE__ */ jsx99(IconButton, { icon: "x", label: "Close", onClick: onClose }) : null
|
|
13510
13539
|
] })
|
|
13511
13540
|
] }),
|
|
13512
|
-
downloadError ? /* @__PURE__ */
|
|
13513
|
-
hasSide ? /* @__PURE__ */
|
|
13541
|
+
downloadError ? /* @__PURE__ */ jsx99("div", { className: "fd-fv-download-error", role: "alert", children: downloadError }) : null,
|
|
13542
|
+
hasSide ? /* @__PURE__ */ jsx99(
|
|
13514
13543
|
Tabs,
|
|
13515
13544
|
{
|
|
13516
13545
|
className: "fd-fv-tabs",
|
|
@@ -13520,18 +13549,18 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13520
13549
|
}
|
|
13521
13550
|
) : null,
|
|
13522
13551
|
/* @__PURE__ */ jsxs89("div", { className: "fd-fv-body", children: [
|
|
13523
|
-
/* @__PURE__ */
|
|
13552
|
+
/* @__PURE__ */ jsx99("div", { className: "fd-fv-preview", role: "region", "aria-label": "Preview of " + (file.name || "file"), children: /* @__PURE__ */ jsx99(
|
|
13524
13553
|
LoadingRegion,
|
|
13525
13554
|
{
|
|
13526
13555
|
state: preview.status === "loading" ? "loading" : preview.status === "error" ? "error" : "ready",
|
|
13527
13556
|
error: preview.error,
|
|
13528
13557
|
label: "Loading preview of " + (file.name || "file"),
|
|
13529
13558
|
onRetry: preview.status === "error" ? preview.retry : void 0,
|
|
13530
|
-
skeleton: /* @__PURE__ */
|
|
13531
|
-
children: /* @__PURE__ */
|
|
13559
|
+
skeleton: /* @__PURE__ */ jsx99(Skeleton, { shape: "card", h: 220 }),
|
|
13560
|
+
children: /* @__PURE__ */ jsx99(PreviewBody, { file, kind, state: preview })
|
|
13532
13561
|
}
|
|
13533
13562
|
) }),
|
|
13534
|
-
hasSide ? /* @__PURE__ */
|
|
13563
|
+
hasSide ? /* @__PURE__ */ jsx99("div", { className: "fd-fv-side", role: "region", "aria-label": sidePanelLabel, children: sidePanel }) : null
|
|
13535
13564
|
] })
|
|
13536
13565
|
]
|
|
13537
13566
|
}
|
|
@@ -13539,8 +13568,8 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
13539
13568
|
}
|
|
13540
13569
|
|
|
13541
13570
|
// src/components/files/FileBrowser.tsx
|
|
13542
|
-
import * as
|
|
13543
|
-
import { Fragment as Fragment29, jsx as
|
|
13571
|
+
import * as React71 from "react";
|
|
13572
|
+
import { Fragment as Fragment29, jsx as jsx100, jsxs as jsxs90 } from "react/jsx-runtime";
|
|
13544
13573
|
function childrenOf(folders, parentId) {
|
|
13545
13574
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
13546
13575
|
}
|
|
@@ -13613,7 +13642,7 @@ function FolderPickerMenu({
|
|
|
13613
13642
|
const panel = useInlinePanel();
|
|
13614
13643
|
const { open: open2, setOpen, ref } = panel;
|
|
13615
13644
|
return /* @__PURE__ */ jsxs90("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
13616
|
-
/* @__PURE__ */
|
|
13645
|
+
/* @__PURE__ */ jsx100(
|
|
13617
13646
|
IconButton,
|
|
13618
13647
|
{
|
|
13619
13648
|
icon: "arrows-out-cardinal",
|
|
@@ -13625,8 +13654,8 @@ function FolderPickerMenu({
|
|
|
13625
13654
|
onClick: () => setOpen((v) => !v)
|
|
13626
13655
|
}
|
|
13627
13656
|
),
|
|
13628
|
-
/* @__PURE__ */
|
|
13629
|
-
/* @__PURE__ */
|
|
13657
|
+
/* @__PURE__ */ jsx100(InlinePanelSurface, { panel, align: "right", offset: 4, width: 220, maxHeight: 280, role: "menu", label, children: /* @__PURE__ */ jsxs90("div", { className: "fd-fb-menu", children: [
|
|
13658
|
+
/* @__PURE__ */ jsx100("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
13630
13659
|
destinations.map((d) => /* @__PURE__ */ jsxs90(
|
|
13631
13660
|
"button",
|
|
13632
13661
|
{
|
|
@@ -13639,7 +13668,7 @@ function FolderPickerMenu({
|
|
|
13639
13668
|
setOpen(false);
|
|
13640
13669
|
},
|
|
13641
13670
|
children: [
|
|
13642
|
-
/* @__PURE__ */
|
|
13671
|
+
/* @__PURE__ */ jsx100("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
13643
13672
|
d.name
|
|
13644
13673
|
]
|
|
13645
13674
|
},
|
|
@@ -13649,8 +13678,8 @@ function FolderPickerMenu({
|
|
|
13649
13678
|
] });
|
|
13650
13679
|
}
|
|
13651
13680
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
13652
|
-
const [over, setOver] =
|
|
13653
|
-
const dragCounter =
|
|
13681
|
+
const [over, setOver] = React71.useState(false);
|
|
13682
|
+
const dragCounter = React71.useRef(0);
|
|
13654
13683
|
const dropHandlers = isDropTarget ? {
|
|
13655
13684
|
onDragEnter: (e) => {
|
|
13656
13685
|
if (!hasInternalPayload(e)) return;
|
|
@@ -13685,26 +13714,26 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
13685
13714
|
draggable: !!draggableId,
|
|
13686
13715
|
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
13687
13716
|
children: [
|
|
13688
|
-
/* @__PURE__ */
|
|
13717
|
+
/* @__PURE__ */ jsx100("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx100("i", { className: "ph ph-" + icon }) }),
|
|
13689
13718
|
/* @__PURE__ */ jsxs90("span", { className: "fd-fb-row-text", children: [
|
|
13690
|
-
/* @__PURE__ */
|
|
13691
|
-
meta ? /* @__PURE__ */
|
|
13719
|
+
/* @__PURE__ */ jsx100("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
13720
|
+
meta ? /* @__PURE__ */ jsx100("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
13692
13721
|
] })
|
|
13693
13722
|
]
|
|
13694
13723
|
}
|
|
13695
13724
|
),
|
|
13696
|
-
actions ? /* @__PURE__ */
|
|
13725
|
+
actions ? /* @__PURE__ */ jsx100("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
13697
13726
|
] });
|
|
13698
13727
|
}
|
|
13699
13728
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
13700
13729
|
const kids = childrenOf(folders, folder.id);
|
|
13701
|
-
const [expanded, setExpanded] =
|
|
13702
|
-
|
|
13730
|
+
const [expanded, setExpanded] = React71.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
13731
|
+
React71.useEffect(() => {
|
|
13703
13732
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
13704
13733
|
}, [currentFolderId, folder.id, folders]);
|
|
13705
13734
|
const isCurrent = folder.id === currentFolderId;
|
|
13706
13735
|
return /* @__PURE__ */ jsxs90("div", { className: "fd-fb-tree-node", children: [
|
|
13707
|
-
/* @__PURE__ */
|
|
13736
|
+
/* @__PURE__ */ jsx100(
|
|
13708
13737
|
RowShell,
|
|
13709
13738
|
{
|
|
13710
13739
|
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
@@ -13714,7 +13743,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13714
13743
|
isDropTarget: canMove,
|
|
13715
13744
|
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
13716
13745
|
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
13717
|
-
actions: kids.length ? /* @__PURE__ */
|
|
13746
|
+
actions: kids.length ? /* @__PURE__ */ jsx100(
|
|
13718
13747
|
IconButton,
|
|
13719
13748
|
{
|
|
13720
13749
|
icon: expanded ? "caret-down" : "caret-right",
|
|
@@ -13726,7 +13755,7 @@ function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveI
|
|
|
13726
13755
|
) : void 0
|
|
13727
13756
|
}
|
|
13728
13757
|
),
|
|
13729
|
-
expanded && kids.length ? /* @__PURE__ */
|
|
13758
|
+
expanded && kids.length ? /* @__PURE__ */ jsx100("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ jsx100(
|
|
13730
13759
|
TreeNode,
|
|
13731
13760
|
{
|
|
13732
13761
|
folder: k,
|
|
@@ -13765,15 +13794,15 @@ function FileBrowser({
|
|
|
13765
13794
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
13766
13795
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
13767
13796
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
13768
|
-
const [createOpen, setCreateOpen] =
|
|
13769
|
-
const [createName, setCreateName] =
|
|
13770
|
-
const [renameTarget, setRenameTarget] =
|
|
13771
|
-
const [renameValue, setRenameValue] =
|
|
13772
|
-
const [deleteTarget, setDeleteTarget] =
|
|
13773
|
-
const uploadInputRef =
|
|
13774
|
-
const crumbFolders =
|
|
13775
|
-
const subfolders =
|
|
13776
|
-
const currentFiles =
|
|
13797
|
+
const [createOpen, setCreateOpen] = React71.useState(false);
|
|
13798
|
+
const [createName, setCreateName] = React71.useState("");
|
|
13799
|
+
const [renameTarget, setRenameTarget] = React71.useState(null);
|
|
13800
|
+
const [renameValue, setRenameValue] = React71.useState("");
|
|
13801
|
+
const [deleteTarget, setDeleteTarget] = React71.useState(null);
|
|
13802
|
+
const uploadInputRef = React71.useRef(null);
|
|
13803
|
+
const crumbFolders = React71.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
13804
|
+
const subfolders = React71.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
13805
|
+
const currentFiles = React71.useMemo(
|
|
13777
13806
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
13778
13807
|
[files, currentFolderId]
|
|
13779
13808
|
);
|
|
@@ -13815,7 +13844,7 @@ function FileBrowser({
|
|
|
13815
13844
|
const content = /* @__PURE__ */ jsxs90("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
13816
13845
|
/* @__PURE__ */ jsxs90("div", { className: "fd-fb-head", children: [
|
|
13817
13846
|
/* @__PURE__ */ jsxs90("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
13818
|
-
/* @__PURE__ */
|
|
13847
|
+
/* @__PURE__ */ jsx100(
|
|
13819
13848
|
BreadcrumbCrumb,
|
|
13820
13849
|
{
|
|
13821
13850
|
label: "Home",
|
|
@@ -13825,7 +13854,7 @@ function FileBrowser({
|
|
|
13825
13854
|
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
13826
13855
|
}
|
|
13827
13856
|
),
|
|
13828
|
-
crumbFolders.map((f, i) => /* @__PURE__ */
|
|
13857
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ jsx100(
|
|
13829
13858
|
BreadcrumbCrumb,
|
|
13830
13859
|
{
|
|
13831
13860
|
label: f.name,
|
|
@@ -13838,10 +13867,10 @@ function FileBrowser({
|
|
|
13838
13867
|
))
|
|
13839
13868
|
] }),
|
|
13840
13869
|
/* @__PURE__ */ jsxs90("span", { className: "fd-fb-actions", children: [
|
|
13841
|
-
canCreateFolder ? /* @__PURE__ */
|
|
13870
|
+
canCreateFolder ? /* @__PURE__ */ jsx100(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
13842
13871
|
canUpload ? /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13843
|
-
/* @__PURE__ */
|
|
13844
|
-
/* @__PURE__ */
|
|
13872
|
+
/* @__PURE__ */ jsx100(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
13873
|
+
/* @__PURE__ */ jsx100(
|
|
13845
13874
|
"input",
|
|
13846
13875
|
{
|
|
13847
13876
|
ref: uploadInputRef,
|
|
@@ -13861,7 +13890,7 @@ function FileBrowser({
|
|
|
13861
13890
|
] }),
|
|
13862
13891
|
/* @__PURE__ */ jsxs90("div", { className: "fd-fb-body", children: [
|
|
13863
13892
|
/* @__PURE__ */ jsxs90("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
13864
|
-
/* @__PURE__ */
|
|
13893
|
+
/* @__PURE__ */ jsx100(
|
|
13865
13894
|
RowShell,
|
|
13866
13895
|
{
|
|
13867
13896
|
icon: "house-simple",
|
|
@@ -13872,7 +13901,7 @@ function FileBrowser({
|
|
|
13872
13901
|
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
13873
13902
|
}
|
|
13874
13903
|
),
|
|
13875
|
-
childrenOf(folders, null).map((f) => /* @__PURE__ */
|
|
13904
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ jsx100(
|
|
13876
13905
|
TreeNode,
|
|
13877
13906
|
{
|
|
13878
13907
|
folder: f,
|
|
@@ -13886,18 +13915,18 @@ function FileBrowser({
|
|
|
13886
13915
|
f.id
|
|
13887
13916
|
))
|
|
13888
13917
|
] }),
|
|
13889
|
-
/* @__PURE__ */
|
|
13918
|
+
/* @__PURE__ */ jsx100("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ jsx100(
|
|
13890
13919
|
LoadingRegion,
|
|
13891
13920
|
{
|
|
13892
13921
|
state: loading ? "loading" : "ready",
|
|
13893
13922
|
label: "Loading folder contents",
|
|
13894
13923
|
skeleton: /* @__PURE__ */ jsxs90("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
13895
|
-
/* @__PURE__ */
|
|
13896
|
-
/* @__PURE__ */
|
|
13897
|
-
/* @__PURE__ */
|
|
13924
|
+
/* @__PURE__ */ jsx100(Skeleton, { h: 44, radius: "10px" }),
|
|
13925
|
+
/* @__PURE__ */ jsx100(Skeleton, { h: 44, radius: "10px" }),
|
|
13926
|
+
/* @__PURE__ */ jsx100(Skeleton, { h: 44, radius: "10px" })
|
|
13898
13927
|
] }),
|
|
13899
|
-
children: isEmpty ? /* @__PURE__ */
|
|
13900
|
-
subfolders.map((f) => /* @__PURE__ */
|
|
13928
|
+
children: isEmpty ? /* @__PURE__ */ jsx100(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__ */ jsxs90("div", { className: "fd-fb-list", children: [
|
|
13929
|
+
subfolders.map((f) => /* @__PURE__ */ jsx100(
|
|
13901
13930
|
RowShell,
|
|
13902
13931
|
{
|
|
13903
13932
|
icon: "folder-simple",
|
|
@@ -13907,8 +13936,8 @@ function FileBrowser({
|
|
|
13907
13936
|
isDropTarget: canMove,
|
|
13908
13937
|
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
13909
13938
|
actions: /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13910
|
-
canRenameFolder ? /* @__PURE__ */
|
|
13911
|
-
canMove ? /* @__PURE__ */
|
|
13939
|
+
canRenameFolder ? /* @__PURE__ */ jsx100(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
13940
|
+
canMove ? /* @__PURE__ */ jsx100(
|
|
13912
13941
|
FolderPickerMenu,
|
|
13913
13942
|
{
|
|
13914
13943
|
label: "Move " + f.name,
|
|
@@ -13916,12 +13945,12 @@ function FileBrowser({
|
|
|
13916
13945
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
13917
13946
|
}
|
|
13918
13947
|
) : null,
|
|
13919
|
-
canDeleteFolder ? /* @__PURE__ */
|
|
13948
|
+
canDeleteFolder ? /* @__PURE__ */ jsx100(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
13920
13949
|
] })
|
|
13921
13950
|
},
|
|
13922
13951
|
f.id
|
|
13923
13952
|
)),
|
|
13924
|
-
currentFiles.map((file) => /* @__PURE__ */
|
|
13953
|
+
currentFiles.map((file) => /* @__PURE__ */ jsx100(
|
|
13925
13954
|
RowShell,
|
|
13926
13955
|
{
|
|
13927
13956
|
icon: iconForMime(file.mime, file.name),
|
|
@@ -13930,7 +13959,7 @@ function FileBrowser({
|
|
|
13930
13959
|
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
13931
13960
|
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
13932
13961
|
actions: /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13933
|
-
canMove ? /* @__PURE__ */
|
|
13962
|
+
canMove ? /* @__PURE__ */ jsx100(
|
|
13934
13963
|
FolderPickerMenu,
|
|
13935
13964
|
{
|
|
13936
13965
|
label: "Move " + file.name,
|
|
@@ -13938,7 +13967,7 @@ function FileBrowser({
|
|
|
13938
13967
|
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
13939
13968
|
}
|
|
13940
13969
|
) : null,
|
|
13941
|
-
canRemoveFile ? /* @__PURE__ */
|
|
13970
|
+
canRemoveFile ? /* @__PURE__ */ jsx100(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
13942
13971
|
] })
|
|
13943
13972
|
},
|
|
13944
13973
|
file.id
|
|
@@ -13947,10 +13976,10 @@ function FileBrowser({
|
|
|
13947
13976
|
}
|
|
13948
13977
|
) })
|
|
13949
13978
|
] }),
|
|
13950
|
-
/* @__PURE__ */
|
|
13951
|
-
/* @__PURE__ */
|
|
13952
|
-
/* @__PURE__ */
|
|
13953
|
-
] }), children: /* @__PURE__ */
|
|
13979
|
+
/* @__PURE__ */ jsx100(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13980
|
+
/* @__PURE__ */ jsx100(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
13981
|
+
/* @__PURE__ */ jsx100(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
13982
|
+
] }), children: /* @__PURE__ */ jsx100(
|
|
13954
13983
|
"input",
|
|
13955
13984
|
{
|
|
13956
13985
|
className: "fd-fb-input",
|
|
@@ -13964,10 +13993,10 @@ function FileBrowser({
|
|
|
13964
13993
|
autoFocus: true
|
|
13965
13994
|
}
|
|
13966
13995
|
) }),
|
|
13967
|
-
/* @__PURE__ */
|
|
13968
|
-
/* @__PURE__ */
|
|
13969
|
-
/* @__PURE__ */
|
|
13970
|
-
] }), children: /* @__PURE__ */
|
|
13996
|
+
/* @__PURE__ */ jsx100(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13997
|
+
/* @__PURE__ */ jsx100(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
13998
|
+
/* @__PURE__ */ jsx100(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
13999
|
+
] }), children: /* @__PURE__ */ jsx100(
|
|
13971
14000
|
"input",
|
|
13972
14001
|
{
|
|
13973
14002
|
className: "fd-fb-input",
|
|
@@ -13981,7 +14010,7 @@ function FileBrowser({
|
|
|
13981
14010
|
autoFocus: true
|
|
13982
14011
|
}
|
|
13983
14012
|
) }),
|
|
13984
|
-
/* @__PURE__ */
|
|
14013
|
+
/* @__PURE__ */ jsx100(
|
|
13985
14014
|
Modal,
|
|
13986
14015
|
{
|
|
13987
14016
|
open: deleteTarget != null,
|
|
@@ -13989,14 +14018,14 @@ function FileBrowser({
|
|
|
13989
14018
|
description: "This can't be undone. The folder must be empty.",
|
|
13990
14019
|
onClose: () => setDeleteTarget(null),
|
|
13991
14020
|
footer: /* @__PURE__ */ jsxs90(Fragment29, { children: [
|
|
13992
|
-
/* @__PURE__ */
|
|
13993
|
-
/* @__PURE__ */
|
|
14021
|
+
/* @__PURE__ */ jsx100(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
14022
|
+
/* @__PURE__ */ jsx100(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
13994
14023
|
] })
|
|
13995
14024
|
}
|
|
13996
14025
|
)
|
|
13997
14026
|
] });
|
|
13998
14027
|
if (!canUpload) return content;
|
|
13999
|
-
return /* @__PURE__ */
|
|
14028
|
+
return /* @__PURE__ */ jsx100(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
14000
14029
|
}
|
|
14001
14030
|
function BreadcrumbCrumb({
|
|
14002
14031
|
label,
|
|
@@ -14005,8 +14034,8 @@ function BreadcrumbCrumb({
|
|
|
14005
14034
|
isDropTarget,
|
|
14006
14035
|
onDropPayload
|
|
14007
14036
|
}) {
|
|
14008
|
-
const [over, setOver] =
|
|
14009
|
-
const dragCounter =
|
|
14037
|
+
const [over, setOver] = React71.useState(false);
|
|
14038
|
+
const dragCounter = React71.useRef(0);
|
|
14010
14039
|
const dropHandlers = isDropTarget ? {
|
|
14011
14040
|
onDragEnter: (e) => {
|
|
14012
14041
|
if (!hasInternalPayload(e)) return;
|
|
@@ -14031,11 +14060,11 @@ function BreadcrumbCrumb({
|
|
|
14031
14060
|
if (payload && onDropPayload) onDropPayload(payload);
|
|
14032
14061
|
}
|
|
14033
14062
|
} : {};
|
|
14034
|
-
return /* @__PURE__ */
|
|
14063
|
+
return /* @__PURE__ */ jsx100("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ jsx100("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ jsx100("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
14035
14064
|
}
|
|
14036
14065
|
|
|
14037
14066
|
// src/kits/query.ts
|
|
14038
|
-
import * as
|
|
14067
|
+
import * as React72 from "react";
|
|
14039
14068
|
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
14040
14069
|
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
14041
14070
|
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
@@ -14090,22 +14119,22 @@ function compare(a, b, dir) {
|
|
|
14090
14119
|
var API = null;
|
|
14091
14120
|
var PREFS = null;
|
|
14092
14121
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
14093
|
-
const [query, setQuery] =
|
|
14122
|
+
const [query, setQuery] = React72.useState(() => {
|
|
14094
14123
|
const store = PREFS || window.PlannerPrefs;
|
|
14095
14124
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
14096
14125
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
14097
14126
|
});
|
|
14098
|
-
const savePref =
|
|
14127
|
+
const savePref = React72.useCallback((patch2) => {
|
|
14099
14128
|
const store = PREFS || window.PlannerPrefs;
|
|
14100
14129
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
14101
14130
|
}, [prefsKey]);
|
|
14102
|
-
const [res, setRes] =
|
|
14103
|
-
const [loading, setLoading] =
|
|
14104
|
-
const seq2 =
|
|
14131
|
+
const [res, setRes] = React72.useState(null);
|
|
14132
|
+
const [loading, setLoading] = React72.useState(true);
|
|
14133
|
+
const seq2 = React72.useRef(0);
|
|
14105
14134
|
const depKey = (deps || []).join("|");
|
|
14106
14135
|
const paramKey = JSON.stringify(params || {});
|
|
14107
14136
|
const queryKey = JSON.stringify(query);
|
|
14108
|
-
|
|
14137
|
+
React72.useEffect(() => {
|
|
14109
14138
|
const id = ++seq2.current;
|
|
14110
14139
|
setLoading(true);
|
|
14111
14140
|
const t = setTimeout(() => {
|
|
@@ -14424,12 +14453,12 @@ function createVersionStore(initialState, options) {
|
|
|
14424
14453
|
}
|
|
14425
14454
|
|
|
14426
14455
|
// src/kits/documentTitle.ts
|
|
14427
|
-
import * as
|
|
14456
|
+
import * as React73 from "react";
|
|
14428
14457
|
function formatDocumentTitle(routeTitle, appName) {
|
|
14429
14458
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
14430
14459
|
}
|
|
14431
14460
|
function useDocumentTitle(routeTitle, appName) {
|
|
14432
|
-
|
|
14461
|
+
React73.useEffect(() => {
|
|
14433
14462
|
if (typeof document === "undefined") return;
|
|
14434
14463
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
14435
14464
|
}, [routeTitle, appName]);
|
|
@@ -14443,6 +14472,7 @@ export {
|
|
|
14443
14472
|
AppShell,
|
|
14444
14473
|
AppSwitcher,
|
|
14445
14474
|
AppearanceMenu,
|
|
14475
|
+
AppearanceProvider,
|
|
14446
14476
|
Avatar,
|
|
14447
14477
|
AvatarStack,
|
|
14448
14478
|
Badge,
|
|
@@ -14454,6 +14484,7 @@ export {
|
|
|
14454
14484
|
CHANNEL_WEIGHTS,
|
|
14455
14485
|
CHAT_UNAVAILABLE,
|
|
14456
14486
|
COPIED_FEEDBACK_MS,
|
|
14487
|
+
CORNER_STACK_INSET_PROPERTY,
|
|
14457
14488
|
Calendar,
|
|
14458
14489
|
Card,
|
|
14459
14490
|
CardGrid,
|
|
@@ -14597,6 +14628,7 @@ export {
|
|
|
14597
14628
|
__resetLayerStackForTests,
|
|
14598
14629
|
acceptMatches,
|
|
14599
14630
|
anyOfFilter,
|
|
14631
|
+
applyAppearance,
|
|
14600
14632
|
applyPrefs,
|
|
14601
14633
|
channelWeightOf,
|
|
14602
14634
|
computeNeedMore,
|
|
@@ -14642,6 +14674,7 @@ export {
|
|
|
14642
14674
|
toAttachment,
|
|
14643
14675
|
tokenize,
|
|
14644
14676
|
useAppearancePrefs,
|
|
14677
|
+
useAppearanceStore,
|
|
14645
14678
|
useChatEngine,
|
|
14646
14679
|
useCopyToClipboard,
|
|
14647
14680
|
useCornerStackSlot,
|
|
@@ -14657,6 +14690,7 @@ export {
|
|
|
14657
14690
|
useStagedFiles,
|
|
14658
14691
|
useToast,
|
|
14659
14692
|
validateFilterValue,
|
|
14660
|
-
visibleMessages
|
|
14693
|
+
visibleMessages,
|
|
14694
|
+
watchAppearance
|
|
14661
14695
|
};
|
|
14662
14696
|
//# sourceMappingURL=index.js.map
|