@sparkstudio/storage-ui 1.0.14 → 1.0.16
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 +163 -40
- package/dist/index.d.cts +15 -13
- package/dist/index.d.ts +15 -13
- package/dist/index.js +173 -40
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -478,6 +478,14 @@ var UploadProgressList = ({
|
|
|
478
478
|
},
|
|
479
479
|
children: [
|
|
480
480
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "bi bi-file-earmark fs-2" }),
|
|
481
|
+
u.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
482
|
+
"div",
|
|
483
|
+
{
|
|
484
|
+
className: "position-absolute top-50 start-50 translate-middle",
|
|
485
|
+
style: { pointerEvents: "none" },
|
|
486
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "spinner-border spinner-border-sm text-primary" })
|
|
487
|
+
}
|
|
488
|
+
),
|
|
481
489
|
u.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger", children: "!" })
|
|
482
490
|
]
|
|
483
491
|
}
|
|
@@ -518,8 +526,81 @@ var UploadProgressList = ({
|
|
|
518
526
|
};
|
|
519
527
|
|
|
520
528
|
// src/components/DesktopFileIcon.tsx
|
|
529
|
+
var import_free_solid_svg_icons = require("@fortawesome/free-solid-svg-icons");
|
|
530
|
+
var import_react_fontawesome = require("@fortawesome/react-fontawesome");
|
|
521
531
|
var import_react4 = require("react");
|
|
522
532
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
533
|
+
function getFileExtension(name) {
|
|
534
|
+
if (!name) return null;
|
|
535
|
+
const lastDot = name.lastIndexOf(".");
|
|
536
|
+
if (lastDot === -1 || lastDot === name.length - 1) return null;
|
|
537
|
+
return name.substring(lastDot + 1).toLowerCase();
|
|
538
|
+
}
|
|
539
|
+
function getIconForExtension(ext) {
|
|
540
|
+
if (!ext) return import_free_solid_svg_icons.faFile;
|
|
541
|
+
switch (ext) {
|
|
542
|
+
// Images
|
|
543
|
+
case "jpg":
|
|
544
|
+
case "jpeg":
|
|
545
|
+
case "png":
|
|
546
|
+
case "gif":
|
|
547
|
+
case "webp":
|
|
548
|
+
case "bmp":
|
|
549
|
+
return import_free_solid_svg_icons.faFileImage;
|
|
550
|
+
// PDF
|
|
551
|
+
case "pdf":
|
|
552
|
+
return import_free_solid_svg_icons.faFilePdf;
|
|
553
|
+
// Word docs
|
|
554
|
+
case "doc":
|
|
555
|
+
case "docx":
|
|
556
|
+
return import_free_solid_svg_icons.faFileWord;
|
|
557
|
+
// Excel / spreadsheets
|
|
558
|
+
case "xls":
|
|
559
|
+
case "xlsx":
|
|
560
|
+
case "csv":
|
|
561
|
+
return import_free_solid_svg_icons.faFileExcel;
|
|
562
|
+
// Archives
|
|
563
|
+
case "zip":
|
|
564
|
+
case "rar":
|
|
565
|
+
case "7z":
|
|
566
|
+
case "tar":
|
|
567
|
+
case "gz":
|
|
568
|
+
return import_free_solid_svg_icons.faFileArchive;
|
|
569
|
+
// Video
|
|
570
|
+
case "mp4":
|
|
571
|
+
case "mov":
|
|
572
|
+
case "avi":
|
|
573
|
+
case "mkv":
|
|
574
|
+
case "webm":
|
|
575
|
+
return import_free_solid_svg_icons.faFileVideo;
|
|
576
|
+
// Audio
|
|
577
|
+
case "mp3":
|
|
578
|
+
case "wav":
|
|
579
|
+
case "ogg":
|
|
580
|
+
case "flac":
|
|
581
|
+
return import_free_solid_svg_icons.faFileAudio;
|
|
582
|
+
// Code files
|
|
583
|
+
case "js":
|
|
584
|
+
case "ts":
|
|
585
|
+
case "tsx":
|
|
586
|
+
case "jsx":
|
|
587
|
+
case "json":
|
|
588
|
+
case "html":
|
|
589
|
+
case "css":
|
|
590
|
+
case "cs":
|
|
591
|
+
case "java":
|
|
592
|
+
case "py":
|
|
593
|
+
case "rb":
|
|
594
|
+
case "php":
|
|
595
|
+
case "sql":
|
|
596
|
+
case "xml":
|
|
597
|
+
case "yml":
|
|
598
|
+
case "yaml":
|
|
599
|
+
return import_free_solid_svg_icons.faFileCode;
|
|
600
|
+
default:
|
|
601
|
+
return import_free_solid_svg_icons.faFile;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
523
604
|
var DesktopFileIcon = ({
|
|
524
605
|
name,
|
|
525
606
|
sizeBytes,
|
|
@@ -531,9 +612,11 @@ var DesktopFileIcon = ({
|
|
|
531
612
|
null
|
|
532
613
|
);
|
|
533
614
|
const [isHovered, setIsHovered] = (0, import_react4.useState)(false);
|
|
615
|
+
const [isDeleting, setIsDeleting] = (0, import_react4.useState)(false);
|
|
534
616
|
const iconRef = (0, import_react4.useRef)(null);
|
|
535
617
|
const menuRef = (0, import_react4.useRef)(null);
|
|
536
618
|
const handleDoubleClick = () => {
|
|
619
|
+
if (isDeleting) return;
|
|
537
620
|
if (onOpen) {
|
|
538
621
|
onOpen();
|
|
539
622
|
return;
|
|
@@ -550,13 +633,14 @@ var DesktopFileIcon = ({
|
|
|
550
633
|
}
|
|
551
634
|
};
|
|
552
635
|
const handleContextMenu = (e) => {
|
|
636
|
+
if (isDeleting) return;
|
|
553
637
|
e.preventDefault();
|
|
554
638
|
setContextMenuPos({ x: e.clientX, y: e.clientY });
|
|
555
639
|
};
|
|
556
640
|
const closeMenu = () => setContextMenuPos(null);
|
|
557
641
|
const handleDownload = () => {
|
|
558
642
|
closeMenu();
|
|
559
|
-
if (!downloadUrl) return;
|
|
643
|
+
if (!downloadUrl || isDeleting) return;
|
|
560
644
|
const a = document.createElement("a");
|
|
561
645
|
a.href = downloadUrl;
|
|
562
646
|
a.download = name ?? "";
|
|
@@ -568,18 +652,26 @@ var DesktopFileIcon = ({
|
|
|
568
652
|
};
|
|
569
653
|
const handleCopyUrl = async () => {
|
|
570
654
|
closeMenu();
|
|
571
|
-
if (!downloadUrl) return;
|
|
655
|
+
if (!downloadUrl || isDeleting) return;
|
|
572
656
|
try {
|
|
573
657
|
await navigator.clipboard?.writeText(downloadUrl);
|
|
574
658
|
} catch (err) {
|
|
575
659
|
console.error("Failed to copy URL", err);
|
|
576
660
|
}
|
|
577
661
|
};
|
|
578
|
-
const handleDelete = () => {
|
|
662
|
+
const handleDelete = async () => {
|
|
579
663
|
closeMenu();
|
|
580
|
-
onDelete
|
|
664
|
+
if (!onDelete) return;
|
|
665
|
+
try {
|
|
666
|
+
setIsDeleting(true);
|
|
667
|
+
await Promise.resolve(onDelete());
|
|
668
|
+
} catch (err) {
|
|
669
|
+
console.error("Delete failed", err);
|
|
670
|
+
}
|
|
581
671
|
};
|
|
582
672
|
const formattedSize = typeof sizeBytes === "number" ? `${(sizeBytes / 1024).toFixed(1)} KB` : void 0;
|
|
673
|
+
const ext = getFileExtension(name);
|
|
674
|
+
const iconToRender = getIconForExtension(ext);
|
|
583
675
|
(0, import_react4.useEffect)(() => {
|
|
584
676
|
if (!contextMenuPos) return;
|
|
585
677
|
const handleGlobalClick = (e) => {
|
|
@@ -602,48 +694,43 @@ var DesktopFileIcon = ({
|
|
|
602
694
|
"div",
|
|
603
695
|
{
|
|
604
696
|
ref: iconRef,
|
|
605
|
-
className: "d-flex flex-column align-items-center rounded-3 p-1 " + (isHovered || contextMenuPos ? "bg-
|
|
697
|
+
className: "d-flex flex-column align-items-center rounded-3 p-1 " + (isHovered || contextMenuPos ? "bg-primary-subtle" : ""),
|
|
606
698
|
style: {
|
|
607
699
|
width: 96,
|
|
608
|
-
cursor: "pointer",
|
|
700
|
+
cursor: isDeleting ? "default" : "pointer",
|
|
609
701
|
userSelect: "none",
|
|
610
|
-
transition: "background-color 0.1s ease,
|
|
702
|
+
transition: "background-color 0.1s ease, opacity 0.1s ease",
|
|
703
|
+
opacity: isDeleting ? 0.6 : 1
|
|
611
704
|
},
|
|
612
705
|
onDoubleClick: handleDoubleClick,
|
|
613
706
|
onContextMenu: handleContextMenu,
|
|
614
707
|
title: name ?? void 0,
|
|
615
708
|
onClick: () => {
|
|
616
|
-
if (contextMenuPos)
|
|
617
|
-
closeMenu();
|
|
618
|
-
}
|
|
709
|
+
if (contextMenuPos) closeMenu();
|
|
619
710
|
},
|
|
620
711
|
onMouseEnter: () => setIsHovered(true),
|
|
621
712
|
onMouseLeave: () => setIsHovered(false),
|
|
622
713
|
children: [
|
|
623
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
624
715
|
"div",
|
|
625
716
|
{
|
|
626
|
-
className: "bg-white border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm",
|
|
717
|
+
className: "bg-white border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm position-relative",
|
|
627
718
|
style: {
|
|
628
719
|
width: 64,
|
|
629
720
|
height: 64
|
|
630
721
|
},
|
|
631
|
-
children:
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
"div",
|
|
636
|
-
{
|
|
637
|
-
className: "small text-center text-truncate",
|
|
638
|
-
style: { width: "100%" },
|
|
639
|
-
children: name
|
|
722
|
+
children: [
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_fontawesome.FontAwesomeIcon, { icon: iconToRender, className: "fs-2" }),
|
|
724
|
+
isDeleting && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "position-absolute top-50 start-50 translate-middle", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "spinner-border spinner-border-sm text-danger" }) })
|
|
725
|
+
]
|
|
640
726
|
}
|
|
641
727
|
),
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "small text-center text-truncate", style: { width: "100%" }, children: name }),
|
|
642
729
|
formattedSize && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("small", { className: "text-muted mt-1", children: formattedSize })
|
|
643
730
|
]
|
|
644
731
|
}
|
|
645
732
|
),
|
|
646
|
-
contextMenuPos && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
733
|
+
contextMenuPos && !isDeleting && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
647
734
|
"div",
|
|
648
735
|
{
|
|
649
736
|
ref: menuRef,
|
|
@@ -752,25 +839,59 @@ var UploadContainer = ({
|
|
|
752
839
|
className: "w-100",
|
|
753
840
|
style: { minHeight: "260px", alignItems: "stretch" },
|
|
754
841
|
children: [
|
|
842
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-100 mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-grow-1 w-100", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UploadProgressList, { uploads }) }) }) }),
|
|
755
843
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
756
844
|
"div",
|
|
757
845
|
{
|
|
758
846
|
className: "w-100 d-flex flex-wrap gap-4 align-content-start",
|
|
759
847
|
style: { minHeight: "140px" },
|
|
760
|
-
children: existingFilesLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-100 d-flex justify-content-center align-items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "spinner-border text-secondary", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "visually-hidden", children: "Loading containers..." }) }) }) : existingFiles.
|
|
848
|
+
children: existingFilesLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-100 d-flex justify-content-center align-items-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "spinner-border text-secondary", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "visually-hidden", children: "Loading containers..." }) }) }) : existingFiles.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
849
|
+
"div",
|
|
850
|
+
{
|
|
851
|
+
className: "w-100 d-flex flex-column align-items-center justify-content-center text-muted",
|
|
852
|
+
style: {
|
|
853
|
+
minHeight: "160px",
|
|
854
|
+
border: "2px dashed #ccc",
|
|
855
|
+
borderRadius: "10px",
|
|
856
|
+
padding: "20px",
|
|
857
|
+
cursor: "pointer",
|
|
858
|
+
transition: "background 0.12s, border-color 0.12s"
|
|
859
|
+
},
|
|
860
|
+
onClick: () => document.getElementById("filePicker")?.click(),
|
|
861
|
+
onMouseEnter: (e) => e.currentTarget.style.borderColor = "#888",
|
|
862
|
+
onMouseLeave: (e) => e.currentTarget.style.borderColor = "#ccc",
|
|
863
|
+
children: [
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
865
|
+
"input",
|
|
866
|
+
{
|
|
867
|
+
id: "filePicker",
|
|
868
|
+
type: "file",
|
|
869
|
+
multiple: true,
|
|
870
|
+
hidden: true,
|
|
871
|
+
onChange: (e) => {
|
|
872
|
+
if (!e.target.files) return;
|
|
873
|
+
onFilesSelected?.(e.target.files);
|
|
874
|
+
startUploadsIfNeeded(e.target.files);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
),
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Drag & drop files here" }),
|
|
879
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("small", { className: "mt-1", children: "\u2026or click to browse" })
|
|
880
|
+
]
|
|
881
|
+
}
|
|
882
|
+
) : existingFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
761
883
|
DesktopFileIcon,
|
|
762
884
|
{
|
|
763
885
|
name: file.Name,
|
|
764
|
-
sizeBytes:
|
|
765
|
-
downloadUrl: file.PublicUrl
|
|
886
|
+
sizeBytes: file.FileSize,
|
|
887
|
+
downloadUrl: file.PublicUrl,
|
|
766
888
|
onOpen: () => handleExistingFileOpen(file),
|
|
767
|
-
onDelete:
|
|
889
|
+
onDelete: () => onDeleteFile?.(file)
|
|
768
890
|
},
|
|
769
891
|
file.Id
|
|
770
892
|
))
|
|
771
893
|
}
|
|
772
|
-
)
|
|
773
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-100 mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-grow-1 w-100", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UploadProgressList, { uploads }) }) }) })
|
|
894
|
+
)
|
|
774
895
|
]
|
|
775
896
|
}
|
|
776
897
|
);
|
|
@@ -802,6 +923,7 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
802
923
|
}, [apiBaseUrl, parentId]);
|
|
803
924
|
return {
|
|
804
925
|
containers,
|
|
926
|
+
setContainers,
|
|
805
927
|
loading,
|
|
806
928
|
error,
|
|
807
929
|
reload: load
|
|
@@ -815,17 +937,18 @@ var ContainerUploadPanel = ({
|
|
|
815
937
|
storageApiBaseUrl,
|
|
816
938
|
parentContainerId
|
|
817
939
|
}) => {
|
|
818
|
-
const { containers, reload, loading } = UseContainers({
|
|
940
|
+
const { containers, setContainers, reload, loading } = UseContainers({
|
|
819
941
|
apiBaseUrl: containerApiBaseUrl,
|
|
820
942
|
parentId: parentContainerId
|
|
821
943
|
});
|
|
822
944
|
const getPresignedUrl = async (file) => {
|
|
823
945
|
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
824
946
|
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
947
|
+
const contentType = file.type || "application/octet-stream";
|
|
825
948
|
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
826
949
|
file.name,
|
|
827
950
|
file.size,
|
|
828
|
-
encodeURIComponent(
|
|
951
|
+
encodeURIComponent(contentType)
|
|
829
952
|
);
|
|
830
953
|
async function getPresignedUrlWithRetry(container, attempts = 3) {
|
|
831
954
|
let lastError;
|
|
@@ -850,13 +973,6 @@ var ContainerUploadPanel = ({
|
|
|
850
973
|
const handleUploadError = (file, err) => {
|
|
851
974
|
console.error("Upload failed:", file.name, err);
|
|
852
975
|
};
|
|
853
|
-
const handleOnDeleteFile = async (file) => {
|
|
854
|
-
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
855
|
-
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
856
|
-
await sdkDb.container.DeleteContainer(file.Id);
|
|
857
|
-
await sdkS3.s3.DeleteS3(file);
|
|
858
|
-
await reload();
|
|
859
|
-
};
|
|
860
976
|
const handleExistingFileClick = (file) => {
|
|
861
977
|
const a = document.createElement("a");
|
|
862
978
|
a.href = file.PublicUrl ?? "";
|
|
@@ -867,6 +983,13 @@ var ContainerUploadPanel = ({
|
|
|
867
983
|
a.click();
|
|
868
984
|
document.body.removeChild(a);
|
|
869
985
|
};
|
|
986
|
+
const handleDeleteFile = async (file) => {
|
|
987
|
+
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
988
|
+
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
989
|
+
await sdkDb.container.DeleteContainer(file.Id);
|
|
990
|
+
await sdkS3.s3.DeleteS3(file);
|
|
991
|
+
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
992
|
+
};
|
|
870
993
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
871
994
|
UploadContainer,
|
|
872
995
|
{
|
|
@@ -877,7 +1000,7 @@ var ContainerUploadPanel = ({
|
|
|
877
1000
|
getPresignedUrl,
|
|
878
1001
|
onUploadComplete: handleUploadComplete,
|
|
879
1002
|
onUploadError: handleUploadError,
|
|
880
|
-
onDeleteFile:
|
|
1003
|
+
onDeleteFile: handleDeleteFile
|
|
881
1004
|
}
|
|
882
1005
|
);
|
|
883
1006
|
};
|
|
@@ -903,8 +1026,8 @@ function HomeContent() {
|
|
|
903
1026
|
user && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
904
1027
|
ContainerUploadPanel,
|
|
905
1028
|
{
|
|
906
|
-
containerApiBaseUrl: "https://
|
|
907
|
-
storageApiBaseUrl: "https://
|
|
1029
|
+
containerApiBaseUrl: "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod",
|
|
1030
|
+
storageApiBaseUrl: "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
908
1031
|
}
|
|
909
1032
|
)
|
|
910
1033
|
] });
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default from 'react';
|
|
2
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
5
|
declare enum ContainerType {
|
|
@@ -102,7 +103,7 @@ interface ContainerUploadPanelProps {
|
|
|
102
103
|
/** Optional parent container – if set, we query children instead of roots. */
|
|
103
104
|
parentContainerId?: string;
|
|
104
105
|
}
|
|
105
|
-
declare const ContainerUploadPanel:
|
|
106
|
+
declare const ContainerUploadPanel: React__default.FC<ContainerUploadPanelProps>;
|
|
106
107
|
|
|
107
108
|
interface DesktopFileIconProps {
|
|
108
109
|
name?: string | null;
|
|
@@ -110,10 +111,10 @@ interface DesktopFileIconProps {
|
|
|
110
111
|
downloadUrl?: string | null;
|
|
111
112
|
/** Double-click / open action */
|
|
112
113
|
onOpen?: () => void;
|
|
113
|
-
/** Delete action */
|
|
114
|
-
onDelete?: () => void;
|
|
114
|
+
/** Delete action (can be async) */
|
|
115
|
+
onDelete?: () => Promise<void> | void;
|
|
115
116
|
}
|
|
116
|
-
declare const DesktopFileIcon:
|
|
117
|
+
declare const DesktopFileIcon: React__default.FC<DesktopFileIconProps>;
|
|
117
118
|
|
|
118
119
|
interface UploadContainerProps {
|
|
119
120
|
multiple?: boolean;
|
|
@@ -129,20 +130,20 @@ interface UploadContainerProps {
|
|
|
129
130
|
onUploadComplete?: (file: File, s3Url: string) => void;
|
|
130
131
|
onUploadError?: (file: File, error: Error) => void;
|
|
131
132
|
}
|
|
132
|
-
declare const UploadContainer:
|
|
133
|
+
declare const UploadContainer: React__default.FC<UploadContainerProps>;
|
|
133
134
|
|
|
134
135
|
interface UploadDropzoneProps {
|
|
135
136
|
isDragging: boolean;
|
|
136
|
-
onDragOver?: (e:
|
|
137
|
-
onDragLeave?: (e:
|
|
138
|
-
onDrop?: (e:
|
|
137
|
+
onDragOver?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
138
|
+
onDragLeave?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
139
|
+
onDrop?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
139
140
|
/** Extra className so you can make this the root wrapper */
|
|
140
141
|
className?: string;
|
|
141
|
-
style?:
|
|
142
|
+
style?: React__default.CSSProperties;
|
|
142
143
|
/** Custom content to render inside the dropzone */
|
|
143
|
-
children?:
|
|
144
|
+
children?: React__default.ReactNode;
|
|
144
145
|
}
|
|
145
|
-
declare const UploadDropzone:
|
|
146
|
+
declare const UploadDropzone: React__default.FC<UploadDropzoneProps>;
|
|
146
147
|
|
|
147
148
|
type UploadStatus = "pending" | "uploading" | "success" | "error";
|
|
148
149
|
interface UploadState {
|
|
@@ -158,7 +159,7 @@ interface UploadState {
|
|
|
158
159
|
interface UploadProgressListProps {
|
|
159
160
|
uploads: UploadState[];
|
|
160
161
|
}
|
|
161
|
-
declare const UploadProgressList:
|
|
162
|
+
declare const UploadProgressList: React__default.FC<UploadProgressListProps>;
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
165
|
* Helper: upload a file to a pre-signed S3 URL with progress + retries.
|
|
@@ -171,6 +172,7 @@ interface UseContainersOptions {
|
|
|
171
172
|
}
|
|
172
173
|
declare function UseContainers({ apiBaseUrl, parentId }: UseContainersOptions): {
|
|
173
174
|
containers: ContainerDTO[];
|
|
175
|
+
setContainers: React.Dispatch<React.SetStateAction<ContainerDTO[]>>;
|
|
174
176
|
loading: boolean;
|
|
175
177
|
error: Error | null;
|
|
176
178
|
reload: () => Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default from 'react';
|
|
2
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
5
|
declare enum ContainerType {
|
|
@@ -102,7 +103,7 @@ interface ContainerUploadPanelProps {
|
|
|
102
103
|
/** Optional parent container – if set, we query children instead of roots. */
|
|
103
104
|
parentContainerId?: string;
|
|
104
105
|
}
|
|
105
|
-
declare const ContainerUploadPanel:
|
|
106
|
+
declare const ContainerUploadPanel: React__default.FC<ContainerUploadPanelProps>;
|
|
106
107
|
|
|
107
108
|
interface DesktopFileIconProps {
|
|
108
109
|
name?: string | null;
|
|
@@ -110,10 +111,10 @@ interface DesktopFileIconProps {
|
|
|
110
111
|
downloadUrl?: string | null;
|
|
111
112
|
/** Double-click / open action */
|
|
112
113
|
onOpen?: () => void;
|
|
113
|
-
/** Delete action */
|
|
114
|
-
onDelete?: () => void;
|
|
114
|
+
/** Delete action (can be async) */
|
|
115
|
+
onDelete?: () => Promise<void> | void;
|
|
115
116
|
}
|
|
116
|
-
declare const DesktopFileIcon:
|
|
117
|
+
declare const DesktopFileIcon: React__default.FC<DesktopFileIconProps>;
|
|
117
118
|
|
|
118
119
|
interface UploadContainerProps {
|
|
119
120
|
multiple?: boolean;
|
|
@@ -129,20 +130,20 @@ interface UploadContainerProps {
|
|
|
129
130
|
onUploadComplete?: (file: File, s3Url: string) => void;
|
|
130
131
|
onUploadError?: (file: File, error: Error) => void;
|
|
131
132
|
}
|
|
132
|
-
declare const UploadContainer:
|
|
133
|
+
declare const UploadContainer: React__default.FC<UploadContainerProps>;
|
|
133
134
|
|
|
134
135
|
interface UploadDropzoneProps {
|
|
135
136
|
isDragging: boolean;
|
|
136
|
-
onDragOver?: (e:
|
|
137
|
-
onDragLeave?: (e:
|
|
138
|
-
onDrop?: (e:
|
|
137
|
+
onDragOver?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
138
|
+
onDragLeave?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
139
|
+
onDrop?: (e: React__default.DragEvent<HTMLDivElement>) => void;
|
|
139
140
|
/** Extra className so you can make this the root wrapper */
|
|
140
141
|
className?: string;
|
|
141
|
-
style?:
|
|
142
|
+
style?: React__default.CSSProperties;
|
|
142
143
|
/** Custom content to render inside the dropzone */
|
|
143
|
-
children?:
|
|
144
|
+
children?: React__default.ReactNode;
|
|
144
145
|
}
|
|
145
|
-
declare const UploadDropzone:
|
|
146
|
+
declare const UploadDropzone: React__default.FC<UploadDropzoneProps>;
|
|
146
147
|
|
|
147
148
|
type UploadStatus = "pending" | "uploading" | "success" | "error";
|
|
148
149
|
interface UploadState {
|
|
@@ -158,7 +159,7 @@ interface UploadState {
|
|
|
158
159
|
interface UploadProgressListProps {
|
|
159
160
|
uploads: UploadState[];
|
|
160
161
|
}
|
|
161
|
-
declare const UploadProgressList:
|
|
162
|
+
declare const UploadProgressList: React__default.FC<UploadProgressListProps>;
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
165
|
* Helper: upload a file to a pre-signed S3 URL with progress + retries.
|
|
@@ -171,6 +172,7 @@ interface UseContainersOptions {
|
|
|
171
172
|
}
|
|
172
173
|
declare function UseContainers({ apiBaseUrl, parentId }: UseContainersOptions): {
|
|
173
174
|
containers: ContainerDTO[];
|
|
175
|
+
setContainers: React.Dispatch<React.SetStateAction<ContainerDTO[]>>;
|
|
174
176
|
loading: boolean;
|
|
175
177
|
error: Error | null;
|
|
176
178
|
reload: () => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -437,6 +437,14 @@ var UploadProgressList = ({
|
|
|
437
437
|
},
|
|
438
438
|
children: [
|
|
439
439
|
/* @__PURE__ */ jsx2("i", { className: "bi bi-file-earmark fs-2" }),
|
|
440
|
+
u.status === "uploading" && /* @__PURE__ */ jsx2(
|
|
441
|
+
"div",
|
|
442
|
+
{
|
|
443
|
+
className: "position-absolute top-50 start-50 translate-middle",
|
|
444
|
+
style: { pointerEvents: "none" },
|
|
445
|
+
children: /* @__PURE__ */ jsx2("div", { className: "spinner-border spinner-border-sm text-primary" })
|
|
446
|
+
}
|
|
447
|
+
),
|
|
440
448
|
u.status === "error" && /* @__PURE__ */ jsx2("span", { className: "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger", children: "!" })
|
|
441
449
|
]
|
|
442
450
|
}
|
|
@@ -477,8 +485,91 @@ var UploadProgressList = ({
|
|
|
477
485
|
};
|
|
478
486
|
|
|
479
487
|
// src/components/DesktopFileIcon.tsx
|
|
488
|
+
import {
|
|
489
|
+
faFile,
|
|
490
|
+
faFilePdf,
|
|
491
|
+
faFileImage,
|
|
492
|
+
faFileWord,
|
|
493
|
+
faFileExcel,
|
|
494
|
+
faFileVideo,
|
|
495
|
+
faFileAudio,
|
|
496
|
+
faFileArchive,
|
|
497
|
+
faFileCode
|
|
498
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
499
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
480
500
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
481
501
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
502
|
+
function getFileExtension(name) {
|
|
503
|
+
if (!name) return null;
|
|
504
|
+
const lastDot = name.lastIndexOf(".");
|
|
505
|
+
if (lastDot === -1 || lastDot === name.length - 1) return null;
|
|
506
|
+
return name.substring(lastDot + 1).toLowerCase();
|
|
507
|
+
}
|
|
508
|
+
function getIconForExtension(ext) {
|
|
509
|
+
if (!ext) return faFile;
|
|
510
|
+
switch (ext) {
|
|
511
|
+
// Images
|
|
512
|
+
case "jpg":
|
|
513
|
+
case "jpeg":
|
|
514
|
+
case "png":
|
|
515
|
+
case "gif":
|
|
516
|
+
case "webp":
|
|
517
|
+
case "bmp":
|
|
518
|
+
return faFileImage;
|
|
519
|
+
// PDF
|
|
520
|
+
case "pdf":
|
|
521
|
+
return faFilePdf;
|
|
522
|
+
// Word docs
|
|
523
|
+
case "doc":
|
|
524
|
+
case "docx":
|
|
525
|
+
return faFileWord;
|
|
526
|
+
// Excel / spreadsheets
|
|
527
|
+
case "xls":
|
|
528
|
+
case "xlsx":
|
|
529
|
+
case "csv":
|
|
530
|
+
return faFileExcel;
|
|
531
|
+
// Archives
|
|
532
|
+
case "zip":
|
|
533
|
+
case "rar":
|
|
534
|
+
case "7z":
|
|
535
|
+
case "tar":
|
|
536
|
+
case "gz":
|
|
537
|
+
return faFileArchive;
|
|
538
|
+
// Video
|
|
539
|
+
case "mp4":
|
|
540
|
+
case "mov":
|
|
541
|
+
case "avi":
|
|
542
|
+
case "mkv":
|
|
543
|
+
case "webm":
|
|
544
|
+
return faFileVideo;
|
|
545
|
+
// Audio
|
|
546
|
+
case "mp3":
|
|
547
|
+
case "wav":
|
|
548
|
+
case "ogg":
|
|
549
|
+
case "flac":
|
|
550
|
+
return faFileAudio;
|
|
551
|
+
// Code files
|
|
552
|
+
case "js":
|
|
553
|
+
case "ts":
|
|
554
|
+
case "tsx":
|
|
555
|
+
case "jsx":
|
|
556
|
+
case "json":
|
|
557
|
+
case "html":
|
|
558
|
+
case "css":
|
|
559
|
+
case "cs":
|
|
560
|
+
case "java":
|
|
561
|
+
case "py":
|
|
562
|
+
case "rb":
|
|
563
|
+
case "php":
|
|
564
|
+
case "sql":
|
|
565
|
+
case "xml":
|
|
566
|
+
case "yml":
|
|
567
|
+
case "yaml":
|
|
568
|
+
return faFileCode;
|
|
569
|
+
default:
|
|
570
|
+
return faFile;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
482
573
|
var DesktopFileIcon = ({
|
|
483
574
|
name,
|
|
484
575
|
sizeBytes,
|
|
@@ -490,9 +581,11 @@ var DesktopFileIcon = ({
|
|
|
490
581
|
null
|
|
491
582
|
);
|
|
492
583
|
const [isHovered, setIsHovered] = useState2(false);
|
|
584
|
+
const [isDeleting, setIsDeleting] = useState2(false);
|
|
493
585
|
const iconRef = useRef(null);
|
|
494
586
|
const menuRef = useRef(null);
|
|
495
587
|
const handleDoubleClick = () => {
|
|
588
|
+
if (isDeleting) return;
|
|
496
589
|
if (onOpen) {
|
|
497
590
|
onOpen();
|
|
498
591
|
return;
|
|
@@ -509,13 +602,14 @@ var DesktopFileIcon = ({
|
|
|
509
602
|
}
|
|
510
603
|
};
|
|
511
604
|
const handleContextMenu = (e) => {
|
|
605
|
+
if (isDeleting) return;
|
|
512
606
|
e.preventDefault();
|
|
513
607
|
setContextMenuPos({ x: e.clientX, y: e.clientY });
|
|
514
608
|
};
|
|
515
609
|
const closeMenu = () => setContextMenuPos(null);
|
|
516
610
|
const handleDownload = () => {
|
|
517
611
|
closeMenu();
|
|
518
|
-
if (!downloadUrl) return;
|
|
612
|
+
if (!downloadUrl || isDeleting) return;
|
|
519
613
|
const a = document.createElement("a");
|
|
520
614
|
a.href = downloadUrl;
|
|
521
615
|
a.download = name ?? "";
|
|
@@ -527,18 +621,26 @@ var DesktopFileIcon = ({
|
|
|
527
621
|
};
|
|
528
622
|
const handleCopyUrl = async () => {
|
|
529
623
|
closeMenu();
|
|
530
|
-
if (!downloadUrl) return;
|
|
624
|
+
if (!downloadUrl || isDeleting) return;
|
|
531
625
|
try {
|
|
532
626
|
await navigator.clipboard?.writeText(downloadUrl);
|
|
533
627
|
} catch (err) {
|
|
534
628
|
console.error("Failed to copy URL", err);
|
|
535
629
|
}
|
|
536
630
|
};
|
|
537
|
-
const handleDelete = () => {
|
|
631
|
+
const handleDelete = async () => {
|
|
538
632
|
closeMenu();
|
|
539
|
-
onDelete
|
|
633
|
+
if (!onDelete) return;
|
|
634
|
+
try {
|
|
635
|
+
setIsDeleting(true);
|
|
636
|
+
await Promise.resolve(onDelete());
|
|
637
|
+
} catch (err) {
|
|
638
|
+
console.error("Delete failed", err);
|
|
639
|
+
}
|
|
540
640
|
};
|
|
541
641
|
const formattedSize = typeof sizeBytes === "number" ? `${(sizeBytes / 1024).toFixed(1)} KB` : void 0;
|
|
642
|
+
const ext = getFileExtension(name);
|
|
643
|
+
const iconToRender = getIconForExtension(ext);
|
|
542
644
|
useEffect(() => {
|
|
543
645
|
if (!contextMenuPos) return;
|
|
544
646
|
const handleGlobalClick = (e) => {
|
|
@@ -561,48 +663,43 @@ var DesktopFileIcon = ({
|
|
|
561
663
|
"div",
|
|
562
664
|
{
|
|
563
665
|
ref: iconRef,
|
|
564
|
-
className: "d-flex flex-column align-items-center rounded-3 p-1 " + (isHovered || contextMenuPos ? "bg-
|
|
666
|
+
className: "d-flex flex-column align-items-center rounded-3 p-1 " + (isHovered || contextMenuPos ? "bg-primary-subtle" : ""),
|
|
565
667
|
style: {
|
|
566
668
|
width: 96,
|
|
567
|
-
cursor: "pointer",
|
|
669
|
+
cursor: isDeleting ? "default" : "pointer",
|
|
568
670
|
userSelect: "none",
|
|
569
|
-
transition: "background-color 0.1s ease,
|
|
671
|
+
transition: "background-color 0.1s ease, opacity 0.1s ease",
|
|
672
|
+
opacity: isDeleting ? 0.6 : 1
|
|
570
673
|
},
|
|
571
674
|
onDoubleClick: handleDoubleClick,
|
|
572
675
|
onContextMenu: handleContextMenu,
|
|
573
676
|
title: name ?? void 0,
|
|
574
677
|
onClick: () => {
|
|
575
|
-
if (contextMenuPos)
|
|
576
|
-
closeMenu();
|
|
577
|
-
}
|
|
678
|
+
if (contextMenuPos) closeMenu();
|
|
578
679
|
},
|
|
579
680
|
onMouseEnter: () => setIsHovered(true),
|
|
580
681
|
onMouseLeave: () => setIsHovered(false),
|
|
581
682
|
children: [
|
|
582
|
-
/* @__PURE__ */
|
|
683
|
+
/* @__PURE__ */ jsxs2(
|
|
583
684
|
"div",
|
|
584
685
|
{
|
|
585
|
-
className: "bg-white border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm",
|
|
686
|
+
className: "bg-white border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm position-relative",
|
|
586
687
|
style: {
|
|
587
688
|
width: 64,
|
|
588
689
|
height: 64
|
|
589
690
|
},
|
|
590
|
-
children:
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
"div",
|
|
595
|
-
{
|
|
596
|
-
className: "small text-center text-truncate",
|
|
597
|
-
style: { width: "100%" },
|
|
598
|
-
children: name
|
|
691
|
+
children: [
|
|
692
|
+
/* @__PURE__ */ jsx3(FontAwesomeIcon, { icon: iconToRender, className: "fs-2" }),
|
|
693
|
+
isDeleting && /* @__PURE__ */ jsx3("div", { className: "position-absolute top-50 start-50 translate-middle", children: /* @__PURE__ */ jsx3("div", { className: "spinner-border spinner-border-sm text-danger" }) })
|
|
694
|
+
]
|
|
599
695
|
}
|
|
600
696
|
),
|
|
697
|
+
/* @__PURE__ */ jsx3("div", { className: "small text-center text-truncate", style: { width: "100%" }, children: name }),
|
|
601
698
|
formattedSize && /* @__PURE__ */ jsx3("small", { className: "text-muted mt-1", children: formattedSize })
|
|
602
699
|
]
|
|
603
700
|
}
|
|
604
701
|
),
|
|
605
|
-
contextMenuPos && /* @__PURE__ */ jsxs2(
|
|
702
|
+
contextMenuPos && !isDeleting && /* @__PURE__ */ jsxs2(
|
|
606
703
|
"div",
|
|
607
704
|
{
|
|
608
705
|
ref: menuRef,
|
|
@@ -711,25 +808,59 @@ var UploadContainer = ({
|
|
|
711
808
|
className: "w-100",
|
|
712
809
|
style: { minHeight: "260px", alignItems: "stretch" },
|
|
713
810
|
children: [
|
|
811
|
+
/* @__PURE__ */ jsx4("div", { className: "w-100 mb-3", children: /* @__PURE__ */ jsx4("div", { className: "d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-3", children: /* @__PURE__ */ jsx4("div", { className: "flex-grow-1 w-100", children: /* @__PURE__ */ jsx4(UploadProgressList, { uploads }) }) }) }),
|
|
714
812
|
/* @__PURE__ */ jsx4(
|
|
715
813
|
"div",
|
|
716
814
|
{
|
|
717
815
|
className: "w-100 d-flex flex-wrap gap-4 align-content-start",
|
|
718
816
|
style: { minHeight: "140px" },
|
|
719
|
-
children: existingFilesLoading ? /* @__PURE__ */ jsx4("div", { className: "w-100 d-flex justify-content-center align-items-center", children: /* @__PURE__ */ jsx4("div", { className: "spinner-border text-secondary", role: "status", children: /* @__PURE__ */ jsx4("span", { className: "visually-hidden", children: "Loading containers..." }) }) }) : existingFiles.
|
|
817
|
+
children: existingFilesLoading ? /* @__PURE__ */ jsx4("div", { className: "w-100 d-flex justify-content-center align-items-center", children: /* @__PURE__ */ jsx4("div", { className: "spinner-border text-secondary", role: "status", children: /* @__PURE__ */ jsx4("span", { className: "visually-hidden", children: "Loading containers..." }) }) }) : existingFiles.length === 0 ? /* @__PURE__ */ jsxs3(
|
|
818
|
+
"div",
|
|
819
|
+
{
|
|
820
|
+
className: "w-100 d-flex flex-column align-items-center justify-content-center text-muted",
|
|
821
|
+
style: {
|
|
822
|
+
minHeight: "160px",
|
|
823
|
+
border: "2px dashed #ccc",
|
|
824
|
+
borderRadius: "10px",
|
|
825
|
+
padding: "20px",
|
|
826
|
+
cursor: "pointer",
|
|
827
|
+
transition: "background 0.12s, border-color 0.12s"
|
|
828
|
+
},
|
|
829
|
+
onClick: () => document.getElementById("filePicker")?.click(),
|
|
830
|
+
onMouseEnter: (e) => e.currentTarget.style.borderColor = "#888",
|
|
831
|
+
onMouseLeave: (e) => e.currentTarget.style.borderColor = "#ccc",
|
|
832
|
+
children: [
|
|
833
|
+
/* @__PURE__ */ jsx4(
|
|
834
|
+
"input",
|
|
835
|
+
{
|
|
836
|
+
id: "filePicker",
|
|
837
|
+
type: "file",
|
|
838
|
+
multiple: true,
|
|
839
|
+
hidden: true,
|
|
840
|
+
onChange: (e) => {
|
|
841
|
+
if (!e.target.files) return;
|
|
842
|
+
onFilesSelected?.(e.target.files);
|
|
843
|
+
startUploadsIfNeeded(e.target.files);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
),
|
|
847
|
+
/* @__PURE__ */ jsx4("strong", { children: "Drag & drop files here" }),
|
|
848
|
+
/* @__PURE__ */ jsx4("small", { className: "mt-1", children: "\u2026or click to browse" })
|
|
849
|
+
]
|
|
850
|
+
}
|
|
851
|
+
) : existingFiles.map((file) => /* @__PURE__ */ jsx4(
|
|
720
852
|
DesktopFileIcon,
|
|
721
853
|
{
|
|
722
854
|
name: file.Name,
|
|
723
|
-
sizeBytes:
|
|
724
|
-
downloadUrl: file.PublicUrl
|
|
855
|
+
sizeBytes: file.FileSize,
|
|
856
|
+
downloadUrl: file.PublicUrl,
|
|
725
857
|
onOpen: () => handleExistingFileOpen(file),
|
|
726
|
-
onDelete:
|
|
858
|
+
onDelete: () => onDeleteFile?.(file)
|
|
727
859
|
},
|
|
728
860
|
file.Id
|
|
729
861
|
))
|
|
730
862
|
}
|
|
731
|
-
)
|
|
732
|
-
/* @__PURE__ */ jsx4("div", { className: "w-100 mt-3", children: /* @__PURE__ */ jsx4("div", { className: "d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-3", children: /* @__PURE__ */ jsx4("div", { className: "flex-grow-1 w-100", children: /* @__PURE__ */ jsx4(UploadProgressList, { uploads }) }) }) })
|
|
863
|
+
)
|
|
733
864
|
]
|
|
734
865
|
}
|
|
735
866
|
);
|
|
@@ -761,6 +892,7 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
761
892
|
}, [apiBaseUrl, parentId]);
|
|
762
893
|
return {
|
|
763
894
|
containers,
|
|
895
|
+
setContainers,
|
|
764
896
|
loading,
|
|
765
897
|
error,
|
|
766
898
|
reload: load
|
|
@@ -774,17 +906,18 @@ var ContainerUploadPanel = ({
|
|
|
774
906
|
storageApiBaseUrl,
|
|
775
907
|
parentContainerId
|
|
776
908
|
}) => {
|
|
777
|
-
const { containers, reload, loading } = UseContainers({
|
|
909
|
+
const { containers, setContainers, reload, loading } = UseContainers({
|
|
778
910
|
apiBaseUrl: containerApiBaseUrl,
|
|
779
911
|
parentId: parentContainerId
|
|
780
912
|
});
|
|
781
913
|
const getPresignedUrl = async (file) => {
|
|
782
914
|
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
783
915
|
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
916
|
+
const contentType = file.type || "application/octet-stream";
|
|
784
917
|
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
785
918
|
file.name,
|
|
786
919
|
file.size,
|
|
787
|
-
encodeURIComponent(
|
|
920
|
+
encodeURIComponent(contentType)
|
|
788
921
|
);
|
|
789
922
|
async function getPresignedUrlWithRetry(container, attempts = 3) {
|
|
790
923
|
let lastError;
|
|
@@ -809,13 +942,6 @@ var ContainerUploadPanel = ({
|
|
|
809
942
|
const handleUploadError = (file, err) => {
|
|
810
943
|
console.error("Upload failed:", file.name, err);
|
|
811
944
|
};
|
|
812
|
-
const handleOnDeleteFile = async (file) => {
|
|
813
|
-
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
814
|
-
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
815
|
-
await sdkDb.container.DeleteContainer(file.Id);
|
|
816
|
-
await sdkS3.s3.DeleteS3(file);
|
|
817
|
-
await reload();
|
|
818
|
-
};
|
|
819
945
|
const handleExistingFileClick = (file) => {
|
|
820
946
|
const a = document.createElement("a");
|
|
821
947
|
a.href = file.PublicUrl ?? "";
|
|
@@ -826,6 +952,13 @@ var ContainerUploadPanel = ({
|
|
|
826
952
|
a.click();
|
|
827
953
|
document.body.removeChild(a);
|
|
828
954
|
};
|
|
955
|
+
const handleDeleteFile = async (file) => {
|
|
956
|
+
const sdkDb = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
957
|
+
const sdkS3 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
958
|
+
await sdkDb.container.DeleteContainer(file.Id);
|
|
959
|
+
await sdkS3.s3.DeleteS3(file);
|
|
960
|
+
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
961
|
+
};
|
|
829
962
|
return /* @__PURE__ */ jsx5(
|
|
830
963
|
UploadContainer,
|
|
831
964
|
{
|
|
@@ -836,7 +969,7 @@ var ContainerUploadPanel = ({
|
|
|
836
969
|
getPresignedUrl,
|
|
837
970
|
onUploadComplete: handleUploadComplete,
|
|
838
971
|
onUploadError: handleUploadError,
|
|
839
|
-
onDeleteFile:
|
|
972
|
+
onDeleteFile: handleDeleteFile
|
|
840
973
|
}
|
|
841
974
|
);
|
|
842
975
|
};
|
|
@@ -867,8 +1000,8 @@ function HomeContent() {
|
|
|
867
1000
|
user && /* @__PURE__ */ jsx6(
|
|
868
1001
|
ContainerUploadPanel,
|
|
869
1002
|
{
|
|
870
|
-
containerApiBaseUrl: "https://
|
|
871
|
-
storageApiBaseUrl: "https://
|
|
1003
|
+
containerApiBaseUrl: "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod",
|
|
1004
|
+
storageApiBaseUrl: "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
872
1005
|
}
|
|
873
1006
|
)
|
|
874
1007
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sparkstudio/storage-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -37,8 +37,10 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@aws-sdk/client-s3": "^3.958.0",
|
|
39
39
|
"@aws-sdk/s3-request-presigner": "^3.958.0",
|
|
40
|
+
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
|
41
|
+
"@fortawesome/react-fontawesome": "^3.1.1",
|
|
40
42
|
"@sparkstudio/authentication-ui": "^1.0.29",
|
|
41
|
-
"@sparkstudio/common-ui": "^1.0.
|
|
43
|
+
"@sparkstudio/common-ui": "^1.0.11",
|
|
42
44
|
"barrelsby": "^2.8.1"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|