@flytedan/flytebot-design-system 0.12.15 → 0.14.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 +558 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +557 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +234 -0
package/dist/index.js
CHANGED
|
@@ -8464,6 +8464,30 @@ function BudgetReallocator({
|
|
|
8464
8464
|
setDraft(spend);
|
|
8465
8465
|
if (onCancel) onCancel();
|
|
8466
8466
|
};
|
|
8467
|
+
const trackRef = React39.useRef(null);
|
|
8468
|
+
const chipRef = React39.useRef(null);
|
|
8469
|
+
const [chipLeft, setChipLeft] = React39.useState(null);
|
|
8470
|
+
React39.useLayoutEffect(() => {
|
|
8471
|
+
const track = trackRef.current;
|
|
8472
|
+
if (!dirty || !track) {
|
|
8473
|
+
setChipLeft(null);
|
|
8474
|
+
return;
|
|
8475
|
+
}
|
|
8476
|
+
const measure = () => {
|
|
8477
|
+
const chip = chipRef.current;
|
|
8478
|
+
if (!chip) return;
|
|
8479
|
+
const trackWidth = track.clientWidth;
|
|
8480
|
+
const chipWidth = chip.offsetWidth;
|
|
8481
|
+
const half = chipWidth / 2;
|
|
8482
|
+
const desired = pct / 100 * trackWidth;
|
|
8483
|
+
setChipLeft(Math.min(Math.max(desired, half), Math.max(trackWidth - half, half)));
|
|
8484
|
+
};
|
|
8485
|
+
measure();
|
|
8486
|
+
if (typeof ResizeObserver !== "function") return;
|
|
8487
|
+
const ro = new ResizeObserver(measure);
|
|
8488
|
+
ro.observe(track);
|
|
8489
|
+
return () => ro.disconnect();
|
|
8490
|
+
}, [dirty, pct]);
|
|
8467
8491
|
return /* @__PURE__ */ jsxs64(
|
|
8468
8492
|
"div",
|
|
8469
8493
|
{
|
|
@@ -8478,9 +8502,20 @@ function BudgetReallocator({
|
|
|
8478
8502
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
8479
8503
|
] }) : null
|
|
8480
8504
|
] }),
|
|
8481
|
-
/* @__PURE__ */ jsxs64("div", { className: "fd-slider", children: [
|
|
8505
|
+
/* @__PURE__ */ jsxs64("div", { className: "fd-slider", ref: trackRef, children: [
|
|
8482
8506
|
/* @__PURE__ */ jsx68("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
8483
|
-
dirty ? /* @__PURE__ */ jsx68(
|
|
8507
|
+
dirty ? /* @__PURE__ */ jsx68(
|
|
8508
|
+
"span",
|
|
8509
|
+
{
|
|
8510
|
+
ref: chipRef,
|
|
8511
|
+
className: "fd-slider-chip",
|
|
8512
|
+
style: {
|
|
8513
|
+
left: chipLeft === null ? pct + "%" : chipLeft,
|
|
8514
|
+
background: delta < 0 ? "var(--danger-solid)" : "var(--ok-solid)"
|
|
8515
|
+
},
|
|
8516
|
+
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
8517
|
+
}
|
|
8518
|
+
) : null,
|
|
8484
8519
|
/* @__PURE__ */ jsx68(
|
|
8485
8520
|
"input",
|
|
8486
8521
|
{
|
|
@@ -10418,8 +10453,520 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
10418
10453
|
);
|
|
10419
10454
|
}
|
|
10420
10455
|
|
|
10421
|
-
// src/
|
|
10456
|
+
// src/components/files/FileBrowser.tsx
|
|
10422
10457
|
import * as React48 from "react";
|
|
10458
|
+
import { Fragment as Fragment23, jsx as jsx78, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
10459
|
+
function childrenOf(folders, parentId) {
|
|
10460
|
+
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
10461
|
+
}
|
|
10462
|
+
function ancestorsOf(folders, id) {
|
|
10463
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
10464
|
+
const chain = [];
|
|
10465
|
+
let cur = id != null ? byId.get(id) : void 0;
|
|
10466
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10467
|
+
while (cur && !seen.has(cur.id)) {
|
|
10468
|
+
seen.add(cur.id);
|
|
10469
|
+
chain.unshift(cur);
|
|
10470
|
+
cur = cur.parentId != null ? byId.get(cur.parentId) : void 0;
|
|
10471
|
+
}
|
|
10472
|
+
return chain;
|
|
10473
|
+
}
|
|
10474
|
+
function isSelfOrDescendant(folders, ancestorId, nodeId) {
|
|
10475
|
+
if (nodeId == null) return false;
|
|
10476
|
+
if (nodeId === ancestorId) return true;
|
|
10477
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
10478
|
+
folders.forEach((f) => {
|
|
10479
|
+
const key = f.parentId ?? "";
|
|
10480
|
+
if (!byParent.has(key)) byParent.set(key, []);
|
|
10481
|
+
byParent.get(key).push(f);
|
|
10482
|
+
});
|
|
10483
|
+
const stack = [...byParent.get(ancestorId) || []];
|
|
10484
|
+
while (stack.length) {
|
|
10485
|
+
const next = stack.pop();
|
|
10486
|
+
if (next.id === nodeId) return true;
|
|
10487
|
+
stack.push(...byParent.get(next.id) || []);
|
|
10488
|
+
}
|
|
10489
|
+
return false;
|
|
10490
|
+
}
|
|
10491
|
+
function flattenDestinations(folders, excludeSubtreeOf) {
|
|
10492
|
+
const out = [{ id: null, name: "Home", depth: 0 }];
|
|
10493
|
+
const walk = (parentId, depth) => {
|
|
10494
|
+
childrenOf(folders, parentId).forEach((f) => {
|
|
10495
|
+
if (excludeSubtreeOf && isSelfOrDescendant(folders, excludeSubtreeOf, f.id)) return;
|
|
10496
|
+
out.push({ id: f.id, name: f.name, depth });
|
|
10497
|
+
walk(f.id, depth + 1);
|
|
10498
|
+
});
|
|
10499
|
+
};
|
|
10500
|
+
walk(null, 1);
|
|
10501
|
+
return out;
|
|
10502
|
+
}
|
|
10503
|
+
var DND_MIME = "application/x-fd-filebrowser";
|
|
10504
|
+
function writeDragPayload(e, payload) {
|
|
10505
|
+
const s = JSON.stringify(payload);
|
|
10506
|
+
e.dataTransfer.setData(DND_MIME, s);
|
|
10507
|
+
e.dataTransfer.setData("text/plain", s);
|
|
10508
|
+
e.dataTransfer.effectAllowed = "move";
|
|
10509
|
+
}
|
|
10510
|
+
function readDragPayload(e) {
|
|
10511
|
+
const raw = e.dataTransfer.getData(DND_MIME) || e.dataTransfer.getData("text/plain");
|
|
10512
|
+
if (!raw) return null;
|
|
10513
|
+
try {
|
|
10514
|
+
const parsed = JSON.parse(raw);
|
|
10515
|
+
if (parsed && (parsed.kind === "file" || parsed.kind === "folder") && typeof parsed.id === "string") return parsed;
|
|
10516
|
+
} catch {
|
|
10517
|
+
}
|
|
10518
|
+
return null;
|
|
10519
|
+
}
|
|
10520
|
+
function hasInternalPayload(e) {
|
|
10521
|
+
return Array.from(e.dataTransfer.types || []).indexOf(DND_MIME) !== -1;
|
|
10522
|
+
}
|
|
10523
|
+
function FolderPickerMenu({
|
|
10524
|
+
label,
|
|
10525
|
+
destinations,
|
|
10526
|
+
onPick
|
|
10527
|
+
}) {
|
|
10528
|
+
const [open, setOpen] = React48.useState(false);
|
|
10529
|
+
const zIndex = useOverlayLayer(open);
|
|
10530
|
+
const ref = React48.useRef(null);
|
|
10531
|
+
React48.useEffect(() => {
|
|
10532
|
+
if (!open) return;
|
|
10533
|
+
const away = (e) => {
|
|
10534
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
10535
|
+
};
|
|
10536
|
+
const esc = (e) => {
|
|
10537
|
+
if (e.key === "Escape") setOpen(false);
|
|
10538
|
+
};
|
|
10539
|
+
document.addEventListener("pointerdown", away);
|
|
10540
|
+
document.addEventListener("keydown", esc);
|
|
10541
|
+
return () => {
|
|
10542
|
+
document.removeEventListener("pointerdown", away);
|
|
10543
|
+
document.removeEventListener("keydown", esc);
|
|
10544
|
+
};
|
|
10545
|
+
}, [open]);
|
|
10546
|
+
return /* @__PURE__ */ jsxs74("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
10547
|
+
/* @__PURE__ */ jsx78(
|
|
10548
|
+
IconButton,
|
|
10549
|
+
{
|
|
10550
|
+
icon: "arrows-out-cardinal",
|
|
10551
|
+
label,
|
|
10552
|
+
size: "sm",
|
|
10553
|
+
variant: "ghost",
|
|
10554
|
+
"aria-haspopup": "menu",
|
|
10555
|
+
"aria-expanded": open,
|
|
10556
|
+
onClick: () => setOpen((v) => !v)
|
|
10557
|
+
}
|
|
10558
|
+
),
|
|
10559
|
+
open ? /* @__PURE__ */ jsx78(LayerProvider, { zIndex, children: /* @__PURE__ */ jsxs74("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
|
|
10560
|
+
/* @__PURE__ */ jsx78("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
10561
|
+
destinations.map((d) => /* @__PURE__ */ jsxs74(
|
|
10562
|
+
"button",
|
|
10563
|
+
{
|
|
10564
|
+
type: "button",
|
|
10565
|
+
role: "menuitem",
|
|
10566
|
+
className: "fd-fb-menu-item",
|
|
10567
|
+
style: { paddingLeft: 10 + d.depth * 14 },
|
|
10568
|
+
onClick: () => {
|
|
10569
|
+
onPick(d.id);
|
|
10570
|
+
setOpen(false);
|
|
10571
|
+
},
|
|
10572
|
+
children: [
|
|
10573
|
+
/* @__PURE__ */ jsx78("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
10574
|
+
d.name
|
|
10575
|
+
]
|
|
10576
|
+
},
|
|
10577
|
+
d.id ?? "__root__"
|
|
10578
|
+
))
|
|
10579
|
+
] }) }) : null
|
|
10580
|
+
] });
|
|
10581
|
+
}
|
|
10582
|
+
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
10583
|
+
const [over, setOver] = React48.useState(false);
|
|
10584
|
+
const dragCounter = React48.useRef(0);
|
|
10585
|
+
const dropHandlers = isDropTarget ? {
|
|
10586
|
+
onDragEnter: (e) => {
|
|
10587
|
+
if (!hasInternalPayload(e)) return;
|
|
10588
|
+
dragCounter.current++;
|
|
10589
|
+
setOver(true);
|
|
10590
|
+
},
|
|
10591
|
+
onDragOver: (e) => {
|
|
10592
|
+
if (!hasInternalPayload(e)) return;
|
|
10593
|
+
e.preventDefault();
|
|
10594
|
+
e.dataTransfer.dropEffect = "move";
|
|
10595
|
+
},
|
|
10596
|
+
onDragLeave: () => {
|
|
10597
|
+
dragCounter.current = Math.max(0, dragCounter.current - 1);
|
|
10598
|
+
if (!dragCounter.current) setOver(false);
|
|
10599
|
+
},
|
|
10600
|
+
onDrop: (e) => {
|
|
10601
|
+
if (!hasInternalPayload(e)) return;
|
|
10602
|
+
e.preventDefault();
|
|
10603
|
+
dragCounter.current = 0;
|
|
10604
|
+
setOver(false);
|
|
10605
|
+
const payload = readDragPayload(e);
|
|
10606
|
+
if (payload && onDropPayload) onDropPayload(payload);
|
|
10607
|
+
}
|
|
10608
|
+
} : {};
|
|
10609
|
+
return /* @__PURE__ */ jsxs74("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
10610
|
+
/* @__PURE__ */ jsxs74(
|
|
10611
|
+
"button",
|
|
10612
|
+
{
|
|
10613
|
+
type: "button",
|
|
10614
|
+
className: "fd-fb-row-main",
|
|
10615
|
+
onClick: onOpen,
|
|
10616
|
+
draggable: !!draggableId,
|
|
10617
|
+
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
10618
|
+
children: [
|
|
10619
|
+
/* @__PURE__ */ jsx78("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx78("i", { className: "ph ph-" + icon }) }),
|
|
10620
|
+
/* @__PURE__ */ jsxs74("span", { className: "fd-fb-row-text", children: [
|
|
10621
|
+
/* @__PURE__ */ jsx78("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
10622
|
+
meta ? /* @__PURE__ */ jsx78("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
10623
|
+
] })
|
|
10624
|
+
]
|
|
10625
|
+
}
|
|
10626
|
+
),
|
|
10627
|
+
actions ? /* @__PURE__ */ jsx78("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
10628
|
+
] });
|
|
10629
|
+
}
|
|
10630
|
+
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
10631
|
+
const kids = childrenOf(folders, folder.id);
|
|
10632
|
+
const [expanded, setExpanded] = React48.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
10633
|
+
React48.useEffect(() => {
|
|
10634
|
+
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
10635
|
+
}, [currentFolderId, folder.id, folders]);
|
|
10636
|
+
const isCurrent = folder.id === currentFolderId;
|
|
10637
|
+
return /* @__PURE__ */ jsxs74("div", { className: "fd-fb-tree-node", children: [
|
|
10638
|
+
/* @__PURE__ */ jsx78(
|
|
10639
|
+
RowShell,
|
|
10640
|
+
{
|
|
10641
|
+
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
10642
|
+
name: folder.name,
|
|
10643
|
+
onOpen: () => onNavigate(folder.id),
|
|
10644
|
+
draggableId: canMove ? { kind: "folder", id: folder.id } : void 0,
|
|
10645
|
+
isDropTarget: canMove,
|
|
10646
|
+
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
10647
|
+
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
10648
|
+
actions: kids.length ? /* @__PURE__ */ jsx78(
|
|
10649
|
+
IconButton,
|
|
10650
|
+
{
|
|
10651
|
+
icon: expanded ? "caret-down" : "caret-right",
|
|
10652
|
+
label: (expanded ? "Collapse " : "Expand ") + folder.name,
|
|
10653
|
+
size: "sm",
|
|
10654
|
+
variant: "ghost",
|
|
10655
|
+
onClick: () => setExpanded((v) => !v)
|
|
10656
|
+
}
|
|
10657
|
+
) : void 0
|
|
10658
|
+
}
|
|
10659
|
+
),
|
|
10660
|
+
expanded && kids.length ? /* @__PURE__ */ jsx78("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ jsx78(
|
|
10661
|
+
TreeNode,
|
|
10662
|
+
{
|
|
10663
|
+
folder: k,
|
|
10664
|
+
depth: depth + 1,
|
|
10665
|
+
folders,
|
|
10666
|
+
currentFolderId,
|
|
10667
|
+
onNavigate,
|
|
10668
|
+
onMoveInto,
|
|
10669
|
+
canMove
|
|
10670
|
+
},
|
|
10671
|
+
k.id
|
|
10672
|
+
)) }) : null
|
|
10673
|
+
] });
|
|
10674
|
+
}
|
|
10675
|
+
function FileBrowser({
|
|
10676
|
+
folders,
|
|
10677
|
+
files,
|
|
10678
|
+
currentFolderId,
|
|
10679
|
+
onNavigate,
|
|
10680
|
+
onCreateFolder,
|
|
10681
|
+
onRenameFolder,
|
|
10682
|
+
onMoveFolder,
|
|
10683
|
+
onMoveFile,
|
|
10684
|
+
onOpenFile,
|
|
10685
|
+
onRemoveFile,
|
|
10686
|
+
onDeleteFolder,
|
|
10687
|
+
onUpload,
|
|
10688
|
+
loading = false,
|
|
10689
|
+
permissions,
|
|
10690
|
+
className = ""
|
|
10691
|
+
}) {
|
|
10692
|
+
const perm = permissions || {};
|
|
10693
|
+
const canCreateFolder = perm.canCreateFolder !== false && !!onCreateFolder;
|
|
10694
|
+
const canRenameFolder = perm.canRenameFolder !== false && !!onRenameFolder;
|
|
10695
|
+
const canMove = perm.canMove !== false && (!!onMoveFolder || !!onMoveFile);
|
|
10696
|
+
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
10697
|
+
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
10698
|
+
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
10699
|
+
const [createOpen, setCreateOpen] = React48.useState(false);
|
|
10700
|
+
const [createName, setCreateName] = React48.useState("");
|
|
10701
|
+
const [renameTarget, setRenameTarget] = React48.useState(null);
|
|
10702
|
+
const [renameValue, setRenameValue] = React48.useState("");
|
|
10703
|
+
const [deleteTarget, setDeleteTarget] = React48.useState(null);
|
|
10704
|
+
const uploadInputRef = React48.useRef(null);
|
|
10705
|
+
const crumbFolders = React48.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
10706
|
+
const subfolders = React48.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
10707
|
+
const currentFiles = React48.useMemo(
|
|
10708
|
+
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
10709
|
+
[files, currentFolderId]
|
|
10710
|
+
);
|
|
10711
|
+
const isEmpty = !subfolders.length && !currentFiles.length;
|
|
10712
|
+
const moveIntoFolder = (payload, targetFolderId) => {
|
|
10713
|
+
if (payload.kind === "folder") {
|
|
10714
|
+
if (payload.id === targetFolderId) return;
|
|
10715
|
+
if (isSelfOrDescendant(folders, payload.id, targetFolderId)) return;
|
|
10716
|
+
onMoveFolder && onMoveFolder(payload.id, targetFolderId);
|
|
10717
|
+
} else {
|
|
10718
|
+
onMoveFile && onMoveFile(payload.id, targetFolderId);
|
|
10719
|
+
}
|
|
10720
|
+
};
|
|
10721
|
+
const openCreate = () => {
|
|
10722
|
+
setCreateName("");
|
|
10723
|
+
setCreateOpen(true);
|
|
10724
|
+
};
|
|
10725
|
+
const submitCreate = () => {
|
|
10726
|
+
const name = createName.trim();
|
|
10727
|
+
if (name && onCreateFolder) onCreateFolder(currentFolderId, name);
|
|
10728
|
+
setCreateOpen(false);
|
|
10729
|
+
};
|
|
10730
|
+
const openRename = (folder) => {
|
|
10731
|
+
setRenameValue(folder.name);
|
|
10732
|
+
setRenameTarget(folder);
|
|
10733
|
+
};
|
|
10734
|
+
const submitRename = () => {
|
|
10735
|
+
const name = renameValue.trim();
|
|
10736
|
+
if (name && renameTarget && onRenameFolder) onRenameFolder(renameTarget.id, name);
|
|
10737
|
+
setRenameTarget(null);
|
|
10738
|
+
};
|
|
10739
|
+
const openDelete = (folder) => {
|
|
10740
|
+
setDeleteTarget(folder);
|
|
10741
|
+
};
|
|
10742
|
+
const confirmDelete = () => {
|
|
10743
|
+
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
10744
|
+
setDeleteTarget(null);
|
|
10745
|
+
};
|
|
10746
|
+
const content = /* @__PURE__ */ jsxs74("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
10747
|
+
/* @__PURE__ */ jsxs74("div", { className: "fd-fb-head", children: [
|
|
10748
|
+
/* @__PURE__ */ jsxs74("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
10749
|
+
/* @__PURE__ */ jsx78(
|
|
10750
|
+
BreadcrumbCrumb,
|
|
10751
|
+
{
|
|
10752
|
+
label: "Home",
|
|
10753
|
+
isCurrent: currentFolderId == null,
|
|
10754
|
+
onClick: () => onNavigate(null),
|
|
10755
|
+
isDropTarget: canMove,
|
|
10756
|
+
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
10757
|
+
}
|
|
10758
|
+
),
|
|
10759
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ jsx78(
|
|
10760
|
+
BreadcrumbCrumb,
|
|
10761
|
+
{
|
|
10762
|
+
label: f.name,
|
|
10763
|
+
isCurrent: i === crumbFolders.length - 1,
|
|
10764
|
+
onClick: () => onNavigate(f.id),
|
|
10765
|
+
isDropTarget: canMove,
|
|
10766
|
+
onDropPayload: (p) => moveIntoFolder(p, f.id)
|
|
10767
|
+
},
|
|
10768
|
+
f.id
|
|
10769
|
+
))
|
|
10770
|
+
] }),
|
|
10771
|
+
/* @__PURE__ */ jsxs74("span", { className: "fd-fb-actions", children: [
|
|
10772
|
+
canCreateFolder ? /* @__PURE__ */ jsx78(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
10773
|
+
canUpload ? /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10774
|
+
/* @__PURE__ */ jsx78(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
10775
|
+
/* @__PURE__ */ jsx78(
|
|
10776
|
+
"input",
|
|
10777
|
+
{
|
|
10778
|
+
ref: uploadInputRef,
|
|
10779
|
+
type: "file",
|
|
10780
|
+
multiple: true,
|
|
10781
|
+
className: "fd-sr",
|
|
10782
|
+
"aria-label": "Upload files",
|
|
10783
|
+
onChange: (e) => {
|
|
10784
|
+
const picked = Array.from(e.target.files || []);
|
|
10785
|
+
if (picked.length && onUpload) onUpload(picked, currentFolderId);
|
|
10786
|
+
e.target.value = "";
|
|
10787
|
+
}
|
|
10788
|
+
}
|
|
10789
|
+
)
|
|
10790
|
+
] }) : null
|
|
10791
|
+
] })
|
|
10792
|
+
] }),
|
|
10793
|
+
/* @__PURE__ */ jsxs74("div", { className: "fd-fb-body", children: [
|
|
10794
|
+
/* @__PURE__ */ jsxs74("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
10795
|
+
/* @__PURE__ */ jsx78(
|
|
10796
|
+
RowShell,
|
|
10797
|
+
{
|
|
10798
|
+
icon: "house-simple",
|
|
10799
|
+
name: "Home",
|
|
10800
|
+
onOpen: () => onNavigate(null),
|
|
10801
|
+
isDropTarget: canMove,
|
|
10802
|
+
onDropPayload: (p) => moveIntoFolder(p, null),
|
|
10803
|
+
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
10804
|
+
}
|
|
10805
|
+
),
|
|
10806
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ jsx78(
|
|
10807
|
+
TreeNode,
|
|
10808
|
+
{
|
|
10809
|
+
folder: f,
|
|
10810
|
+
depth: 0,
|
|
10811
|
+
folders,
|
|
10812
|
+
currentFolderId,
|
|
10813
|
+
onNavigate,
|
|
10814
|
+
onMoveInto: moveIntoFolder,
|
|
10815
|
+
canMove
|
|
10816
|
+
},
|
|
10817
|
+
f.id
|
|
10818
|
+
))
|
|
10819
|
+
] }),
|
|
10820
|
+
/* @__PURE__ */ jsx78("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ jsx78(
|
|
10821
|
+
LoadingRegion,
|
|
10822
|
+
{
|
|
10823
|
+
state: loading ? "loading" : "ready",
|
|
10824
|
+
label: "Loading folder contents",
|
|
10825
|
+
skeleton: /* @__PURE__ */ jsxs74("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
10826
|
+
/* @__PURE__ */ jsx78(Skeleton, { h: 44, radius: "10px" }),
|
|
10827
|
+
/* @__PURE__ */ jsx78(Skeleton, { h: 44, radius: "10px" }),
|
|
10828
|
+
/* @__PURE__ */ jsx78(Skeleton, { h: 44, radius: "10px" })
|
|
10829
|
+
] }),
|
|
10830
|
+
children: isEmpty ? /* @__PURE__ */ jsx78(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ jsxs74("div", { className: "fd-fb-list", children: [
|
|
10831
|
+
subfolders.map((f) => /* @__PURE__ */ jsx78(
|
|
10832
|
+
RowShell,
|
|
10833
|
+
{
|
|
10834
|
+
icon: "folder-simple",
|
|
10835
|
+
name: f.name,
|
|
10836
|
+
onOpen: () => onNavigate(f.id),
|
|
10837
|
+
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
10838
|
+
isDropTarget: canMove,
|
|
10839
|
+
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
10840
|
+
actions: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10841
|
+
canRenameFolder ? /* @__PURE__ */ jsx78(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
10842
|
+
canMove ? /* @__PURE__ */ jsx78(
|
|
10843
|
+
FolderPickerMenu,
|
|
10844
|
+
{
|
|
10845
|
+
label: "Move " + f.name,
|
|
10846
|
+
destinations: flattenDestinations(folders, f.id),
|
|
10847
|
+
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
10848
|
+
}
|
|
10849
|
+
) : null,
|
|
10850
|
+
canDeleteFolder ? /* @__PURE__ */ jsx78(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
10851
|
+
] })
|
|
10852
|
+
},
|
|
10853
|
+
f.id
|
|
10854
|
+
)),
|
|
10855
|
+
currentFiles.map((file) => /* @__PURE__ */ jsx78(
|
|
10856
|
+
RowShell,
|
|
10857
|
+
{
|
|
10858
|
+
icon: iconForMime(file.mime, file.name),
|
|
10859
|
+
name: file.name,
|
|
10860
|
+
meta: file.size ? formatBytes(file.size) : void 0,
|
|
10861
|
+
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
10862
|
+
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
10863
|
+
actions: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10864
|
+
canMove ? /* @__PURE__ */ jsx78(
|
|
10865
|
+
FolderPickerMenu,
|
|
10866
|
+
{
|
|
10867
|
+
label: "Move " + file.name,
|
|
10868
|
+
destinations: flattenDestinations(folders),
|
|
10869
|
+
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
10870
|
+
}
|
|
10871
|
+
) : null,
|
|
10872
|
+
canRemoveFile ? /* @__PURE__ */ jsx78(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
10873
|
+
] })
|
|
10874
|
+
},
|
|
10875
|
+
file.id
|
|
10876
|
+
))
|
|
10877
|
+
] })
|
|
10878
|
+
}
|
|
10879
|
+
) })
|
|
10880
|
+
] }),
|
|
10881
|
+
/* @__PURE__ */ jsx78(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10882
|
+
/* @__PURE__ */ jsx78(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
10883
|
+
/* @__PURE__ */ jsx78(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
10884
|
+
] }), children: /* @__PURE__ */ jsx78(
|
|
10885
|
+
"input",
|
|
10886
|
+
{
|
|
10887
|
+
className: "fd-fb-input",
|
|
10888
|
+
value: createName,
|
|
10889
|
+
onChange: (e) => setCreateName(e.target.value),
|
|
10890
|
+
onKeyDown: (e) => {
|
|
10891
|
+
if (e.key === "Enter") submitCreate();
|
|
10892
|
+
},
|
|
10893
|
+
placeholder: "Folder name",
|
|
10894
|
+
"aria-label": "Folder name",
|
|
10895
|
+
autoFocus: true
|
|
10896
|
+
}
|
|
10897
|
+
) }),
|
|
10898
|
+
/* @__PURE__ */ jsx78(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10899
|
+
/* @__PURE__ */ jsx78(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
10900
|
+
/* @__PURE__ */ jsx78(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
10901
|
+
] }), children: /* @__PURE__ */ jsx78(
|
|
10902
|
+
"input",
|
|
10903
|
+
{
|
|
10904
|
+
className: "fd-fb-input",
|
|
10905
|
+
value: renameValue,
|
|
10906
|
+
onChange: (e) => setRenameValue(e.target.value),
|
|
10907
|
+
onKeyDown: (e) => {
|
|
10908
|
+
if (e.key === "Enter") submitRename();
|
|
10909
|
+
},
|
|
10910
|
+
placeholder: "Folder name",
|
|
10911
|
+
"aria-label": "Folder name",
|
|
10912
|
+
autoFocus: true
|
|
10913
|
+
}
|
|
10914
|
+
) }),
|
|
10915
|
+
/* @__PURE__ */ jsx78(
|
|
10916
|
+
Modal,
|
|
10917
|
+
{
|
|
10918
|
+
open: deleteTarget != null,
|
|
10919
|
+
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
10920
|
+
description: "This can't be undone. The folder must be empty.",
|
|
10921
|
+
onClose: () => setDeleteTarget(null),
|
|
10922
|
+
footer: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10923
|
+
/* @__PURE__ */ jsx78(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
10924
|
+
/* @__PURE__ */ jsx78(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
10925
|
+
] })
|
|
10926
|
+
}
|
|
10927
|
+
)
|
|
10928
|
+
] });
|
|
10929
|
+
if (!canUpload) return content;
|
|
10930
|
+
return /* @__PURE__ */ jsx78(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
10931
|
+
}
|
|
10932
|
+
function BreadcrumbCrumb({
|
|
10933
|
+
label,
|
|
10934
|
+
isCurrent,
|
|
10935
|
+
onClick,
|
|
10936
|
+
isDropTarget,
|
|
10937
|
+
onDropPayload
|
|
10938
|
+
}) {
|
|
10939
|
+
const [over, setOver] = React48.useState(false);
|
|
10940
|
+
const dragCounter = React48.useRef(0);
|
|
10941
|
+
const dropHandlers = isDropTarget ? {
|
|
10942
|
+
onDragEnter: (e) => {
|
|
10943
|
+
if (!hasInternalPayload(e)) return;
|
|
10944
|
+
dragCounter.current++;
|
|
10945
|
+
setOver(true);
|
|
10946
|
+
},
|
|
10947
|
+
onDragOver: (e) => {
|
|
10948
|
+
if (!hasInternalPayload(e)) return;
|
|
10949
|
+
e.preventDefault();
|
|
10950
|
+
e.dataTransfer.dropEffect = "move";
|
|
10951
|
+
},
|
|
10952
|
+
onDragLeave: () => {
|
|
10953
|
+
dragCounter.current = Math.max(0, dragCounter.current - 1);
|
|
10954
|
+
if (!dragCounter.current) setOver(false);
|
|
10955
|
+
},
|
|
10956
|
+
onDrop: (e) => {
|
|
10957
|
+
if (!hasInternalPayload(e)) return;
|
|
10958
|
+
e.preventDefault();
|
|
10959
|
+
dragCounter.current = 0;
|
|
10960
|
+
setOver(false);
|
|
10961
|
+
const payload = readDragPayload(e);
|
|
10962
|
+
if (payload && onDropPayload) onDropPayload(payload);
|
|
10963
|
+
}
|
|
10964
|
+
} : {};
|
|
10965
|
+
return /* @__PURE__ */ jsx78("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ jsx78("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ jsx78("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
10966
|
+
}
|
|
10967
|
+
|
|
10968
|
+
// src/kits/query.ts
|
|
10969
|
+
import * as React49 from "react";
|
|
10423
10970
|
function eqFilter(get2) {
|
|
10424
10971
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10425
10972
|
}
|
|
@@ -10451,22 +10998,22 @@ function compare(a, b, dir) {
|
|
|
10451
10998
|
var API = null;
|
|
10452
10999
|
var PREFS = null;
|
|
10453
11000
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10454
|
-
const [query, setQuery] =
|
|
11001
|
+
const [query, setQuery] = React49.useState(() => {
|
|
10455
11002
|
const store = PREFS || window.PlannerPrefs;
|
|
10456
11003
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10457
11004
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10458
11005
|
});
|
|
10459
|
-
const savePref =
|
|
11006
|
+
const savePref = React49.useCallback((patch2) => {
|
|
10460
11007
|
const store = PREFS || window.PlannerPrefs;
|
|
10461
11008
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10462
11009
|
}, [prefsKey]);
|
|
10463
|
-
const [res, setRes] =
|
|
10464
|
-
const [loading, setLoading] =
|
|
10465
|
-
const seq2 =
|
|
11010
|
+
const [res, setRes] = React49.useState(null);
|
|
11011
|
+
const [loading, setLoading] = React49.useState(true);
|
|
11012
|
+
const seq2 = React49.useRef(0);
|
|
10466
11013
|
const depKey = (deps || []).join("|");
|
|
10467
11014
|
const paramKey = JSON.stringify(params || {});
|
|
10468
11015
|
const queryKey = JSON.stringify(query);
|
|
10469
|
-
|
|
11016
|
+
React49.useEffect(() => {
|
|
10470
11017
|
const id = ++seq2.current;
|
|
10471
11018
|
setLoading(true);
|
|
10472
11019
|
const t = setTimeout(() => {
|
|
@@ -10810,6 +11357,7 @@ export {
|
|
|
10810
11357
|
FILE_VIEWER_CSV_ROW_LIMIT,
|
|
10811
11358
|
FILE_VIEWER_TEXT_LIMIT,
|
|
10812
11359
|
FeatureGate,
|
|
11360
|
+
FileBrowser,
|
|
10813
11361
|
FileChip,
|
|
10814
11362
|
FileGrid,
|
|
10815
11363
|
FileKit,
|