@flytedan/flytebot-design-system 0.12.14 → 0.13.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 +497 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -1
- package/dist/index.d.ts +69 -1
- package/dist/index.js +496 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +254 -14
package/dist/index.cjs
CHANGED
|
@@ -76,6 +76,7 @@ __export(index_exports, {
|
|
|
76
76
|
FILE_VIEWER_CSV_ROW_LIMIT: () => FILE_VIEWER_CSV_ROW_LIMIT,
|
|
77
77
|
FILE_VIEWER_TEXT_LIMIT: () => FILE_VIEWER_TEXT_LIMIT,
|
|
78
78
|
FeatureGate: () => FeatureGate,
|
|
79
|
+
FileBrowser: () => FileBrowser,
|
|
79
80
|
FileChip: () => FileChip,
|
|
80
81
|
FileGrid: () => FileGrid,
|
|
81
82
|
FileKit: () => FileKit,
|
|
@@ -1214,7 +1215,6 @@ function Topbar({
|
|
|
1214
1215
|
}
|
|
1215
1216
|
)
|
|
1216
1217
|
] }, i)) }),
|
|
1217
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { flex: 1 } }),
|
|
1218
1218
|
overflowActions != null ? narrow ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
1219
1219
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1220
1220
|
"button",
|
|
@@ -10627,8 +10627,496 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
10627
10627
|
);
|
|
10628
10628
|
}
|
|
10629
10629
|
|
|
10630
|
-
// src/
|
|
10630
|
+
// src/components/files/FileBrowser.tsx
|
|
10631
10631
|
var React48 = __toESM(require("react"), 1);
|
|
10632
|
+
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
10633
|
+
function childrenOf(folders, parentId) {
|
|
10634
|
+
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
10635
|
+
}
|
|
10636
|
+
function ancestorsOf(folders, id) {
|
|
10637
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
10638
|
+
const chain = [];
|
|
10639
|
+
let cur = id != null ? byId.get(id) : void 0;
|
|
10640
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10641
|
+
while (cur && !seen.has(cur.id)) {
|
|
10642
|
+
seen.add(cur.id);
|
|
10643
|
+
chain.unshift(cur);
|
|
10644
|
+
cur = cur.parentId != null ? byId.get(cur.parentId) : void 0;
|
|
10645
|
+
}
|
|
10646
|
+
return chain;
|
|
10647
|
+
}
|
|
10648
|
+
function isSelfOrDescendant(folders, ancestorId, nodeId) {
|
|
10649
|
+
if (nodeId == null) return false;
|
|
10650
|
+
if (nodeId === ancestorId) return true;
|
|
10651
|
+
const byParent = /* @__PURE__ */ new Map();
|
|
10652
|
+
folders.forEach((f) => {
|
|
10653
|
+
const key = f.parentId ?? "";
|
|
10654
|
+
if (!byParent.has(key)) byParent.set(key, []);
|
|
10655
|
+
byParent.get(key).push(f);
|
|
10656
|
+
});
|
|
10657
|
+
const stack = [...byParent.get(ancestorId) || []];
|
|
10658
|
+
while (stack.length) {
|
|
10659
|
+
const next = stack.pop();
|
|
10660
|
+
if (next.id === nodeId) return true;
|
|
10661
|
+
stack.push(...byParent.get(next.id) || []);
|
|
10662
|
+
}
|
|
10663
|
+
return false;
|
|
10664
|
+
}
|
|
10665
|
+
function flattenDestinations(folders, excludeSubtreeOf) {
|
|
10666
|
+
const out = [{ id: null, name: "Home", depth: 0 }];
|
|
10667
|
+
const walk = (parentId, depth) => {
|
|
10668
|
+
childrenOf(folders, parentId).forEach((f) => {
|
|
10669
|
+
if (excludeSubtreeOf && isSelfOrDescendant(folders, excludeSubtreeOf, f.id)) return;
|
|
10670
|
+
out.push({ id: f.id, name: f.name, depth });
|
|
10671
|
+
walk(f.id, depth + 1);
|
|
10672
|
+
});
|
|
10673
|
+
};
|
|
10674
|
+
walk(null, 1);
|
|
10675
|
+
return out;
|
|
10676
|
+
}
|
|
10677
|
+
var DND_MIME = "application/x-fd-filebrowser";
|
|
10678
|
+
function writeDragPayload(e, payload) {
|
|
10679
|
+
const s = JSON.stringify(payload);
|
|
10680
|
+
e.dataTransfer.setData(DND_MIME, s);
|
|
10681
|
+
e.dataTransfer.setData("text/plain", s);
|
|
10682
|
+
e.dataTransfer.effectAllowed = "move";
|
|
10683
|
+
}
|
|
10684
|
+
function readDragPayload(e) {
|
|
10685
|
+
const raw = e.dataTransfer.getData(DND_MIME) || e.dataTransfer.getData("text/plain");
|
|
10686
|
+
if (!raw) return null;
|
|
10687
|
+
try {
|
|
10688
|
+
const parsed = JSON.parse(raw);
|
|
10689
|
+
if (parsed && (parsed.kind === "file" || parsed.kind === "folder") && typeof parsed.id === "string") return parsed;
|
|
10690
|
+
} catch {
|
|
10691
|
+
}
|
|
10692
|
+
return null;
|
|
10693
|
+
}
|
|
10694
|
+
function hasInternalPayload(e) {
|
|
10695
|
+
return Array.from(e.dataTransfer.types || []).indexOf(DND_MIME) !== -1;
|
|
10696
|
+
}
|
|
10697
|
+
function FolderPickerMenu({
|
|
10698
|
+
label,
|
|
10699
|
+
destinations,
|
|
10700
|
+
onPick
|
|
10701
|
+
}) {
|
|
10702
|
+
const [open, setOpen] = React48.useState(false);
|
|
10703
|
+
const zIndex = useOverlayLayer(open);
|
|
10704
|
+
const ref = React48.useRef(null);
|
|
10705
|
+
React48.useEffect(() => {
|
|
10706
|
+
if (!open) return;
|
|
10707
|
+
const away = (e) => {
|
|
10708
|
+
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
10709
|
+
};
|
|
10710
|
+
const esc = (e) => {
|
|
10711
|
+
if (e.key === "Escape") setOpen(false);
|
|
10712
|
+
};
|
|
10713
|
+
document.addEventListener("pointerdown", away);
|
|
10714
|
+
document.addEventListener("keydown", esc);
|
|
10715
|
+
return () => {
|
|
10716
|
+
document.removeEventListener("pointerdown", away);
|
|
10717
|
+
document.removeEventListener("keydown", esc);
|
|
10718
|
+
};
|
|
10719
|
+
}, [open]);
|
|
10720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-fb-menu-anchor", ref, children: [
|
|
10721
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10722
|
+
IconButton,
|
|
10723
|
+
{
|
|
10724
|
+
icon: "arrows-out-cardinal",
|
|
10725
|
+
label,
|
|
10726
|
+
size: "sm",
|
|
10727
|
+
variant: "ghost",
|
|
10728
|
+
"aria-haspopup": "menu",
|
|
10729
|
+
"aria-expanded": open,
|
|
10730
|
+
onClick: () => setOpen((v) => !v)
|
|
10731
|
+
}
|
|
10732
|
+
),
|
|
10733
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-menu", role: "menu", "aria-label": label, style: { zIndex }, children: [
|
|
10734
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-overline fd-muted fd-fb-menu-title", children: "Move to\u2026" }),
|
|
10735
|
+
destinations.map((d) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
|
|
10736
|
+
"button",
|
|
10737
|
+
{
|
|
10738
|
+
type: "button",
|
|
10739
|
+
role: "menuitem",
|
|
10740
|
+
className: "fd-fb-menu-item",
|
|
10741
|
+
style: { paddingLeft: 10 + d.depth * 14 },
|
|
10742
|
+
onClick: () => {
|
|
10743
|
+
onPick(d.id);
|
|
10744
|
+
setOpen(false);
|
|
10745
|
+
},
|
|
10746
|
+
children: [
|
|
10747
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("i", { className: "ph ph-" + (d.id == null ? "house-simple" : "folder-simple"), "aria-hidden": "true" }),
|
|
10748
|
+
d.name
|
|
10749
|
+
]
|
|
10750
|
+
},
|
|
10751
|
+
d.id ?? "__root__"
|
|
10752
|
+
))
|
|
10753
|
+
] }) }) : null
|
|
10754
|
+
] });
|
|
10755
|
+
}
|
|
10756
|
+
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
10757
|
+
const [over, setOver] = React48.useState(false);
|
|
10758
|
+
const dragCounter = React48.useRef(0);
|
|
10759
|
+
const dropHandlers = isDropTarget ? {
|
|
10760
|
+
onDragEnter: (e) => {
|
|
10761
|
+
if (!hasInternalPayload(e)) return;
|
|
10762
|
+
dragCounter.current++;
|
|
10763
|
+
setOver(true);
|
|
10764
|
+
},
|
|
10765
|
+
onDragOver: (e) => {
|
|
10766
|
+
if (!hasInternalPayload(e)) return;
|
|
10767
|
+
e.preventDefault();
|
|
10768
|
+
e.dataTransfer.dropEffect = "move";
|
|
10769
|
+
},
|
|
10770
|
+
onDragLeave: () => {
|
|
10771
|
+
dragCounter.current = Math.max(0, dragCounter.current - 1);
|
|
10772
|
+
if (!dragCounter.current) setOver(false);
|
|
10773
|
+
},
|
|
10774
|
+
onDrop: (e) => {
|
|
10775
|
+
if (!hasInternalPayload(e)) return;
|
|
10776
|
+
e.preventDefault();
|
|
10777
|
+
dragCounter.current = 0;
|
|
10778
|
+
setOver(false);
|
|
10779
|
+
const payload = readDragPayload(e);
|
|
10780
|
+
if (payload && onDropPayload) onDropPayload(payload);
|
|
10781
|
+
}
|
|
10782
|
+
} : {};
|
|
10783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: ["fd-fb-row", over ? "is-drop-target" : "", className].filter(Boolean).join(" "), ...dropHandlers, children: [
|
|
10784
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
|
|
10785
|
+
"button",
|
|
10786
|
+
{
|
|
10787
|
+
type: "button",
|
|
10788
|
+
className: "fd-fb-row-main",
|
|
10789
|
+
onClick: onOpen,
|
|
10790
|
+
draggable: !!draggableId,
|
|
10791
|
+
onDragStart: draggableId ? (e) => writeDragPayload(e, draggableId) : void 0,
|
|
10792
|
+
children: [
|
|
10793
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-fb-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("i", { className: "ph ph-" + icon }) }),
|
|
10794
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-fb-row-text", children: [
|
|
10795
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-fb-row-name", title: name, children: name }),
|
|
10796
|
+
meta ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-fb-row-meta", children: meta }) : null
|
|
10797
|
+
] })
|
|
10798
|
+
]
|
|
10799
|
+
}
|
|
10800
|
+
),
|
|
10801
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-fb-row-actions", children: actions }) : null
|
|
10802
|
+
] });
|
|
10803
|
+
}
|
|
10804
|
+
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
10805
|
+
const kids = childrenOf(folders, folder.id);
|
|
10806
|
+
const [expanded, setExpanded] = React48.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
10807
|
+
React48.useEffect(() => {
|
|
10808
|
+
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
10809
|
+
}, [currentFolderId, folder.id, folders]);
|
|
10810
|
+
const isCurrent = folder.id === currentFolderId;
|
|
10811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-tree-node", children: [
|
|
10812
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10813
|
+
RowShell,
|
|
10814
|
+
{
|
|
10815
|
+
icon: folder.id === currentFolderId ? "folder-open" : "folder-simple",
|
|
10816
|
+
name: folder.name,
|
|
10817
|
+
onOpen: () => onNavigate(folder.id),
|
|
10818
|
+
draggableId: canMove ? { kind: "folder", id: folder.id } : void 0,
|
|
10819
|
+
isDropTarget: canMove,
|
|
10820
|
+
onDropPayload: (payload) => onMoveInto(payload, folder.id),
|
|
10821
|
+
className: ["fd-fb-tree-row", isCurrent ? "is-current" : ""].filter(Boolean).join(" "),
|
|
10822
|
+
actions: kids.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10823
|
+
IconButton,
|
|
10824
|
+
{
|
|
10825
|
+
icon: expanded ? "caret-down" : "caret-right",
|
|
10826
|
+
label: (expanded ? "Collapse " : "Expand ") + folder.name,
|
|
10827
|
+
size: "sm",
|
|
10828
|
+
variant: "ghost",
|
|
10829
|
+
onClick: () => setExpanded((v) => !v)
|
|
10830
|
+
}
|
|
10831
|
+
) : void 0
|
|
10832
|
+
}
|
|
10833
|
+
),
|
|
10834
|
+
expanded && kids.length ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "fd-fb-tree-children", style: { paddingLeft: 14 }, children: kids.map((k) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10835
|
+
TreeNode,
|
|
10836
|
+
{
|
|
10837
|
+
folder: k,
|
|
10838
|
+
depth: depth + 1,
|
|
10839
|
+
folders,
|
|
10840
|
+
currentFolderId,
|
|
10841
|
+
onNavigate,
|
|
10842
|
+
onMoveInto,
|
|
10843
|
+
canMove
|
|
10844
|
+
},
|
|
10845
|
+
k.id
|
|
10846
|
+
)) }) : null
|
|
10847
|
+
] });
|
|
10848
|
+
}
|
|
10849
|
+
function FileBrowser({
|
|
10850
|
+
folders,
|
|
10851
|
+
files,
|
|
10852
|
+
currentFolderId,
|
|
10853
|
+
onNavigate,
|
|
10854
|
+
onCreateFolder,
|
|
10855
|
+
onRenameFolder,
|
|
10856
|
+
onMoveFolder,
|
|
10857
|
+
onMoveFile,
|
|
10858
|
+
onOpenFile,
|
|
10859
|
+
onRemoveFile,
|
|
10860
|
+
onUpload,
|
|
10861
|
+
loading = false,
|
|
10862
|
+
permissions,
|
|
10863
|
+
className = ""
|
|
10864
|
+
}) {
|
|
10865
|
+
const perm = permissions || {};
|
|
10866
|
+
const canCreateFolder = perm.canCreateFolder !== false && !!onCreateFolder;
|
|
10867
|
+
const canRenameFolder = perm.canRenameFolder !== false && !!onRenameFolder;
|
|
10868
|
+
const canMove = perm.canMove !== false && (!!onMoveFolder || !!onMoveFile);
|
|
10869
|
+
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
10870
|
+
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
10871
|
+
const [createOpen, setCreateOpen] = React48.useState(false);
|
|
10872
|
+
const [createName, setCreateName] = React48.useState("");
|
|
10873
|
+
const [renameTarget, setRenameTarget] = React48.useState(null);
|
|
10874
|
+
const [renameValue, setRenameValue] = React48.useState("");
|
|
10875
|
+
const uploadInputRef = React48.useRef(null);
|
|
10876
|
+
const crumbFolders = React48.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
10877
|
+
const subfolders = React48.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
10878
|
+
const currentFiles = React48.useMemo(
|
|
10879
|
+
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
10880
|
+
[files, currentFolderId]
|
|
10881
|
+
);
|
|
10882
|
+
const isEmpty = !subfolders.length && !currentFiles.length;
|
|
10883
|
+
const moveIntoFolder = (payload, targetFolderId) => {
|
|
10884
|
+
if (payload.kind === "folder") {
|
|
10885
|
+
if (payload.id === targetFolderId) return;
|
|
10886
|
+
if (isSelfOrDescendant(folders, payload.id, targetFolderId)) return;
|
|
10887
|
+
onMoveFolder && onMoveFolder(payload.id, targetFolderId);
|
|
10888
|
+
} else {
|
|
10889
|
+
onMoveFile && onMoveFile(payload.id, targetFolderId);
|
|
10890
|
+
}
|
|
10891
|
+
};
|
|
10892
|
+
const openCreate = () => {
|
|
10893
|
+
setCreateName("");
|
|
10894
|
+
setCreateOpen(true);
|
|
10895
|
+
};
|
|
10896
|
+
const submitCreate = () => {
|
|
10897
|
+
const name = createName.trim();
|
|
10898
|
+
if (name && onCreateFolder) onCreateFolder(currentFolderId, name);
|
|
10899
|
+
setCreateOpen(false);
|
|
10900
|
+
};
|
|
10901
|
+
const openRename = (folder) => {
|
|
10902
|
+
setRenameValue(folder.name);
|
|
10903
|
+
setRenameTarget(folder);
|
|
10904
|
+
};
|
|
10905
|
+
const submitRename = () => {
|
|
10906
|
+
const name = renameValue.trim();
|
|
10907
|
+
if (name && renameTarget && onRenameFolder) onRenameFolder(renameTarget.id, name);
|
|
10908
|
+
setRenameTarget(null);
|
|
10909
|
+
};
|
|
10910
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
10911
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-head", children: [
|
|
10912
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
10913
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10914
|
+
BreadcrumbCrumb,
|
|
10915
|
+
{
|
|
10916
|
+
label: "Home",
|
|
10917
|
+
isCurrent: currentFolderId == null,
|
|
10918
|
+
onClick: () => onNavigate(null),
|
|
10919
|
+
isDropTarget: canMove,
|
|
10920
|
+
onDropPayload: (p) => moveIntoFolder(p, null)
|
|
10921
|
+
}
|
|
10922
|
+
),
|
|
10923
|
+
crumbFolders.map((f, i) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10924
|
+
BreadcrumbCrumb,
|
|
10925
|
+
{
|
|
10926
|
+
label: f.name,
|
|
10927
|
+
isCurrent: i === crumbFolders.length - 1,
|
|
10928
|
+
onClick: () => onNavigate(f.id),
|
|
10929
|
+
isDropTarget: canMove,
|
|
10930
|
+
onDropPayload: (p) => moveIntoFolder(p, f.id)
|
|
10931
|
+
},
|
|
10932
|
+
f.id
|
|
10933
|
+
))
|
|
10934
|
+
] }),
|
|
10935
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("span", { className: "fd-fb-actions", children: [
|
|
10936
|
+
canCreateFolder ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { variant: "secondary", size: "sm", icon: "folder-simple-plus", onClick: openCreate, children: "New folder" }) : null,
|
|
10937
|
+
canUpload ? /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(import_jsx_runtime79.Fragment, { children: [
|
|
10938
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { variant: "secondary", size: "sm", icon: "upload-simple", onClick: () => uploadInputRef.current && uploadInputRef.current.click(), children: "Upload" }),
|
|
10939
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10940
|
+
"input",
|
|
10941
|
+
{
|
|
10942
|
+
ref: uploadInputRef,
|
|
10943
|
+
type: "file",
|
|
10944
|
+
multiple: true,
|
|
10945
|
+
className: "fd-sr",
|
|
10946
|
+
"aria-label": "Upload files",
|
|
10947
|
+
onChange: (e) => {
|
|
10948
|
+
const picked = Array.from(e.target.files || []);
|
|
10949
|
+
if (picked.length && onUpload) onUpload(picked, currentFolderId);
|
|
10950
|
+
e.target.value = "";
|
|
10951
|
+
}
|
|
10952
|
+
}
|
|
10953
|
+
)
|
|
10954
|
+
] }) : null
|
|
10955
|
+
] })
|
|
10956
|
+
] }),
|
|
10957
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-body", children: [
|
|
10958
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-tree", role: "region", "aria-label": "Folder tree", children: [
|
|
10959
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10960
|
+
RowShell,
|
|
10961
|
+
{
|
|
10962
|
+
icon: "house-simple",
|
|
10963
|
+
name: "Home",
|
|
10964
|
+
onOpen: () => onNavigate(null),
|
|
10965
|
+
isDropTarget: canMove,
|
|
10966
|
+
onDropPayload: (p) => moveIntoFolder(p, null),
|
|
10967
|
+
className: ["fd-fb-tree-row", currentFolderId == null ? "is-current" : ""].filter(Boolean).join(" ")
|
|
10968
|
+
}
|
|
10969
|
+
),
|
|
10970
|
+
childrenOf(folders, null).map((f) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10971
|
+
TreeNode,
|
|
10972
|
+
{
|
|
10973
|
+
folder: f,
|
|
10974
|
+
depth: 0,
|
|
10975
|
+
folders,
|
|
10976
|
+
currentFolderId,
|
|
10977
|
+
onNavigate,
|
|
10978
|
+
onMoveInto: moveIntoFolder,
|
|
10979
|
+
canMove
|
|
10980
|
+
},
|
|
10981
|
+
f.id
|
|
10982
|
+
))
|
|
10983
|
+
] }),
|
|
10984
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "fd-fb-main", role: "region", "aria-label": "Folder contents", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10985
|
+
LoadingRegion,
|
|
10986
|
+
{
|
|
10987
|
+
state: loading ? "loading" : "ready",
|
|
10988
|
+
label: "Loading folder contents",
|
|
10989
|
+
skeleton: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-stack", style: { gap: 8, padding: 12 }, children: [
|
|
10990
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
10991
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Skeleton, { h: 44, radius: "10px" }),
|
|
10992
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Skeleton, { h: 44, radius: "10px" })
|
|
10993
|
+
] }),
|
|
10994
|
+
children: isEmpty ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(EmptyState, { icon: "folder-open", title: "This folder is empty", children: canUpload ? "Drop files here, or use Upload above." : "Nothing has been filed here yet." }) : /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "fd-fb-list", children: [
|
|
10995
|
+
subfolders.map((f) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
10996
|
+
RowShell,
|
|
10997
|
+
{
|
|
10998
|
+
icon: "folder-simple",
|
|
10999
|
+
name: f.name,
|
|
11000
|
+
onOpen: () => onNavigate(f.id),
|
|
11001
|
+
draggableId: canMove ? { kind: "folder", id: f.id } : void 0,
|
|
11002
|
+
isDropTarget: canMove,
|
|
11003
|
+
onDropPayload: (p) => moveIntoFolder(p, f.id),
|
|
11004
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(import_jsx_runtime79.Fragment, { children: [
|
|
11005
|
+
canRenameFolder ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(IconButton, { icon: "pencil-simple", label: "Rename " + f.name, size: "sm", variant: "ghost", onClick: () => openRename(f) }) : null,
|
|
11006
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
11007
|
+
FolderPickerMenu,
|
|
11008
|
+
{
|
|
11009
|
+
label: "Move " + f.name,
|
|
11010
|
+
destinations: flattenDestinations(folders, f.id),
|
|
11011
|
+
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
11012
|
+
}
|
|
11013
|
+
) : null
|
|
11014
|
+
] })
|
|
11015
|
+
},
|
|
11016
|
+
f.id
|
|
11017
|
+
)),
|
|
11018
|
+
currentFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
11019
|
+
RowShell,
|
|
11020
|
+
{
|
|
11021
|
+
icon: iconForMime(file.mime, file.name),
|
|
11022
|
+
name: file.name,
|
|
11023
|
+
meta: file.size ? formatBytes(file.size) : void 0,
|
|
11024
|
+
onOpen: onOpenFile ? () => onOpenFile(file) : void 0,
|
|
11025
|
+
draggableId: canMove ? { kind: "file", id: file.id } : void 0,
|
|
11026
|
+
actions: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(import_jsx_runtime79.Fragment, { children: [
|
|
11027
|
+
canMove ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
11028
|
+
FolderPickerMenu,
|
|
11029
|
+
{
|
|
11030
|
+
label: "Move " + file.name,
|
|
11031
|
+
destinations: flattenDestinations(folders),
|
|
11032
|
+
onPick: (target) => onMoveFile && onMoveFile(file.id, target)
|
|
11033
|
+
}
|
|
11034
|
+
) : null,
|
|
11035
|
+
canRemoveFile ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(IconButton, { icon: "trash-simple", label: "Remove " + file.name, size: "sm", variant: "ghost", onClick: () => onRemoveFile && onRemoveFile(file) }) : null
|
|
11036
|
+
] })
|
|
11037
|
+
},
|
|
11038
|
+
file.id
|
|
11039
|
+
))
|
|
11040
|
+
] })
|
|
11041
|
+
}
|
|
11042
|
+
) })
|
|
11043
|
+
] }),
|
|
11044
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Modal, { open: createOpen, title: "New folder", onClose: () => setCreateOpen(false), footer: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(import_jsx_runtime79.Fragment, { children: [
|
|
11045
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { variant: "secondary", onClick: () => setCreateOpen(false), children: "Cancel" }),
|
|
11046
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { onClick: submitCreate, disabled: !createName.trim(), children: "Create" })
|
|
11047
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
11048
|
+
"input",
|
|
11049
|
+
{
|
|
11050
|
+
className: "fd-fb-input",
|
|
11051
|
+
value: createName,
|
|
11052
|
+
onChange: (e) => setCreateName(e.target.value),
|
|
11053
|
+
onKeyDown: (e) => {
|
|
11054
|
+
if (e.key === "Enter") submitCreate();
|
|
11055
|
+
},
|
|
11056
|
+
placeholder: "Folder name",
|
|
11057
|
+
"aria-label": "Folder name",
|
|
11058
|
+
autoFocus: true
|
|
11059
|
+
}
|
|
11060
|
+
) }),
|
|
11061
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Modal, { open: renameTarget != null, title: "Rename folder", onClose: () => setRenameTarget(null), footer: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(import_jsx_runtime79.Fragment, { children: [
|
|
11062
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { variant: "secondary", onClick: () => setRenameTarget(null), children: "Cancel" }),
|
|
11063
|
+
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Button, { onClick: submitRename, disabled: !renameValue.trim(), children: "Save" })
|
|
11064
|
+
] }), children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
11065
|
+
"input",
|
|
11066
|
+
{
|
|
11067
|
+
className: "fd-fb-input",
|
|
11068
|
+
value: renameValue,
|
|
11069
|
+
onChange: (e) => setRenameValue(e.target.value),
|
|
11070
|
+
onKeyDown: (e) => {
|
|
11071
|
+
if (e.key === "Enter") submitRename();
|
|
11072
|
+
},
|
|
11073
|
+
placeholder: "Folder name",
|
|
11074
|
+
"aria-label": "Folder name",
|
|
11075
|
+
autoFocus: true
|
|
11076
|
+
}
|
|
11077
|
+
) })
|
|
11078
|
+
] });
|
|
11079
|
+
if (!canUpload) return content;
|
|
11080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|
|
11081
|
+
}
|
|
11082
|
+
function BreadcrumbCrumb({
|
|
11083
|
+
label,
|
|
11084
|
+
isCurrent,
|
|
11085
|
+
onClick,
|
|
11086
|
+
isDropTarget,
|
|
11087
|
+
onDropPayload
|
|
11088
|
+
}) {
|
|
11089
|
+
const [over, setOver] = React48.useState(false);
|
|
11090
|
+
const dragCounter = React48.useRef(0);
|
|
11091
|
+
const dropHandlers = isDropTarget ? {
|
|
11092
|
+
onDragEnter: (e) => {
|
|
11093
|
+
if (!hasInternalPayload(e)) return;
|
|
11094
|
+
dragCounter.current++;
|
|
11095
|
+
setOver(true);
|
|
11096
|
+
},
|
|
11097
|
+
onDragOver: (e) => {
|
|
11098
|
+
if (!hasInternalPayload(e)) return;
|
|
11099
|
+
e.preventDefault();
|
|
11100
|
+
e.dataTransfer.dropEffect = "move";
|
|
11101
|
+
},
|
|
11102
|
+
onDragLeave: () => {
|
|
11103
|
+
dragCounter.current = Math.max(0, dragCounter.current - 1);
|
|
11104
|
+
if (!dragCounter.current) setOver(false);
|
|
11105
|
+
},
|
|
11106
|
+
onDrop: (e) => {
|
|
11107
|
+
if (!hasInternalPayload(e)) return;
|
|
11108
|
+
e.preventDefault();
|
|
11109
|
+
dragCounter.current = 0;
|
|
11110
|
+
setOver(false);
|
|
11111
|
+
const payload = readDragPayload(e);
|
|
11112
|
+
if (payload && onDropPayload) onDropPayload(payload);
|
|
11113
|
+
}
|
|
11114
|
+
} : {};
|
|
11115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: ["fd-fb-crumb", over ? "is-drop-target" : ""].filter(Boolean).join(" "), ...dropHandlers, children: isCurrent ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: "fd-fb-crumb-current", "aria-current": "page", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("button", { type: "button", className: "fd-fb-crumb-link", onClick, children: label }) });
|
|
11116
|
+
}
|
|
11117
|
+
|
|
11118
|
+
// src/kits/query.ts
|
|
11119
|
+
var React49 = __toESM(require("react"), 1);
|
|
10632
11120
|
function eqFilter(get2) {
|
|
10633
11121
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10634
11122
|
}
|
|
@@ -10660,22 +11148,22 @@ function compare(a, b, dir) {
|
|
|
10660
11148
|
var API = null;
|
|
10661
11149
|
var PREFS = null;
|
|
10662
11150
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10663
|
-
const [query, setQuery] =
|
|
11151
|
+
const [query, setQuery] = React49.useState(() => {
|
|
10664
11152
|
const store = PREFS || window.PlannerPrefs;
|
|
10665
11153
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10666
11154
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10667
11155
|
});
|
|
10668
|
-
const savePref =
|
|
11156
|
+
const savePref = React49.useCallback((patch2) => {
|
|
10669
11157
|
const store = PREFS || window.PlannerPrefs;
|
|
10670
11158
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10671
11159
|
}, [prefsKey]);
|
|
10672
|
-
const [res, setRes] =
|
|
10673
|
-
const [loading, setLoading] =
|
|
10674
|
-
const seq2 =
|
|
11160
|
+
const [res, setRes] = React49.useState(null);
|
|
11161
|
+
const [loading, setLoading] = React49.useState(true);
|
|
11162
|
+
const seq2 = React49.useRef(0);
|
|
10675
11163
|
const depKey = (deps || []).join("|");
|
|
10676
11164
|
const paramKey = JSON.stringify(params || {});
|
|
10677
11165
|
const queryKey = JSON.stringify(query);
|
|
10678
|
-
|
|
11166
|
+
React49.useEffect(() => {
|
|
10679
11167
|
const id = ++seq2.current;
|
|
10680
11168
|
setLoading(true);
|
|
10681
11169
|
const t = setTimeout(() => {
|
|
@@ -11020,6 +11508,7 @@ function createVersionStore(initialState, options) {
|
|
|
11020
11508
|
FILE_VIEWER_CSV_ROW_LIMIT,
|
|
11021
11509
|
FILE_VIEWER_TEXT_LIMIT,
|
|
11022
11510
|
FeatureGate,
|
|
11511
|
+
FileBrowser,
|
|
11023
11512
|
FileChip,
|
|
11024
11513
|
FileGrid,
|
|
11025
11514
|
FileKit,
|