@flytedan/flytebot-design-system 0.28.0 → 0.29.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 +869 -753
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -50
- package/dist/index.d.ts +74 -50
- package/dist/index.js +869 -753
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +50 -0
package/dist/index.js
CHANGED
|
@@ -199,6 +199,15 @@ var ROOT_LAYER = 0;
|
|
|
199
199
|
var LAYER_STEP = 10;
|
|
200
200
|
var ROOT_STEP = 100;
|
|
201
201
|
var OVERLAY_CEILING = 1e4;
|
|
202
|
+
var openEscapeIds = [];
|
|
203
|
+
var registerEscapeLayer = (id) => {
|
|
204
|
+
if (openEscapeIds.includes(id)) return;
|
|
205
|
+
openEscapeIds = [...openEscapeIds, id];
|
|
206
|
+
};
|
|
207
|
+
var unregisterEscapeLayer = (id) => {
|
|
208
|
+
if (!openEscapeIds.includes(id)) return;
|
|
209
|
+
openEscapeIds = openEscapeIds.filter((existing) => existing !== id);
|
|
210
|
+
};
|
|
202
211
|
var LayerContext = React2.createContext(ROOT_LAYER);
|
|
203
212
|
var openRootIds = [];
|
|
204
213
|
var rootListeners = /* @__PURE__ */ new Set();
|
|
@@ -276,6 +285,12 @@ function Popover({
|
|
|
276
285
|
});
|
|
277
286
|
const restore = React2.useRef(null);
|
|
278
287
|
const zIndex = useOverlayLayer(!!open);
|
|
288
|
+
const escapeId = React2.useId();
|
|
289
|
+
React2.useLayoutEffect(() => {
|
|
290
|
+
if (!open) return;
|
|
291
|
+
registerEscapeLayer(escapeId);
|
|
292
|
+
return () => unregisterEscapeLayer(escapeId);
|
|
293
|
+
}, [open, escapeId]);
|
|
279
294
|
React2.useEffect(() => {
|
|
280
295
|
if (!open) return;
|
|
281
296
|
restore.current = typeof document !== "undefined" ? document.activeElement : null;
|
|
@@ -300,10 +315,10 @@ function Popover({
|
|
|
300
315
|
onClose && onClose();
|
|
301
316
|
};
|
|
302
317
|
const key = (e) => {
|
|
303
|
-
if (closeOnEscape
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
318
|
+
if (!closeOnEscape || e.key !== "Escape") return;
|
|
319
|
+
if (openEscapeIds[openEscapeIds.length - 1] !== escapeId) return;
|
|
320
|
+
e.stopPropagation();
|
|
321
|
+
onClose && onClose();
|
|
307
322
|
};
|
|
308
323
|
document.addEventListener("pointerdown", away, true);
|
|
309
324
|
document.addEventListener("keydown", key);
|
|
@@ -311,7 +326,7 @@ function Popover({
|
|
|
311
326
|
document.removeEventListener("pointerdown", away, true);
|
|
312
327
|
document.removeEventListener("keydown", key);
|
|
313
328
|
};
|
|
314
|
-
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef]);
|
|
329
|
+
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef, escapeId]);
|
|
315
330
|
if (!open || !pos) return null;
|
|
316
331
|
return portal(
|
|
317
332
|
/* @__PURE__ */ jsx3(LayerProvider, { zIndex, children: /* @__PURE__ */ jsxs3(
|
|
@@ -1500,11 +1515,13 @@ var BANNER_TONE_STYLE = {
|
|
|
1500
1515
|
text: "var(--danger-text)"
|
|
1501
1516
|
}
|
|
1502
1517
|
};
|
|
1503
|
-
function Banner({ tone = "info", title, detail, actions }) {
|
|
1518
|
+
function Banner({ tone = "info", title, detail, actions, role }) {
|
|
1504
1519
|
const t = BANNER_TONE_STYLE[tone];
|
|
1520
|
+
const liveRole = role || (tone === "danger" || tone === "warn" ? "alert" : "status");
|
|
1505
1521
|
return /* @__PURE__ */ jsxs19(
|
|
1506
1522
|
"div",
|
|
1507
1523
|
{
|
|
1524
|
+
role: liveRole,
|
|
1508
1525
|
style: {
|
|
1509
1526
|
display: "flex",
|
|
1510
1527
|
alignItems: "flex-start",
|
|
@@ -2714,7 +2731,7 @@ function DataTable({
|
|
|
2714
2731
|
}
|
|
2715
2732
|
|
|
2716
2733
|
// src/components/data/FilterBar.tsx
|
|
2717
|
-
import * as
|
|
2734
|
+
import * as React24 from "react";
|
|
2718
2735
|
|
|
2719
2736
|
// src/components/forms/NumberInput.tsx
|
|
2720
2737
|
import * as React21 from "react";
|
|
@@ -2762,8 +2779,11 @@ function NumberInput({
|
|
|
2762
2779
|
"aria-label": ariaLabel
|
|
2763
2780
|
}) {
|
|
2764
2781
|
const fieldId = useFieldId(id);
|
|
2782
|
+
const errorId = fieldId + "-error";
|
|
2765
2783
|
const num = (v) => {
|
|
2766
|
-
const
|
|
2784
|
+
const s = String(v == null ? "" : v).replace(/[^0-9.-]/g, "");
|
|
2785
|
+
if (s === "" || s === "-") return null;
|
|
2786
|
+
const n = Number(s);
|
|
2767
2787
|
return isNaN(n) ? null : n;
|
|
2768
2788
|
};
|
|
2769
2789
|
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
@@ -2816,9 +2836,15 @@ function NumberInput({
|
|
|
2816
2836
|
disabled,
|
|
2817
2837
|
placeholder,
|
|
2818
2838
|
value: shown,
|
|
2839
|
+
"aria-invalid": error ? "true" : void 0,
|
|
2840
|
+
"aria-describedby": error ? errorId : void 0,
|
|
2819
2841
|
onFocus: () => setEditing(true),
|
|
2820
2842
|
onBlur: () => {
|
|
2821
2843
|
setEditing(false);
|
|
2844
|
+
if (text.trim() === "") {
|
|
2845
|
+
fire(void 0);
|
|
2846
|
+
return;
|
|
2847
|
+
}
|
|
2822
2848
|
const n = num(text);
|
|
2823
2849
|
if (n != null) {
|
|
2824
2850
|
const c = clamp(n);
|
|
@@ -2828,6 +2854,10 @@ function NumberInput({
|
|
|
2828
2854
|
},
|
|
2829
2855
|
onChange: (e) => {
|
|
2830
2856
|
setText(e.target.value);
|
|
2857
|
+
if (e.target.value.trim() === "") {
|
|
2858
|
+
fire(void 0);
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2831
2861
|
const n = num(e.target.value);
|
|
2832
2862
|
if (n != null) fire(n);
|
|
2833
2863
|
},
|
|
@@ -2872,7 +2902,7 @@ function NumberInput({
|
|
|
2872
2902
|
)
|
|
2873
2903
|
] })
|
|
2874
2904
|
] }),
|
|
2875
|
-
error ? /* @__PURE__ */ jsxs36("span", { className: "fd-field-error", children: [
|
|
2905
|
+
error ? /* @__PURE__ */ jsxs36("span", { id: errorId, className: "fd-field-error", children: [
|
|
2876
2906
|
/* @__PURE__ */ jsx42("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2877
2907
|
error
|
|
2878
2908
|
] }) : help ? /* @__PURE__ */ jsx42("span", { className: "fd-field-help", children: help }) : null
|
|
@@ -3096,16 +3126,48 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3096
3126
|
] });
|
|
3097
3127
|
}
|
|
3098
3128
|
|
|
3129
|
+
// src/components/forms/listbox.ts
|
|
3130
|
+
import * as React23 from "react";
|
|
3131
|
+
function useListboxNav({ count, onSelect }) {
|
|
3132
|
+
const [active, setActive] = React23.useState(-1);
|
|
3133
|
+
return {
|
|
3134
|
+
active,
|
|
3135
|
+
setActive,
|
|
3136
|
+
move: (dir) => setActive((a) => Math.min(count - 1, Math.max(0, a + dir))),
|
|
3137
|
+
first: () => setActive(0),
|
|
3138
|
+
last: () => setActive(count - 1),
|
|
3139
|
+
activate: () => {
|
|
3140
|
+
if (active >= 0 && active < count) onSelect(active);
|
|
3141
|
+
}
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
function useListboxScrollIntoView(active, listRef, enabled) {
|
|
3145
|
+
React23.useEffect(() => {
|
|
3146
|
+
if (!enabled || active < 0 || !listRef.current) return;
|
|
3147
|
+
const list = listRef.current;
|
|
3148
|
+
const el = list.querySelector('[data-i="' + active + '"]');
|
|
3149
|
+
if (!el) return;
|
|
3150
|
+
const top = el.offsetTop - list.offsetTop;
|
|
3151
|
+
if (top < list.scrollTop) list.scrollTop = top - 4;
|
|
3152
|
+
else if (top + el.offsetHeight > list.scrollTop + list.clientHeight) {
|
|
3153
|
+
list.scrollTop = top + el.offsetHeight - list.clientHeight + 4;
|
|
3154
|
+
}
|
|
3155
|
+
}, [active, enabled]);
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3099
3158
|
// src/components/data/FilterBar.tsx
|
|
3100
3159
|
import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3160
|
+
var PANEL_WIDTH = { multiSelect: 280, range: 240, date: 300 };
|
|
3101
3161
|
var isSet = (v) => !(v == null || v === "" || v === false);
|
|
3162
|
+
function operatorsFor(field) {
|
|
3163
|
+
return field.operators && field.operators.length ? field.operators : ["in", "notIn"];
|
|
3164
|
+
}
|
|
3102
3165
|
function isFieldSet(field, value) {
|
|
3103
3166
|
switch (field.type) {
|
|
3104
3167
|
case "text":
|
|
3105
3168
|
case "select":
|
|
3106
3169
|
return isSet(value);
|
|
3107
|
-
case "multiSelect":
|
|
3108
|
-
case "pasteList": {
|
|
3170
|
+
case "multiSelect": {
|
|
3109
3171
|
const v = value;
|
|
3110
3172
|
return !!v && Array.isArray(v.values) && v.values.length > 0;
|
|
3111
3173
|
}
|
|
@@ -3116,7 +3178,7 @@ function isFieldSet(field, value) {
|
|
|
3116
3178
|
case "date": {
|
|
3117
3179
|
const v = value;
|
|
3118
3180
|
if (!v) return false;
|
|
3119
|
-
return v.kind === "withinDays" ? v.days != null : !!(v.from
|
|
3181
|
+
return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
3120
3182
|
}
|
|
3121
3183
|
}
|
|
3122
3184
|
}
|
|
@@ -3128,8 +3190,7 @@ function chipLabel(field, value) {
|
|
|
3128
3190
|
const chosen = field.options.find((o) => o.value === value);
|
|
3129
3191
|
return chosen ? chosen.label : String(value ?? "");
|
|
3130
3192
|
}
|
|
3131
|
-
case "multiSelect":
|
|
3132
|
-
case "pasteList": {
|
|
3193
|
+
case "multiSelect": {
|
|
3133
3194
|
const v = value;
|
|
3134
3195
|
if (!v || !v.values.length) return "";
|
|
3135
3196
|
const prefix = v.operator === "notIn" ? "Not " : "";
|
|
@@ -3147,7 +3208,7 @@ function chipLabel(field, value) {
|
|
|
3147
3208
|
const v = value;
|
|
3148
3209
|
if (!v) return "";
|
|
3149
3210
|
if (v.kind === "withinDays") return "Last " + v.days + " day" + (v.days === 1 ? "" : "s");
|
|
3150
|
-
return
|
|
3211
|
+
return v.from + " \u2192 " + v.to;
|
|
3151
3212
|
}
|
|
3152
3213
|
}
|
|
3153
3214
|
}
|
|
@@ -3169,338 +3230,374 @@ function OperatorToggle({
|
|
|
3169
3230
|
}
|
|
3170
3231
|
);
|
|
3171
3232
|
}
|
|
3172
|
-
function EditPopover({ zIndex, width, children }) {
|
|
3173
|
-
return /* @__PURE__ */ jsx45(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx45(
|
|
3174
|
-
"span",
|
|
3175
|
-
{
|
|
3176
|
-
className: "fd-view-enter",
|
|
3177
|
-
style: {
|
|
3178
|
-
position: "absolute",
|
|
3179
|
-
top: "calc(100% + 6px)",
|
|
3180
|
-
left: 0,
|
|
3181
|
-
zIndex,
|
|
3182
|
-
width,
|
|
3183
|
-
maxWidth: "calc(100vw - 32px)",
|
|
3184
|
-
display: "block",
|
|
3185
|
-
background: "var(--surface)",
|
|
3186
|
-
border: "1px solid var(--border)",
|
|
3187
|
-
borderRadius: 10,
|
|
3188
|
-
boxShadow: "0 16px 44px rgba(11,13,17,.18)",
|
|
3189
|
-
padding: "var(--s-8)"
|
|
3190
|
-
},
|
|
3191
|
-
children
|
|
3192
|
-
}
|
|
3193
|
-
) });
|
|
3194
|
-
}
|
|
3195
3233
|
function MultiSelectPanel({
|
|
3196
3234
|
field,
|
|
3197
3235
|
value,
|
|
3236
|
+
anchorRef,
|
|
3198
3237
|
onChange,
|
|
3238
|
+
onRemove,
|
|
3199
3239
|
onClose
|
|
3200
3240
|
}) {
|
|
3201
|
-
const
|
|
3241
|
+
const allowedOps = operatorsFor(field);
|
|
3242
|
+
const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? allowedOps[0];
|
|
3202
3243
|
const selected = value?.values ?? [];
|
|
3203
|
-
const
|
|
3204
|
-
|
|
3205
|
-
const
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3244
|
+
const selectedRef = React24.useRef(selected);
|
|
3245
|
+
selectedRef.current = selected;
|
|
3246
|
+
const commit = (nextValues, nextOperator = operator) => {
|
|
3247
|
+
if (nextValues.length === 0) onRemove();
|
|
3248
|
+
else onChange({ operator: nextOperator, values: nextValues });
|
|
3249
|
+
};
|
|
3250
|
+
const [mode2, setMode] = React24.useState("search");
|
|
3251
|
+
const [query, setQuery] = React24.useState("");
|
|
3252
|
+
const [asyncState, setAsyncState] = React24.useState(
|
|
3253
|
+
{ options: null, loading: !!field.loadOptions, error: false }
|
|
3254
|
+
);
|
|
3255
|
+
const [retryTick, setRetryTick] = React24.useState(0);
|
|
3256
|
+
const inputRef = React24.useRef(null);
|
|
3257
|
+
const listRef = React24.useRef(null);
|
|
3258
|
+
const listId = React24.useId();
|
|
3259
|
+
const loadOptionsRef = React24.useRef(field.loadOptions);
|
|
3260
|
+
loadOptionsRef.current = field.loadOptions;
|
|
3261
|
+
React24.useEffect(() => {
|
|
3210
3262
|
inputRef.current?.focus();
|
|
3211
3263
|
}, []);
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3264
|
+
React24.useEffect(() => {
|
|
3265
|
+
const load = loadOptionsRef.current;
|
|
3266
|
+
if (!load) return;
|
|
3267
|
+
const controller = new AbortController();
|
|
3268
|
+
setAsyncState((s) => ({ options: s.options, loading: true, error: false }));
|
|
3217
3269
|
const t = setTimeout(() => {
|
|
3218
|
-
|
|
3219
|
-
if (
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
if (!cancelled) {
|
|
3225
|
-
setAsyncOptions([]);
|
|
3226
|
-
setLoading(false);
|
|
3227
|
-
}
|
|
3270
|
+
load(query, controller.signal).then((opts) => {
|
|
3271
|
+
if (controller.signal.aborted) return;
|
|
3272
|
+
setAsyncState({ options: opts, loading: false, error: false });
|
|
3273
|
+
}).catch((err) => {
|
|
3274
|
+
if (controller.signal.aborted || err && err.name === "AbortError") return;
|
|
3275
|
+
setAsyncState({ options: null, loading: false, error: true });
|
|
3228
3276
|
});
|
|
3229
3277
|
}, 300);
|
|
3230
3278
|
return () => {
|
|
3231
|
-
cancelled = true;
|
|
3232
3279
|
clearTimeout(t);
|
|
3280
|
+
controller.abort();
|
|
3233
3281
|
};
|
|
3234
|
-
}, [query,
|
|
3235
|
-
const options = field.loadOptions ?
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3282
|
+
}, [query, retryTick]);
|
|
3283
|
+
const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
|
|
3284
|
+
const showLoading = !!field.loadOptions && asyncState.loading;
|
|
3285
|
+
const showError = !!field.loadOptions && asyncState.error;
|
|
3286
|
+
const showListbox = !showLoading && !showError;
|
|
3239
3287
|
const isSelected = (o) => selected.some((s) => s.value === o.value);
|
|
3240
3288
|
const toggle = (o) => {
|
|
3241
3289
|
const next = isSelected(o) ? selected.filter((s) => s.value !== o.value) : [...selected, o];
|
|
3242
|
-
|
|
3290
|
+
commit(next);
|
|
3291
|
+
};
|
|
3292
|
+
const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
|
|
3293
|
+
useListboxScrollIntoView(nav.active, listRef, showListbox);
|
|
3294
|
+
React24.useEffect(() => {
|
|
3295
|
+
nav.setActive(0);
|
|
3296
|
+
}, [query, options.length]);
|
|
3297
|
+
const activeId = showListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
|
|
3298
|
+
const [pasteText, setPasteText] = React24.useState("");
|
|
3299
|
+
const [pasteLoading, setPasteLoading] = React24.useState(false);
|
|
3300
|
+
const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
|
|
3301
|
+
const [pasteError, setPasteError] = React24.useState(null);
|
|
3302
|
+
const pasteWrapRef = React24.useRef(null);
|
|
3303
|
+
React24.useEffect(() => {
|
|
3304
|
+
if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
|
|
3305
|
+
}, [mode2]);
|
|
3306
|
+
const doResolve = () => {
|
|
3307
|
+
if (!field.resolve) return;
|
|
3308
|
+
const tokens = Array.from(new Set(pasteText.split(/[\n,]/).map((t) => t.trim()).filter(Boolean)));
|
|
3309
|
+
if (!tokens.length) return;
|
|
3310
|
+
setPasteLoading(true);
|
|
3311
|
+
setPasteError(null);
|
|
3312
|
+
field.resolve(tokens).then((result) => {
|
|
3313
|
+
setPasteLoading(false);
|
|
3314
|
+
setUnmatchedTokens(result.unmatched);
|
|
3315
|
+
const merged = new Map(selectedRef.current.map((s) => [s.value, s]));
|
|
3316
|
+
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3317
|
+
commit(Array.from(merged.values()));
|
|
3318
|
+
setPasteText("");
|
|
3319
|
+
}).catch((err) => {
|
|
3320
|
+
setPasteLoading(false);
|
|
3321
|
+
setPasteError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3322
|
+
});
|
|
3243
3323
|
};
|
|
3244
|
-
const
|
|
3245
|
-
|
|
3246
|
-
/* @__PURE__ */ jsx45(
|
|
3324
|
+
const header = /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3325
|
+
allowedOps.length > 1 ? /* @__PURE__ */ jsx45(OperatorToggle, { operator, onChange: (op) => commit(selected, op), label: field.label }) : null,
|
|
3326
|
+
field.resolve ? /* @__PURE__ */ jsx45(
|
|
3327
|
+
SegmentedControl,
|
|
3328
|
+
{
|
|
3329
|
+
"aria-label": field.label + " \u2014 search or paste a list",
|
|
3330
|
+
options: [{ value: "search", label: "Search" }, { value: "paste", label: "Paste a list" }],
|
|
3331
|
+
value: mode2,
|
|
3332
|
+
onChange: (m) => setMode(m)
|
|
3333
|
+
}
|
|
3334
|
+
) : null,
|
|
3335
|
+
mode2 === "search" ? /* @__PURE__ */ jsxs39("span", { className: "fd-pop-search", children: [
|
|
3336
|
+
/* @__PURE__ */ jsx45("i", { className: "ph ph-magnifying-glass", "aria-hidden": "true" }),
|
|
3337
|
+
/* @__PURE__ */ jsx45(
|
|
3338
|
+
"input",
|
|
3339
|
+
{
|
|
3340
|
+
ref: inputRef,
|
|
3341
|
+
role: "combobox",
|
|
3342
|
+
"aria-expanded": showListbox,
|
|
3343
|
+
"aria-controls": showListbox ? listId : void 0,
|
|
3344
|
+
"aria-autocomplete": "list",
|
|
3345
|
+
"aria-activedescendant": activeId,
|
|
3346
|
+
"aria-label": field.label,
|
|
3347
|
+
value: query,
|
|
3348
|
+
placeholder: field.placeholder || "Search\u2026",
|
|
3349
|
+
onChange: (e) => setQuery(e.target.value),
|
|
3350
|
+
onKeyDown: (e) => {
|
|
3351
|
+
if (e.key === "ArrowDown") {
|
|
3352
|
+
e.preventDefault();
|
|
3353
|
+
nav.move(1);
|
|
3354
|
+
} else if (e.key === "ArrowUp") {
|
|
3355
|
+
e.preventDefault();
|
|
3356
|
+
nav.move(-1);
|
|
3357
|
+
} else if (e.key === "Home") {
|
|
3358
|
+
e.preventDefault();
|
|
3359
|
+
nav.first();
|
|
3360
|
+
} else if (e.key === "End") {
|
|
3361
|
+
e.preventDefault();
|
|
3362
|
+
nav.last();
|
|
3363
|
+
} else if (e.key === "Enter") {
|
|
3364
|
+
e.preventDefault();
|
|
3365
|
+
nav.activate();
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
)
|
|
3370
|
+
] }) : null
|
|
3371
|
+
] });
|
|
3372
|
+
const body = mode2 === "paste" ? /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", ref: pasteWrapRef, children: [
|
|
3247
3373
|
/* @__PURE__ */ jsx45(
|
|
3248
|
-
|
|
3374
|
+
Textarea,
|
|
3249
3375
|
{
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
"aria-label": field.label,
|
|
3257
|
-
className: "fd-input",
|
|
3258
|
-
style: { width: "100%", padding: "6px 10px" },
|
|
3259
|
-
value: query,
|
|
3260
|
-
placeholder: field.placeholder || "Search\u2026",
|
|
3261
|
-
onChange: (e) => setQuery(e.target.value),
|
|
3376
|
+
"aria-label": field.label + " \u2014 paste a list",
|
|
3377
|
+
rows: 4,
|
|
3378
|
+
placeholder: field.pastePlaceholder || field.placeholder || "Paste names, one per line or comma-separated",
|
|
3379
|
+
value: pasteText,
|
|
3380
|
+
disabled: pasteLoading,
|
|
3381
|
+
onChange: (e) => setPasteText(e.target.value),
|
|
3262
3382
|
onKeyDown: (e) => {
|
|
3263
|
-
if (e.key === "
|
|
3264
|
-
e.preventDefault();
|
|
3265
|
-
setActive((a) => Math.min(a + 1, options.length - 1));
|
|
3266
|
-
} else if (e.key === "ArrowUp") {
|
|
3267
|
-
e.preventDefault();
|
|
3268
|
-
setActive((a) => Math.max(a - 1, 0));
|
|
3269
|
-
} else if (e.key === "Enter") {
|
|
3383
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
3270
3384
|
e.preventDefault();
|
|
3271
|
-
|
|
3272
|
-
} else if (e.key === "Escape") {
|
|
3273
|
-
e.stopPropagation();
|
|
3274
|
-
onClose();
|
|
3385
|
+
doResolve();
|
|
3275
3386
|
}
|
|
3276
3387
|
}
|
|
3277
3388
|
}
|
|
3278
3389
|
),
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
"aria-label": field.label,
|
|
3288
|
-
"aria-multiselectable": "true",
|
|
3289
|
-
className: "fd-stack",
|
|
3290
|
-
style: { gap: 2, maxHeight: 220, overflowY: "auto" },
|
|
3291
|
-
children: options.map((o, i) => {
|
|
3292
|
-
const on = isSelected(o);
|
|
3293
|
-
return /* @__PURE__ */ jsxs39(
|
|
3294
|
-
"button",
|
|
3295
|
-
{
|
|
3296
|
-
type: "button",
|
|
3297
|
-
id: listId + "-opt-" + i,
|
|
3298
|
-
role: "option",
|
|
3299
|
-
"aria-selected": on,
|
|
3300
|
-
className: "fd-row",
|
|
3301
|
-
onMouseEnter: () => setActive(i),
|
|
3302
|
-
onClick: () => toggle(o),
|
|
3303
|
-
style: {
|
|
3304
|
-
gap: "var(--s-8)",
|
|
3305
|
-
padding: "4px 8px",
|
|
3306
|
-
borderRadius: 7,
|
|
3307
|
-
border: 0,
|
|
3308
|
-
width: "100%",
|
|
3309
|
-
textAlign: "left",
|
|
3310
|
-
cursor: "pointer",
|
|
3311
|
-
background: i === active ? "var(--surface-brand)" : "transparent"
|
|
3312
|
-
},
|
|
3313
|
-
children: [
|
|
3314
|
-
/* @__PURE__ */ jsx45("i", { className: on ? "ph ph-check-square" : "ph ph-square", "aria-hidden": "true" }),
|
|
3315
|
-
/* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: o.label })
|
|
3316
|
-
]
|
|
3317
|
-
},
|
|
3318
|
-
o.value
|
|
3319
|
-
);
|
|
3320
|
-
})
|
|
3321
|
-
}
|
|
3322
|
-
),
|
|
3323
|
-
selected.length > 0 ? /* @__PURE__ */ jsxs39("span", { className: "fd-body-sm fd-muted", children: [
|
|
3324
|
-
selected.length,
|
|
3325
|
-
" selected"
|
|
3390
|
+
pasteError ? /* @__PURE__ */ jsx45(Banner, { tone: "danger", title: "Couldn't resolve the list", detail: pasteError }) : null,
|
|
3391
|
+
unmatchedTokens.length > 0 ? /* @__PURE__ */ jsx45(Banner, { tone: "warn", title: unmatchedTokens.length + " didn't match", detail: unmatchedTokens.join(", ") }) : null,
|
|
3392
|
+
selected.length > 0 ? /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-xs", children: [
|
|
3393
|
+
/* @__PURE__ */ jsxs39("span", { className: "fd-body-sm fd-muted", children: [
|
|
3394
|
+
selected.length,
|
|
3395
|
+
" matched"
|
|
3396
|
+
] }),
|
|
3397
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ jsx45(Tag, { onRemove: () => commit(selected.filter((s) => s.value !== v.value)), children: v.label }, v.value)) })
|
|
3326
3398
|
] }) : null
|
|
3327
|
-
] })
|
|
3399
|
+
] }) : showLoading ? /* @__PURE__ */ jsxs39("span", { className: "fd-row fd-gap-xs", role: "status", children: [
|
|
3400
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-spinner", "aria-hidden": "true" }),
|
|
3401
|
+
" Loading\u2026"
|
|
3402
|
+
] }) : showError ? /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3403
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-body-sm", role: "alert", children: "Couldn't load options." }),
|
|
3404
|
+
/* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: () => setRetryTick((n) => n + 1), children: "Retry" })
|
|
3405
|
+
] }) : options.length === 0 ? /* @__PURE__ */ jsx45("span", { className: "fd-body-sm fd-muted", role: "status", children: "No matches" }) : /* @__PURE__ */ jsx45("span", { id: listId, role: "listbox", "aria-label": field.label, "aria-multiselectable": "true", ref: listRef, className: "fd-pop-list", children: options.map((o, i) => {
|
|
3406
|
+
const on = isSelected(o);
|
|
3407
|
+
return /* @__PURE__ */ jsxs39(
|
|
3408
|
+
"div",
|
|
3409
|
+
{
|
|
3410
|
+
id: listId + "-opt-" + i,
|
|
3411
|
+
"data-i": i,
|
|
3412
|
+
role: "option",
|
|
3413
|
+
tabIndex: -1,
|
|
3414
|
+
"aria-selected": on,
|
|
3415
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3416
|
+
onMouseEnter: () => nav.setActive(i),
|
|
3417
|
+
onClick: () => toggle(o),
|
|
3418
|
+
children: [
|
|
3419
|
+
/* @__PURE__ */ jsx45("i", { className: "fd-filterbar-opt-check ph " + (on ? "ph-check-square is-checked" : "ph-square"), "aria-hidden": "true" }),
|
|
3420
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-opt-label", children: o.label })
|
|
3421
|
+
]
|
|
3422
|
+
},
|
|
3423
|
+
o.value
|
|
3424
|
+
);
|
|
3425
|
+
}) });
|
|
3426
|
+
const footer = mode2 === "paste" ? /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: doResolve, disabled: pasteLoading || !pasteText.trim(), children: pasteLoading ? "Resolving\u2026" : "Resolve" }) : void 0;
|
|
3427
|
+
return /* @__PURE__ */ jsx45(
|
|
3428
|
+
Popover,
|
|
3429
|
+
{
|
|
3430
|
+
open: true,
|
|
3431
|
+
anchorRef,
|
|
3432
|
+
onClose,
|
|
3433
|
+
placement: "bottom-start",
|
|
3434
|
+
offset: 6,
|
|
3435
|
+
width: PANEL_WIDTH.multiSelect,
|
|
3436
|
+
label: field.label,
|
|
3437
|
+
header,
|
|
3438
|
+
footer,
|
|
3439
|
+
children: body
|
|
3440
|
+
}
|
|
3441
|
+
);
|
|
3328
3442
|
}
|
|
3329
3443
|
function RangePanel({
|
|
3330
3444
|
field,
|
|
3331
3445
|
value,
|
|
3446
|
+
anchorRef,
|
|
3332
3447
|
onChange,
|
|
3448
|
+
onRemove,
|
|
3333
3449
|
onClose
|
|
3334
3450
|
}) {
|
|
3335
|
-
const
|
|
3336
|
-
const
|
|
3337
|
-
const
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3451
|
+
const [draftMin, setDraftMin] = React24.useState(value?.min);
|
|
3452
|
+
const [draftMax, setDraftMax] = React24.useState(value?.max);
|
|
3453
|
+
const invalid = draftMin != null && draftMax != null && draftMin > draftMax;
|
|
3454
|
+
const apply = (nextMin, nextMax) => {
|
|
3455
|
+
setDraftMin(nextMin);
|
|
3456
|
+
setDraftMax(nextMax);
|
|
3457
|
+
if (nextMin == null && nextMax == null) {
|
|
3458
|
+
onRemove();
|
|
3459
|
+
return;
|
|
3460
|
+
}
|
|
3461
|
+
if (nextMin != null && nextMax != null && nextMin > nextMax) return;
|
|
3462
|
+
onChange({ min: nextMin, max: nextMax });
|
|
3463
|
+
};
|
|
3464
|
+
return /* @__PURE__ */ jsx45(
|
|
3465
|
+
Popover,
|
|
3466
|
+
{
|
|
3467
|
+
open: true,
|
|
3468
|
+
anchorRef,
|
|
3469
|
+
onClose,
|
|
3470
|
+
placement: "bottom-start",
|
|
3471
|
+
offset: 6,
|
|
3472
|
+
width: PANEL_WIDTH.range,
|
|
3473
|
+
label: field.label,
|
|
3474
|
+
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" }),
|
|
3475
|
+
children: /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3476
|
+
/* @__PURE__ */ jsx45(
|
|
3477
|
+
NumberInput,
|
|
3478
|
+
{
|
|
3479
|
+
label: field.minLabel || "At least",
|
|
3480
|
+
value: draftMin ?? "",
|
|
3481
|
+
min: field.min,
|
|
3482
|
+
max: field.max,
|
|
3483
|
+
step: field.step,
|
|
3484
|
+
placeholder: field.minPlaceholder,
|
|
3485
|
+
onChange: (e) => apply(e.target.value, draftMax)
|
|
3486
|
+
}
|
|
3487
|
+
),
|
|
3488
|
+
/* @__PURE__ */ jsx45(
|
|
3489
|
+
NumberInput,
|
|
3490
|
+
{
|
|
3491
|
+
label: field.maxLabel || "At most",
|
|
3492
|
+
value: draftMax ?? "",
|
|
3493
|
+
min: field.min,
|
|
3494
|
+
max: field.max,
|
|
3495
|
+
step: field.step,
|
|
3496
|
+
error: invalid ? "Must be \u2265 " + draftMin : void 0,
|
|
3497
|
+
placeholder: field.maxPlaceholder,
|
|
3498
|
+
onChange: (e) => apply(draftMin, e.target.value)
|
|
3499
|
+
}
|
|
3500
|
+
)
|
|
3501
|
+
] })
|
|
3502
|
+
}
|
|
3503
|
+
);
|
|
3366
3504
|
}
|
|
3367
3505
|
function DatePanel({
|
|
3368
3506
|
field,
|
|
3369
3507
|
value,
|
|
3508
|
+
anchorRef,
|
|
3370
3509
|
onChange,
|
|
3510
|
+
onRemove,
|
|
3371
3511
|
onClose
|
|
3372
3512
|
}) {
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
range: true,
|
|
3405
|
-
label: "Date range",
|
|
3406
|
-
value: value?.kind === "between" ? { start: value.from, end: value.to } : void 0,
|
|
3407
|
-
onChange: (e) => onChange({ kind: "between", from: e.target.value.start || "", to: e.target.value.end || "" })
|
|
3513
|
+
const defaultDays = field.defaultDays ?? 30;
|
|
3514
|
+
const [draft, setDraft] = React24.useState(value ?? { kind: "withinDays", days: defaultDays });
|
|
3515
|
+
const committedRef = React24.useRef(!!value);
|
|
3516
|
+
const applyWithinDays = (days) => {
|
|
3517
|
+
const next = { kind: "withinDays", days: days ?? defaultDays };
|
|
3518
|
+
setDraft(next);
|
|
3519
|
+
if (days != null) {
|
|
3520
|
+
committedRef.current = true;
|
|
3521
|
+
onChange(next);
|
|
3522
|
+
}
|
|
3523
|
+
};
|
|
3524
|
+
const applyBetween = (from, to) => {
|
|
3525
|
+
const next = { kind: "between", from, to };
|
|
3526
|
+
setDraft(next);
|
|
3527
|
+
if (from && to) {
|
|
3528
|
+
committedRef.current = true;
|
|
3529
|
+
onChange(next);
|
|
3530
|
+
} else if (committedRef.current) {
|
|
3531
|
+
committedRef.current = false;
|
|
3532
|
+
onRemove();
|
|
3533
|
+
}
|
|
3534
|
+
};
|
|
3535
|
+
const switchKind = (kind) => {
|
|
3536
|
+
if (kind === "withinDays") {
|
|
3537
|
+
const days = draft.kind === "withinDays" ? draft.days : defaultDays;
|
|
3538
|
+
setDraft({ kind: "withinDays", days });
|
|
3539
|
+
} else {
|
|
3540
|
+
setDraft({ kind: "between", from: "", to: "" });
|
|
3541
|
+
if (committedRef.current) {
|
|
3542
|
+
committedRef.current = false;
|
|
3543
|
+
onRemove();
|
|
3408
3544
|
}
|
|
3409
|
-
|
|
3410
|
-
/* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
|
|
3411
|
-
] });
|
|
3412
|
-
}
|
|
3413
|
-
function PasteListPanel({
|
|
3414
|
-
field,
|
|
3415
|
-
value,
|
|
3416
|
-
onChange,
|
|
3417
|
-
onClose
|
|
3418
|
-
}) {
|
|
3419
|
-
const operator = value?.operator ?? "in";
|
|
3420
|
-
const selected = value?.values ?? [];
|
|
3421
|
-
const [text, setText] = React23.useState("");
|
|
3422
|
-
const [loading, setLoading] = React23.useState(false);
|
|
3423
|
-
const [unmatched, setUnmatched] = React23.useState([]);
|
|
3424
|
-
const [error, setError] = React23.useState(null);
|
|
3425
|
-
const wrapRef = React23.useRef(null);
|
|
3426
|
-
React23.useEffect(() => {
|
|
3427
|
-
wrapRef.current?.querySelector("textarea")?.focus();
|
|
3428
|
-
}, []);
|
|
3429
|
-
const doResolve = () => {
|
|
3430
|
-
const tokens = text.split(/[\n,]/).map((t) => t.trim()).filter(Boolean);
|
|
3431
|
-
if (!tokens.length) return;
|
|
3432
|
-
setLoading(true);
|
|
3433
|
-
setError(null);
|
|
3434
|
-
field.resolve(tokens).then((result) => {
|
|
3435
|
-
setLoading(false);
|
|
3436
|
-
setUnmatched(result.unmatched);
|
|
3437
|
-
const merged = new Map(selected.map((s) => [s.value, s]));
|
|
3438
|
-
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3439
|
-
onChange({ operator, values: Array.from(merged.values()) });
|
|
3440
|
-
setText("");
|
|
3441
|
-
}).catch((err) => {
|
|
3442
|
-
setLoading(false);
|
|
3443
|
-
setError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3444
|
-
});
|
|
3545
|
+
}
|
|
3445
3546
|
};
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3547
|
+
const confirm = () => {
|
|
3548
|
+
if (draft.kind === "withinDays") {
|
|
3549
|
+
committedRef.current = true;
|
|
3550
|
+
onChange(draft);
|
|
3551
|
+
}
|
|
3552
|
+
onClose();
|
|
3553
|
+
};
|
|
3554
|
+
return /* @__PURE__ */ jsx45(
|
|
3555
|
+
Popover,
|
|
3556
|
+
{
|
|
3557
|
+
open: true,
|
|
3558
|
+
anchorRef,
|
|
3559
|
+
onClose,
|
|
3560
|
+
placement: "bottom-start",
|
|
3561
|
+
offset: 6,
|
|
3562
|
+
width: PANEL_WIDTH.date,
|
|
3563
|
+
label: field.label,
|
|
3564
|
+
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: confirm, children: "Done" }),
|
|
3565
|
+
children: /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3566
|
+
/* @__PURE__ */ jsx45(
|
|
3567
|
+
SegmentedControl,
|
|
3568
|
+
{
|
|
3569
|
+
"aria-label": field.label + " \u2014 relative or between dates",
|
|
3570
|
+
options: [
|
|
3571
|
+
{ value: "withinDays", label: "Within last N days" },
|
|
3572
|
+
{ value: "between", label: "Between dates" }
|
|
3573
|
+
],
|
|
3574
|
+
value: draft.kind,
|
|
3575
|
+
onChange: (k) => switchKind(k)
|
|
3461
3576
|
}
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
] })
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
/* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
|
|
3476
|
-
] });
|
|
3577
|
+
),
|
|
3578
|
+
draft.kind === "withinDays" ? /* @__PURE__ */ jsx45(NumberInput, { label: "Days", min: 1, value: draft.days, onChange: (e) => applyWithinDays(e.target.value) }) : /* @__PURE__ */ jsx45(
|
|
3579
|
+
DatePicker,
|
|
3580
|
+
{
|
|
3581
|
+
range: true,
|
|
3582
|
+
label: "Date range",
|
|
3583
|
+
value: { start: draft.from, end: draft.to },
|
|
3584
|
+
onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
|
|
3585
|
+
}
|
|
3586
|
+
)
|
|
3587
|
+
] })
|
|
3588
|
+
}
|
|
3589
|
+
);
|
|
3477
3590
|
}
|
|
3478
3591
|
function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
|
|
3479
|
-
const [panel, setPanel] =
|
|
3480
|
-
const
|
|
3481
|
-
const
|
|
3482
|
-
const textInputRef =
|
|
3483
|
-
const optionsRef =
|
|
3592
|
+
const [panel, setPanel] = React24.useState(null);
|
|
3593
|
+
const editAnchorRef = React24.useRef(null);
|
|
3594
|
+
const addAnchorRef = React24.useRef(null);
|
|
3595
|
+
const textInputRef = React24.useRef(null);
|
|
3596
|
+
const optionsRef = React24.useRef(null);
|
|
3484
3597
|
const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
|
|
3485
|
-
const
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
const away = (e) => {
|
|
3489
|
-
const target = e.target;
|
|
3490
|
-
if (target.closest && target.closest(".fd-pop")) return;
|
|
3491
|
-
if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
|
|
3492
|
-
};
|
|
3493
|
-
const esc = (e) => {
|
|
3494
|
-
if (e.key === "Escape") setPanel(null);
|
|
3495
|
-
};
|
|
3496
|
-
document.addEventListener("pointerdown", away);
|
|
3497
|
-
document.addEventListener("keydown", esc);
|
|
3498
|
-
return () => {
|
|
3499
|
-
document.removeEventListener("pointerdown", away);
|
|
3500
|
-
document.removeEventListener("keydown", esc);
|
|
3501
|
-
};
|
|
3502
|
-
}, [dismissible]);
|
|
3503
|
-
React23.useEffect(() => {
|
|
3598
|
+
const startEditing = (key) => setPanel({ kind: "edit", key });
|
|
3599
|
+
const closeEditing = () => setPanel(null);
|
|
3600
|
+
React24.useEffect(() => {
|
|
3504
3601
|
if (!panel || panel.kind !== "edit") return;
|
|
3505
3602
|
if (editingField?.type === "text") {
|
|
3506
3603
|
textInputRef.current?.focus();
|
|
@@ -3510,72 +3607,77 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3510
3607
|
}
|
|
3511
3608
|
}, [panel]);
|
|
3512
3609
|
const addableFields = fields.filter((f) => !isFieldSet(f, filters[f.key]));
|
|
3513
|
-
const
|
|
3514
|
-
|
|
3610
|
+
const addMenuItems = [
|
|
3611
|
+
{ kind: "section", label: "Add filter" },
|
|
3612
|
+
...addableFields.map((f) => ({ id: f.key, label: f.label, onSelect: () => startEditing(f.key) }))
|
|
3613
|
+
];
|
|
3614
|
+
return /* @__PURE__ */ jsxs39("span", { className: ["fd-filterbar", className].filter(Boolean).join(" "), ...rest, children: [
|
|
3515
3615
|
fields.map((field) => {
|
|
3516
3616
|
const value = filters[field.key];
|
|
3517
3617
|
const editing = panel?.kind === "edit" && panel.key === field.key;
|
|
3518
3618
|
if (editing && field.type === "text") {
|
|
3519
|
-
return /* @__PURE__ */ jsxs39(
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
if (e.key === "Enter") setPanel(null);
|
|
3535
|
-
else if (e.key === "Escape") {
|
|
3536
|
-
e.stopPropagation();
|
|
3537
|
-
setPanel(null);
|
|
3538
|
-
}
|
|
3539
|
-
},
|
|
3540
|
-
onBlur: () => setPanel(null),
|
|
3541
|
-
style: { all: "unset", minWidth: 90, color: "var(--text-on-surface-brand)" }
|
|
3542
|
-
}
|
|
3543
|
-
),
|
|
3544
|
-
isSet(value) ? /* @__PURE__ */ jsx45(
|
|
3545
|
-
"span",
|
|
3546
|
-
{
|
|
3547
|
-
className: "fd-tag-remove",
|
|
3548
|
-
role: "button",
|
|
3549
|
-
"aria-label": "Remove " + field.label,
|
|
3550
|
-
onClick: (e) => {
|
|
3551
|
-
e.stopPropagation();
|
|
3552
|
-
onFilterRemove(field.key);
|
|
3553
|
-
setPanel(null);
|
|
3554
|
-
},
|
|
3555
|
-
children: /* @__PURE__ */ jsx45("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
3619
|
+
return /* @__PURE__ */ jsxs39("span", { className: ["fd-tag", "fd-filterbar-text"].join(" "), children: [
|
|
3620
|
+
/* @__PURE__ */ jsx45(
|
|
3621
|
+
"input",
|
|
3622
|
+
{
|
|
3623
|
+
ref: textInputRef,
|
|
3624
|
+
className: "fd-filterbar-text-input",
|
|
3625
|
+
value: value ?? "",
|
|
3626
|
+
placeholder: field.placeholder || field.label,
|
|
3627
|
+
"aria-label": field.label,
|
|
3628
|
+
onChange: (e) => onFilterChange(field.key, e.target.value),
|
|
3629
|
+
onKeyDown: (e) => {
|
|
3630
|
+
if (e.key === "Enter") setPanel(null);
|
|
3631
|
+
else if (e.key === "Escape") {
|
|
3632
|
+
e.stopPropagation();
|
|
3633
|
+
setPanel(null);
|
|
3556
3634
|
}
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
}
|
|
3563
|
-
if (editing && field.type === "select") {
|
|
3564
|
-
const chosen = field.options.find((o) => o.value === value);
|
|
3565
|
-
return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3566
|
-
/* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3567
|
-
if (isSet(value)) onFilterRemove(field.key);
|
|
3568
|
-
setPanel(null);
|
|
3569
|
-
}, children: [
|
|
3570
|
-
field.label,
|
|
3571
|
-
chosen ? ": " + chosen.label : ""
|
|
3572
|
-
] }),
|
|
3573
|
-
/* @__PURE__ */ jsx45(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx45(
|
|
3635
|
+
},
|
|
3636
|
+
onBlur: () => setPanel(null)
|
|
3637
|
+
}
|
|
3638
|
+
),
|
|
3639
|
+
isSet(value) ? /* @__PURE__ */ jsx45(
|
|
3574
3640
|
"span",
|
|
3575
3641
|
{
|
|
3576
|
-
className: "fd-
|
|
3577
|
-
|
|
3578
|
-
|
|
3642
|
+
className: "fd-tag-remove",
|
|
3643
|
+
role: "button",
|
|
3644
|
+
"aria-label": "Remove " + field.label,
|
|
3645
|
+
onClick: (e) => {
|
|
3646
|
+
e.stopPropagation();
|
|
3647
|
+
onFilterRemove(field.key);
|
|
3648
|
+
setPanel(null);
|
|
3649
|
+
},
|
|
3650
|
+
children: /* @__PURE__ */ jsx45("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
3651
|
+
}
|
|
3652
|
+
) : null
|
|
3653
|
+
] }, field.key);
|
|
3654
|
+
}
|
|
3655
|
+
const set = isFieldSet(field, value);
|
|
3656
|
+
if (!editing && !set) return null;
|
|
3657
|
+
const chipRef = editing ? editAnchorRef : void 0;
|
|
3658
|
+
const toggleOrClose = () => editing ? closeEditing() : startEditing(field.key);
|
|
3659
|
+
const remove = () => {
|
|
3660
|
+
if (set) onFilterRemove(field.key);
|
|
3661
|
+
closeEditing();
|
|
3662
|
+
};
|
|
3663
|
+
const chipText = field.label + (set ? ": " + chipLabel(field, value) : "");
|
|
3664
|
+
if (field.type === "text") {
|
|
3665
|
+
return /* @__PURE__ */ jsx45(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }, field.key);
|
|
3666
|
+
}
|
|
3667
|
+
if (field.type === "select") {
|
|
3668
|
+
return /* @__PURE__ */ jsxs39("span", { children: [
|
|
3669
|
+
/* @__PURE__ */ jsx45("span", { ref: chipRef, children: /* @__PURE__ */ jsx45(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3670
|
+
editing ? /* @__PURE__ */ jsx45(
|
|
3671
|
+
Popover,
|
|
3672
|
+
{
|
|
3673
|
+
open: true,
|
|
3674
|
+
anchorRef: editAnchorRef,
|
|
3675
|
+
onClose: closeEditing,
|
|
3676
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
3677
|
+
offset: 6,
|
|
3678
|
+
minWidth: 200,
|
|
3679
|
+
label: field.label,
|
|
3680
|
+
children: /* @__PURE__ */ jsx45("span", { role: "listbox", "aria-label": field.label, ref: optionsRef, className: "fd-pop-list", children: field.options.map((o) => {
|
|
3579
3681
|
const on = o.value === value;
|
|
3580
3682
|
return /* @__PURE__ */ jsx45(
|
|
3581
3683
|
"button",
|
|
@@ -3583,84 +3685,72 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3583
3685
|
type: "button",
|
|
3584
3686
|
role: "option",
|
|
3585
3687
|
"aria-selected": on,
|
|
3586
|
-
className: "fd-
|
|
3688
|
+
className: ["fd-opt", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3587
3689
|
onClick: () => {
|
|
3588
3690
|
onFilterChange(field.key, o.value);
|
|
3589
3691
|
setPanel(null);
|
|
3590
3692
|
},
|
|
3591
|
-
|
|
3592
|
-
children: /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: on ? 700 : 500, color: on ? "var(--text-on-surface-brand)" : "var(--text)" }, children: o.label })
|
|
3693
|
+
children: /* @__PURE__ */ jsx45("span", { className: "fd-opt-label", children: o.label })
|
|
3593
3694
|
},
|
|
3594
3695
|
o.value
|
|
3595
3696
|
);
|
|
3596
3697
|
}) })
|
|
3597
3698
|
}
|
|
3598
|
-
)
|
|
3599
|
-
] }, field.key);
|
|
3600
|
-
}
|
|
3601
|
-
if (editing && field.type === "multiSelect") {
|
|
3602
|
-
const mv = value;
|
|
3603
|
-
return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3604
|
-
/* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3605
|
-
if (isFieldSet(field, value)) onFilterRemove(field.key);
|
|
3606
|
-
setPanel(null);
|
|
3607
|
-
}, children: [
|
|
3608
|
-
field.label,
|
|
3609
|
-
isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
|
|
3610
|
-
] }),
|
|
3611
|
-
/* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 260, children: /* @__PURE__ */ jsx45(MultiSelectPanel, { field, value: mv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
|
|
3699
|
+
) : null
|
|
3612
3700
|
] }, field.key);
|
|
3613
3701
|
}
|
|
3614
|
-
if (
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
/* @__PURE__ */
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
const dv = value;
|
|
3629
|
-
return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3630
|
-
/* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3631
|
-
if (isFieldSet(field, value)) onFilterRemove(field.key);
|
|
3632
|
-
setPanel(null);
|
|
3633
|
-
}, children: [
|
|
3634
|
-
field.label,
|
|
3635
|
-
isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
|
|
3636
|
-
] }),
|
|
3637
|
-
/* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 300, children: /* @__PURE__ */ jsx45(DatePanel, { field, value: dv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
|
|
3702
|
+
if (field.type === "multiSelect") {
|
|
3703
|
+
return /* @__PURE__ */ jsxs39("span", { children: [
|
|
3704
|
+
/* @__PURE__ */ jsx45("span", { ref: chipRef, children: /* @__PURE__ */ jsx45(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3705
|
+
editing ? /* @__PURE__ */ jsx45(
|
|
3706
|
+
MultiSelectPanel,
|
|
3707
|
+
{
|
|
3708
|
+
field,
|
|
3709
|
+
value,
|
|
3710
|
+
anchorRef: editAnchorRef,
|
|
3711
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3712
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3713
|
+
onClose: closeEditing
|
|
3714
|
+
}
|
|
3715
|
+
) : null
|
|
3638
3716
|
] }, field.key);
|
|
3639
3717
|
}
|
|
3640
|
-
if (
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
/* @__PURE__ */
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3718
|
+
if (field.type === "range") {
|
|
3719
|
+
return /* @__PURE__ */ jsxs39("span", { children: [
|
|
3720
|
+
/* @__PURE__ */ jsx45("span", { ref: chipRef, children: /* @__PURE__ */ jsx45(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3721
|
+
editing ? /* @__PURE__ */ jsx45(
|
|
3722
|
+
RangePanel,
|
|
3723
|
+
{
|
|
3724
|
+
field,
|
|
3725
|
+
value,
|
|
3726
|
+
anchorRef: editAnchorRef,
|
|
3727
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3728
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3729
|
+
onClose: closeEditing
|
|
3730
|
+
}
|
|
3731
|
+
) : null
|
|
3651
3732
|
] }, field.key);
|
|
3652
3733
|
}
|
|
3653
|
-
if (
|
|
3654
|
-
return /* @__PURE__ */ jsxs39(
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3734
|
+
if (field.type === "date") {
|
|
3735
|
+
return /* @__PURE__ */ jsxs39("span", { children: [
|
|
3736
|
+
/* @__PURE__ */ jsx45("span", { ref: chipRef, children: /* @__PURE__ */ jsx45(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3737
|
+
editing ? /* @__PURE__ */ jsx45(
|
|
3738
|
+
DatePanel,
|
|
3739
|
+
{
|
|
3740
|
+
field,
|
|
3741
|
+
value,
|
|
3742
|
+
anchorRef: editAnchorRef,
|
|
3743
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3744
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3745
|
+
onClose: closeEditing
|
|
3746
|
+
}
|
|
3747
|
+
) : null
|
|
3658
3748
|
] }, field.key);
|
|
3659
3749
|
}
|
|
3660
3750
|
return null;
|
|
3661
3751
|
}),
|
|
3662
|
-
addableFields.length > 0 ? /* @__PURE__ */ jsxs39("span", {
|
|
3663
|
-
/* @__PURE__ */ jsx45(
|
|
3752
|
+
addableFields.length > 0 ? /* @__PURE__ */ jsxs39("span", { children: [
|
|
3753
|
+
/* @__PURE__ */ jsx45("span", { ref: addAnchorRef, children: /* @__PURE__ */ jsx45(
|
|
3664
3754
|
Button,
|
|
3665
3755
|
{
|
|
3666
3756
|
size: "sm",
|
|
@@ -3671,29 +3761,20 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3671
3761
|
onClick: () => setPanel(panel?.kind === "add" ? null : { kind: "add" }),
|
|
3672
3762
|
children: "Filter"
|
|
3673
3763
|
}
|
|
3674
|
-
),
|
|
3675
|
-
|
|
3676
|
-
|
|
3764
|
+
) }),
|
|
3765
|
+
/* @__PURE__ */ jsx45(
|
|
3766
|
+
Popover,
|
|
3677
3767
|
{
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
role: "menuitem",
|
|
3687
|
-
className: "fd-row",
|
|
3688
|
-
onClick: () => startEditing(f.key),
|
|
3689
|
-
style: { gap: 8, padding: "4px 8px", borderRadius: 7, border: 0, width: "100%", textAlign: "left", cursor: "pointer", background: "transparent" },
|
|
3690
|
-
children: /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: f.label })
|
|
3691
|
-
},
|
|
3692
|
-
f.key
|
|
3693
|
-
))
|
|
3694
|
-
] })
|
|
3768
|
+
open: panel?.kind === "add",
|
|
3769
|
+
anchorRef: addAnchorRef,
|
|
3770
|
+
onClose: closeEditing,
|
|
3771
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
3772
|
+
minWidth: 200,
|
|
3773
|
+
role: "menu",
|
|
3774
|
+
label: "Add filter",
|
|
3775
|
+
children: /* @__PURE__ */ jsx45(Menu, { items: addMenuItems })
|
|
3695
3776
|
}
|
|
3696
|
-
)
|
|
3777
|
+
)
|
|
3697
3778
|
] }) : null
|
|
3698
3779
|
] });
|
|
3699
3780
|
}
|
|
@@ -3725,7 +3806,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
|
|
|
3725
3806
|
}
|
|
3726
3807
|
|
|
3727
3808
|
// src/components/data/CodeBlock.tsx
|
|
3728
|
-
import * as
|
|
3809
|
+
import * as React25 from "react";
|
|
3729
3810
|
import { Fragment as Fragment6, jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
3730
3811
|
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)$/;
|
|
3731
3812
|
var RULES = {
|
|
@@ -3881,13 +3962,13 @@ function tokenize(src, lang) {
|
|
|
3881
3962
|
return out;
|
|
3882
3963
|
}
|
|
3883
3964
|
function Highlighted({ code, lang }) {
|
|
3884
|
-
const toks =
|
|
3965
|
+
const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
|
|
3885
3966
|
return /* @__PURE__ */ jsx47(Fragment6, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx47("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
|
|
3886
3967
|
}
|
|
3887
3968
|
function useCopy() {
|
|
3888
|
-
const [done, setDone] =
|
|
3889
|
-
const timer =
|
|
3890
|
-
|
|
3969
|
+
const [done, setDone] = React25.useState(false);
|
|
3970
|
+
const timer = React25.useRef(null);
|
|
3971
|
+
React25.useEffect(() => () => {
|
|
3891
3972
|
if (timer.current) clearTimeout(timer.current);
|
|
3892
3973
|
}, []);
|
|
3893
3974
|
const copy = (text) => {
|
|
@@ -3923,8 +4004,8 @@ function CodeBlock({
|
|
|
3923
4004
|
actions,
|
|
3924
4005
|
className = ""
|
|
3925
4006
|
}) {
|
|
3926
|
-
const [wrap, setWrap] =
|
|
3927
|
-
const [open, setOpen] =
|
|
4007
|
+
const [wrap, setWrap] = React25.useState(!!wrapDefault);
|
|
4008
|
+
const [open, setOpen] = React25.useState(false);
|
|
3928
4009
|
const [copied, copy] = useCopy();
|
|
3929
4010
|
const body = String(code).replace(/\n$/, "");
|
|
3930
4011
|
const lines = body.split("\n");
|
|
@@ -3953,7 +4034,7 @@ function CodeBlock({
|
|
|
3953
4034
|
] });
|
|
3954
4035
|
}
|
|
3955
4036
|
function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
|
|
3956
|
-
const [open, setOpen] =
|
|
4037
|
+
const [open, setOpen] = React25.useState(false);
|
|
3957
4038
|
const [copied, copy] = useCopy();
|
|
3958
4039
|
const raw = String(diff).replace(/\n$/, "");
|
|
3959
4040
|
const all = raw.split("\n").map((line) => {
|
|
@@ -3999,7 +4080,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
|
|
|
3999
4080
|
}
|
|
4000
4081
|
|
|
4001
4082
|
// src/components/data/Markdown.tsx
|
|
4002
|
-
import * as
|
|
4083
|
+
import * as React26 from "react";
|
|
4003
4084
|
import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
4004
4085
|
var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
|
|
4005
4086
|
var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
|
|
@@ -4038,7 +4119,7 @@ function inlineNodes(src, ctx, keyBase) {
|
|
|
4038
4119
|
const href = safeHref(g(2));
|
|
4039
4120
|
out.push(href ? /* @__PURE__ */ jsx48("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__ */ jsx48("span", { children: g(1) }, key()));
|
|
4040
4121
|
} else if (kind === "cite") {
|
|
4041
|
-
out.push(ctx.renderCitation ? /* @__PURE__ */ jsx48(
|
|
4122
|
+
out.push(ctx.renderCitation ? /* @__PURE__ */ jsx48(React26.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx48("sup", { className: "fd-md-cite", children: g(1) }, key()));
|
|
4042
4123
|
} else if (kind === "strongem") out.push(/* @__PURE__ */ jsx48("strong", { children: /* @__PURE__ */ jsx48("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
|
|
4043
4124
|
else if (kind === "strong") out.push(/* @__PURE__ */ jsx48("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
4044
4125
|
else if (kind === "em") out.push(/* @__PURE__ */ jsx48("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
@@ -4203,7 +4284,7 @@ function Markdown({
|
|
|
4203
4284
|
onLinkClick
|
|
4204
4285
|
}) {
|
|
4205
4286
|
const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
|
|
4206
|
-
const blocks =
|
|
4287
|
+
const blocks = React26.useMemo(() => parseBlocks(source), [source]);
|
|
4207
4288
|
return /* @__PURE__ */ jsx48("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
|
|
4208
4289
|
}
|
|
4209
4290
|
function MarkdownInline({ source = "", className = "", onLinkClick }) {
|
|
@@ -4317,7 +4398,7 @@ function Pagination({
|
|
|
4317
4398
|
}
|
|
4318
4399
|
|
|
4319
4400
|
// src/components/data/RelativeTime.tsx
|
|
4320
|
-
import * as
|
|
4401
|
+
import * as React27 from "react";
|
|
4321
4402
|
import { jsxs as jsxs45 } from "react/jsx-runtime";
|
|
4322
4403
|
var MIN = 6e4;
|
|
4323
4404
|
var HOUR = 36e5;
|
|
@@ -4369,9 +4450,9 @@ function formatDuration(ms) {
|
|
|
4369
4450
|
return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
|
|
4370
4451
|
}
|
|
4371
4452
|
function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
|
|
4372
|
-
const [, force] =
|
|
4453
|
+
const [, force] = React27.useState(0);
|
|
4373
4454
|
const t = value instanceof Date ? value.getTime() : Date.parse(value);
|
|
4374
|
-
|
|
4455
|
+
React27.useEffect(() => {
|
|
4375
4456
|
if (!refresh2 || !t || isNaN(t)) return;
|
|
4376
4457
|
const abs = Math.abs(t - Date.now());
|
|
4377
4458
|
if (abs > DAY) return;
|
|
@@ -4387,7 +4468,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
|
|
|
4387
4468
|
}
|
|
4388
4469
|
|
|
4389
4470
|
// src/components/data/ScoreMeter.tsx
|
|
4390
|
-
import * as
|
|
4471
|
+
import * as React28 from "react";
|
|
4391
4472
|
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
4392
4473
|
function ScoreMeter({
|
|
4393
4474
|
score,
|
|
@@ -4402,10 +4483,10 @@ function ScoreMeter({
|
|
|
4402
4483
|
breakdownWidth = 280,
|
|
4403
4484
|
className = ""
|
|
4404
4485
|
}) {
|
|
4405
|
-
const [open, setOpen] =
|
|
4406
|
-
const ref =
|
|
4486
|
+
const [open, setOpen] = React28.useState(false);
|
|
4487
|
+
const ref = React28.useRef(null);
|
|
4407
4488
|
const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
|
|
4408
|
-
const body = /* @__PURE__ */ jsxs46(
|
|
4489
|
+
const body = /* @__PURE__ */ jsxs46(React28.Fragment, { children: [
|
|
4409
4490
|
/* @__PURE__ */ jsx51("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx51(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
|
|
4410
4491
|
showScore ? /* @__PURE__ */ jsx51("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
|
|
4411
4492
|
] });
|
|
@@ -4424,7 +4505,7 @@ function ScoreMeter({
|
|
|
4424
4505
|
}
|
|
4425
4506
|
);
|
|
4426
4507
|
}
|
|
4427
|
-
return /* @__PURE__ */ jsxs46(
|
|
4508
|
+
return /* @__PURE__ */ jsxs46(React28.Fragment, { children: [
|
|
4428
4509
|
/* @__PURE__ */ jsx51(
|
|
4429
4510
|
"button",
|
|
4430
4511
|
{
|
|
@@ -4455,13 +4536,13 @@ function ScoreMeter({
|
|
|
4455
4536
|
}
|
|
4456
4537
|
|
|
4457
4538
|
// src/components/data/SortMenu.tsx
|
|
4458
|
-
import * as
|
|
4539
|
+
import * as React29 from "react";
|
|
4459
4540
|
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
4460
4541
|
function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
|
|
4461
|
-
const [open, setOpen] =
|
|
4542
|
+
const [open, setOpen] = React29.useState(false);
|
|
4462
4543
|
const zIndex = useOverlayLayer(open);
|
|
4463
|
-
const ref =
|
|
4464
|
-
|
|
4544
|
+
const ref = React29.useRef(null);
|
|
4545
|
+
React29.useEffect(() => {
|
|
4465
4546
|
if (!open) return;
|
|
4466
4547
|
const away = (e) => {
|
|
4467
4548
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -4523,7 +4604,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
|
|
|
4523
4604
|
}
|
|
4524
4605
|
|
|
4525
4606
|
// src/components/data/StepList.tsx
|
|
4526
|
-
import * as
|
|
4607
|
+
import * as React30 from "react";
|
|
4527
4608
|
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
4528
4609
|
var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
|
|
4529
4610
|
function StepList({
|
|
@@ -4536,9 +4617,9 @@ function StepList({
|
|
|
4536
4617
|
dense = false,
|
|
4537
4618
|
className = ""
|
|
4538
4619
|
}) {
|
|
4539
|
-
const [openState, setOpenState] =
|
|
4620
|
+
const [openState, setOpenState] = React30.useState(defaultOpen);
|
|
4540
4621
|
const open = openProp == null ? openState : openProp;
|
|
4541
|
-
const [expanded, setExpanded] =
|
|
4622
|
+
const [expanded, setExpanded] = React30.useState({});
|
|
4542
4623
|
if (!steps.length) return null;
|
|
4543
4624
|
const running = steps.some((s) => s.status === "running");
|
|
4544
4625
|
const failed = steps.filter((s) => s.status === "error").length;
|
|
@@ -4596,7 +4677,7 @@ function StepList({
|
|
|
4596
4677
|
}
|
|
4597
4678
|
|
|
4598
4679
|
// src/components/data/VirtualList.tsx
|
|
4599
|
-
import * as
|
|
4680
|
+
import * as React31 from "react";
|
|
4600
4681
|
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4601
4682
|
var VIRTUAL_LIST_BUFFER_ROWS = 20;
|
|
4602
4683
|
var VIRTUAL_LIST_ROW_GAP = 6;
|
|
@@ -4648,35 +4729,35 @@ function VirtualList({
|
|
|
4648
4729
|
className = "",
|
|
4649
4730
|
style
|
|
4650
4731
|
}) {
|
|
4651
|
-
const [scrollTop, setScrollTop] =
|
|
4652
|
-
const loaded =
|
|
4732
|
+
const [scrollTop, setScrollTop] = React31.useState(0);
|
|
4733
|
+
const loaded = React31.useMemo(
|
|
4653
4734
|
() => ({ firstItemIndex, count: items.length }),
|
|
4654
4735
|
[firstItemIndex, items.length]
|
|
4655
4736
|
);
|
|
4656
4737
|
const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
|
|
4657
4738
|
const bandKey = firstItemIndex + ":" + items.length;
|
|
4658
|
-
const win =
|
|
4739
|
+
const win = React31.useMemo(
|
|
4659
4740
|
() => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
|
|
4660
4741
|
[scrollTop, height, itemHeight, total, loaded]
|
|
4661
4742
|
);
|
|
4662
|
-
const need =
|
|
4743
|
+
const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
|
|
4663
4744
|
const wantStart = need.start && hasMore?.start !== false;
|
|
4664
4745
|
const wantEnd = need.end && hasMore?.end !== false;
|
|
4665
4746
|
const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
|
|
4666
4747
|
const askKey = bandKey + "@" + bucket2;
|
|
4667
|
-
const asked =
|
|
4668
|
-
|
|
4748
|
+
const asked = React31.useRef({ start: null, end: null });
|
|
4749
|
+
React31.useEffect(() => {
|
|
4669
4750
|
if (loading || !wantStart || asked.current.start === askKey) return;
|
|
4670
4751
|
asked.current.start = askKey;
|
|
4671
4752
|
onNeedMore("start", win);
|
|
4672
4753
|
}, [wantStart, loading, askKey, onNeedMore, win]);
|
|
4673
|
-
|
|
4754
|
+
React31.useEffect(() => {
|
|
4674
4755
|
if (loading || !wantEnd || asked.current.end === askKey) return;
|
|
4675
4756
|
asked.current.end = askKey;
|
|
4676
4757
|
onNeedMore("end", win);
|
|
4677
4758
|
}, [wantEnd, loading, askKey, onNeedMore, win]);
|
|
4678
|
-
const lastKeysRef =
|
|
4679
|
-
const newKeys =
|
|
4759
|
+
const lastKeysRef = React31.useRef(null);
|
|
4760
|
+
const newKeys = React31.useMemo(() => {
|
|
4680
4761
|
const prev = lastKeysRef.current;
|
|
4681
4762
|
if (!prev) return /* @__PURE__ */ new Set();
|
|
4682
4763
|
const fresh = /* @__PURE__ */ new Set();
|
|
@@ -4686,7 +4767,7 @@ function VirtualList({
|
|
|
4686
4767
|
}
|
|
4687
4768
|
return fresh;
|
|
4688
4769
|
}, [items]);
|
|
4689
|
-
|
|
4770
|
+
React31.useEffect(() => {
|
|
4690
4771
|
lastKeysRef.current = new Set(items.map(keyOf));
|
|
4691
4772
|
}, [items]);
|
|
4692
4773
|
const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
|
|
@@ -4731,7 +4812,7 @@ function VirtualList({
|
|
|
4731
4812
|
}
|
|
4732
4813
|
|
|
4733
4814
|
// src/components/data/EntityRow.tsx
|
|
4734
|
-
import * as
|
|
4815
|
+
import * as React32 from "react";
|
|
4735
4816
|
import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
4736
4817
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
4737
4818
|
var METRIC_TONE_COLOR = {
|
|
@@ -4744,7 +4825,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
|
|
|
4744
4825
|
const key = m.id || m.label || i;
|
|
4745
4826
|
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
4746
4827
|
const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
4747
|
-
const content = /* @__PURE__ */ jsxs50(
|
|
4828
|
+
const content = /* @__PURE__ */ jsxs50(React32.Fragment, { children: [
|
|
4748
4829
|
m.icon ? /* @__PURE__ */ jsx55("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
4749
4830
|
/* @__PURE__ */ jsx55("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
4750
4831
|
/* @__PURE__ */ jsx55("span", { className: "fd-sr", children: " " + m.label })
|
|
@@ -4836,7 +4917,7 @@ function EntityRow({
|
|
|
4836
4917
|
}
|
|
4837
4918
|
|
|
4838
4919
|
// src/components/data/TransferList.tsx
|
|
4839
|
-
import * as
|
|
4920
|
+
import * as React33 from "react";
|
|
4840
4921
|
import { createPortal as createPortal4 } from "react-dom";
|
|
4841
4922
|
|
|
4842
4923
|
// src/components/forms/Input.tsx
|
|
@@ -4942,12 +5023,12 @@ function TransferList({
|
|
|
4942
5023
|
listHeight = 440,
|
|
4943
5024
|
className = ""
|
|
4944
5025
|
}) {
|
|
4945
|
-
const [drag, setDrag] =
|
|
4946
|
-
const [dragOverSide, setDragOverSide] =
|
|
4947
|
-
const dragRef =
|
|
4948
|
-
const armedRef =
|
|
4949
|
-
const sideRefs =
|
|
4950
|
-
const hitTestSide =
|
|
5026
|
+
const [drag, setDrag] = React33.useState(null);
|
|
5027
|
+
const [dragOverSide, setDragOverSide] = React33.useState(null);
|
|
5028
|
+
const dragRef = React33.useRef(null);
|
|
5029
|
+
const armedRef = React33.useRef(null);
|
|
5030
|
+
const sideRefs = React33.useRef({ left: null, right: null });
|
|
5031
|
+
const hitTestSide = React33.useCallback((x, y) => {
|
|
4951
5032
|
for (const side of ["left", "right"]) {
|
|
4952
5033
|
const el = sideRefs.current[side];
|
|
4953
5034
|
if (!el) continue;
|
|
@@ -4956,7 +5037,7 @@ function TransferList({
|
|
|
4956
5037
|
}
|
|
4957
5038
|
return null;
|
|
4958
5039
|
}, []);
|
|
4959
|
-
const findItem =
|
|
5040
|
+
const findItem = React33.useCallback(
|
|
4960
5041
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
4961
5042
|
[left.items, right.items, keyOf]
|
|
4962
5043
|
);
|
|
@@ -4978,7 +5059,7 @@ function TransferList({
|
|
|
4978
5059
|
height: rect.height
|
|
4979
5060
|
};
|
|
4980
5061
|
};
|
|
4981
|
-
|
|
5062
|
+
React33.useEffect(() => {
|
|
4982
5063
|
const onMovePointer = (e) => {
|
|
4983
5064
|
const armed = armedRef.current;
|
|
4984
5065
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -5031,7 +5112,7 @@ function TransferList({
|
|
|
5031
5112
|
window.removeEventListener("pointercancel", endDrag);
|
|
5032
5113
|
};
|
|
5033
5114
|
}, [hitTestSide, findItem, onMove]);
|
|
5034
|
-
|
|
5115
|
+
React33.useEffect(() => {
|
|
5035
5116
|
if (!drag || typeof document === "undefined") return;
|
|
5036
5117
|
const prev = document.body.style.userSelect;
|
|
5037
5118
|
document.body.style.userSelect = "none";
|
|
@@ -5139,11 +5220,11 @@ function TransferList({
|
|
|
5139
5220
|
}
|
|
5140
5221
|
|
|
5141
5222
|
// src/components/forms/Checkbox.tsx
|
|
5142
|
-
import * as
|
|
5223
|
+
import * as React34 from "react";
|
|
5143
5224
|
import { jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
5144
5225
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
5145
|
-
const ref =
|
|
5146
|
-
|
|
5226
|
+
const ref = React34.useRef(null);
|
|
5227
|
+
React34.useEffect(() => {
|
|
5147
5228
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
5148
5229
|
}, [indeterminate]);
|
|
5149
5230
|
return /* @__PURE__ */ jsxs53("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -5187,7 +5268,7 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
5187
5268
|
}
|
|
5188
5269
|
|
|
5189
5270
|
// src/components/forms/Select.tsx
|
|
5190
|
-
import * as
|
|
5271
|
+
import * as React35 from "react";
|
|
5191
5272
|
import { jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
5192
5273
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
5193
5274
|
function Select({
|
|
@@ -5214,13 +5295,12 @@ function Select({
|
|
|
5214
5295
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
5215
5296
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
5216
5297
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
5217
|
-
const [open, setOpen] =
|
|
5218
|
-
const [q, setQ] =
|
|
5219
|
-
const
|
|
5220
|
-
const
|
|
5221
|
-
const
|
|
5222
|
-
const
|
|
5223
|
-
const typeBuf = React34.useRef({ s: "", t: 0 });
|
|
5298
|
+
const [open, setOpen] = React35.useState(false);
|
|
5299
|
+
const [q, setQ] = React35.useState("");
|
|
5300
|
+
const rootRef = React35.useRef(null);
|
|
5301
|
+
const boxRef = React35.useRef(null);
|
|
5302
|
+
const listRef = React35.useRef(null);
|
|
5303
|
+
const typeBuf = React35.useRef({ s: "", t: 0 });
|
|
5224
5304
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
5225
5305
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
5226
5306
|
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;
|
|
@@ -5237,23 +5317,16 @@ function Select({
|
|
|
5237
5317
|
fire(o.value);
|
|
5238
5318
|
setOpen(false);
|
|
5239
5319
|
};
|
|
5320
|
+
const nav = useListboxNav({ count: visible.length, onSelect: (i) => pick(visible[i]) });
|
|
5321
|
+
useListboxScrollIntoView(nav.active, listRef, open);
|
|
5240
5322
|
const toggle = () => {
|
|
5241
5323
|
if (disabled || loading) return;
|
|
5242
5324
|
if (!open) {
|
|
5243
5325
|
setQ("");
|
|
5244
|
-
setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5326
|
+
nav.setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5245
5327
|
}
|
|
5246
5328
|
setOpen(!open);
|
|
5247
5329
|
};
|
|
5248
|
-
React34.useEffect(() => {
|
|
5249
|
-
if (!open || active < 0 || !listRef.current) return;
|
|
5250
|
-
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
5251
|
-
if (el) {
|
|
5252
|
-
const L = listRef.current, top = el.offsetTop - L.offsetTop;
|
|
5253
|
-
if (top < L.scrollTop) L.scrollTop = top - 4;
|
|
5254
|
-
else if (top + el.offsetHeight > L.scrollTop + L.clientHeight) L.scrollTop = top + el.offsetHeight - L.clientHeight + 4;
|
|
5255
|
-
}
|
|
5256
|
-
}, [active, open]);
|
|
5257
5330
|
const onKey = (e) => {
|
|
5258
5331
|
if (disabled) return;
|
|
5259
5332
|
if (!open && (e.key === "Enter" || e.key === " " || e.key === "ArrowDown" || e.key === "ArrowUp")) {
|
|
@@ -5275,19 +5348,19 @@ function Select({
|
|
|
5275
5348
|
setOpen(false);
|
|
5276
5349
|
} else if (e.key === "ArrowDown") {
|
|
5277
5350
|
e.preventDefault();
|
|
5278
|
-
|
|
5351
|
+
nav.move(1);
|
|
5279
5352
|
} else if (e.key === "ArrowUp") {
|
|
5280
5353
|
e.preventDefault();
|
|
5281
|
-
|
|
5354
|
+
nav.move(-1);
|
|
5282
5355
|
} else if (e.key === "Home") {
|
|
5283
5356
|
e.preventDefault();
|
|
5284
|
-
|
|
5357
|
+
nav.first();
|
|
5285
5358
|
} else if (e.key === "End") {
|
|
5286
5359
|
e.preventDefault();
|
|
5287
|
-
|
|
5360
|
+
nav.last();
|
|
5288
5361
|
} else if (e.key === "Enter") {
|
|
5289
5362
|
e.preventDefault();
|
|
5290
|
-
|
|
5363
|
+
nav.activate();
|
|
5291
5364
|
} else if (e.key === "Tab") setOpen(false);
|
|
5292
5365
|
};
|
|
5293
5366
|
const groups = [];
|
|
@@ -5360,13 +5433,13 @@ function Select({
|
|
|
5360
5433
|
onKeyDown: onKey,
|
|
5361
5434
|
onChange: (e) => {
|
|
5362
5435
|
setQ(e.target.value);
|
|
5363
|
-
setActive(0);
|
|
5436
|
+
nav.setActive(0);
|
|
5364
5437
|
}
|
|
5365
5438
|
}
|
|
5366
5439
|
),
|
|
5367
5440
|
q ? /* @__PURE__ */ jsx62("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
5368
5441
|
] }) : void 0,
|
|
5369
|
-
footer: multiple ? /* @__PURE__ */ jsxs56(
|
|
5442
|
+
footer: multiple ? /* @__PURE__ */ jsxs56(React35.Fragment, { children: [
|
|
5370
5443
|
/* @__PURE__ */ jsx62(
|
|
5371
5444
|
"button",
|
|
5372
5445
|
{
|
|
@@ -5397,7 +5470,7 @@ function Select({
|
|
|
5397
5470
|
'Nothing matches "',
|
|
5398
5471
|
q,
|
|
5399
5472
|
'".'
|
|
5400
|
-
] }) : groups.map((grp) => /* @__PURE__ */ jsxs56(
|
|
5473
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs56(React35.Fragment, { children: [
|
|
5401
5474
|
grp.g ? /* @__PURE__ */ jsx62("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
5402
5475
|
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs56(
|
|
5403
5476
|
"button",
|
|
@@ -5407,8 +5480,8 @@ function Select({
|
|
|
5407
5480
|
role: "option",
|
|
5408
5481
|
"aria-selected": isOn(o.value),
|
|
5409
5482
|
"aria-disabled": o.disabled || void 0,
|
|
5410
|
-
className: ["fd-opt", i === active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
5411
|
-
onMouseEnter: () => setActive(i),
|
|
5483
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
5484
|
+
onMouseEnter: () => nav.setActive(i),
|
|
5412
5485
|
onClick: () => pick(o),
|
|
5413
5486
|
children: [
|
|
5414
5487
|
multiple ? /* @__PURE__ */ jsx62("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx62("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
@@ -5434,7 +5507,7 @@ function Select({
|
|
|
5434
5507
|
}
|
|
5435
5508
|
|
|
5436
5509
|
// src/components/forms/TimePicker.tsx
|
|
5437
|
-
import * as
|
|
5510
|
+
import * as React36 from "react";
|
|
5438
5511
|
import { jsx as jsx63, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
5439
5512
|
var pad = (n) => String(n).padStart(2, "0");
|
|
5440
5513
|
function ClockFace({ value = "09:00", onChange }) {
|
|
@@ -5443,9 +5516,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5443
5516
|
if (isNaN(m)) m = 0;
|
|
5444
5517
|
const pm = h24 >= 12;
|
|
5445
5518
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
5446
|
-
const [mode2, setMode] =
|
|
5447
|
-
const faceRef =
|
|
5448
|
-
const dragging =
|
|
5519
|
+
const [mode2, setMode] = React36.useState("h");
|
|
5520
|
+
const faceRef = React36.useRef(null);
|
|
5521
|
+
const dragging = React36.useRef(false);
|
|
5449
5522
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
5450
5523
|
const R = 108, NR = 80;
|
|
5451
5524
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -5518,9 +5591,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5518
5591
|
}
|
|
5519
5592
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
5520
5593
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
5521
|
-
const [open, setOpen] =
|
|
5522
|
-
const rootRef =
|
|
5523
|
-
const boxRef =
|
|
5594
|
+
const [open, setOpen] = React36.useState(false);
|
|
5595
|
+
const rootRef = React36.useRef(null);
|
|
5596
|
+
const boxRef = React36.useRef(null);
|
|
5524
5597
|
const disp = () => {
|
|
5525
5598
|
if (!value) return "";
|
|
5526
5599
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -5563,7 +5636,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5563
5636
|
offset: 6,
|
|
5564
5637
|
width: 262,
|
|
5565
5638
|
role: "presentation",
|
|
5566
|
-
footer: /* @__PURE__ */ jsxs57(
|
|
5639
|
+
footer: /* @__PURE__ */ jsxs57(React36.Fragment, { children: [
|
|
5567
5640
|
/* @__PURE__ */ jsx63(
|
|
5568
5641
|
"button",
|
|
5569
5642
|
{
|
|
@@ -5591,7 +5664,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5591
5664
|
}
|
|
5592
5665
|
|
|
5593
5666
|
// src/components/forms/Slider.tsx
|
|
5594
|
-
import * as
|
|
5667
|
+
import * as React37 from "react";
|
|
5595
5668
|
import { jsx as jsx64, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
5596
5669
|
function Slider({
|
|
5597
5670
|
label,
|
|
@@ -5609,7 +5682,7 @@ function Slider({
|
|
|
5609
5682
|
...rest
|
|
5610
5683
|
}) {
|
|
5611
5684
|
const fieldId = useFieldId(id);
|
|
5612
|
-
const [dragging, setDragging] =
|
|
5685
|
+
const [dragging, setDragging] = React37.useState(false);
|
|
5613
5686
|
const v = value === void 0 ? min : Number(value);
|
|
5614
5687
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5615
5688
|
return /* @__PURE__ */ jsxs58("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -5643,7 +5716,7 @@ function Slider({
|
|
|
5643
5716
|
}
|
|
5644
5717
|
|
|
5645
5718
|
// src/components/forms/RangeSlider.tsx
|
|
5646
|
-
import * as
|
|
5719
|
+
import * as React38 from "react";
|
|
5647
5720
|
import { jsx as jsx65, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
5648
5721
|
function RangeSlider({
|
|
5649
5722
|
label,
|
|
@@ -5663,9 +5736,9 @@ function RangeSlider({
|
|
|
5663
5736
|
}) {
|
|
5664
5737
|
const fmt2 = format || ((v) => String(v));
|
|
5665
5738
|
const [a, b] = value || [min, max];
|
|
5666
|
-
const [drag, setDrag] =
|
|
5667
|
-
const [focus, setFocus] =
|
|
5668
|
-
const railRef =
|
|
5739
|
+
const [drag, setDrag] = React38.useState(null);
|
|
5740
|
+
const [focus, setFocus] = React38.useState(null);
|
|
5741
|
+
const railRef = React38.useRef(null);
|
|
5669
5742
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5670
5743
|
const clampPair = (i, v) => {
|
|
5671
5744
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -5680,7 +5753,7 @@ function RangeSlider({
|
|
|
5680
5753
|
const r = railRef.current.getBoundingClientRect();
|
|
5681
5754
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
5682
5755
|
};
|
|
5683
|
-
|
|
5756
|
+
React38.useEffect(() => {
|
|
5684
5757
|
if (drag === null) return;
|
|
5685
5758
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
5686
5759
|
const upH = () => setDrag(null);
|
|
@@ -5761,7 +5834,7 @@ function RangeSlider({
|
|
|
5761
5834
|
/* @__PURE__ */ jsxs59("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
5762
5835
|
/* @__PURE__ */ jsx65("span", { className: "fd-range-rail", ref: railRef }),
|
|
5763
5836
|
/* @__PURE__ */ jsx65("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
5764
|
-
marks.map((m) => /* @__PURE__ */ jsxs59(
|
|
5837
|
+
marks.map((m) => /* @__PURE__ */ jsxs59(React38.Fragment, { children: [
|
|
5765
5838
|
/* @__PURE__ */ jsx65("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
5766
5839
|
m.label ? /* @__PURE__ */ jsx65("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
5767
5840
|
] }, m.value)),
|
|
@@ -5790,7 +5863,7 @@ function RangeSlider({
|
|
|
5790
5863
|
}
|
|
5791
5864
|
|
|
5792
5865
|
// src/components/forms/Dropzone.tsx
|
|
5793
|
-
import * as
|
|
5866
|
+
import * as React39 from "react";
|
|
5794
5867
|
import { jsx as jsx66, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
5795
5868
|
function Dropzone({
|
|
5796
5869
|
onFiles,
|
|
@@ -5805,8 +5878,8 @@ function Dropzone({
|
|
|
5805
5878
|
className = "",
|
|
5806
5879
|
style
|
|
5807
5880
|
}) {
|
|
5808
|
-
const [over, setOver] =
|
|
5809
|
-
const depth =
|
|
5881
|
+
const [over, setOver] = React39.useState(false);
|
|
5882
|
+
const depth = React39.useRef(0);
|
|
5810
5883
|
const has = (e) => {
|
|
5811
5884
|
const dt = e.dataTransfer;
|
|
5812
5885
|
if (!dt) return false;
|
|
@@ -5868,8 +5941,8 @@ function FilePickButton({
|
|
|
5868
5941
|
className = "",
|
|
5869
5942
|
children
|
|
5870
5943
|
}) {
|
|
5871
|
-
const ref =
|
|
5872
|
-
return /* @__PURE__ */ jsxs60(
|
|
5944
|
+
const ref = React39.useRef(null);
|
|
5945
|
+
return /* @__PURE__ */ jsxs60(React39.Fragment, { children: [
|
|
5873
5946
|
/* @__PURE__ */ jsx66(
|
|
5874
5947
|
"button",
|
|
5875
5948
|
{
|
|
@@ -5902,10 +5975,10 @@ function FilePickButton({
|
|
|
5902
5975
|
}
|
|
5903
5976
|
function useStagedFiles(upload, opts) {
|
|
5904
5977
|
const o = opts || {};
|
|
5905
|
-
const [items, setItems] =
|
|
5906
|
-
const controllers =
|
|
5978
|
+
const [items, setItems] = React39.useState([]);
|
|
5979
|
+
const controllers = React39.useRef({});
|
|
5907
5980
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
5908
|
-
const run =
|
|
5981
|
+
const run = React39.useCallback((att) => {
|
|
5909
5982
|
if (!upload) return;
|
|
5910
5983
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
5911
5984
|
controllers.current[att.id] = ac;
|
|
@@ -5922,14 +5995,14 @@ function useStagedFiles(upload, opts) {
|
|
|
5922
5995
|
delete controllers.current[att.id];
|
|
5923
5996
|
});
|
|
5924
5997
|
}, [upload]);
|
|
5925
|
-
const add =
|
|
5998
|
+
const add = React39.useCallback((files) => {
|
|
5926
5999
|
if (!upload) return [];
|
|
5927
6000
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
5928
6001
|
setItems((list) => list.concat(atts));
|
|
5929
6002
|
atts.forEach(run);
|
|
5930
6003
|
return atts;
|
|
5931
6004
|
}, [upload, run]);
|
|
5932
|
-
const remove =
|
|
6005
|
+
const remove = React39.useCallback((att) => {
|
|
5933
6006
|
const ac = controllers.current[att.id];
|
|
5934
6007
|
if (ac) {
|
|
5935
6008
|
try {
|
|
@@ -5940,10 +6013,10 @@ function useStagedFiles(upload, opts) {
|
|
|
5940
6013
|
}
|
|
5941
6014
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
5942
6015
|
}, []);
|
|
5943
|
-
const retry =
|
|
6016
|
+
const retry = React39.useCallback((att) => {
|
|
5944
6017
|
run(att);
|
|
5945
6018
|
}, [run]);
|
|
5946
|
-
const clear =
|
|
6019
|
+
const clear = React39.useCallback(() => {
|
|
5947
6020
|
Object.values(controllers.current).forEach((ac) => {
|
|
5948
6021
|
try {
|
|
5949
6022
|
ac && ac.abort();
|
|
@@ -6067,7 +6140,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
6067
6140
|
}
|
|
6068
6141
|
|
|
6069
6142
|
// src/components/forms/MarkdownEditor.tsx
|
|
6070
|
-
import * as
|
|
6143
|
+
import * as React40 from "react";
|
|
6071
6144
|
import { jsx as jsx68, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
6072
6145
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
6073
6146
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -6281,7 +6354,7 @@ function syncDom(root, value) {
|
|
|
6281
6354
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
6282
6355
|
}
|
|
6283
6356
|
var LIST_CONT = RE_LI;
|
|
6284
|
-
var MarkdownEditor =
|
|
6357
|
+
var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
|
|
6285
6358
|
value = "",
|
|
6286
6359
|
onChange,
|
|
6287
6360
|
onSubmit,
|
|
@@ -6300,10 +6373,10 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6300
6373
|
className = "",
|
|
6301
6374
|
id
|
|
6302
6375
|
}, ref) {
|
|
6303
|
-
const boxRef =
|
|
6304
|
-
const composing =
|
|
6305
|
-
const pendingCaret =
|
|
6306
|
-
|
|
6376
|
+
const boxRef = React40.useRef(null);
|
|
6377
|
+
const composing = React40.useRef(false);
|
|
6378
|
+
const pendingCaret = React40.useRef(null);
|
|
6379
|
+
React40.useLayoutEffect(() => {
|
|
6307
6380
|
const root = boxRef.current;
|
|
6308
6381
|
if (!root || composing.current) return;
|
|
6309
6382
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -6312,7 +6385,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6312
6385
|
pendingCaret.current = null;
|
|
6313
6386
|
if (active && caret != null) placeCaret(root, caret);
|
|
6314
6387
|
}, [value]);
|
|
6315
|
-
|
|
6388
|
+
React40.useEffect(() => {
|
|
6316
6389
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
6317
6390
|
}, [autoFocus]);
|
|
6318
6391
|
const caretNow = () => {
|
|
@@ -6379,7 +6452,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6379
6452
|
api.replaceRange(from, to, next, from + next.length);
|
|
6380
6453
|
}
|
|
6381
6454
|
};
|
|
6382
|
-
|
|
6455
|
+
React40.useImperativeHandle(ref, () => api);
|
|
6383
6456
|
function detect(text, caret) {
|
|
6384
6457
|
if (!onTrigger) return;
|
|
6385
6458
|
const upto = text.slice(0, caret);
|
|
@@ -6531,16 +6604,16 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6531
6604
|
});
|
|
6532
6605
|
|
|
6533
6606
|
// src/components/platform/AccountMenu.tsx
|
|
6534
|
-
import * as
|
|
6607
|
+
import * as React42 from "react";
|
|
6535
6608
|
|
|
6536
6609
|
// src/kits/sessionContext.tsx
|
|
6537
|
-
import * as
|
|
6538
|
-
var SessionContext =
|
|
6610
|
+
import * as React41 from "react";
|
|
6611
|
+
var SessionContext = React41.createContext(null);
|
|
6539
6612
|
function SessionProvider({ value, children }) {
|
|
6540
|
-
return
|
|
6613
|
+
return React41.createElement(SessionContext.Provider, { value }, children);
|
|
6541
6614
|
}
|
|
6542
6615
|
function useSessionContext() {
|
|
6543
|
-
const ctx =
|
|
6616
|
+
const ctx = React41.useContext(SessionContext);
|
|
6544
6617
|
if (!ctx) {
|
|
6545
6618
|
throw new Error(
|
|
6546
6619
|
"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."
|
|
@@ -6580,11 +6653,11 @@ function AccountMenu({
|
|
|
6580
6653
|
...rest
|
|
6581
6654
|
}) {
|
|
6582
6655
|
const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
|
|
6583
|
-
const [open, setOpen] =
|
|
6584
|
-
const [switching, setSwitching] =
|
|
6585
|
-
const [signingOut, setSigningOut] =
|
|
6586
|
-
const [signOutError, setSignOutError] =
|
|
6587
|
-
const ref =
|
|
6656
|
+
const [open, setOpen] = React42.useState(false);
|
|
6657
|
+
const [switching, setSwitching] = React42.useState(false);
|
|
6658
|
+
const [signingOut, setSigningOut] = React42.useState(false);
|
|
6659
|
+
const [signOutError, setSignOutError] = React42.useState(null);
|
|
6660
|
+
const ref = React42.useRef(null);
|
|
6588
6661
|
const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
|
|
6589
6662
|
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
|
|
6590
6663
|
const closeMenu = () => {
|
|
@@ -6709,13 +6782,13 @@ function AccountMenu({
|
|
|
6709
6782
|
}
|
|
6710
6783
|
|
|
6711
6784
|
// src/components/platform/AppSwitcher.tsx
|
|
6712
|
-
import * as
|
|
6785
|
+
import * as React43 from "react";
|
|
6713
6786
|
import { jsx as jsx70, jsxs as jsxs64 } from "react/jsx-runtime";
|
|
6714
6787
|
function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
6715
6788
|
const { apps: contextApps } = useSessionContext();
|
|
6716
6789
|
const apps = appsProp ?? contextApps ?? [];
|
|
6717
|
-
const [open, setOpen] =
|
|
6718
|
-
const anchorRef =
|
|
6790
|
+
const [open, setOpen] = React43.useState(false);
|
|
6791
|
+
const anchorRef = React43.useRef(null);
|
|
6719
6792
|
if (!apps.length) return null;
|
|
6720
6793
|
const items = apps.map((app) => ({
|
|
6721
6794
|
id: app.key,
|
|
@@ -6729,7 +6802,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6729
6802
|
window.location.href = app.url;
|
|
6730
6803
|
}
|
|
6731
6804
|
}));
|
|
6732
|
-
return /* @__PURE__ */ jsxs64(
|
|
6805
|
+
return /* @__PURE__ */ jsxs64(React43.Fragment, { children: [
|
|
6733
6806
|
/* @__PURE__ */ jsx70("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx70(
|
|
6734
6807
|
IconButton,
|
|
6735
6808
|
{
|
|
@@ -6758,10 +6831,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6758
6831
|
}
|
|
6759
6832
|
|
|
6760
6833
|
// src/components/platform/AppearanceMenu.tsx
|
|
6761
|
-
import * as
|
|
6834
|
+
import * as React45 from "react";
|
|
6762
6835
|
|
|
6763
6836
|
// src/kits/appearance.ts
|
|
6764
|
-
import * as
|
|
6837
|
+
import * as React44 from "react";
|
|
6765
6838
|
var DEFAULT_STORAGE_KEY = "fd-appearance";
|
|
6766
6839
|
var DEFAULT_PREFS = {
|
|
6767
6840
|
theme: "system",
|
|
@@ -6856,11 +6929,11 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
6856
6929
|
else root.removeAttribute("data-motion");
|
|
6857
6930
|
}
|
|
6858
6931
|
function useAppearancePrefs(store) {
|
|
6859
|
-
const prefs =
|
|
6860
|
-
|
|
6932
|
+
const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
6933
|
+
React44.useEffect(() => {
|
|
6861
6934
|
applyPrefs(prefs);
|
|
6862
6935
|
}, [prefs]);
|
|
6863
|
-
|
|
6936
|
+
React44.useEffect(() => {
|
|
6864
6937
|
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
6865
6938
|
return;
|
|
6866
6939
|
}
|
|
@@ -6869,7 +6942,7 @@ function useAppearancePrefs(store) {
|
|
|
6869
6942
|
mq.addEventListener("change", onChange);
|
|
6870
6943
|
return () => mq.removeEventListener("change", onChange);
|
|
6871
6944
|
}, [prefs]);
|
|
6872
|
-
const update =
|
|
6945
|
+
const update = React44.useCallback(
|
|
6873
6946
|
(patch) => {
|
|
6874
6947
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
6875
6948
|
},
|
|
@@ -6892,15 +6965,15 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
6892
6965
|
{ value: "xl", label: "XL" }
|
|
6893
6966
|
];
|
|
6894
6967
|
function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
|
|
6895
|
-
const store =
|
|
6968
|
+
const store = React45.useMemo(
|
|
6896
6969
|
() => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
|
|
6897
6970
|
[storeProp, storageKey, storage, defaults]
|
|
6898
6971
|
);
|
|
6899
6972
|
const [prefs, update] = useAppearancePrefs(store);
|
|
6900
|
-
const [open, setOpen] =
|
|
6901
|
-
const anchorRef =
|
|
6973
|
+
const [open, setOpen] = React45.useState(false);
|
|
6974
|
+
const anchorRef = React45.useRef(null);
|
|
6902
6975
|
const patch = (p) => update(p);
|
|
6903
|
-
return /* @__PURE__ */ jsxs65(
|
|
6976
|
+
return /* @__PURE__ */ jsxs65(React45.Fragment, { children: [
|
|
6904
6977
|
/* @__PURE__ */ jsx71("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx71(
|
|
6905
6978
|
IconButton,
|
|
6906
6979
|
{
|
|
@@ -6969,14 +7042,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
6969
7042
|
}
|
|
6970
7043
|
|
|
6971
7044
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6972
|
-
import * as
|
|
7045
|
+
import * as React46 from "react";
|
|
6973
7046
|
import { jsx as jsx72, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
6974
7047
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6975
7048
|
function Json({ obj }) {
|
|
6976
7049
|
return /* @__PURE__ */ jsx72("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6977
7050
|
}
|
|
6978
7051
|
function Endpoint({ s, onRequest }) {
|
|
6979
|
-
const [tried, setTried] =
|
|
7052
|
+
const [tried, setTried] = React46.useState(null);
|
|
6980
7053
|
const run = async () => {
|
|
6981
7054
|
setTried("busy");
|
|
6982
7055
|
const t0 = (window.performance || Date).now();
|
|
@@ -7049,10 +7122,10 @@ function ApiSpecBrowser({
|
|
|
7049
7122
|
className = "",
|
|
7050
7123
|
...rest
|
|
7051
7124
|
}) {
|
|
7052
|
-
const [q, setQ] =
|
|
7053
|
-
const [method, setMethod] =
|
|
7054
|
-
const [mod, setMod] =
|
|
7055
|
-
const [listOnly, setListOnly] =
|
|
7125
|
+
const [q, setQ] = React46.useState("");
|
|
7126
|
+
const [method, setMethod] = React46.useState(null);
|
|
7127
|
+
const [mod, setMod] = React46.useState(null);
|
|
7128
|
+
const [listOnly, setListOnly] = React46.useState(false);
|
|
7056
7129
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
7057
7130
|
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())));
|
|
7058
7131
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -7131,7 +7204,7 @@ function ApiSpecBrowser({
|
|
|
7131
7204
|
}
|
|
7132
7205
|
|
|
7133
7206
|
// src/components/platform/ProfilePage.tsx
|
|
7134
|
-
import * as
|
|
7207
|
+
import * as React47 from "react";
|
|
7135
7208
|
import { jsx as jsx73, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
7136
7209
|
function fieldInitialValue(field, user) {
|
|
7137
7210
|
if (field.value) return field.value(user);
|
|
@@ -7167,21 +7240,21 @@ function ProfilePage({
|
|
|
7167
7240
|
}) {
|
|
7168
7241
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
7169
7242
|
const user = userProp || sessionUser;
|
|
7170
|
-
const initialFieldValues =
|
|
7243
|
+
const initialFieldValues = React47.useMemo(() => {
|
|
7171
7244
|
const values2 = {};
|
|
7172
7245
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
7173
7246
|
return values2;
|
|
7174
7247
|
}, [user.id, fields]);
|
|
7175
|
-
const initialNotify =
|
|
7248
|
+
const initialNotify = React47.useMemo(() => {
|
|
7176
7249
|
const values2 = {};
|
|
7177
7250
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
7178
7251
|
return values2;
|
|
7179
7252
|
}, [user.id, notifications]);
|
|
7180
|
-
const [values, setValues] =
|
|
7181
|
-
const [notify, setNotify] =
|
|
7182
|
-
const [saving, setSaving] =
|
|
7183
|
-
const [saved, setSaved] =
|
|
7184
|
-
const [prevUserId, setPrevUserId] =
|
|
7253
|
+
const [values, setValues] = React47.useState(initialFieldValues);
|
|
7254
|
+
const [notify, setNotify] = React47.useState(initialNotify);
|
|
7255
|
+
const [saving, setSaving] = React47.useState(false);
|
|
7256
|
+
const [saved, setSaved] = React47.useState(false);
|
|
7257
|
+
const [prevUserId, setPrevUserId] = React47.useState(user.id);
|
|
7185
7258
|
if (user.id !== prevUserId) {
|
|
7186
7259
|
setPrevUserId(user.id);
|
|
7187
7260
|
setValues(initialFieldValues);
|
|
@@ -7369,11 +7442,11 @@ function ProfilePage({
|
|
|
7369
7442
|
}
|
|
7370
7443
|
|
|
7371
7444
|
// src/components/platform/SignInPage.tsx
|
|
7372
|
-
import * as
|
|
7445
|
+
import * as React48 from "react";
|
|
7373
7446
|
import { Fragment as Fragment18, jsx as jsx74, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
7374
7447
|
function SignInPage({ productName, onSignIn, continueAs, error }) {
|
|
7375
|
-
const [signingIn, setSigningIn] =
|
|
7376
|
-
const [resuming, setResuming] =
|
|
7448
|
+
const [signingIn, setSigningIn] = React48.useState(false);
|
|
7449
|
+
const [resuming, setResuming] = React48.useState(false);
|
|
7377
7450
|
function handleSignIn() {
|
|
7378
7451
|
setSigningIn(true);
|
|
7379
7452
|
onSignIn();
|
|
@@ -7562,10 +7635,10 @@ function GoogleGlyph() {
|
|
|
7562
7635
|
}
|
|
7563
7636
|
|
|
7564
7637
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7565
|
-
import * as
|
|
7638
|
+
import * as React51 from "react";
|
|
7566
7639
|
|
|
7567
7640
|
// src/kits/session.ts
|
|
7568
|
-
import * as
|
|
7641
|
+
import * as React49 from "react";
|
|
7569
7642
|
var PERMISSION_CATALOG = [
|
|
7570
7643
|
{ group: "Plans", items: [
|
|
7571
7644
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -9132,8 +9205,8 @@ function roadmap(overrides) {
|
|
|
9132
9205
|
};
|
|
9133
9206
|
}
|
|
9134
9207
|
function useSession() {
|
|
9135
|
-
const [s, setS] =
|
|
9136
|
-
|
|
9208
|
+
const [s, setS] = React49.useState(getSession);
|
|
9209
|
+
React49.useEffect(() => subscribe(setS), []);
|
|
9137
9210
|
return s;
|
|
9138
9211
|
}
|
|
9139
9212
|
var SessionKit = {
|
|
@@ -9166,7 +9239,7 @@ var SessionKit = {
|
|
|
9166
9239
|
};
|
|
9167
9240
|
function DemoSessionProvider({ children }) {
|
|
9168
9241
|
const session = useSession();
|
|
9169
|
-
const value =
|
|
9242
|
+
const value = React49.useMemo(
|
|
9170
9243
|
() => ({
|
|
9171
9244
|
user: session.user,
|
|
9172
9245
|
roles: session.roles,
|
|
@@ -9182,11 +9255,11 @@ function DemoSessionProvider({ children }) {
|
|
|
9182
9255
|
}),
|
|
9183
9256
|
[session]
|
|
9184
9257
|
);
|
|
9185
|
-
return
|
|
9258
|
+
return React49.createElement(SessionProvider, { value }, children);
|
|
9186
9259
|
}
|
|
9187
9260
|
|
|
9188
9261
|
// src/kits/runtime.ts
|
|
9189
|
-
import * as
|
|
9262
|
+
import * as React50 from "react";
|
|
9190
9263
|
var WIRED_ENDPOINTS = [
|
|
9191
9264
|
// Nothing yet. Every id below would come from a real service:
|
|
9192
9265
|
// "plan.get", "placements.list", …
|
|
@@ -9357,8 +9430,8 @@ var RuntimeKit = {
|
|
|
9357
9430
|
};
|
|
9358
9431
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
9359
9432
|
function useRuntimeMode() {
|
|
9360
|
-
const [m, setM] =
|
|
9361
|
-
|
|
9433
|
+
const [m, setM] = React50.useState(RuntimeKit.getMode());
|
|
9434
|
+
React50.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
9362
9435
|
return m;
|
|
9363
9436
|
}
|
|
9364
9437
|
function useFeatureStatus(key) {
|
|
@@ -9441,12 +9514,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
9441
9514
|
}
|
|
9442
9515
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
9443
9516
|
const session = SessionKit.useSession();
|
|
9444
|
-
const [project, setProject] =
|
|
9445
|
-
const [q, setQ] =
|
|
9446
|
-
const scrollRef =
|
|
9447
|
-
const nowRef =
|
|
9448
|
-
const rm =
|
|
9449
|
-
const byKey =
|
|
9517
|
+
const [project, setProject] = React51.useState("");
|
|
9518
|
+
const [q, setQ] = React51.useState("");
|
|
9519
|
+
const scrollRef = React51.useRef(null);
|
|
9520
|
+
const nowRef = React51.useRef(null);
|
|
9521
|
+
const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
9522
|
+
const byKey = React51.useMemo(() => {
|
|
9450
9523
|
const m = {};
|
|
9451
9524
|
rm.items.forEach((i) => {
|
|
9452
9525
|
m[i.key] = i;
|
|
@@ -9455,7 +9528,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9455
9528
|
}, [rm]);
|
|
9456
9529
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
9457
9530
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
9458
|
-
|
|
9531
|
+
React51.useEffect(() => {
|
|
9459
9532
|
let raf1 = 0, raf2 = 0;
|
|
9460
9533
|
const place = () => {
|
|
9461
9534
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -9529,7 +9602,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9529
9602
|
lastPhase = item.phase;
|
|
9530
9603
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
9531
9604
|
const isBoundary = n === firstPending;
|
|
9532
|
-
return /* @__PURE__ */ jsxs69(
|
|
9605
|
+
return /* @__PURE__ */ jsxs69(React51.Fragment, { children: [
|
|
9533
9606
|
showPhase ? /* @__PURE__ */ jsxs69("div", { className: "fd-rm-era", children: [
|
|
9534
9607
|
/* @__PURE__ */ jsxs69("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
9535
9608
|
/* @__PURE__ */ jsx75("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -9573,7 +9646,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9573
9646
|
}
|
|
9574
9647
|
|
|
9575
9648
|
// src/components/platform/ComingSoon.tsx
|
|
9576
|
-
import * as
|
|
9649
|
+
import * as React52 from "react";
|
|
9577
9650
|
import { createPortal as createPortal5 } from "react-dom";
|
|
9578
9651
|
import { Fragment as Fragment20, jsx as jsx76, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9579
9652
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
@@ -9591,8 +9664,8 @@ function writeBypassed(list) {
|
|
|
9591
9664
|
}
|
|
9592
9665
|
}
|
|
9593
9666
|
function useBypass(key) {
|
|
9594
|
-
const [on, setOn] =
|
|
9595
|
-
|
|
9667
|
+
const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
9668
|
+
React52.useEffect(() => {
|
|
9596
9669
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
9597
9670
|
}, [key]);
|
|
9598
9671
|
const set = (next) => {
|
|
@@ -9639,9 +9712,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
9639
9712
|
] });
|
|
9640
9713
|
}
|
|
9641
9714
|
function useHoverCard(open) {
|
|
9642
|
-
const anchor =
|
|
9643
|
-
const [pos, setPos] =
|
|
9644
|
-
|
|
9715
|
+
const anchor = React52.useRef(null);
|
|
9716
|
+
const [pos, setPos] = React52.useState(null);
|
|
9717
|
+
React52.useLayoutEffect(() => {
|
|
9645
9718
|
if (!open || !anchor.current) {
|
|
9646
9719
|
setPos(null);
|
|
9647
9720
|
return;
|
|
@@ -9768,10 +9841,10 @@ function ComingSoon({
|
|
|
9768
9841
|
] });
|
|
9769
9842
|
}
|
|
9770
9843
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
9771
|
-
const [open, setOpen] =
|
|
9844
|
+
const [open, setOpen] = React52.useState(false);
|
|
9772
9845
|
const [anchor, pos] = useHoverCard(open);
|
|
9773
9846
|
const zIndex = useOverlayLayer(open);
|
|
9774
|
-
const close =
|
|
9847
|
+
const close = React52.useRef(null);
|
|
9775
9848
|
const show = () => {
|
|
9776
9849
|
if (close.current) {
|
|
9777
9850
|
clearTimeout(close.current);
|
|
@@ -9787,7 +9860,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
9787
9860
|
setOpen(false);
|
|
9788
9861
|
}, 140);
|
|
9789
9862
|
};
|
|
9790
|
-
|
|
9863
|
+
React52.useEffect(() => () => {
|
|
9791
9864
|
if (close.current) clearTimeout(close.current);
|
|
9792
9865
|
}, []);
|
|
9793
9866
|
return /* @__PURE__ */ jsxs70(
|
|
@@ -9958,14 +10031,14 @@ function PermissionHint({ perm, children }) {
|
|
|
9958
10031
|
}
|
|
9959
10032
|
|
|
9960
10033
|
// src/components/platform/ModeSwitch.tsx
|
|
9961
|
-
import * as
|
|
10034
|
+
import * as React53 from "react";
|
|
9962
10035
|
import { Fragment as Fragment21, jsx as jsx78, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
9963
10036
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
9964
10037
|
const mode2 = useRuntimeMode();
|
|
9965
|
-
const [open, setOpen] =
|
|
10038
|
+
const [open, setOpen] = React53.useState(false);
|
|
9966
10039
|
const zIndex = useOverlayLayer(open);
|
|
9967
|
-
const ref =
|
|
9968
|
-
|
|
10040
|
+
const ref = React53.useRef(null);
|
|
10041
|
+
React53.useEffect(() => {
|
|
9969
10042
|
if (!open) return;
|
|
9970
10043
|
const away = (e) => {
|
|
9971
10044
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -10221,7 +10294,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
10221
10294
|
}
|
|
10222
10295
|
|
|
10223
10296
|
// src/components/planner/MixGap.tsx
|
|
10224
|
-
import * as
|
|
10297
|
+
import * as React54 from "react";
|
|
10225
10298
|
import { Fragment as Fragment22, jsx as jsx81, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
10226
10299
|
var MIX_GAP_LAYOUT = {
|
|
10227
10300
|
trackHeight: 30,
|
|
@@ -10236,7 +10309,7 @@ function mixGapOffset(value, max) {
|
|
|
10236
10309
|
}
|
|
10237
10310
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
10238
10311
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
10239
|
-
const [hover, setHover] =
|
|
10312
|
+
const [hover, setHover] = React54.useState(null);
|
|
10240
10313
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
10241
10314
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
10242
10315
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
@@ -10379,7 +10452,7 @@ function ChannelContribution({
|
|
|
10379
10452
|
}
|
|
10380
10453
|
|
|
10381
10454
|
// src/components/planner/BudgetReallocator.tsx
|
|
10382
|
-
import * as
|
|
10455
|
+
import * as React55 from "react";
|
|
10383
10456
|
import { Fragment as Fragment23, jsx as jsx83, jsxs as jsxs77 } from "react/jsx-runtime";
|
|
10384
10457
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
10385
10458
|
function BudgetReallocator({
|
|
@@ -10395,8 +10468,8 @@ function BudgetReallocator({
|
|
|
10395
10468
|
onCancel,
|
|
10396
10469
|
className = ""
|
|
10397
10470
|
}) {
|
|
10398
|
-
const [draft, setDraft] =
|
|
10399
|
-
|
|
10471
|
+
const [draft, setDraft] = React55.useState(spend);
|
|
10472
|
+
React55.useEffect(() => setDraft(spend), [spend]);
|
|
10400
10473
|
const dirty = draft !== spend;
|
|
10401
10474
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
10402
10475
|
const nextBand = bandFor(nextCrp);
|
|
@@ -10411,10 +10484,10 @@ function BudgetReallocator({
|
|
|
10411
10484
|
setDraft(spend);
|
|
10412
10485
|
if (onCancel) onCancel();
|
|
10413
10486
|
};
|
|
10414
|
-
const trackRef =
|
|
10415
|
-
const chipRef =
|
|
10416
|
-
const [chipLeft, setChipLeft] =
|
|
10417
|
-
|
|
10487
|
+
const trackRef = React55.useRef(null);
|
|
10488
|
+
const chipRef = React55.useRef(null);
|
|
10489
|
+
const [chipLeft, setChipLeft] = React55.useState(null);
|
|
10490
|
+
React55.useLayoutEffect(() => {
|
|
10418
10491
|
const track = trackRef.current;
|
|
10419
10492
|
if (!dirty || !track) {
|
|
10420
10493
|
setChipLeft(null);
|
|
@@ -10601,7 +10674,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
10601
10674
|
}
|
|
10602
10675
|
|
|
10603
10676
|
// src/components/planner/PreferenceMeter.tsx
|
|
10604
|
-
import * as
|
|
10677
|
+
import * as React56 from "react";
|
|
10605
10678
|
import { jsx as jsx86, jsxs as jsxs80 } from "react/jsx-runtime";
|
|
10606
10679
|
function preferenceScore(criteria) {
|
|
10607
10680
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -10631,7 +10704,7 @@ function PreferenceMeter({
|
|
|
10631
10704
|
className = ""
|
|
10632
10705
|
}) {
|
|
10633
10706
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
10634
|
-
const segments =
|
|
10707
|
+
const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
10635
10708
|
return /* @__PURE__ */ jsx86(
|
|
10636
10709
|
ScoreMeter,
|
|
10637
10710
|
{
|
|
@@ -10670,10 +10743,10 @@ function PreferenceMeter({
|
|
|
10670
10743
|
}
|
|
10671
10744
|
|
|
10672
10745
|
// src/components/chat/AgentChatPanel.tsx
|
|
10673
|
-
import * as
|
|
10746
|
+
import * as React62 from "react";
|
|
10674
10747
|
|
|
10675
10748
|
// src/components/chat/chatEngine.ts
|
|
10676
|
-
import * as
|
|
10749
|
+
import * as React57 from "react";
|
|
10677
10750
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
10678
10751
|
var JOB_PENDING = ["queued", "running"];
|
|
10679
10752
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -10727,22 +10800,22 @@ function useChatEngine(opts) {
|
|
|
10727
10800
|
onClear,
|
|
10728
10801
|
onFeedback
|
|
10729
10802
|
} = opts || {};
|
|
10730
|
-
const [status, setStatus] =
|
|
10731
|
-
const [threadId, setThreadId] =
|
|
10732
|
-
const [messages, setMessages] =
|
|
10733
|
-
const [queue, setQueue] =
|
|
10734
|
-
const [fatal, setFatal] =
|
|
10735
|
-
const [busy, setBusy] =
|
|
10736
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
10737
|
-
const listRef =
|
|
10738
|
-
const queueRef =
|
|
10739
|
-
const busyRef =
|
|
10740
|
-
const stoppedRef =
|
|
10741
|
-
const abortRef =
|
|
10742
|
-
const serverCount =
|
|
10743
|
-
const threadRef =
|
|
10744
|
-
const mounted =
|
|
10745
|
-
|
|
10803
|
+
const [status, setStatus] = React57.useState("idle");
|
|
10804
|
+
const [threadId, setThreadId] = React57.useState(null);
|
|
10805
|
+
const [messages, setMessages] = React57.useState([]);
|
|
10806
|
+
const [queue, setQueue] = React57.useState([]);
|
|
10807
|
+
const [fatal, setFatal] = React57.useState(null);
|
|
10808
|
+
const [busy, setBusy] = React57.useState(false);
|
|
10809
|
+
const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
|
|
10810
|
+
const listRef = React57.useRef([]);
|
|
10811
|
+
const queueRef = React57.useRef([]);
|
|
10812
|
+
const busyRef = React57.useRef(false);
|
|
10813
|
+
const stoppedRef = React57.useRef(false);
|
|
10814
|
+
const abortRef = React57.useRef(null);
|
|
10815
|
+
const serverCount = React57.useRef(0);
|
|
10816
|
+
const threadRef = React57.useRef(null);
|
|
10817
|
+
const mounted = React57.useRef(true);
|
|
10818
|
+
React57.useEffect(() => {
|
|
10746
10819
|
mounted.current = true;
|
|
10747
10820
|
return () => {
|
|
10748
10821
|
mounted.current = false;
|
|
@@ -10764,14 +10837,14 @@ function useChatEngine(opts) {
|
|
|
10764
10837
|
}
|
|
10765
10838
|
return false;
|
|
10766
10839
|
};
|
|
10767
|
-
const loadThread =
|
|
10840
|
+
const loadThread = React57.useCallback(async (id) => {
|
|
10768
10841
|
const data = await apiAdapter.getThread(id);
|
|
10769
10842
|
const list = [...data && data.messages || []];
|
|
10770
10843
|
serverCount.current = list.length;
|
|
10771
10844
|
commit(list);
|
|
10772
10845
|
return list;
|
|
10773
10846
|
}, [apiAdapter]);
|
|
10774
|
-
|
|
10847
|
+
React57.useEffect(() => {
|
|
10775
10848
|
if (!apiAdapter) {
|
|
10776
10849
|
setStatus("idle");
|
|
10777
10850
|
setFatal(null);
|
|
@@ -10984,7 +11057,7 @@ function useChatEngine(opts) {
|
|
|
10984
11057
|
await dispatchTurn(turn);
|
|
10985
11058
|
}
|
|
10986
11059
|
}
|
|
10987
|
-
const send =
|
|
11060
|
+
const send = React57.useCallback((text, attachments) => {
|
|
10988
11061
|
const body = (text || "").trim();
|
|
10989
11062
|
if (!body && !(attachments && attachments.length)) return;
|
|
10990
11063
|
if (status === "disconnected") return;
|
|
@@ -10994,7 +11067,7 @@ function useChatEngine(opts) {
|
|
|
10994
11067
|
stoppedRef.current = false;
|
|
10995
11068
|
drain();
|
|
10996
11069
|
}, [status]);
|
|
10997
|
-
const stop =
|
|
11070
|
+
const stop = React57.useCallback(() => {
|
|
10998
11071
|
stoppedRef.current = true;
|
|
10999
11072
|
const ac = abortRef.current;
|
|
11000
11073
|
if (ac) {
|
|
@@ -11013,11 +11086,11 @@ function useChatEngine(opts) {
|
|
|
11013
11086
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
11014
11087
|
}
|
|
11015
11088
|
}, [apiAdapter]);
|
|
11016
|
-
const removeQueued =
|
|
11089
|
+
const removeQueued = React57.useCallback((id) => {
|
|
11017
11090
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
11018
11091
|
setQueue(queueRef.current.slice());
|
|
11019
11092
|
}, []);
|
|
11020
|
-
const retry =
|
|
11093
|
+
const retry = React57.useCallback(() => {
|
|
11021
11094
|
const list = listRef.current;
|
|
11022
11095
|
let at = -1;
|
|
11023
11096
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -11033,19 +11106,19 @@ function useChatEngine(opts) {
|
|
|
11033
11106
|
setQueue(queueRef.current.slice());
|
|
11034
11107
|
drain();
|
|
11035
11108
|
}, []);
|
|
11036
|
-
const clear =
|
|
11109
|
+
const clear = React57.useCallback(() => {
|
|
11037
11110
|
commit([]);
|
|
11038
11111
|
serverCount.current = 0;
|
|
11039
11112
|
queueRef.current = [];
|
|
11040
11113
|
setQueue([]);
|
|
11041
11114
|
onClear && onClear();
|
|
11042
11115
|
}, [onClear]);
|
|
11043
|
-
const setFeedback =
|
|
11116
|
+
const setFeedback = React57.useCallback((id, value) => {
|
|
11044
11117
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
11045
11118
|
const msg = listRef.current.find((m) => m.id === id);
|
|
11046
11119
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
11047
11120
|
}, [onFeedback]);
|
|
11048
|
-
const reload =
|
|
11121
|
+
const reload = React57.useCallback(async () => {
|
|
11049
11122
|
if (!threadRef.current) return;
|
|
11050
11123
|
setStatus("loading");
|
|
11051
11124
|
try {
|
|
@@ -11083,10 +11156,10 @@ var ChatKit = {
|
|
|
11083
11156
|
};
|
|
11084
11157
|
|
|
11085
11158
|
// src/components/chat/ChatTranscript.tsx
|
|
11086
|
-
import * as
|
|
11159
|
+
import * as React59 from "react";
|
|
11087
11160
|
|
|
11088
11161
|
// src/components/chat/ChatTurn.tsx
|
|
11089
|
-
import * as
|
|
11162
|
+
import * as React58 from "react";
|
|
11090
11163
|
import { jsx as jsx87, jsxs as jsxs81 } from "react/jsx-runtime";
|
|
11091
11164
|
function JsonView({ value }) {
|
|
11092
11165
|
let text;
|
|
@@ -11123,7 +11196,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
11123
11196
|
] });
|
|
11124
11197
|
}
|
|
11125
11198
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
11126
|
-
const [open, setOpen] =
|
|
11199
|
+
const [open, setOpen] = React58.useState(defaultOpen);
|
|
11127
11200
|
if (!text) return null;
|
|
11128
11201
|
return /* @__PURE__ */ jsxs81("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
11129
11202
|
/* @__PURE__ */ jsxs81("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11140,7 +11213,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
11140
11213
|
] });
|
|
11141
11214
|
}
|
|
11142
11215
|
function Citations({ items = [], onOpen }) {
|
|
11143
|
-
const [open, setOpen] =
|
|
11216
|
+
const [open, setOpen] = React58.useState(false);
|
|
11144
11217
|
if (!items.length) return null;
|
|
11145
11218
|
return /* @__PURE__ */ jsxs81("div", { className: "fdc-cites", children: [
|
|
11146
11219
|
/* @__PURE__ */ jsxs81("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11166,7 +11239,7 @@ function clampText(text, max) {
|
|
|
11166
11239
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
11167
11240
|
}
|
|
11168
11241
|
function MessageBody({ message: m, ctx }) {
|
|
11169
|
-
const [expanded, setExpanded] =
|
|
11242
|
+
const [expanded, setExpanded] = React58.useState(false);
|
|
11170
11243
|
const isUser = m.role === "user";
|
|
11171
11244
|
const raw = m.text || "";
|
|
11172
11245
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -11233,9 +11306,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
11233
11306
|
] });
|
|
11234
11307
|
}
|
|
11235
11308
|
function useCopyRun() {
|
|
11236
|
-
const [done, setDone] =
|
|
11237
|
-
const t =
|
|
11238
|
-
|
|
11309
|
+
const [done, setDone] = React58.useState(false);
|
|
11310
|
+
const t = React58.useRef(null);
|
|
11311
|
+
React58.useEffect(() => () => {
|
|
11239
11312
|
if (t.current) clearTimeout(t.current);
|
|
11240
11313
|
}, []);
|
|
11241
11314
|
return [done, (text) => {
|
|
@@ -11262,7 +11335,7 @@ function RunActions({ group, ctx }) {
|
|
|
11262
11335
|
] }),
|
|
11263
11336
|
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx87("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx87("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
11264
11337
|
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx87("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx87("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
11265
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs81(
|
|
11338
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs81(React58.Fragment, { children: [
|
|
11266
11339
|
/* @__PURE__ */ jsx87("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__ */ jsx87("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
11267
11340
|
/* @__PURE__ */ jsx87("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__ */ jsx87("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
11268
11341
|
] }) : null,
|
|
@@ -11357,10 +11430,10 @@ function ChatTranscript({
|
|
|
11357
11430
|
renderEmpty,
|
|
11358
11431
|
className = ""
|
|
11359
11432
|
}) {
|
|
11360
|
-
const scroller =
|
|
11361
|
-
const stick =
|
|
11362
|
-
const [pill, setPill] =
|
|
11363
|
-
const seen =
|
|
11433
|
+
const scroller = React59.useRef(null);
|
|
11434
|
+
const stick = React59.useRef(true);
|
|
11435
|
+
const [pill, setPill] = React59.useState(0);
|
|
11436
|
+
const seen = React59.useRef(0);
|
|
11364
11437
|
const toBottom = (smooth) => {
|
|
11365
11438
|
const el = scroller.current;
|
|
11366
11439
|
if (!el) return;
|
|
@@ -11379,7 +11452,7 @@ function ChatTranscript({
|
|
|
11379
11452
|
seen.current = messages.length;
|
|
11380
11453
|
}
|
|
11381
11454
|
};
|
|
11382
|
-
|
|
11455
|
+
React59.useLayoutEffect(() => {
|
|
11383
11456
|
const el = scroller.current;
|
|
11384
11457
|
if (!el) return;
|
|
11385
11458
|
if (stick.current) {
|
|
@@ -11387,7 +11460,7 @@ function ChatTranscript({
|
|
|
11387
11460
|
seen.current = messages.length;
|
|
11388
11461
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
11389
11462
|
}, [messages]);
|
|
11390
|
-
|
|
11463
|
+
React59.useEffect(() => {
|
|
11391
11464
|
const el = scroller.current;
|
|
11392
11465
|
const inner = el && el.firstChild;
|
|
11393
11466
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -11397,7 +11470,7 @@ function ChatTranscript({
|
|
|
11397
11470
|
ro.observe(inner);
|
|
11398
11471
|
return () => ro.disconnect();
|
|
11399
11472
|
}, []);
|
|
11400
|
-
const groups =
|
|
11473
|
+
const groups = React59.useMemo(() => groupMessages(messages), [messages]);
|
|
11401
11474
|
const empty = !messages.length && status === "ready";
|
|
11402
11475
|
return /* @__PURE__ */ jsxs82("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
11403
11476
|
/* @__PURE__ */ jsxs82("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -11421,7 +11494,7 @@ function ChatTranscript({
|
|
|
11421
11494
|
const prev = groups[i - 1];
|
|
11422
11495
|
const k = dayKey(g.messages[0].timestamp);
|
|
11423
11496
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
11424
|
-
return /* @__PURE__ */ jsxs82(
|
|
11497
|
+
return /* @__PURE__ */ jsxs82(React59.Fragment, { children: [
|
|
11425
11498
|
showDay ? /* @__PURE__ */ jsx88("div", { className: "fdc-day", children: /* @__PURE__ */ jsx88("span", { children: dayLabel(k) }) }) : null,
|
|
11426
11499
|
/* @__PURE__ */ jsx88(ChatTurn, { group: g, ctx })
|
|
11427
11500
|
] }, g.key || i);
|
|
@@ -11438,7 +11511,7 @@ function ChatTranscript({
|
|
|
11438
11511
|
var TranscriptKit = { groupMessages };
|
|
11439
11512
|
|
|
11440
11513
|
// src/components/chat/ChatComposer.tsx
|
|
11441
|
-
import * as
|
|
11514
|
+
import * as React60 from "react";
|
|
11442
11515
|
import { jsx as jsx89, jsxs as jsxs83 } from "react/jsx-runtime";
|
|
11443
11516
|
function ChatComposer({
|
|
11444
11517
|
onSubmit,
|
|
@@ -11466,17 +11539,17 @@ function ChatComposer({
|
|
|
11466
11539
|
onReject,
|
|
11467
11540
|
onOpenAttachment
|
|
11468
11541
|
}) {
|
|
11469
|
-
const [text, setText] =
|
|
11470
|
-
const [trigger, setTrigger] =
|
|
11471
|
-
const [mentionItems, setMentionItems] =
|
|
11472
|
-
const [listening, setListening] =
|
|
11473
|
-
const [notice, setNotice] =
|
|
11474
|
-
const editor =
|
|
11475
|
-
const wrap =
|
|
11476
|
-
const stopVoice =
|
|
11542
|
+
const [text, setText] = React60.useState(draft || "");
|
|
11543
|
+
const [trigger, setTrigger] = React60.useState(null);
|
|
11544
|
+
const [mentionItems, setMentionItems] = React60.useState([]);
|
|
11545
|
+
const [listening, setListening] = React60.useState(false);
|
|
11546
|
+
const [notice, setNotice] = React60.useState(null);
|
|
11547
|
+
const editor = React60.useRef(null);
|
|
11548
|
+
const wrap = React60.useRef(null);
|
|
11549
|
+
const stopVoice = React60.useRef(null);
|
|
11477
11550
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
11478
11551
|
} });
|
|
11479
|
-
|
|
11552
|
+
React60.useEffect(() => {
|
|
11480
11553
|
if (draft != null && draft !== text) setText(draft);
|
|
11481
11554
|
}, [draft]);
|
|
11482
11555
|
const change = (v) => {
|
|
@@ -11512,7 +11585,7 @@ function ChatComposer({
|
|
|
11512
11585
|
e.preventDefault();
|
|
11513
11586
|
staged.add(found.files);
|
|
11514
11587
|
};
|
|
11515
|
-
|
|
11588
|
+
React60.useEffect(() => {
|
|
11516
11589
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
11517
11590
|
setMentionItems([]);
|
|
11518
11591
|
return;
|
|
@@ -11530,7 +11603,7 @@ function ChatComposer({
|
|
|
11530
11603
|
const q = (trigger.query || "").toLowerCase();
|
|
11531
11604
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
11532
11605
|
}, [trigger, mentionSources]);
|
|
11533
|
-
const slashItems =
|
|
11606
|
+
const slashItems = React60.useMemo(() => {
|
|
11534
11607
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
11535
11608
|
const q = (trigger.query || "").toLowerCase();
|
|
11536
11609
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -11704,12 +11777,12 @@ function ChatComposer({
|
|
|
11704
11777
|
}
|
|
11705
11778
|
|
|
11706
11779
|
// src/components/chat/ChatSessionBar.tsx
|
|
11707
|
-
import * as
|
|
11780
|
+
import * as React61 from "react";
|
|
11708
11781
|
import { jsx as jsx90, jsxs as jsxs84 } from "react/jsx-runtime";
|
|
11709
11782
|
var compact2 = meterFormats.compact;
|
|
11710
11783
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
11711
|
-
const [open, setOpen] =
|
|
11712
|
-
const anchor =
|
|
11784
|
+
const [open, setOpen] = React61.useState(false);
|
|
11785
|
+
const anchor = React61.useRef(null);
|
|
11713
11786
|
const stats = sessionStats || null;
|
|
11714
11787
|
const cu = contextUsage || null;
|
|
11715
11788
|
const limits = usageLimits || null;
|
|
@@ -11724,7 +11797,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
11724
11797
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
11725
11798
|
if (cu) bits.push(pct + "% context");
|
|
11726
11799
|
const expandable = !!(cu || limits);
|
|
11727
|
-
return /* @__PURE__ */ jsxs84(
|
|
11800
|
+
return /* @__PURE__ */ jsxs84(React61.Fragment, { children: [
|
|
11728
11801
|
/* @__PURE__ */ jsxs84("div", { className: "fdc-bar", children: [
|
|
11729
11802
|
/* @__PURE__ */ jsxs84(
|
|
11730
11803
|
"button",
|
|
@@ -11865,7 +11938,7 @@ function ModelControls({
|
|
|
11865
11938
|
] })
|
|
11866
11939
|
});
|
|
11867
11940
|
}
|
|
11868
|
-
return /* @__PURE__ */ jsxs84(
|
|
11941
|
+
return /* @__PURE__ */ jsxs84(React61.Fragment, { children: [
|
|
11869
11942
|
/* @__PURE__ */ jsx90(
|
|
11870
11943
|
MenuButton,
|
|
11871
11944
|
{
|
|
@@ -11982,11 +12055,11 @@ function AgentChatPanel({
|
|
|
11982
12055
|
onFeedback,
|
|
11983
12056
|
onEditMessage
|
|
11984
12057
|
}) {
|
|
11985
|
-
const [panelWidth, setPanelWidth] =
|
|
11986
|
-
const [applied, setApplied] =
|
|
11987
|
-
const [draft, setDraft] =
|
|
11988
|
-
const dragging =
|
|
11989
|
-
|
|
12058
|
+
const [panelWidth, setPanelWidth] = React62.useState(width);
|
|
12059
|
+
const [applied, setApplied] = React62.useState({});
|
|
12060
|
+
const [draft, setDraft] = React62.useState("");
|
|
12061
|
+
const dragging = React62.useRef(null);
|
|
12062
|
+
React62.useEffect(() => setPanelWidth(width), [width]);
|
|
11990
12063
|
const engine = useChatEngine({
|
|
11991
12064
|
contextType,
|
|
11992
12065
|
contextId,
|
|
@@ -12190,7 +12263,7 @@ function AgentChatPanel({
|
|
|
12190
12263
|
}
|
|
12191
12264
|
|
|
12192
12265
|
// src/components/files/FileViewer.tsx
|
|
12193
|
-
import * as
|
|
12266
|
+
import * as React63 from "react";
|
|
12194
12267
|
import { jsx as jsx92, jsxs as jsxs86 } from "react/jsx-runtime";
|
|
12195
12268
|
function previewKindOf(file) {
|
|
12196
12269
|
const mime = (file.mime || "").toLowerCase();
|
|
@@ -12247,13 +12320,13 @@ function parseDelimited(text, delimiter) {
|
|
|
12247
12320
|
return rows;
|
|
12248
12321
|
}
|
|
12249
12322
|
function usePreview(file, kind, resolveUrl) {
|
|
12250
|
-
const [state, setState] =
|
|
12251
|
-
const [attempt, setAttempt] =
|
|
12252
|
-
const resolveRef =
|
|
12253
|
-
|
|
12323
|
+
const [state, setState] = React63.useState({ status: "loading" });
|
|
12324
|
+
const [attempt, setAttempt] = React63.useState(0);
|
|
12325
|
+
const resolveRef = React63.useRef(resolveUrl);
|
|
12326
|
+
React63.useEffect(() => {
|
|
12254
12327
|
resolveRef.current = resolveUrl;
|
|
12255
12328
|
}, [resolveUrl]);
|
|
12256
|
-
|
|
12329
|
+
React63.useEffect(() => {
|
|
12257
12330
|
if (kind === "none") {
|
|
12258
12331
|
setState({ status: "ready" });
|
|
12259
12332
|
return;
|
|
@@ -12283,7 +12356,7 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
12283
12356
|
if (ac) ac.abort();
|
|
12284
12357
|
};
|
|
12285
12358
|
}, [file.id, kind, attempt]);
|
|
12286
|
-
return { ...state, retry:
|
|
12359
|
+
return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
12287
12360
|
}
|
|
12288
12361
|
function PreviewBody({ file, kind, state }) {
|
|
12289
12362
|
if (kind === "image") return /* @__PURE__ */ jsx92("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
@@ -12328,13 +12401,13 @@ function PreviewBody({ file, kind, state }) {
|
|
|
12328
12401
|
] });
|
|
12329
12402
|
}
|
|
12330
12403
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
12331
|
-
const kind =
|
|
12404
|
+
const kind = React63.useMemo(() => previewKindOf(file), [file]);
|
|
12332
12405
|
const preview = usePreview(file, kind, resolveUrl);
|
|
12333
|
-
const [tab, setTab] =
|
|
12334
|
-
const [downloading, setDownloading] =
|
|
12335
|
-
const [downloadError, setDownloadError] =
|
|
12406
|
+
const [tab, setTab] = React63.useState("preview");
|
|
12407
|
+
const [downloading, setDownloading] = React63.useState(false);
|
|
12408
|
+
const [downloadError, setDownloadError] = React63.useState(null);
|
|
12336
12409
|
const hasSide = sidePanel != null;
|
|
12337
|
-
|
|
12410
|
+
React63.useEffect(() => {
|
|
12338
12411
|
setTab("preview");
|
|
12339
12412
|
}, [file.id]);
|
|
12340
12413
|
const download = () => {
|
|
@@ -12401,7 +12474,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
12401
12474
|
}
|
|
12402
12475
|
|
|
12403
12476
|
// src/components/files/FileBrowser.tsx
|
|
12404
|
-
import * as
|
|
12477
|
+
import * as React64 from "react";
|
|
12405
12478
|
import { Fragment as Fragment27, jsx as jsx93, jsxs as jsxs87 } from "react/jsx-runtime";
|
|
12406
12479
|
function childrenOf(folders, parentId) {
|
|
12407
12480
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -12472,10 +12545,10 @@ function FolderPickerMenu({
|
|
|
12472
12545
|
destinations,
|
|
12473
12546
|
onPick
|
|
12474
12547
|
}) {
|
|
12475
|
-
const [open, setOpen] =
|
|
12548
|
+
const [open, setOpen] = React64.useState(false);
|
|
12476
12549
|
const zIndex = useOverlayLayer(open);
|
|
12477
|
-
const ref =
|
|
12478
|
-
|
|
12550
|
+
const ref = React64.useRef(null);
|
|
12551
|
+
React64.useEffect(() => {
|
|
12479
12552
|
if (!open) return;
|
|
12480
12553
|
const away = (e) => {
|
|
12481
12554
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -12527,8 +12600,8 @@ function FolderPickerMenu({
|
|
|
12527
12600
|
] });
|
|
12528
12601
|
}
|
|
12529
12602
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
12530
|
-
const [over, setOver] =
|
|
12531
|
-
const dragCounter =
|
|
12603
|
+
const [over, setOver] = React64.useState(false);
|
|
12604
|
+
const dragCounter = React64.useRef(0);
|
|
12532
12605
|
const dropHandlers = isDropTarget ? {
|
|
12533
12606
|
onDragEnter: (e) => {
|
|
12534
12607
|
if (!hasInternalPayload(e)) return;
|
|
@@ -12576,8 +12649,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
12576
12649
|
}
|
|
12577
12650
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
12578
12651
|
const kids = childrenOf(folders, folder.id);
|
|
12579
|
-
const [expanded, setExpanded] =
|
|
12580
|
-
|
|
12652
|
+
const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
12653
|
+
React64.useEffect(() => {
|
|
12581
12654
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
12582
12655
|
}, [currentFolderId, folder.id, folders]);
|
|
12583
12656
|
const isCurrent = folder.id === currentFolderId;
|
|
@@ -12643,15 +12716,15 @@ function FileBrowser({
|
|
|
12643
12716
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
12644
12717
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
12645
12718
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
12646
|
-
const [createOpen, setCreateOpen] =
|
|
12647
|
-
const [createName, setCreateName] =
|
|
12648
|
-
const [renameTarget, setRenameTarget] =
|
|
12649
|
-
const [renameValue, setRenameValue] =
|
|
12650
|
-
const [deleteTarget, setDeleteTarget] =
|
|
12651
|
-
const uploadInputRef =
|
|
12652
|
-
const crumbFolders =
|
|
12653
|
-
const subfolders =
|
|
12654
|
-
const currentFiles =
|
|
12719
|
+
const [createOpen, setCreateOpen] = React64.useState(false);
|
|
12720
|
+
const [createName, setCreateName] = React64.useState("");
|
|
12721
|
+
const [renameTarget, setRenameTarget] = React64.useState(null);
|
|
12722
|
+
const [renameValue, setRenameValue] = React64.useState("");
|
|
12723
|
+
const [deleteTarget, setDeleteTarget] = React64.useState(null);
|
|
12724
|
+
const uploadInputRef = React64.useRef(null);
|
|
12725
|
+
const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12726
|
+
const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12727
|
+
const currentFiles = React64.useMemo(
|
|
12655
12728
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
12656
12729
|
[files, currentFolderId]
|
|
12657
12730
|
);
|
|
@@ -12883,8 +12956,8 @@ function BreadcrumbCrumb({
|
|
|
12883
12956
|
isDropTarget,
|
|
12884
12957
|
onDropPayload
|
|
12885
12958
|
}) {
|
|
12886
|
-
const [over, setOver] =
|
|
12887
|
-
const dragCounter =
|
|
12959
|
+
const [over, setOver] = React64.useState(false);
|
|
12960
|
+
const dragCounter = React64.useRef(0);
|
|
12888
12961
|
const dropHandlers = isDropTarget ? {
|
|
12889
12962
|
onDragEnter: (e) => {
|
|
12890
12963
|
if (!hasInternalPayload(e)) return;
|
|
@@ -12913,9 +12986,27 @@ function BreadcrumbCrumb({
|
|
|
12913
12986
|
}
|
|
12914
12987
|
|
|
12915
12988
|
// src/kits/query.ts
|
|
12916
|
-
import * as
|
|
12989
|
+
import * as React65 from "react";
|
|
12990
|
+
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
12991
|
+
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
12992
|
+
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
12993
|
+
function isActiveFilterValue(v) {
|
|
12994
|
+
if (v == null || v === "" || v === false) return false;
|
|
12995
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
12996
|
+
if (isMultiSelectShaped(v)) return v.values.length > 0;
|
|
12997
|
+
if (isRangeShaped(v)) return v.min != null || v.max != null;
|
|
12998
|
+
if (isDateShaped(v)) return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
12999
|
+
return true;
|
|
13000
|
+
}
|
|
12917
13001
|
function eqFilter(get2) {
|
|
12918
|
-
return (row, value) =>
|
|
13002
|
+
return (row, value) => {
|
|
13003
|
+
if (Array.isArray(value)) return value.includes(get2(row));
|
|
13004
|
+
if (isMultiSelectShaped(value)) {
|
|
13005
|
+
const hit = value.values.some((o) => o.value === get2(row));
|
|
13006
|
+
return value.operator === "notIn" ? !hit : hit;
|
|
13007
|
+
}
|
|
13008
|
+
return get2(row) === value;
|
|
13009
|
+
};
|
|
12919
13010
|
}
|
|
12920
13011
|
function anyOfFilter(get2) {
|
|
12921
13012
|
return (row, value) => {
|
|
@@ -12926,10 +13017,15 @@ function anyOfFilter(get2) {
|
|
|
12926
13017
|
function rangeFilter(get2) {
|
|
12927
13018
|
return (row, value) => {
|
|
12928
13019
|
const n = get2(row);
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
13020
|
+
let lo = 0;
|
|
13021
|
+
let hi = Number.POSITIVE_INFINITY;
|
|
13022
|
+
if (Array.isArray(value)) {
|
|
13023
|
+
lo = Number(value[0] ?? 0);
|
|
13024
|
+
hi = value[1] == null ? Number.POSITIVE_INFINITY : Number(value[1]);
|
|
13025
|
+
} else if (isRangeShaped(value)) {
|
|
13026
|
+
lo = value.min ?? 0;
|
|
13027
|
+
hi = value.max ?? Number.POSITIVE_INFINITY;
|
|
13028
|
+
}
|
|
12933
13029
|
return n >= lo && (hi === Number.POSITIVE_INFINITY || n <= hi);
|
|
12934
13030
|
};
|
|
12935
13031
|
}
|
|
@@ -12945,22 +13041,22 @@ function compare(a, b, dir) {
|
|
|
12945
13041
|
var API = null;
|
|
12946
13042
|
var PREFS = null;
|
|
12947
13043
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
12948
|
-
const [query, setQuery] =
|
|
13044
|
+
const [query, setQuery] = React65.useState(() => {
|
|
12949
13045
|
const store = PREFS || window.PlannerPrefs;
|
|
12950
13046
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
12951
13047
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
12952
13048
|
});
|
|
12953
|
-
const savePref =
|
|
13049
|
+
const savePref = React65.useCallback((patch2) => {
|
|
12954
13050
|
const store = PREFS || window.PlannerPrefs;
|
|
12955
13051
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
12956
13052
|
}, [prefsKey]);
|
|
12957
|
-
const [res, setRes] =
|
|
12958
|
-
const [loading, setLoading] =
|
|
12959
|
-
const seq2 =
|
|
13053
|
+
const [res, setRes] = React65.useState(null);
|
|
13054
|
+
const [loading, setLoading] = React65.useState(true);
|
|
13055
|
+
const seq2 = React65.useRef(0);
|
|
12960
13056
|
const depKey = (deps || []).join("|");
|
|
12961
13057
|
const paramKey = JSON.stringify(params || {});
|
|
12962
13058
|
const queryKey = JSON.stringify(query);
|
|
12963
|
-
|
|
13059
|
+
React65.useEffect(() => {
|
|
12964
13060
|
const id = ++seq2.current;
|
|
12965
13061
|
setLoading(true);
|
|
12966
13062
|
const t = setTimeout(() => {
|
|
@@ -12996,7 +13092,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
|
12996
13092
|
loading,
|
|
12997
13093
|
/** True only on the very first load — later loads keep showing stale rows. */
|
|
12998
13094
|
initialLoading: loading && !res,
|
|
12999
|
-
activeFilterCount: Object.values(query.filters).filter(
|
|
13095
|
+
activeFilterCount: Object.values(query.filters).filter(isActiveFilterValue).length,
|
|
13000
13096
|
setPage: (page) => patch({ page }, false),
|
|
13001
13097
|
setPageSize: (pageSize) => {
|
|
13002
13098
|
savePref({ pageSize });
|
|
@@ -13059,7 +13155,6 @@ var QueryKit = {
|
|
|
13059
13155
|
const Q = { ...DEFAULTS, ...query || {} };
|
|
13060
13156
|
const c = cfg;
|
|
13061
13157
|
const filters = Q.filters || {};
|
|
13062
|
-
const active = (v) => !(v == null || v === "" || v === false || Array.isArray(v) && !v.length);
|
|
13063
13158
|
let out = rows;
|
|
13064
13159
|
const term = (Q.q || "").trim().toLowerCase();
|
|
13065
13160
|
if (term && c.searchKeys) {
|
|
@@ -13069,7 +13164,7 @@ var QueryKit = {
|
|
|
13069
13164
|
const searched = out;
|
|
13070
13165
|
Object.entries(filters).forEach(([id, val]) => {
|
|
13071
13166
|
const fn = c.filters && c.filters[id];
|
|
13072
|
-
if (!
|
|
13167
|
+
if (!isActiveFilterValue(val) || !fn) return;
|
|
13073
13168
|
out = out.filter((r) => fn(r, val));
|
|
13074
13169
|
});
|
|
13075
13170
|
const matched = out;
|
|
@@ -13116,9 +13211,30 @@ var QueryKit = {
|
|
|
13116
13211
|
if (Q.sort) parts.push("sort=" + Q.sort + "&dir=" + Q.dir);
|
|
13117
13212
|
if (Q.q) parts.push("q=" + encodeURIComponent(Q.q));
|
|
13118
13213
|
Object.entries(Q.filters || {}).forEach(([k, v]) => {
|
|
13119
|
-
if (
|
|
13120
|
-
if (Array.isArray(v))
|
|
13121
|
-
|
|
13214
|
+
if (!isActiveFilterValue(v)) return;
|
|
13215
|
+
if (Array.isArray(v)) {
|
|
13216
|
+
v.forEach((x) => parts.push(k + "=" + encodeURIComponent(x === Infinity ? "*" : x)));
|
|
13217
|
+
return;
|
|
13218
|
+
}
|
|
13219
|
+
if (isMultiSelectShaped(v)) {
|
|
13220
|
+
const prefix = v.operator === "notIn" ? "notIn:" : "";
|
|
13221
|
+
v.values.forEach((o) => parts.push(k + "=" + encodeURIComponent(prefix + String(o.value))));
|
|
13222
|
+
return;
|
|
13223
|
+
}
|
|
13224
|
+
if (isRangeShaped(v)) {
|
|
13225
|
+
if (v.min != null) parts.push(k + ".min=" + encodeURIComponent(String(v.min)));
|
|
13226
|
+
if (v.max != null) parts.push(k + ".max=" + encodeURIComponent(String(v.max)));
|
|
13227
|
+
return;
|
|
13228
|
+
}
|
|
13229
|
+
if (isDateShaped(v)) {
|
|
13230
|
+
if (v.kind === "withinDays") parts.push(k + "=withinDays:" + encodeURIComponent(String(v.days)));
|
|
13231
|
+
else {
|
|
13232
|
+
parts.push(k + ".from=" + encodeURIComponent(String(v.from)));
|
|
13233
|
+
parts.push(k + ".to=" + encodeURIComponent(String(v.to)));
|
|
13234
|
+
}
|
|
13235
|
+
return;
|
|
13236
|
+
}
|
|
13237
|
+
parts.push(k + "=" + encodeURIComponent(v));
|
|
13122
13238
|
});
|
|
13123
13239
|
return parts.join("&");
|
|
13124
13240
|
},
|
|
@@ -13259,12 +13375,12 @@ function createVersionStore(initialState, options) {
|
|
|
13259
13375
|
}
|
|
13260
13376
|
|
|
13261
13377
|
// src/kits/documentTitle.ts
|
|
13262
|
-
import * as
|
|
13378
|
+
import * as React66 from "react";
|
|
13263
13379
|
function formatDocumentTitle(routeTitle, appName) {
|
|
13264
13380
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
13265
13381
|
}
|
|
13266
13382
|
function useDocumentTitle(routeTitle, appName) {
|
|
13267
|
-
|
|
13383
|
+
React66.useEffect(() => {
|
|
13268
13384
|
if (typeof document === "undefined") return;
|
|
13269
13385
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
13270
13386
|
}, [routeTitle, appName]);
|