@flytedan/flytebot-design-system 0.15.0 → 0.17.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 +641 -486
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -20
- package/dist/index.d.ts +160 -20
- package/dist/index.js +639 -486
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -885,37 +885,48 @@ function Spinner({ size = "md", label = "Loading", className = "", style, ...res
|
|
|
885
885
|
}
|
|
886
886
|
|
|
887
887
|
// src/components/navigation/SidebarNav.tsx
|
|
888
|
+
import * as React6 from "react";
|
|
888
889
|
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
889
890
|
function Tip({ label, children }) {
|
|
890
891
|
return /* @__PURE__ */ jsx13("span", { title: label, style: { display: "inline-flex", flex: "none" }, children });
|
|
891
892
|
}
|
|
892
|
-
|
|
893
|
-
return /* @__PURE__ */ jsxs10(
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
children:
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
}
|
|
893
|
+
var SidebarNav = React6.forwardRef(function SidebarNav2({ brand, groups = [], current: current2, onNavigate, footer, open = false, className = "", ...rest }, ref) {
|
|
894
|
+
return /* @__PURE__ */ jsxs10(
|
|
895
|
+
"nav",
|
|
896
|
+
{
|
|
897
|
+
ref,
|
|
898
|
+
tabIndex: -1,
|
|
899
|
+
className: ["fd-side", className].filter(Boolean).join(" "),
|
|
900
|
+
"data-open": open ? "true" : "false",
|
|
901
|
+
...rest,
|
|
902
|
+
children: [
|
|
903
|
+
brand ? /* @__PURE__ */ jsx13("div", { style: { height: "var(--topbar-h)", display: "flex", alignItems: "center", padding: "0 18px", borderBottom: "1px solid var(--border)", flex: "none", overflow: "hidden" }, children: brand }) : null,
|
|
904
|
+
/* @__PURE__ */ jsx13("div", { style: { flex: 1, overflow: "auto", padding: "4px 10px 18px" }, children: groups.map((g, gi) => /* @__PURE__ */ jsxs10("div", { children: [
|
|
905
|
+
g.label ? /* @__PURE__ */ jsx13("div", { className: "fd-side-group", children: g.label }) : null,
|
|
906
|
+
/* @__PURE__ */ jsx13("div", { className: "fd-stack", style: { gap: 2 }, children: g.items.map((it) => /* @__PURE__ */ jsxs10(
|
|
907
|
+
"button",
|
|
908
|
+
{
|
|
909
|
+
type: "button",
|
|
910
|
+
className: "fd-side-item",
|
|
911
|
+
"aria-current": current2 === it.value ? "page" : void 0,
|
|
912
|
+
onClick: onNavigate ? () => onNavigate(it.value) : void 0,
|
|
913
|
+
children: [
|
|
914
|
+
/* @__PURE__ */ jsx13("span", { className: "fd-side-item-icon", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }),
|
|
915
|
+
/* @__PURE__ */ jsx13("span", { style: { flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, title: truncationTitle(it.label), children: it.label }),
|
|
916
|
+
it.preview ? /* @__PURE__ */ jsx13(Tip, { label: "Designed, backend not wired yet", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-traffic-cone", style: { fontSize: 13, color: "var(--warn-solid)", flex: "none" } }) }) : null,
|
|
917
|
+
it.locked ? /* @__PURE__ */ jsx13(Tip, { label: "You do not have permission for this", children: /* @__PURE__ */ jsx13("i", { className: "ph ph-lock-simple", style: { fontSize: 13, color: "var(--text-muted)", flex: "none" } }) }) : null,
|
|
918
|
+
it.count !== void 0 ? /* @__PURE__ */ jsx13("span", { className: "fd-side-item-count", children: it.count }) : null,
|
|
919
|
+
it.loading ? /* @__PURE__ */ jsx13("span", { className: "fd-skel fd-skel-text", style: { width: 22, height: 11, marginLeft: "auto" } }) : null
|
|
920
|
+
]
|
|
921
|
+
},
|
|
922
|
+
it.value
|
|
923
|
+
)) })
|
|
924
|
+
] }, gi)) }),
|
|
925
|
+
footer ? /* @__PURE__ */ jsx13("div", { style: { borderTop: "1px solid var(--border)", padding: 14, flex: "none" }, children: footer }) : null
|
|
926
|
+
]
|
|
927
|
+
}
|
|
928
|
+
);
|
|
929
|
+
});
|
|
919
930
|
|
|
920
931
|
// src/components/navigation/FlytedeskBrand.tsx
|
|
921
932
|
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
@@ -956,13 +967,13 @@ function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
|
|
|
956
967
|
}
|
|
957
968
|
|
|
958
969
|
// src/components/navigation/Topbar.tsx
|
|
959
|
-
import * as
|
|
970
|
+
import * as React7 from "react";
|
|
960
971
|
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
961
972
|
function useIsNarrow(breakpoint) {
|
|
962
|
-
const [narrow, setNarrow] =
|
|
973
|
+
const [narrow, setNarrow] = React7.useState(
|
|
963
974
|
() => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
|
|
964
975
|
);
|
|
965
|
-
|
|
976
|
+
React7.useEffect(() => {
|
|
966
977
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
967
978
|
const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
968
979
|
const apply = () => setNarrow(mq.matches);
|
|
@@ -983,11 +994,11 @@ function Topbar({
|
|
|
983
994
|
...rest
|
|
984
995
|
}) {
|
|
985
996
|
const narrow = useIsNarrow(overflowBreakpoint);
|
|
986
|
-
const [moreOpen, setMoreOpen] =
|
|
987
|
-
const moreRef =
|
|
997
|
+
const [moreOpen, setMoreOpen] = React7.useState(false);
|
|
998
|
+
const moreRef = React7.useRef(null);
|
|
988
999
|
return /* @__PURE__ */ jsxs13("header", { className: ["fd-topbar", narrow ? "is-narrow" : "", className].filter(Boolean).join(" "), ...rest, children: [
|
|
989
1000
|
onMenu ? /* @__PURE__ */ jsx16("button", { type: "button", className: "fd-btn-icon", "aria-label": "Menu", onClick: onMenu, children: /* @__PURE__ */ jsx16("i", { className: "ph ph-list" }) }) : null,
|
|
990
|
-
/* @__PURE__ */ jsx16("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs13(
|
|
1001
|
+
/* @__PURE__ */ jsx16("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs13(React7.Fragment, { children: [
|
|
991
1002
|
i > 0 ? /* @__PURE__ */ jsx16("i", { className: "ph ph-caret-right", style: { fontSize: 11, opacity: 0.6 }, "aria-hidden": "true" }) : null,
|
|
992
1003
|
i === crumbs.length - 1 ? (
|
|
993
1004
|
// MP-141: the current crumb mixes a static route label with (usually) a
|
|
@@ -1196,18 +1207,18 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
|
|
|
1196
1207
|
}
|
|
1197
1208
|
|
|
1198
1209
|
// src/components/feedback/Tooltip.tsx
|
|
1199
|
-
import * as
|
|
1210
|
+
import * as React8 from "react";
|
|
1200
1211
|
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1201
1212
|
var CLOSE_DELAY_MS = 120;
|
|
1202
1213
|
function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
1203
|
-
const anchorRef =
|
|
1204
|
-
const bubbleRef =
|
|
1205
|
-
const [reason, setReason] =
|
|
1206
|
-
const closeTimer =
|
|
1207
|
-
const id =
|
|
1214
|
+
const anchorRef = React8.useRef(null);
|
|
1215
|
+
const bubbleRef = React8.useRef(null);
|
|
1216
|
+
const [reason, setReason] = React8.useState(null);
|
|
1217
|
+
const closeTimer = React8.useRef(null);
|
|
1218
|
+
const id = React8.useId();
|
|
1208
1219
|
const descId = id + "-desc";
|
|
1209
1220
|
const open = reason != null;
|
|
1210
|
-
const cancelClose =
|
|
1221
|
+
const cancelClose = React8.useCallback(() => {
|
|
1211
1222
|
if (closeTimer.current) {
|
|
1212
1223
|
clearTimeout(closeTimer.current);
|
|
1213
1224
|
closeTimer.current = null;
|
|
@@ -1217,7 +1228,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1217
1228
|
cancelClose();
|
|
1218
1229
|
setReason(why);
|
|
1219
1230
|
};
|
|
1220
|
-
const hide =
|
|
1231
|
+
const hide = React8.useCallback(() => {
|
|
1221
1232
|
cancelClose();
|
|
1222
1233
|
setReason(null);
|
|
1223
1234
|
}, [cancelClose]);
|
|
@@ -1232,7 +1243,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1232
1243
|
setReason((r) => r === "hover" ? null : r);
|
|
1233
1244
|
}, CLOSE_DELAY_MS);
|
|
1234
1245
|
};
|
|
1235
|
-
|
|
1246
|
+
React8.useEffect(() => cancelClose, [cancelClose]);
|
|
1236
1247
|
const pos = usePopoverPosition(open, anchorRef, {
|
|
1237
1248
|
placement: placement === "bottom" ? "bottom-center" : "top-center",
|
|
1238
1249
|
offset: 8,
|
|
@@ -1242,7 +1253,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1242
1253
|
onDetach: hide
|
|
1243
1254
|
});
|
|
1244
1255
|
const zIndex = useOverlayLayer(open);
|
|
1245
|
-
|
|
1256
|
+
React8.useEffect(() => {
|
|
1246
1257
|
if (!open) return;
|
|
1247
1258
|
const key = (e) => {
|
|
1248
1259
|
if (e.key === "Escape") hide();
|
|
@@ -1270,7 +1281,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1270
1281
|
}
|
|
1271
1282
|
if (keyboard) show("focus");
|
|
1272
1283
|
};
|
|
1273
|
-
const described =
|
|
1284
|
+
const described = React8.isValidElement(children) ? React8.cloneElement(children, {
|
|
1274
1285
|
"aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
|
|
1275
1286
|
}) : children;
|
|
1276
1287
|
return /* @__PURE__ */ jsxs20(
|
|
@@ -1278,7 +1289,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1278
1289
|
{
|
|
1279
1290
|
ref: anchorRef,
|
|
1280
1291
|
className: "fd-tooltip-anchor",
|
|
1281
|
-
"aria-describedby":
|
|
1292
|
+
"aria-describedby": React8.isValidElement(children) ? void 0 : descId,
|
|
1282
1293
|
onPointerEnter: (e) => {
|
|
1283
1294
|
if (isMouse(e)) hover();
|
|
1284
1295
|
},
|
|
@@ -1322,7 +1333,7 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
|
1322
1333
|
}
|
|
1323
1334
|
|
|
1324
1335
|
// src/components/data/Clamp.tsx
|
|
1325
|
-
import * as
|
|
1336
|
+
import * as React9 from "react";
|
|
1326
1337
|
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1327
1338
|
function Clamp({
|
|
1328
1339
|
children,
|
|
@@ -1334,16 +1345,16 @@ function Clamp({
|
|
|
1334
1345
|
onToggle,
|
|
1335
1346
|
className = ""
|
|
1336
1347
|
}) {
|
|
1337
|
-
const [open, setOpen] =
|
|
1338
|
-
const [overflows, setOverflows] =
|
|
1339
|
-
const bodyRef =
|
|
1340
|
-
const charClamped =
|
|
1348
|
+
const [open, setOpen] = React9.useState(false);
|
|
1349
|
+
const [overflows, setOverflows] = React9.useState(false);
|
|
1350
|
+
const bodyRef = React9.useRef(null);
|
|
1351
|
+
const charClamped = React9.useMemo(() => {
|
|
1341
1352
|
if (open || !maxChars || typeof text !== "string" || text.length <= maxChars) return null;
|
|
1342
1353
|
const cut = text.slice(0, maxChars);
|
|
1343
1354
|
const at = cut.lastIndexOf(" ");
|
|
1344
1355
|
return (at > maxChars * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
1345
1356
|
}, [text, maxChars, open]);
|
|
1346
|
-
|
|
1357
|
+
React9.useLayoutEffect(() => {
|
|
1347
1358
|
const node = bodyRef.current;
|
|
1348
1359
|
if (maxChars || !node || !maxHeight) return;
|
|
1349
1360
|
const measure = () => {
|
|
@@ -1482,18 +1493,18 @@ function DataTable({
|
|
|
1482
1493
|
}
|
|
1483
1494
|
|
|
1484
1495
|
// src/components/data/FilterBar.tsx
|
|
1485
|
-
import * as
|
|
1496
|
+
import * as React10 from "react";
|
|
1486
1497
|
import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1487
1498
|
var isSet = (v) => !(v == null || v === "" || v === false);
|
|
1488
1499
|
function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
|
|
1489
|
-
const [panel, setPanel] =
|
|
1500
|
+
const [panel, setPanel] = React10.useState(null);
|
|
1490
1501
|
const zIndex = useOverlayLayer(!!panel);
|
|
1491
|
-
const rootRef =
|
|
1492
|
-
const textInputRef =
|
|
1493
|
-
const optionsRef =
|
|
1502
|
+
const rootRef = React10.useRef(null);
|
|
1503
|
+
const textInputRef = React10.useRef(null);
|
|
1504
|
+
const optionsRef = React10.useRef(null);
|
|
1494
1505
|
const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
|
|
1495
1506
|
const dismissible = !!panel && (panel.kind === "add" || panel.kind === "edit" && editingField?.type === "select");
|
|
1496
|
-
|
|
1507
|
+
React10.useEffect(() => {
|
|
1497
1508
|
if (!dismissible) return;
|
|
1498
1509
|
const away = (e) => {
|
|
1499
1510
|
if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
|
|
@@ -1508,7 +1519,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
1508
1519
|
document.removeEventListener("keydown", esc);
|
|
1509
1520
|
};
|
|
1510
1521
|
}, [dismissible]);
|
|
1511
|
-
|
|
1522
|
+
React10.useEffect(() => {
|
|
1512
1523
|
if (!panel || panel.kind !== "edit") return;
|
|
1513
1524
|
if (editingField?.type === "text") {
|
|
1514
1525
|
textInputRef.current?.focus();
|
|
@@ -1674,7 +1685,7 @@ function StatTile({ label, value, sub, delta, loading = false, compact: compact3
|
|
|
1674
1685
|
}
|
|
1675
1686
|
|
|
1676
1687
|
// src/components/data/CodeBlock.tsx
|
|
1677
|
-
import * as
|
|
1688
|
+
import * as React11 from "react";
|
|
1678
1689
|
import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1679
1690
|
var JS_KW = /^(?:const|let|var|function|return|if|else|for|while|do|new|class|extends|import|from|export|default|await|async|try|catch|finally|throw|typeof|instanceof|of|in|switch|case|break|continue|delete|void|yield|static|get|set|this|super|interface|type|enum|implements|public|private|protected|readonly|abstract|as|satisfies|declare|namespace)$/;
|
|
1680
1691
|
var RULES = {
|
|
@@ -1830,13 +1841,13 @@ function tokenize(src, lang) {
|
|
|
1830
1841
|
return out;
|
|
1831
1842
|
}
|
|
1832
1843
|
function Highlighted({ code, lang }) {
|
|
1833
|
-
const toks =
|
|
1844
|
+
const toks = React11.useMemo(() => tokenize(code, lang), [code, lang]);
|
|
1834
1845
|
return /* @__PURE__ */ jsx30(Fragment5, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx30("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
|
|
1835
1846
|
}
|
|
1836
1847
|
function useCopy() {
|
|
1837
|
-
const [done, setDone] =
|
|
1838
|
-
const timer =
|
|
1839
|
-
|
|
1848
|
+
const [done, setDone] = React11.useState(false);
|
|
1849
|
+
const timer = React11.useRef(null);
|
|
1850
|
+
React11.useEffect(() => () => {
|
|
1840
1851
|
if (timer.current) clearTimeout(timer.current);
|
|
1841
1852
|
}, []);
|
|
1842
1853
|
const copy = (text) => {
|
|
@@ -1872,8 +1883,8 @@ function CodeBlock({
|
|
|
1872
1883
|
actions,
|
|
1873
1884
|
className = ""
|
|
1874
1885
|
}) {
|
|
1875
|
-
const [wrap, setWrap] =
|
|
1876
|
-
const [open, setOpen] =
|
|
1886
|
+
const [wrap, setWrap] = React11.useState(!!wrapDefault);
|
|
1887
|
+
const [open, setOpen] = React11.useState(false);
|
|
1877
1888
|
const [copied, copy] = useCopy();
|
|
1878
1889
|
const body = String(code).replace(/\n$/, "");
|
|
1879
1890
|
const lines = body.split("\n");
|
|
@@ -1902,7 +1913,7 @@ function CodeBlock({
|
|
|
1902
1913
|
] });
|
|
1903
1914
|
}
|
|
1904
1915
|
function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
|
|
1905
|
-
const [open, setOpen] =
|
|
1916
|
+
const [open, setOpen] = React11.useState(false);
|
|
1906
1917
|
const [copied, copy] = useCopy();
|
|
1907
1918
|
const raw = String(diff).replace(/\n$/, "");
|
|
1908
1919
|
const all = raw.split("\n").map((line) => {
|
|
@@ -1948,7 +1959,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
|
|
|
1948
1959
|
}
|
|
1949
1960
|
|
|
1950
1961
|
// src/components/data/Markdown.tsx
|
|
1951
|
-
import * as
|
|
1962
|
+
import * as React12 from "react";
|
|
1952
1963
|
import { jsx as jsx31, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1953
1964
|
var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
|
|
1954
1965
|
var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
|
|
@@ -1987,7 +1998,7 @@ function inlineNodes(src, ctx, keyBase) {
|
|
|
1987
1998
|
const href = safeHref(g(2));
|
|
1988
1999
|
out.push(href ? /* @__PURE__ */ jsx31("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ jsx31("span", { children: g(1) }, key()));
|
|
1989
2000
|
} else if (kind === "cite") {
|
|
1990
|
-
out.push(ctx.renderCitation ? /* @__PURE__ */ jsx31(
|
|
2001
|
+
out.push(ctx.renderCitation ? /* @__PURE__ */ jsx31(React12.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx31("sup", { className: "fd-md-cite", children: g(1) }, key()));
|
|
1991
2002
|
} else if (kind === "strongem") out.push(/* @__PURE__ */ jsx31("strong", { children: /* @__PURE__ */ jsx31("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
|
|
1992
2003
|
else if (kind === "strong") out.push(/* @__PURE__ */ jsx31("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
1993
2004
|
else if (kind === "em") out.push(/* @__PURE__ */ jsx31("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
@@ -2152,7 +2163,7 @@ function Markdown({
|
|
|
2152
2163
|
onLinkClick
|
|
2153
2164
|
}) {
|
|
2154
2165
|
const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
|
|
2155
|
-
const blocks =
|
|
2166
|
+
const blocks = React12.useMemo(() => parseBlocks(source), [source]);
|
|
2156
2167
|
return /* @__PURE__ */ jsx31("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
|
|
2157
2168
|
}
|
|
2158
2169
|
function MarkdownInline({ source = "", className = "", onLinkClick }) {
|
|
@@ -2266,7 +2277,7 @@ function Pagination({
|
|
|
2266
2277
|
}
|
|
2267
2278
|
|
|
2268
2279
|
// src/components/data/RelativeTime.tsx
|
|
2269
|
-
import * as
|
|
2280
|
+
import * as React13 from "react";
|
|
2270
2281
|
import { jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2271
2282
|
var MIN = 6e4;
|
|
2272
2283
|
var HOUR = 36e5;
|
|
@@ -2318,9 +2329,9 @@ function formatDuration(ms) {
|
|
|
2318
2329
|
return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
|
|
2319
2330
|
}
|
|
2320
2331
|
function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
|
|
2321
|
-
const [, force] =
|
|
2332
|
+
const [, force] = React13.useState(0);
|
|
2322
2333
|
const t = value instanceof Date ? value.getTime() : Date.parse(value);
|
|
2323
|
-
|
|
2334
|
+
React13.useEffect(() => {
|
|
2324
2335
|
if (!refresh2 || !t || isNaN(t)) return;
|
|
2325
2336
|
const abs = Math.abs(t - Date.now());
|
|
2326
2337
|
if (abs > DAY) return;
|
|
@@ -2336,10 +2347,10 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
|
|
|
2336
2347
|
}
|
|
2337
2348
|
|
|
2338
2349
|
// src/components/data/ScoreMeter.tsx
|
|
2339
|
-
import * as
|
|
2350
|
+
import * as React15 from "react";
|
|
2340
2351
|
|
|
2341
2352
|
// src/components/data/SegmentedMeter.tsx
|
|
2342
|
-
import * as
|
|
2353
|
+
import * as React14 from "react";
|
|
2343
2354
|
|
|
2344
2355
|
// src/kits/files.ts
|
|
2345
2356
|
function formatBytes(n) {
|
|
@@ -2544,7 +2555,7 @@ function SegmentedMeter({
|
|
|
2544
2555
|
const pct = safeTotal ? Math.min(100, Math.round(used / safeTotal * 100)) : 0;
|
|
2545
2556
|
const w = (v) => safeTotal ? Math.max(0, Math.min(100, Number(v) / safeTotal * 100)) : 0;
|
|
2546
2557
|
const fill = (s, i) => s.color || (s.variant ? VARIANT_FILL[s.variant] : void 0) || CHART[i % CHART.length];
|
|
2547
|
-
const generatedId =
|
|
2558
|
+
const generatedId = React14.useId();
|
|
2548
2559
|
const uid2 = id || generatedId;
|
|
2549
2560
|
return /* @__PURE__ */ jsxs31("div", { className: ["fd-segmeter", className].filter(Boolean).join(" "), onClick, children: [
|
|
2550
2561
|
label || showTotal ? /* @__PURE__ */ jsxs31("div", { className: "fd-segmeter-head", children: [
|
|
@@ -2628,10 +2639,10 @@ function ScoreMeter({
|
|
|
2628
2639
|
breakdownWidth = 280,
|
|
2629
2640
|
className = ""
|
|
2630
2641
|
}) {
|
|
2631
|
-
const [open, setOpen] =
|
|
2632
|
-
const ref =
|
|
2642
|
+
const [open, setOpen] = React15.useState(false);
|
|
2643
|
+
const ref = React15.useRef(null);
|
|
2633
2644
|
const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
|
|
2634
|
-
const body = /* @__PURE__ */ jsxs32(
|
|
2645
|
+
const body = /* @__PURE__ */ jsxs32(React15.Fragment, { children: [
|
|
2635
2646
|
/* @__PURE__ */ jsx35("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx35(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
|
|
2636
2647
|
showScore ? /* @__PURE__ */ jsx35("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
|
|
2637
2648
|
] });
|
|
@@ -2650,7 +2661,7 @@ function ScoreMeter({
|
|
|
2650
2661
|
}
|
|
2651
2662
|
);
|
|
2652
2663
|
}
|
|
2653
|
-
return /* @__PURE__ */ jsxs32(
|
|
2664
|
+
return /* @__PURE__ */ jsxs32(React15.Fragment, { children: [
|
|
2654
2665
|
/* @__PURE__ */ jsx35(
|
|
2655
2666
|
"button",
|
|
2656
2667
|
{
|
|
@@ -2681,13 +2692,13 @@ function ScoreMeter({
|
|
|
2681
2692
|
}
|
|
2682
2693
|
|
|
2683
2694
|
// src/components/data/SortMenu.tsx
|
|
2684
|
-
import * as
|
|
2695
|
+
import * as React16 from "react";
|
|
2685
2696
|
import { jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2686
2697
|
function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
|
|
2687
|
-
const [open, setOpen] =
|
|
2698
|
+
const [open, setOpen] = React16.useState(false);
|
|
2688
2699
|
const zIndex = useOverlayLayer(open);
|
|
2689
|
-
const ref =
|
|
2690
|
-
|
|
2700
|
+
const ref = React16.useRef(null);
|
|
2701
|
+
React16.useEffect(() => {
|
|
2691
2702
|
if (!open) return;
|
|
2692
2703
|
const away = (e) => {
|
|
2693
2704
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -2749,7 +2760,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
|
|
|
2749
2760
|
}
|
|
2750
2761
|
|
|
2751
2762
|
// src/components/data/StepList.tsx
|
|
2752
|
-
import * as
|
|
2763
|
+
import * as React17 from "react";
|
|
2753
2764
|
import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2754
2765
|
var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
|
|
2755
2766
|
function StepList({
|
|
@@ -2762,9 +2773,9 @@ function StepList({
|
|
|
2762
2773
|
dense = false,
|
|
2763
2774
|
className = ""
|
|
2764
2775
|
}) {
|
|
2765
|
-
const [openState, setOpenState] =
|
|
2776
|
+
const [openState, setOpenState] = React17.useState(defaultOpen);
|
|
2766
2777
|
const open = openProp == null ? openState : openProp;
|
|
2767
|
-
const [expanded, setExpanded] =
|
|
2778
|
+
const [expanded, setExpanded] = React17.useState({});
|
|
2768
2779
|
if (!steps.length) return null;
|
|
2769
2780
|
const running = steps.some((s) => s.status === "running");
|
|
2770
2781
|
const failed = steps.filter((s) => s.status === "error").length;
|
|
@@ -2822,7 +2833,7 @@ function StepList({
|
|
|
2822
2833
|
}
|
|
2823
2834
|
|
|
2824
2835
|
// src/components/data/VirtualList.tsx
|
|
2825
|
-
import * as
|
|
2836
|
+
import * as React18 from "react";
|
|
2826
2837
|
import { jsx as jsx38, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2827
2838
|
var VIRTUAL_LIST_BUFFER_ROWS = 20;
|
|
2828
2839
|
var VIRTUAL_LIST_ROW_GAP = 6;
|
|
@@ -2874,35 +2885,35 @@ function VirtualList({
|
|
|
2874
2885
|
className = "",
|
|
2875
2886
|
style
|
|
2876
2887
|
}) {
|
|
2877
|
-
const [scrollTop, setScrollTop] =
|
|
2878
|
-
const loaded =
|
|
2888
|
+
const [scrollTop, setScrollTop] = React18.useState(0);
|
|
2889
|
+
const loaded = React18.useMemo(
|
|
2879
2890
|
() => ({ firstItemIndex, count: items.length }),
|
|
2880
2891
|
[firstItemIndex, items.length]
|
|
2881
2892
|
);
|
|
2882
2893
|
const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
|
|
2883
2894
|
const bandKey = firstItemIndex + ":" + items.length;
|
|
2884
|
-
const win =
|
|
2895
|
+
const win = React18.useMemo(
|
|
2885
2896
|
() => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
|
|
2886
2897
|
[scrollTop, height, itemHeight, total, loaded]
|
|
2887
2898
|
);
|
|
2888
|
-
const need =
|
|
2899
|
+
const need = React18.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
|
|
2889
2900
|
const wantStart = need.start && hasMore?.start !== false;
|
|
2890
2901
|
const wantEnd = need.end && hasMore?.end !== false;
|
|
2891
2902
|
const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
|
|
2892
2903
|
const askKey = bandKey + "@" + bucket2;
|
|
2893
|
-
const asked =
|
|
2894
|
-
|
|
2904
|
+
const asked = React18.useRef({ start: null, end: null });
|
|
2905
|
+
React18.useEffect(() => {
|
|
2895
2906
|
if (loading || !wantStart || asked.current.start === askKey) return;
|
|
2896
2907
|
asked.current.start = askKey;
|
|
2897
2908
|
onNeedMore("start", win);
|
|
2898
2909
|
}, [wantStart, loading, askKey, onNeedMore, win]);
|
|
2899
|
-
|
|
2910
|
+
React18.useEffect(() => {
|
|
2900
2911
|
if (loading || !wantEnd || asked.current.end === askKey) return;
|
|
2901
2912
|
asked.current.end = askKey;
|
|
2902
2913
|
onNeedMore("end", win);
|
|
2903
2914
|
}, [wantEnd, loading, askKey, onNeedMore, win]);
|
|
2904
|
-
const lastKeysRef =
|
|
2905
|
-
const newKeys =
|
|
2915
|
+
const lastKeysRef = React18.useRef(null);
|
|
2916
|
+
const newKeys = React18.useMemo(() => {
|
|
2906
2917
|
const prev = lastKeysRef.current;
|
|
2907
2918
|
if (!prev) return /* @__PURE__ */ new Set();
|
|
2908
2919
|
const fresh = /* @__PURE__ */ new Set();
|
|
@@ -2912,7 +2923,7 @@ function VirtualList({
|
|
|
2912
2923
|
}
|
|
2913
2924
|
return fresh;
|
|
2914
2925
|
}, [items]);
|
|
2915
|
-
|
|
2926
|
+
React18.useEffect(() => {
|
|
2916
2927
|
lastKeysRef.current = new Set(items.map(keyOf));
|
|
2917
2928
|
}, [items]);
|
|
2918
2929
|
const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
|
|
@@ -2957,7 +2968,7 @@ function VirtualList({
|
|
|
2957
2968
|
}
|
|
2958
2969
|
|
|
2959
2970
|
// src/components/data/EntityRow.tsx
|
|
2960
|
-
import * as
|
|
2971
|
+
import * as React19 from "react";
|
|
2961
2972
|
import { jsx as jsx39, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2962
2973
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
2963
2974
|
var METRIC_TONE_COLOR = {
|
|
@@ -2970,7 +2981,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
|
|
|
2970
2981
|
const key = m.id || m.label || i;
|
|
2971
2982
|
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
2972
2983
|
const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
2973
|
-
const content = /* @__PURE__ */ jsxs36(
|
|
2984
|
+
const content = /* @__PURE__ */ jsxs36(React19.Fragment, { children: [
|
|
2974
2985
|
m.icon ? /* @__PURE__ */ jsx39("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
2975
2986
|
/* @__PURE__ */ jsx39("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
2976
2987
|
/* @__PURE__ */ jsx39("span", { className: "fd-sr", children: " " + m.label })
|
|
@@ -3062,14 +3073,14 @@ function EntityRow({
|
|
|
3062
3073
|
}
|
|
3063
3074
|
|
|
3064
3075
|
// src/components/data/TransferList.tsx
|
|
3065
|
-
import * as
|
|
3076
|
+
import * as React21 from "react";
|
|
3066
3077
|
import { createPortal as createPortal4 } from "react-dom";
|
|
3067
3078
|
|
|
3068
3079
|
// src/components/forms/field.tsx
|
|
3069
|
-
import * as
|
|
3080
|
+
import * as React20 from "react";
|
|
3070
3081
|
import { jsx as jsx40, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3071
3082
|
function useFieldId(id) {
|
|
3072
|
-
const generated =
|
|
3083
|
+
const generated = React20.useId();
|
|
3073
3084
|
return id || generated;
|
|
3074
3085
|
}
|
|
3075
3086
|
function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
|
|
@@ -3187,12 +3198,12 @@ function TransferList({
|
|
|
3187
3198
|
listHeight = 440,
|
|
3188
3199
|
className = ""
|
|
3189
3200
|
}) {
|
|
3190
|
-
const [drag, setDrag] =
|
|
3191
|
-
const [dragOverSide, setDragOverSide] =
|
|
3192
|
-
const dragRef =
|
|
3193
|
-
const armedRef =
|
|
3194
|
-
const sideRefs =
|
|
3195
|
-
const hitTestSide =
|
|
3201
|
+
const [drag, setDrag] = React21.useState(null);
|
|
3202
|
+
const [dragOverSide, setDragOverSide] = React21.useState(null);
|
|
3203
|
+
const dragRef = React21.useRef(null);
|
|
3204
|
+
const armedRef = React21.useRef(null);
|
|
3205
|
+
const sideRefs = React21.useRef({ left: null, right: null });
|
|
3206
|
+
const hitTestSide = React21.useCallback((x, y) => {
|
|
3196
3207
|
for (const side of ["left", "right"]) {
|
|
3197
3208
|
const el = sideRefs.current[side];
|
|
3198
3209
|
if (!el) continue;
|
|
@@ -3201,7 +3212,7 @@ function TransferList({
|
|
|
3201
3212
|
}
|
|
3202
3213
|
return null;
|
|
3203
3214
|
}, []);
|
|
3204
|
-
const findItem =
|
|
3215
|
+
const findItem = React21.useCallback(
|
|
3205
3216
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
3206
3217
|
[left.items, right.items, keyOf]
|
|
3207
3218
|
);
|
|
@@ -3223,7 +3234,7 @@ function TransferList({
|
|
|
3223
3234
|
height: rect.height
|
|
3224
3235
|
};
|
|
3225
3236
|
};
|
|
3226
|
-
|
|
3237
|
+
React21.useEffect(() => {
|
|
3227
3238
|
const onMovePointer = (e) => {
|
|
3228
3239
|
const armed = armedRef.current;
|
|
3229
3240
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -3276,7 +3287,7 @@ function TransferList({
|
|
|
3276
3287
|
window.removeEventListener("pointercancel", endDrag);
|
|
3277
3288
|
};
|
|
3278
3289
|
}, [hitTestSide, findItem, onMove]);
|
|
3279
|
-
|
|
3290
|
+
React21.useEffect(() => {
|
|
3280
3291
|
if (!drag || typeof document === "undefined") return;
|
|
3281
3292
|
const prev = document.body.style.userSelect;
|
|
3282
3293
|
document.body.style.userSelect = "none";
|
|
@@ -3384,11 +3395,11 @@ function TransferList({
|
|
|
3384
3395
|
}
|
|
3385
3396
|
|
|
3386
3397
|
// src/components/forms/Checkbox.tsx
|
|
3387
|
-
import * as
|
|
3398
|
+
import * as React22 from "react";
|
|
3388
3399
|
import { jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3389
3400
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
3390
|
-
const ref =
|
|
3391
|
-
|
|
3401
|
+
const ref = React22.useRef(null);
|
|
3402
|
+
React22.useEffect(() => {
|
|
3392
3403
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
3393
3404
|
}, [indeterminate]);
|
|
3394
3405
|
return /* @__PURE__ */ jsxs40("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -3447,7 +3458,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3447
3458
|
}
|
|
3448
3459
|
|
|
3449
3460
|
// src/components/forms/NumberInput.tsx
|
|
3450
|
-
import * as
|
|
3461
|
+
import * as React23 from "react";
|
|
3451
3462
|
import { jsx as jsx48, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3452
3463
|
function NumberInput({
|
|
3453
3464
|
label,
|
|
@@ -3475,10 +3486,10 @@ function NumberInput({
|
|
|
3475
3486
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
3476
3487
|
return isNaN(n) ? null : n;
|
|
3477
3488
|
};
|
|
3478
|
-
const [text, setText] =
|
|
3479
|
-
const [editing, setEditing] =
|
|
3480
|
-
const timer =
|
|
3481
|
-
|
|
3489
|
+
const [text, setText] = React23.useState(value == null || value === "" ? "" : String(value));
|
|
3490
|
+
const [editing, setEditing] = React23.useState(false);
|
|
3491
|
+
const timer = React23.useRef(null);
|
|
3492
|
+
React23.useEffect(() => {
|
|
3482
3493
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
3483
3494
|
}, [value, editing]);
|
|
3484
3495
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -3502,7 +3513,7 @@ function NumberInput({
|
|
|
3502
3513
|
const release = () => {
|
|
3503
3514
|
if (timer.current) clearTimeout(timer.current);
|
|
3504
3515
|
};
|
|
3505
|
-
|
|
3516
|
+
React23.useEffect(() => () => {
|
|
3506
3517
|
if (timer.current) clearTimeout(timer.current);
|
|
3507
3518
|
}, []);
|
|
3508
3519
|
const shown = editing ? text : (() => {
|
|
@@ -3589,7 +3600,7 @@ function NumberInput({
|
|
|
3589
3600
|
}
|
|
3590
3601
|
|
|
3591
3602
|
// src/components/forms/Select.tsx
|
|
3592
|
-
import * as
|
|
3603
|
+
import * as React24 from "react";
|
|
3593
3604
|
import { jsx as jsx49, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3594
3605
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
3595
3606
|
function Select({
|
|
@@ -3616,13 +3627,13 @@ function Select({
|
|
|
3616
3627
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
3617
3628
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
3618
3629
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3619
|
-
const [open, setOpen] =
|
|
3620
|
-
const [q, setQ] =
|
|
3621
|
-
const [active, setActive] =
|
|
3622
|
-
const rootRef =
|
|
3623
|
-
const boxRef =
|
|
3624
|
-
const listRef =
|
|
3625
|
-
const typeBuf =
|
|
3630
|
+
const [open, setOpen] = React24.useState(false);
|
|
3631
|
+
const [q, setQ] = React24.useState("");
|
|
3632
|
+
const [active, setActive] = React24.useState(-1);
|
|
3633
|
+
const rootRef = React24.useRef(null);
|
|
3634
|
+
const boxRef = React24.useRef(null);
|
|
3635
|
+
const listRef = React24.useRef(null);
|
|
3636
|
+
const typeBuf = React24.useRef({ s: "", t: 0 });
|
|
3626
3637
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
3627
3638
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
3628
3639
|
const boxText = multiple ? chosen.length === 0 ? placeholder : chosen.length === 1 ? chosen[0].label : summary ? summary(chosen.map((o) => o.value)) : chosen.length + " selected" : selected ? selected.label : placeholder;
|
|
@@ -3647,7 +3658,7 @@ function Select({
|
|
|
3647
3658
|
}
|
|
3648
3659
|
setOpen(!open);
|
|
3649
3660
|
};
|
|
3650
|
-
|
|
3661
|
+
React24.useEffect(() => {
|
|
3651
3662
|
if (!open || active < 0 || !listRef.current) return;
|
|
3652
3663
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
3653
3664
|
if (el) {
|
|
@@ -3768,7 +3779,7 @@ function Select({
|
|
|
3768
3779
|
),
|
|
3769
3780
|
q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
3770
3781
|
] }) : void 0,
|
|
3771
|
-
footer: multiple ? /* @__PURE__ */ jsxs45(
|
|
3782
|
+
footer: multiple ? /* @__PURE__ */ jsxs45(React24.Fragment, { children: [
|
|
3772
3783
|
/* @__PURE__ */ jsx49(
|
|
3773
3784
|
"button",
|
|
3774
3785
|
{
|
|
@@ -3799,7 +3810,7 @@ function Select({
|
|
|
3799
3810
|
'Nothing matches "',
|
|
3800
3811
|
q,
|
|
3801
3812
|
'".'
|
|
3802
|
-
] }) : groups.map((grp) => /* @__PURE__ */ jsxs45(
|
|
3813
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs45(React24.Fragment, { children: [
|
|
3803
3814
|
grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3804
3815
|
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs45(
|
|
3805
3816
|
"button",
|
|
@@ -3836,7 +3847,7 @@ function Select({
|
|
|
3836
3847
|
}
|
|
3837
3848
|
|
|
3838
3849
|
// src/components/forms/DatePicker.tsx
|
|
3839
|
-
import * as
|
|
3850
|
+
import * as React25 from "react";
|
|
3840
3851
|
import { jsx as jsx50, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3841
3852
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3842
3853
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
@@ -3854,10 +3865,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3854
3865
|
const today = /* @__PURE__ */ new Date();
|
|
3855
3866
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3856
3867
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3857
|
-
const [vy, setVy] =
|
|
3858
|
-
const [vm, setVm] =
|
|
3859
|
-
const [mode2, setMode] =
|
|
3860
|
-
const [hover, setHover] =
|
|
3868
|
+
const [vy, setVy] = React25.useState(anchor.getFullYear());
|
|
3869
|
+
const [vm, setVm] = React25.useState(anchor.getMonth());
|
|
3870
|
+
const [mode2, setMode] = React25.useState("days");
|
|
3871
|
+
const [hover, setHover] = React25.useState(null);
|
|
3861
3872
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3862
3873
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3863
3874
|
const inRange = (d) => {
|
|
@@ -3973,9 +3984,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3973
3984
|
}
|
|
3974
3985
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
|
|
3975
3986
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3976
|
-
const [open, setOpen] =
|
|
3977
|
-
const rootRef =
|
|
3978
|
-
const boxRef =
|
|
3987
|
+
const [open, setOpen] = React25.useState(false);
|
|
3988
|
+
const rootRef = React25.useRef(null);
|
|
3989
|
+
const boxRef = React25.useRef(null);
|
|
3979
3990
|
const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
|
|
3980
3991
|
const toggle = () => {
|
|
3981
3992
|
if (!disabled) setOpen(!open);
|
|
@@ -4038,7 +4049,7 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
4038
4049
|
}
|
|
4039
4050
|
|
|
4040
4051
|
// src/components/forms/TimePicker.tsx
|
|
4041
|
-
import * as
|
|
4052
|
+
import * as React26 from "react";
|
|
4042
4053
|
import { jsx as jsx51, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
4043
4054
|
var pad = (n) => String(n).padStart(2, "0");
|
|
4044
4055
|
function ClockFace({ value = "09:00", onChange }) {
|
|
@@ -4047,9 +4058,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
4047
4058
|
if (isNaN(m)) m = 0;
|
|
4048
4059
|
const pm = h24 >= 12;
|
|
4049
4060
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
4050
|
-
const [mode2, setMode] =
|
|
4051
|
-
const faceRef =
|
|
4052
|
-
const dragging =
|
|
4061
|
+
const [mode2, setMode] = React26.useState("h");
|
|
4062
|
+
const faceRef = React26.useRef(null);
|
|
4063
|
+
const dragging = React26.useRef(false);
|
|
4053
4064
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
4054
4065
|
const R = 108, NR = 80;
|
|
4055
4066
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -4122,9 +4133,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
4122
4133
|
}
|
|
4123
4134
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
4124
4135
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
4125
|
-
const [open, setOpen] =
|
|
4126
|
-
const rootRef =
|
|
4127
|
-
const boxRef =
|
|
4136
|
+
const [open, setOpen] = React26.useState(false);
|
|
4137
|
+
const rootRef = React26.useRef(null);
|
|
4138
|
+
const boxRef = React26.useRef(null);
|
|
4128
4139
|
const disp = () => {
|
|
4129
4140
|
if (!value) return "";
|
|
4130
4141
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -4167,7 +4178,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4167
4178
|
offset: 6,
|
|
4168
4179
|
width: 262,
|
|
4169
4180
|
role: "presentation",
|
|
4170
|
-
footer: /* @__PURE__ */ jsxs47(
|
|
4181
|
+
footer: /* @__PURE__ */ jsxs47(React26.Fragment, { children: [
|
|
4171
4182
|
/* @__PURE__ */ jsx51(
|
|
4172
4183
|
"button",
|
|
4173
4184
|
{
|
|
@@ -4195,7 +4206,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4195
4206
|
}
|
|
4196
4207
|
|
|
4197
4208
|
// src/components/forms/Slider.tsx
|
|
4198
|
-
import * as
|
|
4209
|
+
import * as React27 from "react";
|
|
4199
4210
|
import { jsx as jsx52, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
4200
4211
|
function Slider({
|
|
4201
4212
|
label,
|
|
@@ -4213,7 +4224,7 @@ function Slider({
|
|
|
4213
4224
|
...rest
|
|
4214
4225
|
}) {
|
|
4215
4226
|
const fieldId = useFieldId(id);
|
|
4216
|
-
const [dragging, setDragging] =
|
|
4227
|
+
const [dragging, setDragging] = React27.useState(false);
|
|
4217
4228
|
const v = value === void 0 ? min : Number(value);
|
|
4218
4229
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4219
4230
|
return /* @__PURE__ */ jsxs48("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -4247,7 +4258,7 @@ function Slider({
|
|
|
4247
4258
|
}
|
|
4248
4259
|
|
|
4249
4260
|
// src/components/forms/RangeSlider.tsx
|
|
4250
|
-
import * as
|
|
4261
|
+
import * as React28 from "react";
|
|
4251
4262
|
import { jsx as jsx53, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4252
4263
|
function RangeSlider({
|
|
4253
4264
|
label,
|
|
@@ -4267,9 +4278,9 @@ function RangeSlider({
|
|
|
4267
4278
|
}) {
|
|
4268
4279
|
const fmt2 = format || ((v) => String(v));
|
|
4269
4280
|
const [a, b] = value || [min, max];
|
|
4270
|
-
const [drag, setDrag] =
|
|
4271
|
-
const [focus, setFocus] =
|
|
4272
|
-
const railRef =
|
|
4281
|
+
const [drag, setDrag] = React28.useState(null);
|
|
4282
|
+
const [focus, setFocus] = React28.useState(null);
|
|
4283
|
+
const railRef = React28.useRef(null);
|
|
4273
4284
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4274
4285
|
const clampPair = (i, v) => {
|
|
4275
4286
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -4284,7 +4295,7 @@ function RangeSlider({
|
|
|
4284
4295
|
const r = railRef.current.getBoundingClientRect();
|
|
4285
4296
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
4286
4297
|
};
|
|
4287
|
-
|
|
4298
|
+
React28.useEffect(() => {
|
|
4288
4299
|
if (drag === null) return;
|
|
4289
4300
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
4290
4301
|
const upH = () => setDrag(null);
|
|
@@ -4365,7 +4376,7 @@ function RangeSlider({
|
|
|
4365
4376
|
/* @__PURE__ */ jsxs49("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
4366
4377
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
|
|
4367
4378
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
4368
|
-
marks.map((m) => /* @__PURE__ */ jsxs49(
|
|
4379
|
+
marks.map((m) => /* @__PURE__ */ jsxs49(React28.Fragment, { children: [
|
|
4369
4380
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
4370
4381
|
m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
4371
4382
|
] }, m.value)),
|
|
@@ -4394,7 +4405,7 @@ function RangeSlider({
|
|
|
4394
4405
|
}
|
|
4395
4406
|
|
|
4396
4407
|
// src/components/forms/Dropzone.tsx
|
|
4397
|
-
import * as
|
|
4408
|
+
import * as React29 from "react";
|
|
4398
4409
|
import { jsx as jsx54, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
4399
4410
|
function Dropzone({
|
|
4400
4411
|
onFiles,
|
|
@@ -4409,8 +4420,8 @@ function Dropzone({
|
|
|
4409
4420
|
className = "",
|
|
4410
4421
|
style
|
|
4411
4422
|
}) {
|
|
4412
|
-
const [over, setOver] =
|
|
4413
|
-
const depth =
|
|
4423
|
+
const [over, setOver] = React29.useState(false);
|
|
4424
|
+
const depth = React29.useRef(0);
|
|
4414
4425
|
const has = (e) => {
|
|
4415
4426
|
const dt = e.dataTransfer;
|
|
4416
4427
|
if (!dt) return false;
|
|
@@ -4472,8 +4483,8 @@ function FilePickButton({
|
|
|
4472
4483
|
className = "",
|
|
4473
4484
|
children
|
|
4474
4485
|
}) {
|
|
4475
|
-
const ref =
|
|
4476
|
-
return /* @__PURE__ */ jsxs50(
|
|
4486
|
+
const ref = React29.useRef(null);
|
|
4487
|
+
return /* @__PURE__ */ jsxs50(React29.Fragment, { children: [
|
|
4477
4488
|
/* @__PURE__ */ jsx54(
|
|
4478
4489
|
"button",
|
|
4479
4490
|
{
|
|
@@ -4506,10 +4517,10 @@ function FilePickButton({
|
|
|
4506
4517
|
}
|
|
4507
4518
|
function useStagedFiles(upload, opts) {
|
|
4508
4519
|
const o = opts || {};
|
|
4509
|
-
const [items, setItems] =
|
|
4510
|
-
const controllers =
|
|
4520
|
+
const [items, setItems] = React29.useState([]);
|
|
4521
|
+
const controllers = React29.useRef({});
|
|
4511
4522
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
4512
|
-
const run =
|
|
4523
|
+
const run = React29.useCallback((att) => {
|
|
4513
4524
|
if (!upload) return;
|
|
4514
4525
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
4515
4526
|
controllers.current[att.id] = ac;
|
|
@@ -4526,14 +4537,14 @@ function useStagedFiles(upload, opts) {
|
|
|
4526
4537
|
delete controllers.current[att.id];
|
|
4527
4538
|
});
|
|
4528
4539
|
}, [upload]);
|
|
4529
|
-
const add =
|
|
4540
|
+
const add = React29.useCallback((files) => {
|
|
4530
4541
|
if (!upload) return [];
|
|
4531
4542
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
4532
4543
|
setItems((list) => list.concat(atts));
|
|
4533
4544
|
atts.forEach(run);
|
|
4534
4545
|
return atts;
|
|
4535
4546
|
}, [upload, run]);
|
|
4536
|
-
const remove =
|
|
4547
|
+
const remove = React29.useCallback((att) => {
|
|
4537
4548
|
const ac = controllers.current[att.id];
|
|
4538
4549
|
if (ac) {
|
|
4539
4550
|
try {
|
|
@@ -4544,10 +4555,10 @@ function useStagedFiles(upload, opts) {
|
|
|
4544
4555
|
}
|
|
4545
4556
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
4546
4557
|
}, []);
|
|
4547
|
-
const retry =
|
|
4558
|
+
const retry = React29.useCallback((att) => {
|
|
4548
4559
|
run(att);
|
|
4549
4560
|
}, [run]);
|
|
4550
|
-
const clear =
|
|
4561
|
+
const clear = React29.useCallback(() => {
|
|
4551
4562
|
Object.values(controllers.current).forEach((ac) => {
|
|
4552
4563
|
try {
|
|
4553
4564
|
ac && ac.abort();
|
|
@@ -4671,7 +4682,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
4671
4682
|
}
|
|
4672
4683
|
|
|
4673
4684
|
// src/components/forms/MarkdownEditor.tsx
|
|
4674
|
-
import * as
|
|
4685
|
+
import * as React30 from "react";
|
|
4675
4686
|
import { jsx as jsx56, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
4676
4687
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
4677
4688
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -4885,7 +4896,7 @@ function syncDom(root, value) {
|
|
|
4885
4896
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4886
4897
|
}
|
|
4887
4898
|
var LIST_CONT = RE_LI;
|
|
4888
|
-
var MarkdownEditor =
|
|
4899
|
+
var MarkdownEditor = React30.forwardRef(function MarkdownEditor2({
|
|
4889
4900
|
value = "",
|
|
4890
4901
|
onChange,
|
|
4891
4902
|
onSubmit,
|
|
@@ -4904,10 +4915,10 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
|
|
|
4904
4915
|
className = "",
|
|
4905
4916
|
id
|
|
4906
4917
|
}, ref) {
|
|
4907
|
-
const boxRef =
|
|
4908
|
-
const composing =
|
|
4909
|
-
const pendingCaret =
|
|
4910
|
-
|
|
4918
|
+
const boxRef = React30.useRef(null);
|
|
4919
|
+
const composing = React30.useRef(false);
|
|
4920
|
+
const pendingCaret = React30.useRef(null);
|
|
4921
|
+
React30.useLayoutEffect(() => {
|
|
4911
4922
|
const root = boxRef.current;
|
|
4912
4923
|
if (!root || composing.current) return;
|
|
4913
4924
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4916,7 +4927,7 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
|
|
|
4916
4927
|
pendingCaret.current = null;
|
|
4917
4928
|
if (active && caret != null) placeCaret(root, caret);
|
|
4918
4929
|
}, [value]);
|
|
4919
|
-
|
|
4930
|
+
React30.useEffect(() => {
|
|
4920
4931
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4921
4932
|
}, [autoFocus]);
|
|
4922
4933
|
const caretNow = () => {
|
|
@@ -4983,7 +4994,7 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
|
|
|
4983
4994
|
api.replaceRange(from, to, next, from + next.length);
|
|
4984
4995
|
}
|
|
4985
4996
|
};
|
|
4986
|
-
|
|
4997
|
+
React30.useImperativeHandle(ref, () => api);
|
|
4987
4998
|
function detect(text, caret) {
|
|
4988
4999
|
if (!onTrigger) return;
|
|
4989
5000
|
const upto = text.slice(0, caret);
|
|
@@ -5135,16 +5146,16 @@ var MarkdownEditor = React29.forwardRef(function MarkdownEditor2({
|
|
|
5135
5146
|
});
|
|
5136
5147
|
|
|
5137
5148
|
// src/components/platform/AccountMenu.tsx
|
|
5138
|
-
import * as
|
|
5149
|
+
import * as React32 from "react";
|
|
5139
5150
|
|
|
5140
5151
|
// src/kits/sessionContext.tsx
|
|
5141
|
-
import * as
|
|
5142
|
-
var SessionContext =
|
|
5152
|
+
import * as React31 from "react";
|
|
5153
|
+
var SessionContext = React31.createContext(null);
|
|
5143
5154
|
function SessionProvider({ value, children }) {
|
|
5144
|
-
return
|
|
5155
|
+
return React31.createElement(SessionContext.Provider, { value }, children);
|
|
5145
5156
|
}
|
|
5146
5157
|
function useSessionContext() {
|
|
5147
|
-
const ctx =
|
|
5158
|
+
const ctx = React31.useContext(SessionContext);
|
|
5148
5159
|
if (!ctx) {
|
|
5149
5160
|
throw new Error(
|
|
5150
5161
|
"useSessionContext() was called outside a <SessionProvider>. Wrap your app root in <SessionProvider value={...}> with your real session, or \u2014 in the docs site or a demo \u2014 in <DemoSessionProvider>, before rendering AccountMenu, Gate, ProfilePage or AppSwitcher."
|
|
@@ -5155,20 +5166,8 @@ function useSessionContext() {
|
|
|
5155
5166
|
|
|
5156
5167
|
// src/components/platform/AccountMenu.tsx
|
|
5157
5168
|
import { Fragment as Fragment14, jsx as jsx57, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
5158
|
-
var DEFAULT_LINKS = [
|
|
5159
|
-
|
|
5160
|
-
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
5161
|
-
];
|
|
5162
|
-
var DEFAULT_GROUPS = [
|
|
5163
|
-
{
|
|
5164
|
-
label: "Administration",
|
|
5165
|
-
links: [
|
|
5166
|
-
{ id: "users", label: "Users", icon: "users-three", href: "../admin/index.html#users", perm: "users.view" },
|
|
5167
|
-
{ id: "roles", label: "Roles & permissions", icon: "shield-check", href: "../admin/index.html#roles", perm: "roles.manage" },
|
|
5168
|
-
{ id: "flags", label: "Feature flags", icon: "toggle-right", href: "../admin/index.html#flags", perm: "flags.manage" }
|
|
5169
|
-
]
|
|
5170
|
-
}
|
|
5171
|
-
];
|
|
5169
|
+
var DEFAULT_LINKS = [];
|
|
5170
|
+
var DEFAULT_GROUPS = [];
|
|
5172
5171
|
function Item({ item, onPick }) {
|
|
5173
5172
|
return /* @__PURE__ */ jsxs53(
|
|
5174
5173
|
"button",
|
|
@@ -5196,10 +5195,10 @@ function AccountMenu({
|
|
|
5196
5195
|
...rest
|
|
5197
5196
|
}) {
|
|
5198
5197
|
const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
|
|
5199
|
-
const [open, setOpen] =
|
|
5200
|
-
const [switching, setSwitching] =
|
|
5201
|
-
const [signingOut, setSigningOut] =
|
|
5202
|
-
const ref =
|
|
5198
|
+
const [open, setOpen] = React32.useState(false);
|
|
5199
|
+
const [switching, setSwitching] = React32.useState(false);
|
|
5200
|
+
const [signingOut, setSigningOut] = React32.useState(false);
|
|
5201
|
+
const ref = React32.useRef(null);
|
|
5203
5202
|
const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
|
|
5204
5203
|
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
|
|
5205
5204
|
const pick = (item) => {
|
|
@@ -5302,13 +5301,13 @@ function AccountMenu({
|
|
|
5302
5301
|
}
|
|
5303
5302
|
|
|
5304
5303
|
// src/components/platform/AppSwitcher.tsx
|
|
5305
|
-
import * as
|
|
5304
|
+
import * as React33 from "react";
|
|
5306
5305
|
import { jsx as jsx58, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
5307
5306
|
function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
5308
5307
|
const { apps: contextApps } = useSessionContext();
|
|
5309
5308
|
const apps = appsProp ?? contextApps ?? [];
|
|
5310
|
-
const [open, setOpen] =
|
|
5311
|
-
const anchorRef =
|
|
5309
|
+
const [open, setOpen] = React33.useState(false);
|
|
5310
|
+
const anchorRef = React33.useRef(null);
|
|
5312
5311
|
if (!apps.length) return null;
|
|
5313
5312
|
const items = apps.map((app) => ({
|
|
5314
5313
|
id: app.key,
|
|
@@ -5322,7 +5321,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
5322
5321
|
window.location.href = app.url;
|
|
5323
5322
|
}
|
|
5324
5323
|
}));
|
|
5325
|
-
return /* @__PURE__ */ jsxs54(
|
|
5324
|
+
return /* @__PURE__ */ jsxs54(React33.Fragment, { children: [
|
|
5326
5325
|
/* @__PURE__ */ jsx58("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx58(
|
|
5327
5326
|
IconButton,
|
|
5328
5327
|
{
|
|
@@ -5351,10 +5350,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
5351
5350
|
}
|
|
5352
5351
|
|
|
5353
5352
|
// src/components/platform/AppearanceMenu.tsx
|
|
5354
|
-
import * as
|
|
5353
|
+
import * as React35 from "react";
|
|
5355
5354
|
|
|
5356
5355
|
// src/kits/appearance.ts
|
|
5357
|
-
import * as
|
|
5356
|
+
import * as React34 from "react";
|
|
5358
5357
|
var DEFAULT_STORAGE_KEY = "fd-appearance";
|
|
5359
5358
|
var DEFAULT_PREFS = {
|
|
5360
5359
|
theme: "system",
|
|
@@ -5403,6 +5402,43 @@ function savePrefs(prefs, opts) {
|
|
|
5403
5402
|
} catch {
|
|
5404
5403
|
}
|
|
5405
5404
|
}
|
|
5405
|
+
function createLocalStorageAppearanceStore(opts) {
|
|
5406
|
+
const key = opts?.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
5407
|
+
const storage = resolveStorage(opts);
|
|
5408
|
+
let snapshot = loadPrefs(opts);
|
|
5409
|
+
const listeners3 = /* @__PURE__ */ new Set();
|
|
5410
|
+
const notify = () => listeners3.forEach((l) => l());
|
|
5411
|
+
const onStorageEvent = (e) => {
|
|
5412
|
+
if (e.key !== null && e.key !== key) return;
|
|
5413
|
+
snapshot = loadPrefs(opts);
|
|
5414
|
+
notify();
|
|
5415
|
+
};
|
|
5416
|
+
return {
|
|
5417
|
+
getSnapshot: () => snapshot,
|
|
5418
|
+
write(prefs) {
|
|
5419
|
+
snapshot = prefs;
|
|
5420
|
+
if (storage) {
|
|
5421
|
+
try {
|
|
5422
|
+
storage.setItem(key, JSON.stringify(prefs));
|
|
5423
|
+
} catch {
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
notify();
|
|
5427
|
+
},
|
|
5428
|
+
subscribe(onChange) {
|
|
5429
|
+
listeners3.add(onChange);
|
|
5430
|
+
if (listeners3.size === 1 && typeof window !== "undefined") {
|
|
5431
|
+
window.addEventListener("storage", onStorageEvent);
|
|
5432
|
+
}
|
|
5433
|
+
return () => {
|
|
5434
|
+
listeners3.delete(onChange);
|
|
5435
|
+
if (listeners3.size === 0 && typeof window !== "undefined") {
|
|
5436
|
+
window.removeEventListener("storage", onStorageEvent);
|
|
5437
|
+
}
|
|
5438
|
+
};
|
|
5439
|
+
}
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5406
5442
|
function applyPrefs(prefs, root = document.documentElement) {
|
|
5407
5443
|
root.setAttribute("data-theme", resolveTheme(prefs.theme));
|
|
5408
5444
|
root.setAttribute("data-text-scale", prefs.textScale);
|
|
@@ -5411,13 +5447,12 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
5411
5447
|
if (prefs.reduceMotion) root.setAttribute("data-motion", "reduce");
|
|
5412
5448
|
else root.removeAttribute("data-motion");
|
|
5413
5449
|
}
|
|
5414
|
-
function useAppearancePrefs(
|
|
5415
|
-
const
|
|
5416
|
-
|
|
5450
|
+
function useAppearancePrefs(store) {
|
|
5451
|
+
const prefs = React34.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
5452
|
+
React34.useEffect(() => {
|
|
5417
5453
|
applyPrefs(prefs);
|
|
5418
|
-
savePrefs(prefs, opts);
|
|
5419
5454
|
}, [prefs]);
|
|
5420
|
-
|
|
5455
|
+
React34.useEffect(() => {
|
|
5421
5456
|
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
5422
5457
|
return;
|
|
5423
5458
|
}
|
|
@@ -5426,9 +5461,12 @@ function useAppearancePrefs(opts) {
|
|
|
5426
5461
|
mq.addEventListener("change", onChange);
|
|
5427
5462
|
return () => mq.removeEventListener("change", onChange);
|
|
5428
5463
|
}, [prefs]);
|
|
5429
|
-
const update =
|
|
5430
|
-
|
|
5431
|
-
|
|
5464
|
+
const update = React34.useCallback(
|
|
5465
|
+
(patch) => {
|
|
5466
|
+
store.write({ ...store.getSnapshot(), ...patch });
|
|
5467
|
+
},
|
|
5468
|
+
[store]
|
|
5469
|
+
);
|
|
5432
5470
|
return [prefs, update];
|
|
5433
5471
|
}
|
|
5434
5472
|
|
|
@@ -5445,12 +5483,16 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
5445
5483
|
{ value: "lg", label: "L" },
|
|
5446
5484
|
{ value: "xl", label: "XL" }
|
|
5447
5485
|
];
|
|
5448
|
-
function AppearanceMenu({ className = "",
|
|
5449
|
-
const
|
|
5450
|
-
|
|
5451
|
-
|
|
5486
|
+
function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
|
|
5487
|
+
const store = React35.useMemo(
|
|
5488
|
+
() => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
|
|
5489
|
+
[storeProp, storageKey, storage, defaults]
|
|
5490
|
+
);
|
|
5491
|
+
const [prefs, update] = useAppearancePrefs(store);
|
|
5492
|
+
const [open, setOpen] = React35.useState(false);
|
|
5493
|
+
const anchorRef = React35.useRef(null);
|
|
5452
5494
|
const patch = (p) => update(p);
|
|
5453
|
-
return /* @__PURE__ */ jsxs55(
|
|
5495
|
+
return /* @__PURE__ */ jsxs55(React35.Fragment, { children: [
|
|
5454
5496
|
/* @__PURE__ */ jsx59("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx59(
|
|
5455
5497
|
IconButton,
|
|
5456
5498
|
{
|
|
@@ -5519,14 +5561,14 @@ function AppearanceMenu({ className = "", ...storeOptions }) {
|
|
|
5519
5561
|
}
|
|
5520
5562
|
|
|
5521
5563
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
5522
|
-
import * as
|
|
5564
|
+
import * as React36 from "react";
|
|
5523
5565
|
import { jsx as jsx60, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
5524
5566
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
5525
5567
|
function Json({ obj }) {
|
|
5526
5568
|
return /* @__PURE__ */ jsx60("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
5527
5569
|
}
|
|
5528
5570
|
function Endpoint({ s, onRequest }) {
|
|
5529
|
-
const [tried, setTried] =
|
|
5571
|
+
const [tried, setTried] = React36.useState(null);
|
|
5530
5572
|
const run = async () => {
|
|
5531
5573
|
setTried("busy");
|
|
5532
5574
|
const t0 = (window.performance || Date).now();
|
|
@@ -5599,10 +5641,10 @@ function ApiSpecBrowser({
|
|
|
5599
5641
|
className = "",
|
|
5600
5642
|
...rest
|
|
5601
5643
|
}) {
|
|
5602
|
-
const [q, setQ] =
|
|
5603
|
-
const [method, setMethod] =
|
|
5604
|
-
const [mod, setMod] =
|
|
5605
|
-
const [listOnly, setListOnly] =
|
|
5644
|
+
const [q, setQ] = React36.useState("");
|
|
5645
|
+
const [method, setMethod] = React36.useState(null);
|
|
5646
|
+
const [mod, setMod] = React36.useState(null);
|
|
5647
|
+
const [listOnly, setListOnly] = React36.useState(false);
|
|
5606
5648
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
5607
5649
|
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())));
|
|
5608
5650
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -5681,139 +5723,174 @@ function ApiSpecBrowser({
|
|
|
5681
5723
|
}
|
|
5682
5724
|
|
|
5683
5725
|
// src/components/platform/ProfilePage.tsx
|
|
5684
|
-
import * as
|
|
5726
|
+
import * as React37 from "react";
|
|
5685
5727
|
import { jsx as jsx61, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5728
|
+
function fieldInitialValue(field, user) {
|
|
5729
|
+
if (field.value) return field.value(user);
|
|
5730
|
+
const raw = user[field.key];
|
|
5731
|
+
return raw == null ? "" : String(raw);
|
|
5732
|
+
}
|
|
5733
|
+
function groupFields(fields) {
|
|
5734
|
+
const order = [];
|
|
5735
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
5736
|
+
for (const field of fields) {
|
|
5737
|
+
const group = field.group ?? "Identity";
|
|
5738
|
+
if (!byGroup.has(group)) {
|
|
5739
|
+
byGroup.set(group, { group, description: field.groupDescription, fields: [] });
|
|
5740
|
+
order.push(group);
|
|
5741
|
+
}
|
|
5742
|
+
const entry = byGroup.get(group);
|
|
5743
|
+
if (entry.description === void 0) entry.description = field.groupDescription;
|
|
5744
|
+
entry.fields.push(field);
|
|
5745
|
+
}
|
|
5746
|
+
return order.map((g) => byGroup.get(g));
|
|
5747
|
+
}
|
|
5748
|
+
function ProfilePage({
|
|
5749
|
+
user: userProp,
|
|
5750
|
+
fields = [],
|
|
5751
|
+
notifications = [],
|
|
5752
|
+
extra,
|
|
5753
|
+
onChangePhoto,
|
|
5754
|
+
onSave,
|
|
5755
|
+
onNavigate,
|
|
5756
|
+
sessions,
|
|
5757
|
+
onSignOutEverywhere,
|
|
5758
|
+
className = ""
|
|
5759
|
+
}) {
|
|
5695
5760
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
5696
5761
|
const user = userProp || sessionUser;
|
|
5697
|
-
const
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
const [
|
|
5708
|
-
const
|
|
5709
|
-
|
|
5762
|
+
const initialFieldValues = React37.useMemo(() => {
|
|
5763
|
+
const values2 = {};
|
|
5764
|
+
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
5765
|
+
return values2;
|
|
5766
|
+
}, [user.id, fields]);
|
|
5767
|
+
const initialNotify = React37.useMemo(() => {
|
|
5768
|
+
const values2 = {};
|
|
5769
|
+
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
5770
|
+
return values2;
|
|
5771
|
+
}, [user.id, notifications]);
|
|
5772
|
+
const [values, setValues] = React37.useState(initialFieldValues);
|
|
5773
|
+
const [notify, setNotify] = React37.useState(initialNotify);
|
|
5774
|
+
const [saving, setSaving] = React37.useState(false);
|
|
5775
|
+
const [saved, setSaved] = React37.useState(false);
|
|
5776
|
+
const [prevUserId, setPrevUserId] = React37.useState(user.id);
|
|
5777
|
+
if (user.id !== prevUserId) {
|
|
5778
|
+
setPrevUserId(user.id);
|
|
5779
|
+
setValues(initialFieldValues);
|
|
5780
|
+
setNotify(initialNotify);
|
|
5781
|
+
setSaved(false);
|
|
5782
|
+
}
|
|
5783
|
+
const setField = (key, v) => {
|
|
5784
|
+
setValues((d) => ({ ...d, [key]: v }));
|
|
5710
5785
|
setSaved(false);
|
|
5711
5786
|
};
|
|
5712
|
-
const
|
|
5713
|
-
|
|
5787
|
+
const toggleNotify = (key) => {
|
|
5788
|
+
setNotify((d) => ({ ...d, [key]: !d[key] }));
|
|
5714
5789
|
setSaved(false);
|
|
5715
5790
|
};
|
|
5716
|
-
const dirty =
|
|
5717
|
-
const canSave = !!(onSave || saveProfile2);
|
|
5791
|
+
const dirty = fields.some((f) => values[f.key] !== initialFieldValues[f.key]) || notifications.some((n) => notify[n.key] !== initialNotify[n.key]);
|
|
5792
|
+
const canSave = !!(onSave || saveProfile2) && (fields.length > 0 || notifications.length > 0);
|
|
5718
5793
|
const save = async () => {
|
|
5719
5794
|
if (!canSave) return;
|
|
5720
5795
|
setSaving(true);
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5796
|
+
const draft = { ...values };
|
|
5797
|
+
if (notifications.length > 0) draft.notify = notify;
|
|
5798
|
+
try {
|
|
5799
|
+
if (onSave) await onSave(draft);
|
|
5800
|
+
else await saveProfile2(draft);
|
|
5801
|
+
setSaved(true);
|
|
5802
|
+
} finally {
|
|
5803
|
+
setSaving(false);
|
|
5804
|
+
}
|
|
5725
5805
|
};
|
|
5726
|
-
const
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5806
|
+
const discard = () => {
|
|
5807
|
+
setValues(initialFieldValues);
|
|
5808
|
+
setNotify(initialNotify);
|
|
5809
|
+
setSaved(false);
|
|
5810
|
+
};
|
|
5811
|
+
const displayName = fields.some((f) => f.key === "name") ? values.name || user.name : user.name;
|
|
5812
|
+
const fieldGroups = groupFields(fields);
|
|
5813
|
+
return /* @__PURE__ */ jsxs57("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 20, maxWidth: 860 }, children: [
|
|
5732
5814
|
/* @__PURE__ */ jsxs57("div", { className: "fd-stack", style: { gap: 10 }, children: [
|
|
5733
5815
|
/* @__PURE__ */ jsx61("span", { className: "fd-overline fd-muted", children: "Account" }),
|
|
5734
5816
|
/* @__PURE__ */ jsx61("h1", { className: "fd-h1", style: { margin: 0 }, children: "Your profile" }),
|
|
5735
5817
|
/* @__PURE__ */ jsx61("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." })
|
|
5736
5818
|
] }),
|
|
5737
5819
|
/* @__PURE__ */ jsx61(Card, { elevation: "flat", children: /* @__PURE__ */ jsxs57("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap", alignItems: "flex-start" }, children: [
|
|
5738
|
-
/* @__PURE__ */ jsx61(Avatar, { name:
|
|
5820
|
+
/* @__PURE__ */ jsx61(Avatar, { name: displayName, size: "lg" }),
|
|
5739
5821
|
/* @__PURE__ */ jsxs57("div", { className: "fd-stack", style: { gap: 4, flex: 1, minWidth: 200 }, children: [
|
|
5740
|
-
/* @__PURE__ */ jsx61("span", { className: "fd-h3", style: { margin: 0 }, children:
|
|
5741
|
-
/* @__PURE__ */ jsxs57("span", { className: "fd-body-sm fd-muted", children: [
|
|
5742
|
-
draft.title || "No title set",
|
|
5743
|
-
" \xB7 ",
|
|
5744
|
-
user.team || "No team"
|
|
5745
|
-
] }),
|
|
5822
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-h3", style: { margin: 0 }, children: displayName }),
|
|
5746
5823
|
/* @__PURE__ */ jsxs57("span", { className: "fd-row", style: { gap: 6, flexWrap: "wrap", paddingTop: 4 }, children: [
|
|
5747
5824
|
roles.map((r) => /* @__PURE__ */ jsx61(Badge, { tone: r.id === "owner" ? "success" : "neutral", children: r.name }, r.id)),
|
|
5748
5825
|
user.sso ? /* @__PURE__ */ jsx61(Badge, { tone: "info", icon: "shield-check", children: "SSO" }) : null
|
|
5749
5826
|
] })
|
|
5750
5827
|
] }),
|
|
5751
|
-
/* @__PURE__ */ jsx61(Button, { variant: "secondary", size: "sm", icon: "image", children: "Change photo" })
|
|
5828
|
+
onChangePhoto ? /* @__PURE__ */ jsx61(Button, { variant: "secondary", size: "sm", icon: "image", onClick: onChangePhoto, children: "Change photo" }) : null
|
|
5752
5829
|
] }) }),
|
|
5753
|
-
/* @__PURE__ */ jsx61(
|
|
5830
|
+
fieldGroups.map(({ group, description, fields: groupFieldDefs }) => /* @__PURE__ */ jsx61(
|
|
5754
5831
|
Card,
|
|
5755
5832
|
{
|
|
5756
|
-
title: /* @__PURE__ */ jsxs57("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
5757
|
-
/* @__PURE__ */ jsx61("span", { children:
|
|
5758
|
-
/* @__PURE__ */ jsx61("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children:
|
|
5759
|
-
] }),
|
|
5833
|
+
title: description ? /* @__PURE__ */ jsxs57("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
5834
|
+
/* @__PURE__ */ jsx61("span", { children: group }),
|
|
5835
|
+
/* @__PURE__ */ jsx61("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: description })
|
|
5836
|
+
] }) : group,
|
|
5760
5837
|
elevation: "flat",
|
|
5761
5838
|
children: /* @__PURE__ */ jsxs57("div", { className: "fd-stack", style: { gap: 14 }, children: [
|
|
5762
|
-
/* @__PURE__ */
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5839
|
+
/* @__PURE__ */ jsx61("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit,minmax(220px,1fr))", gap: 14 }, children: groupFieldDefs.filter((f) => f.type !== "textarea").map((field) => {
|
|
5840
|
+
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
5841
|
+
const readOnly = field.readOnly || field.type === "readonly";
|
|
5842
|
+
if (field.type === "select") {
|
|
5843
|
+
return /* @__PURE__ */ jsx61(
|
|
5844
|
+
Select,
|
|
5845
|
+
{
|
|
5846
|
+
label: field.label,
|
|
5847
|
+
value: values[field.key],
|
|
5848
|
+
onChange: readOnly ? void 0 : (e) => setField(field.key, e.target.value),
|
|
5849
|
+
options: field.options ?? [],
|
|
5850
|
+
placeholder: field.placeholder,
|
|
5851
|
+
help,
|
|
5852
|
+
disabled: readOnly
|
|
5853
|
+
},
|
|
5854
|
+
field.key
|
|
5855
|
+
);
|
|
5856
|
+
}
|
|
5857
|
+
return /* @__PURE__ */ jsx61(
|
|
5768
5858
|
Input,
|
|
5769
5859
|
{
|
|
5770
|
-
label:
|
|
5771
|
-
value:
|
|
5772
|
-
readOnly:
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5860
|
+
label: field.label,
|
|
5861
|
+
value: values[field.key],
|
|
5862
|
+
onChange: readOnly ? void 0 : (e) => setField(field.key, e.target.value),
|
|
5863
|
+
readOnly,
|
|
5864
|
+
disabled: readOnly,
|
|
5865
|
+
placeholder: field.placeholder,
|
|
5866
|
+
help
|
|
5867
|
+
},
|
|
5868
|
+
field.key
|
|
5869
|
+
);
|
|
5870
|
+
}) }),
|
|
5871
|
+
groupFieldDefs.filter((f) => f.type === "textarea").map((field) => {
|
|
5872
|
+
const help = typeof field.help === "function" ? field.help(user) : field.help;
|
|
5873
|
+
return /* @__PURE__ */ jsx61(
|
|
5874
|
+
Textarea,
|
|
5875
|
+
{
|
|
5876
|
+
label: field.label,
|
|
5877
|
+
value: values[field.key],
|
|
5878
|
+
onChange: field.readOnly ? void 0 : (e) => setField(field.key, e.target.value),
|
|
5879
|
+
readOnly: field.readOnly,
|
|
5880
|
+
disabled: field.readOnly,
|
|
5881
|
+
rows: field.rows ?? 3,
|
|
5882
|
+
placeholder: field.placeholder,
|
|
5883
|
+
help
|
|
5884
|
+
},
|
|
5885
|
+
field.key
|
|
5886
|
+
);
|
|
5887
|
+
})
|
|
5790
5888
|
] })
|
|
5791
|
-
}
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
{
|
|
5797
|
-
label: "Time zone",
|
|
5798
|
-
value: draft.timezone,
|
|
5799
|
-
onChange: (e) => set("timezone", e.target.value),
|
|
5800
|
-
options: TIMEZONES,
|
|
5801
|
-
help: "Flight dates and schedules render in this zone."
|
|
5802
|
-
}
|
|
5803
|
-
),
|
|
5804
|
-
/* @__PURE__ */ jsx61(Select, { label: "Start of week", options: ["Monday", "Sunday"], placeholder: "Monday" })
|
|
5805
|
-
] }) }),
|
|
5806
|
-
/* @__PURE__ */ jsx61(
|
|
5807
|
-
Card,
|
|
5808
|
-
{
|
|
5809
|
-
title: /* @__PURE__ */ jsxs57("span", { className: "fd-stack", style: { gap: 2 }, children: [
|
|
5810
|
-
/* @__PURE__ */ jsx61("span", { children: "Notifications" }),
|
|
5811
|
-
/* @__PURE__ */ jsx61("span", { className: "fd-body-sm fd-muted", style: { fontWeight: 400 }, children: "Email only for now \u2014 in-app notifications are on the roadmap" })
|
|
5812
|
-
] }),
|
|
5813
|
-
elevation: "flat",
|
|
5814
|
-
children: /* @__PURE__ */ jsx61("div", { className: "fd-stack", style: { gap: 14 }, children: NOTIFY.map((n) => /* @__PURE__ */ jsx61(Switch, { checked: !!draft.notify[n.key], onChange: () => setNotify(n.key), label: n.label, description: n.detail }, n.key)) })
|
|
5815
|
-
}
|
|
5816
|
-
),
|
|
5889
|
+
},
|
|
5890
|
+
group
|
|
5891
|
+
)),
|
|
5892
|
+
extra,
|
|
5893
|
+
notifications.length > 0 ? /* @__PURE__ */ jsx61(Card, { title: "Notifications", elevation: "flat", children: /* @__PURE__ */ jsx61("div", { className: "fd-stack", style: { gap: 14 }, children: notifications.map((n) => /* @__PURE__ */ jsx61(Switch, { checked: !!notify[n.key], onChange: () => toggleNotify(n.key), label: n.label, description: n.description }, n.key)) }) }) : null,
|
|
5817
5894
|
/* @__PURE__ */ jsxs57(
|
|
5818
5895
|
Card,
|
|
5819
5896
|
{
|
|
@@ -5845,13 +5922,13 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
5845
5922
|
]
|
|
5846
5923
|
}
|
|
5847
5924
|
),
|
|
5848
|
-
|
|
5925
|
+
sessions ? /* @__PURE__ */ jsx61(
|
|
5849
5926
|
Card,
|
|
5850
5927
|
{
|
|
5851
5928
|
title: "Signed-in devices",
|
|
5852
5929
|
elevation: "flat",
|
|
5853
|
-
action: /* @__PURE__ */ jsx61(Button, { size: "sm", variant: "ghost", icon: "sign-out", children: "Sign out everywhere" }),
|
|
5854
|
-
children: /* @__PURE__ */ jsx61("div", { className: "fd-stack", style: { gap: 0 }, children:
|
|
5930
|
+
action: /* @__PURE__ */ jsx61(Button, { size: "sm", variant: "ghost", icon: "sign-out", onClick: onSignOutEverywhere, children: "Sign out everywhere" }),
|
|
5931
|
+
children: /* @__PURE__ */ jsx61("div", { className: "fd-stack", style: { gap: 0 }, children: sessions.length === 0 ? /* @__PURE__ */ jsx61("p", { className: "fd-body-sm fd-muted", style: { margin: 0 }, children: "No other signed-in devices." }) : sessions.map((s) => /* @__PURE__ */ jsxs57("div", { className: "fd-row", style: { gap: 12, padding: "10px 0", borderTop: "1px solid var(--border)", flexWrap: "wrap" }, children: [
|
|
5855
5932
|
/* @__PURE__ */ jsx61("i", { className: "ph ph-device-mobile", style: { fontSize: 16, color: "var(--text-muted)" }, "aria-hidden": "true" }),
|
|
5856
5933
|
/* @__PURE__ */ jsxs57("span", { className: "fd-stack", style: { gap: 1, flex: 1, minWidth: 160 }, children: [
|
|
5857
5934
|
/* @__PURE__ */ jsx61("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: s.device }),
|
|
@@ -5877,29 +5954,17 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
5877
5954
|
boxShadow: "0 -4px 16px rgba(11,13,17,.06)"
|
|
5878
5955
|
}, children: [
|
|
5879
5956
|
/* @__PURE__ */ jsx61("span", { className: "fd-body-sm", style: { fontWeight: 600, flex: 1 }, children: saved ? "Saved." : dirty ? "Unsaved changes" : "No pending changes" }),
|
|
5880
|
-
/* @__PURE__ */ jsx61(
|
|
5881
|
-
Button,
|
|
5882
|
-
{
|
|
5883
|
-
size: "sm",
|
|
5884
|
-
variant: "ghost",
|
|
5885
|
-
disabled: !dirty || saving,
|
|
5886
|
-
onClick: () => {
|
|
5887
|
-
setDraft({ name: user.name || "", title: user.title || "", email: user.email || "", phone: user.phone || "", timezone: user.timezone || TIMEZONES[2], bio: user.bio || "", notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true } });
|
|
5888
|
-
setSaved(false);
|
|
5889
|
-
},
|
|
5890
|
-
children: "Discard"
|
|
5891
|
-
}
|
|
5892
|
-
),
|
|
5957
|
+
/* @__PURE__ */ jsx61(Button, { size: "sm", variant: "ghost", disabled: !dirty || saving, onClick: discard, children: "Discard" }),
|
|
5893
5958
|
/* @__PURE__ */ jsx61(Button, { size: "sm", icon: "check", disabled: !dirty || !canSave, loading: saving, onClick: save, children: "Save changes" })
|
|
5894
5959
|
] })
|
|
5895
5960
|
] });
|
|
5896
5961
|
}
|
|
5897
5962
|
|
|
5898
5963
|
// src/components/platform/RoadmapTimeline.tsx
|
|
5899
|
-
import * as
|
|
5964
|
+
import * as React40 from "react";
|
|
5900
5965
|
|
|
5901
5966
|
// src/kits/session.ts
|
|
5902
|
-
import * as
|
|
5967
|
+
import * as React38 from "react";
|
|
5903
5968
|
var PERMISSION_CATALOG = [
|
|
5904
5969
|
{ group: "Plans", items: [
|
|
5905
5970
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -7466,8 +7531,8 @@ function roadmap(overrides) {
|
|
|
7466
7531
|
};
|
|
7467
7532
|
}
|
|
7468
7533
|
function useSession() {
|
|
7469
|
-
const [s, setS] =
|
|
7470
|
-
|
|
7534
|
+
const [s, setS] = React38.useState(getSession);
|
|
7535
|
+
React38.useEffect(() => subscribe(setS), []);
|
|
7471
7536
|
return s;
|
|
7472
7537
|
}
|
|
7473
7538
|
var SessionKit = {
|
|
@@ -7500,7 +7565,7 @@ var SessionKit = {
|
|
|
7500
7565
|
};
|
|
7501
7566
|
function DemoSessionProvider({ children }) {
|
|
7502
7567
|
const session = useSession();
|
|
7503
|
-
const value =
|
|
7568
|
+
const value = React38.useMemo(
|
|
7504
7569
|
() => ({
|
|
7505
7570
|
user: session.user,
|
|
7506
7571
|
roles: session.roles,
|
|
@@ -7516,11 +7581,11 @@ function DemoSessionProvider({ children }) {
|
|
|
7516
7581
|
}),
|
|
7517
7582
|
[session]
|
|
7518
7583
|
);
|
|
7519
|
-
return
|
|
7584
|
+
return React38.createElement(SessionProvider, { value }, children);
|
|
7520
7585
|
}
|
|
7521
7586
|
|
|
7522
7587
|
// src/kits/runtime.ts
|
|
7523
|
-
import * as
|
|
7588
|
+
import * as React39 from "react";
|
|
7524
7589
|
var WIRED_ENDPOINTS = [
|
|
7525
7590
|
// Nothing yet. Every id below would come from a real service:
|
|
7526
7591
|
// "plan.get", "placements.list", …
|
|
@@ -7691,8 +7756,8 @@ var RuntimeKit = {
|
|
|
7691
7756
|
};
|
|
7692
7757
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
7693
7758
|
function useRuntimeMode() {
|
|
7694
|
-
const [m, setM] =
|
|
7695
|
-
|
|
7759
|
+
const [m, setM] = React39.useState(RuntimeKit.getMode());
|
|
7760
|
+
React39.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
7696
7761
|
return m;
|
|
7697
7762
|
}
|
|
7698
7763
|
function useFeatureStatus(key) {
|
|
@@ -7775,12 +7840,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7775
7840
|
}
|
|
7776
7841
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
7777
7842
|
const session = SessionKit.useSession();
|
|
7778
|
-
const [project, setProject] =
|
|
7779
|
-
const [q, setQ] =
|
|
7780
|
-
const scrollRef =
|
|
7781
|
-
const nowRef =
|
|
7782
|
-
const rm =
|
|
7783
|
-
const byKey =
|
|
7843
|
+
const [project, setProject] = React40.useState("");
|
|
7844
|
+
const [q, setQ] = React40.useState("");
|
|
7845
|
+
const scrollRef = React40.useRef(null);
|
|
7846
|
+
const nowRef = React40.useRef(null);
|
|
7847
|
+
const rm = React40.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7848
|
+
const byKey = React40.useMemo(() => {
|
|
7784
7849
|
const m = {};
|
|
7785
7850
|
rm.items.forEach((i) => {
|
|
7786
7851
|
m[i.key] = i;
|
|
@@ -7789,7 +7854,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7789
7854
|
}, [rm]);
|
|
7790
7855
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
7791
7856
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
7792
|
-
|
|
7857
|
+
React40.useEffect(() => {
|
|
7793
7858
|
let raf1 = 0, raf2 = 0;
|
|
7794
7859
|
const place = () => {
|
|
7795
7860
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -7863,7 +7928,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7863
7928
|
lastPhase = item.phase;
|
|
7864
7929
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
7865
7930
|
const isBoundary = n === firstPending;
|
|
7866
|
-
return /* @__PURE__ */ jsxs58(
|
|
7931
|
+
return /* @__PURE__ */ jsxs58(React40.Fragment, { children: [
|
|
7867
7932
|
showPhase ? /* @__PURE__ */ jsxs58("div", { className: "fd-rm-era", children: [
|
|
7868
7933
|
/* @__PURE__ */ jsxs58("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7869
7934
|
/* @__PURE__ */ jsx62("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -7907,7 +7972,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7907
7972
|
}
|
|
7908
7973
|
|
|
7909
7974
|
// src/components/platform/ComingSoon.tsx
|
|
7910
|
-
import * as
|
|
7975
|
+
import * as React41 from "react";
|
|
7911
7976
|
import { createPortal as createPortal5 } from "react-dom";
|
|
7912
7977
|
import { Fragment as Fragment18, jsx as jsx63, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
7913
7978
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
@@ -7925,8 +7990,8 @@ function writeBypassed(list) {
|
|
|
7925
7990
|
}
|
|
7926
7991
|
}
|
|
7927
7992
|
function useBypass(key) {
|
|
7928
|
-
const [on, setOn] =
|
|
7929
|
-
|
|
7993
|
+
const [on, setOn] = React41.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7994
|
+
React41.useEffect(() => {
|
|
7930
7995
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
7931
7996
|
}, [key]);
|
|
7932
7997
|
const set = (next) => {
|
|
@@ -7973,9 +8038,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
7973
8038
|
] });
|
|
7974
8039
|
}
|
|
7975
8040
|
function useHoverCard(open) {
|
|
7976
|
-
const anchor =
|
|
7977
|
-
const [pos, setPos] =
|
|
7978
|
-
|
|
8041
|
+
const anchor = React41.useRef(null);
|
|
8042
|
+
const [pos, setPos] = React41.useState(null);
|
|
8043
|
+
React41.useLayoutEffect(() => {
|
|
7979
8044
|
if (!open || !anchor.current) {
|
|
7980
8045
|
setPos(null);
|
|
7981
8046
|
return;
|
|
@@ -8102,10 +8167,10 @@ function ComingSoon({
|
|
|
8102
8167
|
] });
|
|
8103
8168
|
}
|
|
8104
8169
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
8105
|
-
const [open, setOpen] =
|
|
8170
|
+
const [open, setOpen] = React41.useState(false);
|
|
8106
8171
|
const [anchor, pos] = useHoverCard(open);
|
|
8107
8172
|
const zIndex = useOverlayLayer(open);
|
|
8108
|
-
const close =
|
|
8173
|
+
const close = React41.useRef(null);
|
|
8109
8174
|
const show = () => {
|
|
8110
8175
|
if (close.current) {
|
|
8111
8176
|
clearTimeout(close.current);
|
|
@@ -8121,7 +8186,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
8121
8186
|
setOpen(false);
|
|
8122
8187
|
}, 140);
|
|
8123
8188
|
};
|
|
8124
|
-
|
|
8189
|
+
React41.useEffect(() => () => {
|
|
8125
8190
|
if (close.current) clearTimeout(close.current);
|
|
8126
8191
|
}, []);
|
|
8127
8192
|
return /* @__PURE__ */ jsxs59(
|
|
@@ -8292,14 +8357,14 @@ function PermissionHint({ perm, children }) {
|
|
|
8292
8357
|
}
|
|
8293
8358
|
|
|
8294
8359
|
// src/components/platform/ModeSwitch.tsx
|
|
8295
|
-
import * as
|
|
8360
|
+
import * as React42 from "react";
|
|
8296
8361
|
import { Fragment as Fragment19, jsx as jsx65, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
8297
8362
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
8298
8363
|
const mode2 = useRuntimeMode();
|
|
8299
|
-
const [open, setOpen] =
|
|
8364
|
+
const [open, setOpen] = React42.useState(false);
|
|
8300
8365
|
const zIndex = useOverlayLayer(open);
|
|
8301
|
-
const ref =
|
|
8302
|
-
|
|
8366
|
+
const ref = React42.useRef(null);
|
|
8367
|
+
React42.useEffect(() => {
|
|
8303
8368
|
if (!open) return;
|
|
8304
8369
|
const away = (e) => {
|
|
8305
8370
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -8555,7 +8620,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8555
8620
|
}
|
|
8556
8621
|
|
|
8557
8622
|
// src/components/planner/MixGap.tsx
|
|
8558
|
-
import * as
|
|
8623
|
+
import * as React43 from "react";
|
|
8559
8624
|
import { Fragment as Fragment20, jsx as jsx68, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
8560
8625
|
var MIX_GAP_LAYOUT = {
|
|
8561
8626
|
trackHeight: 30,
|
|
@@ -8570,7 +8635,7 @@ function mixGapOffset(value, max) {
|
|
|
8570
8635
|
}
|
|
8571
8636
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
8572
8637
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
8573
|
-
const [hover, setHover] =
|
|
8638
|
+
const [hover, setHover] = React43.useState(null);
|
|
8574
8639
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
8575
8640
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
8576
8641
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
@@ -8713,7 +8778,7 @@ function ChannelContribution({
|
|
|
8713
8778
|
}
|
|
8714
8779
|
|
|
8715
8780
|
// src/components/planner/BudgetReallocator.tsx
|
|
8716
|
-
import * as
|
|
8781
|
+
import * as React44 from "react";
|
|
8717
8782
|
import { Fragment as Fragment21, jsx as jsx70, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8718
8783
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
8719
8784
|
function BudgetReallocator({
|
|
@@ -8729,8 +8794,8 @@ function BudgetReallocator({
|
|
|
8729
8794
|
onCancel,
|
|
8730
8795
|
className = ""
|
|
8731
8796
|
}) {
|
|
8732
|
-
const [draft, setDraft] =
|
|
8733
|
-
|
|
8797
|
+
const [draft, setDraft] = React44.useState(spend);
|
|
8798
|
+
React44.useEffect(() => setDraft(spend), [spend]);
|
|
8734
8799
|
const dirty = draft !== spend;
|
|
8735
8800
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
8736
8801
|
const nextBand = bandFor(nextCrp);
|
|
@@ -8745,10 +8810,10 @@ function BudgetReallocator({
|
|
|
8745
8810
|
setDraft(spend);
|
|
8746
8811
|
if (onCancel) onCancel();
|
|
8747
8812
|
};
|
|
8748
|
-
const trackRef =
|
|
8749
|
-
const chipRef =
|
|
8750
|
-
const [chipLeft, setChipLeft] =
|
|
8751
|
-
|
|
8813
|
+
const trackRef = React44.useRef(null);
|
|
8814
|
+
const chipRef = React44.useRef(null);
|
|
8815
|
+
const [chipLeft, setChipLeft] = React44.useState(null);
|
|
8816
|
+
React44.useLayoutEffect(() => {
|
|
8752
8817
|
const track = trackRef.current;
|
|
8753
8818
|
if (!dirty || !track) {
|
|
8754
8819
|
setChipLeft(null);
|
|
@@ -8935,7 +9000,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
8935
9000
|
}
|
|
8936
9001
|
|
|
8937
9002
|
// src/components/planner/PreferenceMeter.tsx
|
|
8938
|
-
import * as
|
|
9003
|
+
import * as React45 from "react";
|
|
8939
9004
|
import { jsx as jsx73, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
8940
9005
|
function preferenceScore(criteria) {
|
|
8941
9006
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -8965,7 +9030,7 @@ function PreferenceMeter({
|
|
|
8965
9030
|
className = ""
|
|
8966
9031
|
}) {
|
|
8967
9032
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
8968
|
-
const segments =
|
|
9033
|
+
const segments = React45.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
8969
9034
|
return /* @__PURE__ */ jsx73(
|
|
8970
9035
|
ScoreMeter,
|
|
8971
9036
|
{
|
|
@@ -9004,10 +9069,10 @@ function PreferenceMeter({
|
|
|
9004
9069
|
}
|
|
9005
9070
|
|
|
9006
9071
|
// src/components/chat/AgentChatPanel.tsx
|
|
9007
|
-
import * as
|
|
9072
|
+
import * as React51 from "react";
|
|
9008
9073
|
|
|
9009
9074
|
// src/components/chat/chatEngine.ts
|
|
9010
|
-
import * as
|
|
9075
|
+
import * as React46 from "react";
|
|
9011
9076
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
9012
9077
|
var JOB_PENDING = ["queued", "running"];
|
|
9013
9078
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -9061,22 +9126,22 @@ function useChatEngine(opts) {
|
|
|
9061
9126
|
onClear,
|
|
9062
9127
|
onFeedback
|
|
9063
9128
|
} = opts || {};
|
|
9064
|
-
const [status, setStatus] =
|
|
9065
|
-
const [threadId, setThreadId] =
|
|
9066
|
-
const [messages, setMessages] =
|
|
9067
|
-
const [queue, setQueue] =
|
|
9068
|
-
const [fatal, setFatal] =
|
|
9069
|
-
const [busy, setBusy] =
|
|
9070
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
9071
|
-
const listRef =
|
|
9072
|
-
const queueRef =
|
|
9073
|
-
const busyRef =
|
|
9074
|
-
const stoppedRef =
|
|
9075
|
-
const abortRef =
|
|
9076
|
-
const serverCount =
|
|
9077
|
-
const threadRef =
|
|
9078
|
-
const mounted =
|
|
9079
|
-
|
|
9129
|
+
const [status, setStatus] = React46.useState("idle");
|
|
9130
|
+
const [threadId, setThreadId] = React46.useState(null);
|
|
9131
|
+
const [messages, setMessages] = React46.useState([]);
|
|
9132
|
+
const [queue, setQueue] = React46.useState([]);
|
|
9133
|
+
const [fatal, setFatal] = React46.useState(null);
|
|
9134
|
+
const [busy, setBusy] = React46.useState(false);
|
|
9135
|
+
const [turnStartedAt, setTurnStartedAt] = React46.useState(null);
|
|
9136
|
+
const listRef = React46.useRef([]);
|
|
9137
|
+
const queueRef = React46.useRef([]);
|
|
9138
|
+
const busyRef = React46.useRef(false);
|
|
9139
|
+
const stoppedRef = React46.useRef(false);
|
|
9140
|
+
const abortRef = React46.useRef(null);
|
|
9141
|
+
const serverCount = React46.useRef(0);
|
|
9142
|
+
const threadRef = React46.useRef(null);
|
|
9143
|
+
const mounted = React46.useRef(true);
|
|
9144
|
+
React46.useEffect(() => {
|
|
9080
9145
|
mounted.current = true;
|
|
9081
9146
|
return () => {
|
|
9082
9147
|
mounted.current = false;
|
|
@@ -9098,14 +9163,14 @@ function useChatEngine(opts) {
|
|
|
9098
9163
|
}
|
|
9099
9164
|
return false;
|
|
9100
9165
|
};
|
|
9101
|
-
const loadThread =
|
|
9166
|
+
const loadThread = React46.useCallback(async (id) => {
|
|
9102
9167
|
const data = await apiAdapter.getThread(id);
|
|
9103
9168
|
const list = [...data && data.messages || []];
|
|
9104
9169
|
serverCount.current = list.length;
|
|
9105
9170
|
commit(list);
|
|
9106
9171
|
return list;
|
|
9107
9172
|
}, [apiAdapter]);
|
|
9108
|
-
|
|
9173
|
+
React46.useEffect(() => {
|
|
9109
9174
|
if (!apiAdapter) {
|
|
9110
9175
|
setStatus("idle");
|
|
9111
9176
|
setFatal(null);
|
|
@@ -9318,7 +9383,7 @@ function useChatEngine(opts) {
|
|
|
9318
9383
|
await dispatchTurn(turn);
|
|
9319
9384
|
}
|
|
9320
9385
|
}
|
|
9321
|
-
const send =
|
|
9386
|
+
const send = React46.useCallback((text, attachments) => {
|
|
9322
9387
|
const body = (text || "").trim();
|
|
9323
9388
|
if (!body && !(attachments && attachments.length)) return;
|
|
9324
9389
|
if (status === "disconnected") return;
|
|
@@ -9328,7 +9393,7 @@ function useChatEngine(opts) {
|
|
|
9328
9393
|
stoppedRef.current = false;
|
|
9329
9394
|
drain();
|
|
9330
9395
|
}, [status]);
|
|
9331
|
-
const stop =
|
|
9396
|
+
const stop = React46.useCallback(() => {
|
|
9332
9397
|
stoppedRef.current = true;
|
|
9333
9398
|
const ac = abortRef.current;
|
|
9334
9399
|
if (ac) {
|
|
@@ -9347,11 +9412,11 @@ function useChatEngine(opts) {
|
|
|
9347
9412
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
9348
9413
|
}
|
|
9349
9414
|
}, [apiAdapter]);
|
|
9350
|
-
const removeQueued =
|
|
9415
|
+
const removeQueued = React46.useCallback((id) => {
|
|
9351
9416
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
9352
9417
|
setQueue(queueRef.current.slice());
|
|
9353
9418
|
}, []);
|
|
9354
|
-
const retry =
|
|
9419
|
+
const retry = React46.useCallback(() => {
|
|
9355
9420
|
const list = listRef.current;
|
|
9356
9421
|
let at = -1;
|
|
9357
9422
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -9367,19 +9432,19 @@ function useChatEngine(opts) {
|
|
|
9367
9432
|
setQueue(queueRef.current.slice());
|
|
9368
9433
|
drain();
|
|
9369
9434
|
}, []);
|
|
9370
|
-
const clear =
|
|
9435
|
+
const clear = React46.useCallback(() => {
|
|
9371
9436
|
commit([]);
|
|
9372
9437
|
serverCount.current = 0;
|
|
9373
9438
|
queueRef.current = [];
|
|
9374
9439
|
setQueue([]);
|
|
9375
9440
|
onClear && onClear();
|
|
9376
9441
|
}, [onClear]);
|
|
9377
|
-
const setFeedback =
|
|
9442
|
+
const setFeedback = React46.useCallback((id, value) => {
|
|
9378
9443
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
9379
9444
|
const msg = listRef.current.find((m) => m.id === id);
|
|
9380
9445
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
9381
9446
|
}, [onFeedback]);
|
|
9382
|
-
const reload =
|
|
9447
|
+
const reload = React46.useCallback(async () => {
|
|
9383
9448
|
if (!threadRef.current) return;
|
|
9384
9449
|
setStatus("loading");
|
|
9385
9450
|
try {
|
|
@@ -9417,10 +9482,10 @@ var ChatKit = {
|
|
|
9417
9482
|
};
|
|
9418
9483
|
|
|
9419
9484
|
// src/components/chat/ChatTranscript.tsx
|
|
9420
|
-
import * as
|
|
9485
|
+
import * as React48 from "react";
|
|
9421
9486
|
|
|
9422
9487
|
// src/components/chat/ChatTurn.tsx
|
|
9423
|
-
import * as
|
|
9488
|
+
import * as React47 from "react";
|
|
9424
9489
|
import { jsx as jsx74, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9425
9490
|
function JsonView({ value }) {
|
|
9426
9491
|
let text;
|
|
@@ -9457,7 +9522,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
9457
9522
|
] });
|
|
9458
9523
|
}
|
|
9459
9524
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
9460
|
-
const [open, setOpen] =
|
|
9525
|
+
const [open, setOpen] = React47.useState(defaultOpen);
|
|
9461
9526
|
if (!text) return null;
|
|
9462
9527
|
return /* @__PURE__ */ jsxs70("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
9463
9528
|
/* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9474,7 +9539,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
9474
9539
|
] });
|
|
9475
9540
|
}
|
|
9476
9541
|
function Citations({ items = [], onOpen }) {
|
|
9477
|
-
const [open, setOpen] =
|
|
9542
|
+
const [open, setOpen] = React47.useState(false);
|
|
9478
9543
|
if (!items.length) return null;
|
|
9479
9544
|
return /* @__PURE__ */ jsxs70("div", { className: "fdc-cites", children: [
|
|
9480
9545
|
/* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9500,7 +9565,7 @@ function clampText(text, max) {
|
|
|
9500
9565
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
9501
9566
|
}
|
|
9502
9567
|
function MessageBody({ message: m, ctx }) {
|
|
9503
|
-
const [expanded, setExpanded] =
|
|
9568
|
+
const [expanded, setExpanded] = React47.useState(false);
|
|
9504
9569
|
const isUser = m.role === "user";
|
|
9505
9570
|
const raw = m.text || "";
|
|
9506
9571
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -9567,9 +9632,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
9567
9632
|
] });
|
|
9568
9633
|
}
|
|
9569
9634
|
function useCopyRun() {
|
|
9570
|
-
const [done, setDone] =
|
|
9571
|
-
const t =
|
|
9572
|
-
|
|
9635
|
+
const [done, setDone] = React47.useState(false);
|
|
9636
|
+
const t = React47.useRef(null);
|
|
9637
|
+
React47.useEffect(() => () => {
|
|
9573
9638
|
if (t.current) clearTimeout(t.current);
|
|
9574
9639
|
}, []);
|
|
9575
9640
|
return [done, (text) => {
|
|
@@ -9596,7 +9661,7 @@ function RunActions({ group, ctx }) {
|
|
|
9596
9661
|
] }),
|
|
9597
9662
|
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
9598
9663
|
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx74("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx74("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
9599
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs70(
|
|
9664
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs70(React47.Fragment, { children: [
|
|
9600
9665
|
/* @__PURE__ */ jsx74("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__ */ jsx74("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
9601
9666
|
/* @__PURE__ */ jsx74("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__ */ jsx74("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
9602
9667
|
] }) : null,
|
|
@@ -9691,10 +9756,10 @@ function ChatTranscript({
|
|
|
9691
9756
|
renderEmpty,
|
|
9692
9757
|
className = ""
|
|
9693
9758
|
}) {
|
|
9694
|
-
const scroller =
|
|
9695
|
-
const stick =
|
|
9696
|
-
const [pill, setPill] =
|
|
9697
|
-
const seen =
|
|
9759
|
+
const scroller = React48.useRef(null);
|
|
9760
|
+
const stick = React48.useRef(true);
|
|
9761
|
+
const [pill, setPill] = React48.useState(0);
|
|
9762
|
+
const seen = React48.useRef(0);
|
|
9698
9763
|
const toBottom = (smooth) => {
|
|
9699
9764
|
const el = scroller.current;
|
|
9700
9765
|
if (!el) return;
|
|
@@ -9713,7 +9778,7 @@ function ChatTranscript({
|
|
|
9713
9778
|
seen.current = messages.length;
|
|
9714
9779
|
}
|
|
9715
9780
|
};
|
|
9716
|
-
|
|
9781
|
+
React48.useLayoutEffect(() => {
|
|
9717
9782
|
const el = scroller.current;
|
|
9718
9783
|
if (!el) return;
|
|
9719
9784
|
if (stick.current) {
|
|
@@ -9721,7 +9786,7 @@ function ChatTranscript({
|
|
|
9721
9786
|
seen.current = messages.length;
|
|
9722
9787
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
9723
9788
|
}, [messages]);
|
|
9724
|
-
|
|
9789
|
+
React48.useEffect(() => {
|
|
9725
9790
|
const el = scroller.current;
|
|
9726
9791
|
const inner = el && el.firstChild;
|
|
9727
9792
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -9731,7 +9796,7 @@ function ChatTranscript({
|
|
|
9731
9796
|
ro.observe(inner);
|
|
9732
9797
|
return () => ro.disconnect();
|
|
9733
9798
|
}, []);
|
|
9734
|
-
const groups =
|
|
9799
|
+
const groups = React48.useMemo(() => groupMessages(messages), [messages]);
|
|
9735
9800
|
const empty = !messages.length && status === "ready";
|
|
9736
9801
|
return /* @__PURE__ */ jsxs71("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
9737
9802
|
/* @__PURE__ */ jsxs71("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -9755,7 +9820,7 @@ function ChatTranscript({
|
|
|
9755
9820
|
const prev = groups[i - 1];
|
|
9756
9821
|
const k = dayKey(g.messages[0].timestamp);
|
|
9757
9822
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
9758
|
-
return /* @__PURE__ */ jsxs71(
|
|
9823
|
+
return /* @__PURE__ */ jsxs71(React48.Fragment, { children: [
|
|
9759
9824
|
showDay ? /* @__PURE__ */ jsx75("div", { className: "fdc-day", children: /* @__PURE__ */ jsx75("span", { children: dayLabel(k) }) }) : null,
|
|
9760
9825
|
/* @__PURE__ */ jsx75(ChatTurn, { group: g, ctx })
|
|
9761
9826
|
] }, g.key || i);
|
|
@@ -9772,7 +9837,7 @@ function ChatTranscript({
|
|
|
9772
9837
|
var TranscriptKit = { groupMessages };
|
|
9773
9838
|
|
|
9774
9839
|
// src/components/chat/ChatComposer.tsx
|
|
9775
|
-
import * as
|
|
9840
|
+
import * as React49 from "react";
|
|
9776
9841
|
import { jsx as jsx76, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
9777
9842
|
function ChatComposer({
|
|
9778
9843
|
onSubmit,
|
|
@@ -9800,17 +9865,17 @@ function ChatComposer({
|
|
|
9800
9865
|
onReject,
|
|
9801
9866
|
onOpenAttachment
|
|
9802
9867
|
}) {
|
|
9803
|
-
const [text, setText] =
|
|
9804
|
-
const [trigger, setTrigger] =
|
|
9805
|
-
const [mentionItems, setMentionItems] =
|
|
9806
|
-
const [listening, setListening] =
|
|
9807
|
-
const [notice, setNotice] =
|
|
9808
|
-
const editor =
|
|
9809
|
-
const wrap =
|
|
9810
|
-
const stopVoice =
|
|
9868
|
+
const [text, setText] = React49.useState(draft || "");
|
|
9869
|
+
const [trigger, setTrigger] = React49.useState(null);
|
|
9870
|
+
const [mentionItems, setMentionItems] = React49.useState([]);
|
|
9871
|
+
const [listening, setListening] = React49.useState(false);
|
|
9872
|
+
const [notice, setNotice] = React49.useState(null);
|
|
9873
|
+
const editor = React49.useRef(null);
|
|
9874
|
+
const wrap = React49.useRef(null);
|
|
9875
|
+
const stopVoice = React49.useRef(null);
|
|
9811
9876
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
9812
9877
|
} });
|
|
9813
|
-
|
|
9878
|
+
React49.useEffect(() => {
|
|
9814
9879
|
if (draft != null && draft !== text) setText(draft);
|
|
9815
9880
|
}, [draft]);
|
|
9816
9881
|
const change = (v) => {
|
|
@@ -9846,7 +9911,7 @@ function ChatComposer({
|
|
|
9846
9911
|
e.preventDefault();
|
|
9847
9912
|
staged.add(found.files);
|
|
9848
9913
|
};
|
|
9849
|
-
|
|
9914
|
+
React49.useEffect(() => {
|
|
9850
9915
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
9851
9916
|
setMentionItems([]);
|
|
9852
9917
|
return;
|
|
@@ -9864,7 +9929,7 @@ function ChatComposer({
|
|
|
9864
9929
|
const q = (trigger.query || "").toLowerCase();
|
|
9865
9930
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
9866
9931
|
}, [trigger, mentionSources]);
|
|
9867
|
-
const slashItems =
|
|
9932
|
+
const slashItems = React49.useMemo(() => {
|
|
9868
9933
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
9869
9934
|
const q = (trigger.query || "").toLowerCase();
|
|
9870
9935
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -10038,12 +10103,12 @@ function ChatComposer({
|
|
|
10038
10103
|
}
|
|
10039
10104
|
|
|
10040
10105
|
// src/components/chat/ChatSessionBar.tsx
|
|
10041
|
-
import * as
|
|
10106
|
+
import * as React50 from "react";
|
|
10042
10107
|
import { jsx as jsx77, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
10043
10108
|
var compact2 = meterFormats.compact;
|
|
10044
10109
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
10045
|
-
const [open, setOpen] =
|
|
10046
|
-
const anchor =
|
|
10110
|
+
const [open, setOpen] = React50.useState(false);
|
|
10111
|
+
const anchor = React50.useRef(null);
|
|
10047
10112
|
const stats = sessionStats || null;
|
|
10048
10113
|
const cu = contextUsage || null;
|
|
10049
10114
|
const limits = usageLimits || null;
|
|
@@ -10058,7 +10123,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
10058
10123
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
10059
10124
|
if (cu) bits.push(pct + "% context");
|
|
10060
10125
|
const expandable = !!(cu || limits);
|
|
10061
|
-
return /* @__PURE__ */ jsxs73(
|
|
10126
|
+
return /* @__PURE__ */ jsxs73(React50.Fragment, { children: [
|
|
10062
10127
|
/* @__PURE__ */ jsxs73("div", { className: "fdc-bar", children: [
|
|
10063
10128
|
/* @__PURE__ */ jsxs73(
|
|
10064
10129
|
"button",
|
|
@@ -10199,7 +10264,7 @@ function ModelControls({
|
|
|
10199
10264
|
] })
|
|
10200
10265
|
});
|
|
10201
10266
|
}
|
|
10202
|
-
return /* @__PURE__ */ jsxs73(
|
|
10267
|
+
return /* @__PURE__ */ jsxs73(React50.Fragment, { children: [
|
|
10203
10268
|
/* @__PURE__ */ jsx77(
|
|
10204
10269
|
MenuButton,
|
|
10205
10270
|
{
|
|
@@ -10316,11 +10381,11 @@ function AgentChatPanel({
|
|
|
10316
10381
|
onFeedback,
|
|
10317
10382
|
onEditMessage
|
|
10318
10383
|
}) {
|
|
10319
|
-
const [panelWidth, setPanelWidth] =
|
|
10320
|
-
const [applied, setApplied] =
|
|
10321
|
-
const [draft, setDraft] =
|
|
10322
|
-
const dragging =
|
|
10323
|
-
|
|
10384
|
+
const [panelWidth, setPanelWidth] = React51.useState(width);
|
|
10385
|
+
const [applied, setApplied] = React51.useState({});
|
|
10386
|
+
const [draft, setDraft] = React51.useState("");
|
|
10387
|
+
const dragging = React51.useRef(null);
|
|
10388
|
+
React51.useEffect(() => setPanelWidth(width), [width]);
|
|
10324
10389
|
const engine = useChatEngine({
|
|
10325
10390
|
contextType,
|
|
10326
10391
|
contextId,
|
|
@@ -10524,7 +10589,7 @@ function AgentChatPanel({
|
|
|
10524
10589
|
}
|
|
10525
10590
|
|
|
10526
10591
|
// src/components/files/FileViewer.tsx
|
|
10527
|
-
import * as
|
|
10592
|
+
import * as React52 from "react";
|
|
10528
10593
|
import { jsx as jsx79, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
10529
10594
|
function previewKindOf(file) {
|
|
10530
10595
|
const mime = (file.mime || "").toLowerCase();
|
|
@@ -10581,13 +10646,13 @@ function parseDelimited(text, delimiter) {
|
|
|
10581
10646
|
return rows;
|
|
10582
10647
|
}
|
|
10583
10648
|
function usePreview(file, kind, resolveUrl) {
|
|
10584
|
-
const [state, setState] =
|
|
10585
|
-
const [attempt, setAttempt] =
|
|
10586
|
-
const resolveRef =
|
|
10587
|
-
|
|
10649
|
+
const [state, setState] = React52.useState({ status: "loading" });
|
|
10650
|
+
const [attempt, setAttempt] = React52.useState(0);
|
|
10651
|
+
const resolveRef = React52.useRef(resolveUrl);
|
|
10652
|
+
React52.useEffect(() => {
|
|
10588
10653
|
resolveRef.current = resolveUrl;
|
|
10589
10654
|
}, [resolveUrl]);
|
|
10590
|
-
|
|
10655
|
+
React52.useEffect(() => {
|
|
10591
10656
|
if (kind === "none") {
|
|
10592
10657
|
setState({ status: "ready" });
|
|
10593
10658
|
return;
|
|
@@ -10617,7 +10682,7 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
10617
10682
|
if (ac) ac.abort();
|
|
10618
10683
|
};
|
|
10619
10684
|
}, [file.id, kind, attempt]);
|
|
10620
|
-
return { ...state, retry:
|
|
10685
|
+
return { ...state, retry: React52.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
10621
10686
|
}
|
|
10622
10687
|
function PreviewBody({ file, kind, state }) {
|
|
10623
10688
|
if (kind === "image") return /* @__PURE__ */ jsx79("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
@@ -10662,13 +10727,13 @@ function PreviewBody({ file, kind, state }) {
|
|
|
10662
10727
|
] });
|
|
10663
10728
|
}
|
|
10664
10729
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
10665
|
-
const kind =
|
|
10730
|
+
const kind = React52.useMemo(() => previewKindOf(file), [file]);
|
|
10666
10731
|
const preview = usePreview(file, kind, resolveUrl);
|
|
10667
|
-
const [tab, setTab] =
|
|
10668
|
-
const [downloading, setDownloading] =
|
|
10669
|
-
const [downloadError, setDownloadError] =
|
|
10732
|
+
const [tab, setTab] = React52.useState("preview");
|
|
10733
|
+
const [downloading, setDownloading] = React52.useState(false);
|
|
10734
|
+
const [downloadError, setDownloadError] = React52.useState(null);
|
|
10670
10735
|
const hasSide = sidePanel != null;
|
|
10671
|
-
|
|
10736
|
+
React52.useEffect(() => {
|
|
10672
10737
|
setTab("preview");
|
|
10673
10738
|
}, [file.id]);
|
|
10674
10739
|
const download = () => {
|
|
@@ -10735,7 +10800,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
10735
10800
|
}
|
|
10736
10801
|
|
|
10737
10802
|
// src/components/files/FileBrowser.tsx
|
|
10738
|
-
import * as
|
|
10803
|
+
import * as React53 from "react";
|
|
10739
10804
|
import { Fragment as Fragment25, jsx as jsx80, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
10740
10805
|
function childrenOf(folders, parentId) {
|
|
10741
10806
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -10806,10 +10871,10 @@ function FolderPickerMenu({
|
|
|
10806
10871
|
destinations,
|
|
10807
10872
|
onPick
|
|
10808
10873
|
}) {
|
|
10809
|
-
const [open, setOpen] =
|
|
10874
|
+
const [open, setOpen] = React53.useState(false);
|
|
10810
10875
|
const zIndex = useOverlayLayer(open);
|
|
10811
|
-
const ref =
|
|
10812
|
-
|
|
10876
|
+
const ref = React53.useRef(null);
|
|
10877
|
+
React53.useEffect(() => {
|
|
10813
10878
|
if (!open) return;
|
|
10814
10879
|
const away = (e) => {
|
|
10815
10880
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -10861,8 +10926,8 @@ function FolderPickerMenu({
|
|
|
10861
10926
|
] });
|
|
10862
10927
|
}
|
|
10863
10928
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
10864
|
-
const [over, setOver] =
|
|
10865
|
-
const dragCounter =
|
|
10929
|
+
const [over, setOver] = React53.useState(false);
|
|
10930
|
+
const dragCounter = React53.useRef(0);
|
|
10866
10931
|
const dropHandlers = isDropTarget ? {
|
|
10867
10932
|
onDragEnter: (e) => {
|
|
10868
10933
|
if (!hasInternalPayload(e)) return;
|
|
@@ -10910,8 +10975,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
10910
10975
|
}
|
|
10911
10976
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
10912
10977
|
const kids = childrenOf(folders, folder.id);
|
|
10913
|
-
const [expanded, setExpanded] =
|
|
10914
|
-
|
|
10978
|
+
const [expanded, setExpanded] = React53.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
10979
|
+
React53.useEffect(() => {
|
|
10915
10980
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
10916
10981
|
}, [currentFolderId, folder.id, folders]);
|
|
10917
10982
|
const isCurrent = folder.id === currentFolderId;
|
|
@@ -10977,15 +11042,15 @@ function FileBrowser({
|
|
|
10977
11042
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
10978
11043
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
10979
11044
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
10980
|
-
const [createOpen, setCreateOpen] =
|
|
10981
|
-
const [createName, setCreateName] =
|
|
10982
|
-
const [renameTarget, setRenameTarget] =
|
|
10983
|
-
const [renameValue, setRenameValue] =
|
|
10984
|
-
const [deleteTarget, setDeleteTarget] =
|
|
10985
|
-
const uploadInputRef =
|
|
10986
|
-
const crumbFolders =
|
|
10987
|
-
const subfolders =
|
|
10988
|
-
const currentFiles =
|
|
11045
|
+
const [createOpen, setCreateOpen] = React53.useState(false);
|
|
11046
|
+
const [createName, setCreateName] = React53.useState("");
|
|
11047
|
+
const [renameTarget, setRenameTarget] = React53.useState(null);
|
|
11048
|
+
const [renameValue, setRenameValue] = React53.useState("");
|
|
11049
|
+
const [deleteTarget, setDeleteTarget] = React53.useState(null);
|
|
11050
|
+
const uploadInputRef = React53.useRef(null);
|
|
11051
|
+
const crumbFolders = React53.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11052
|
+
const subfolders = React53.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
11053
|
+
const currentFiles = React53.useMemo(
|
|
10989
11054
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
10990
11055
|
[files, currentFolderId]
|
|
10991
11056
|
);
|
|
@@ -11217,8 +11282,8 @@ function BreadcrumbCrumb({
|
|
|
11217
11282
|
isDropTarget,
|
|
11218
11283
|
onDropPayload
|
|
11219
11284
|
}) {
|
|
11220
|
-
const [over, setOver] =
|
|
11221
|
-
const dragCounter =
|
|
11285
|
+
const [over, setOver] = React53.useState(false);
|
|
11286
|
+
const dragCounter = React53.useRef(0);
|
|
11222
11287
|
const dropHandlers = isDropTarget ? {
|
|
11223
11288
|
onDragEnter: (e) => {
|
|
11224
11289
|
if (!hasInternalPayload(e)) return;
|
|
@@ -11247,7 +11312,7 @@ function BreadcrumbCrumb({
|
|
|
11247
11312
|
}
|
|
11248
11313
|
|
|
11249
11314
|
// src/kits/query.ts
|
|
11250
|
-
import * as
|
|
11315
|
+
import * as React54 from "react";
|
|
11251
11316
|
function eqFilter(get2) {
|
|
11252
11317
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
11253
11318
|
}
|
|
@@ -11279,22 +11344,22 @@ function compare(a, b, dir) {
|
|
|
11279
11344
|
var API = null;
|
|
11280
11345
|
var PREFS = null;
|
|
11281
11346
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
11282
|
-
const [query, setQuery] =
|
|
11347
|
+
const [query, setQuery] = React54.useState(() => {
|
|
11283
11348
|
const store = PREFS || window.PlannerPrefs;
|
|
11284
11349
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
11285
11350
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
11286
11351
|
});
|
|
11287
|
-
const savePref =
|
|
11352
|
+
const savePref = React54.useCallback((patch2) => {
|
|
11288
11353
|
const store = PREFS || window.PlannerPrefs;
|
|
11289
11354
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
11290
11355
|
}, [prefsKey]);
|
|
11291
|
-
const [res, setRes] =
|
|
11292
|
-
const [loading, setLoading] =
|
|
11293
|
-
const seq2 =
|
|
11356
|
+
const [res, setRes] = React54.useState(null);
|
|
11357
|
+
const [loading, setLoading] = React54.useState(true);
|
|
11358
|
+
const seq2 = React54.useRef(0);
|
|
11294
11359
|
const depKey = (deps || []).join("|");
|
|
11295
11360
|
const paramKey = JSON.stringify(params || {});
|
|
11296
11361
|
const queryKey = JSON.stringify(query);
|
|
11297
|
-
|
|
11362
|
+
React54.useEffect(() => {
|
|
11298
11363
|
const id = ++seq2.current;
|
|
11299
11364
|
setLoading(true);
|
|
11300
11365
|
const t = setTimeout(() => {
|
|
@@ -11591,6 +11656,92 @@ function createVersionStore(initialState, options) {
|
|
|
11591
11656
|
}
|
|
11592
11657
|
};
|
|
11593
11658
|
}
|
|
11659
|
+
|
|
11660
|
+
// src/kits/useResponsiveRail.ts
|
|
11661
|
+
import * as React55 from "react";
|
|
11662
|
+
function matchesBreakpoint(breakpoint) {
|
|
11663
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches;
|
|
11664
|
+
}
|
|
11665
|
+
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
11666
|
+
function getFocusable(container) {
|
|
11667
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
11668
|
+
}
|
|
11669
|
+
function useResponsiveRail(options = {}) {
|
|
11670
|
+
const { breakpoint = 1024, initialOpen = true, onPersist } = options;
|
|
11671
|
+
const navRef = React55.useRef(null);
|
|
11672
|
+
const [overlay, setOverlay] = React55.useState(() => matchesBreakpoint(breakpoint));
|
|
11673
|
+
const [open, setOpenRaw] = React55.useState(() => matchesBreakpoint(breakpoint) ? false : initialOpen);
|
|
11674
|
+
const setOpen = React55.useCallback(
|
|
11675
|
+
(value) => {
|
|
11676
|
+
setOpenRaw(value);
|
|
11677
|
+
if (!matchesBreakpoint(breakpoint)) onPersist?.(value);
|
|
11678
|
+
},
|
|
11679
|
+
[breakpoint, onPersist]
|
|
11680
|
+
);
|
|
11681
|
+
const toggle = React55.useCallback(() => setOpen(!open), [open, setOpen]);
|
|
11682
|
+
const close = React55.useCallback(() => setOpenRaw(false), []);
|
|
11683
|
+
React55.useEffect(() => {
|
|
11684
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
11685
|
+
const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
11686
|
+
const handler = (e) => {
|
|
11687
|
+
setOverlay(e.matches);
|
|
11688
|
+
setOpenRaw(!e.matches);
|
|
11689
|
+
};
|
|
11690
|
+
mq.addEventListener("change", handler);
|
|
11691
|
+
return () => mq.removeEventListener("change", handler);
|
|
11692
|
+
}, [breakpoint]);
|
|
11693
|
+
React55.useEffect(() => {
|
|
11694
|
+
if (!overlay || !open) return;
|
|
11695
|
+
const handler = (e) => {
|
|
11696
|
+
if (e.key === "Escape") close();
|
|
11697
|
+
};
|
|
11698
|
+
document.addEventListener("keydown", handler);
|
|
11699
|
+
return () => document.removeEventListener("keydown", handler);
|
|
11700
|
+
}, [overlay, open, close]);
|
|
11701
|
+
React55.useEffect(() => {
|
|
11702
|
+
if (!overlay || !open) return;
|
|
11703
|
+
const previousOverflow = document.body.style.overflow;
|
|
11704
|
+
document.body.style.overflow = "hidden";
|
|
11705
|
+
return () => {
|
|
11706
|
+
document.body.style.overflow = previousOverflow;
|
|
11707
|
+
};
|
|
11708
|
+
}, [overlay, open]);
|
|
11709
|
+
React55.useEffect(() => {
|
|
11710
|
+
if (!overlay || !open) return;
|
|
11711
|
+
const container = navRef.current;
|
|
11712
|
+
if (!container) return;
|
|
11713
|
+
const previouslyFocused = document.activeElement;
|
|
11714
|
+
const focusable = getFocusable(container);
|
|
11715
|
+
(focusable[0] ?? container).focus();
|
|
11716
|
+
const handler = (e) => {
|
|
11717
|
+
if (e.key !== "Tab") return;
|
|
11718
|
+
const items = getFocusable(container);
|
|
11719
|
+
if (items.length === 0) {
|
|
11720
|
+
e.preventDefault();
|
|
11721
|
+
return;
|
|
11722
|
+
}
|
|
11723
|
+
const first = items[0];
|
|
11724
|
+
const last = items[items.length - 1];
|
|
11725
|
+
const active = document.activeElement;
|
|
11726
|
+
const outside = !(active instanceof Node) || !container.contains(active);
|
|
11727
|
+
if (e.shiftKey) {
|
|
11728
|
+
if (outside || active === first) {
|
|
11729
|
+
e.preventDefault();
|
|
11730
|
+
last.focus();
|
|
11731
|
+
}
|
|
11732
|
+
} else if (outside || active === last) {
|
|
11733
|
+
e.preventDefault();
|
|
11734
|
+
first.focus();
|
|
11735
|
+
}
|
|
11736
|
+
};
|
|
11737
|
+
document.addEventListener("keydown", handler);
|
|
11738
|
+
return () => {
|
|
11739
|
+
document.removeEventListener("keydown", handler);
|
|
11740
|
+
previouslyFocused?.focus?.();
|
|
11741
|
+
};
|
|
11742
|
+
}, [overlay, open]);
|
|
11743
|
+
return { open, overlay, navRef, toggle, close, setOpen };
|
|
11744
|
+
}
|
|
11594
11745
|
export {
|
|
11595
11746
|
AccountMenu,
|
|
11596
11747
|
AgentChatPanel,
|
|
@@ -11734,6 +11885,7 @@ export {
|
|
|
11734
11885
|
channelWeightOf,
|
|
11735
11886
|
computeNeedMore,
|
|
11736
11887
|
computeVirtualWindow,
|
|
11888
|
+
createLocalStorageAppearanceStore,
|
|
11737
11889
|
createVersionStore,
|
|
11738
11890
|
eqFilter,
|
|
11739
11891
|
extensionOf,
|
|
@@ -11773,6 +11925,7 @@ export {
|
|
|
11773
11925
|
useChatEngine,
|
|
11774
11926
|
useFeatureStatus,
|
|
11775
11927
|
usePopoverPosition,
|
|
11928
|
+
useResponsiveRail,
|
|
11776
11929
|
useRuntimeMode,
|
|
11777
11930
|
useServerTable,
|
|
11778
11931
|
useSessionContext,
|