@sparkstudio/storage-ui 1.0.28 → 1.0.30
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 +999 -275
- package/dist/index.d.cts +85 -18
- package/dist/index.d.ts +85 -18
- package/dist/index.js +990 -264
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -233,51 +233,8 @@ var ContainerType = /* @__PURE__ */ ((ContainerType2) => {
|
|
|
233
233
|
return ContainerType2;
|
|
234
234
|
})(ContainerType || {});
|
|
235
235
|
|
|
236
|
-
// src/components/
|
|
237
|
-
import "react";
|
|
238
|
-
|
|
239
|
-
// src/components/UploadContainer.tsx
|
|
240
|
-
import { useState as useState3 } from "react";
|
|
241
|
-
|
|
242
|
-
// src/components/UploadDropzone.tsx
|
|
243
|
-
import "react";
|
|
244
|
-
import { jsx } from "react/jsx-runtime";
|
|
245
|
-
var UploadDropzone = ({
|
|
246
|
-
isDragging,
|
|
247
|
-
onDragOver,
|
|
248
|
-
onDragLeave,
|
|
249
|
-
onDrop,
|
|
250
|
-
className = "",
|
|
251
|
-
style,
|
|
252
|
-
children
|
|
253
|
-
}) => {
|
|
254
|
-
const baseClass = "rounded-3 d-flex flex-column align-items-center justify-content-center";
|
|
255
|
-
const stateClass = isDragging ? "bg-body-secondary border-dashed border-2 border-secondary" : "bg-body-trasparent border-solid border-transparent border-2";
|
|
256
|
-
const combinedClassName = `${baseClass} ${stateClass} ${className}`.trim();
|
|
257
|
-
const handleDragOver = (e) => {
|
|
258
|
-
e.preventDefault();
|
|
259
|
-
onDragOver?.(e);
|
|
260
|
-
};
|
|
261
|
-
const handleDragLeave = (e) => {
|
|
262
|
-
e.preventDefault();
|
|
263
|
-
onDragLeave?.(e);
|
|
264
|
-
};
|
|
265
|
-
const handleDrop = (e) => {
|
|
266
|
-
e.preventDefault();
|
|
267
|
-
onDrop?.(e);
|
|
268
|
-
};
|
|
269
|
-
return /* @__PURE__ */ jsx(
|
|
270
|
-
"div",
|
|
271
|
-
{
|
|
272
|
-
className: combinedClassName,
|
|
273
|
-
style: { minHeight: "140px", ...style },
|
|
274
|
-
onDragOver: handleDragOver,
|
|
275
|
-
onDragLeave: handleDragLeave,
|
|
276
|
-
onDrop: handleDrop,
|
|
277
|
-
children
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
};
|
|
236
|
+
// src/components/ContainerIdGridPanel.tsx
|
|
237
|
+
import { useEffect, useMemo as useMemo2, useRef, useState as useState3 } from "react";
|
|
281
238
|
|
|
282
239
|
// src/hooks/UseUploadManager.ts
|
|
283
240
|
import { useState, useCallback } from "react";
|
|
@@ -431,13 +388,13 @@ function UseUploadManager({
|
|
|
431
388
|
|
|
432
389
|
// src/components/UploadProgressList.tsx
|
|
433
390
|
import "react";
|
|
434
|
-
import { jsx
|
|
391
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
435
392
|
var UploadProgressList = ({
|
|
436
393
|
uploads
|
|
437
394
|
}) => {
|
|
438
395
|
const visibleUploads = uploads.filter((u) => u.status !== "success");
|
|
439
396
|
if (visibleUploads.length === 0) return null;
|
|
440
|
-
return /* @__PURE__ */
|
|
397
|
+
return /* @__PURE__ */ jsx(
|
|
441
398
|
"div",
|
|
442
399
|
{
|
|
443
400
|
className: "w-100 d-flex flex-wrap gap-4 align-content-start mt-3",
|
|
@@ -461,20 +418,20 @@ var UploadProgressList = ({
|
|
|
461
418
|
height: 64
|
|
462
419
|
},
|
|
463
420
|
children: [
|
|
464
|
-
/* @__PURE__ */
|
|
465
|
-
u.status === "uploading" && /* @__PURE__ */
|
|
421
|
+
/* @__PURE__ */ jsx("i", { className: "bi bi-file-earmark fs-2" }),
|
|
422
|
+
u.status === "uploading" && /* @__PURE__ */ jsx(
|
|
466
423
|
"div",
|
|
467
424
|
{
|
|
468
425
|
className: "position-absolute top-50 start-50 translate-middle",
|
|
469
426
|
style: { pointerEvents: "none" },
|
|
470
|
-
children: /* @__PURE__ */
|
|
427
|
+
children: /* @__PURE__ */ jsx("div", { className: "spinner-border spinner-border-sm text-primary" })
|
|
471
428
|
}
|
|
472
429
|
),
|
|
473
|
-
u.status === "error" && /* @__PURE__ */
|
|
430
|
+
u.status === "error" && /* @__PURE__ */ jsx("span", { className: "position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger", children: "!" })
|
|
474
431
|
]
|
|
475
432
|
}
|
|
476
433
|
),
|
|
477
|
-
/* @__PURE__ */
|
|
434
|
+
/* @__PURE__ */ jsx(
|
|
478
435
|
"div",
|
|
479
436
|
{
|
|
480
437
|
className: "small text-center text-truncate",
|
|
@@ -482,7 +439,7 @@ var UploadProgressList = ({
|
|
|
482
439
|
children: u.file.name
|
|
483
440
|
}
|
|
484
441
|
),
|
|
485
|
-
/* @__PURE__ */
|
|
442
|
+
/* @__PURE__ */ jsx("div", { className: "w-100 mt-1", children: /* @__PURE__ */ jsx("div", { className: "progress", style: { height: "4px" }, children: /* @__PURE__ */ jsx(
|
|
486
443
|
"div",
|
|
487
444
|
{
|
|
488
445
|
className: "progress-bar " + (u.status === "error" ? "bg-danger" : ""),
|
|
@@ -493,7 +450,7 @@ var UploadProgressList = ({
|
|
|
493
450
|
"aria-valuemax": 100
|
|
494
451
|
}
|
|
495
452
|
) }) }),
|
|
496
|
-
u.status === "error" && /* @__PURE__ */
|
|
453
|
+
u.status === "error" && /* @__PURE__ */ jsx(
|
|
497
454
|
"div",
|
|
498
455
|
{
|
|
499
456
|
className: "text-danger small mt-1 text-center",
|
|
@@ -509,6 +466,559 @@ var UploadProgressList = ({
|
|
|
509
466
|
);
|
|
510
467
|
};
|
|
511
468
|
|
|
469
|
+
// src/components/FileIconGrid.tsx
|
|
470
|
+
import "react";
|
|
471
|
+
|
|
472
|
+
// src/components/FileIconCard.tsx
|
|
473
|
+
import { useMemo, useState as useState2 } from "react";
|
|
474
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
475
|
+
function sanitizeIconHtml(input) {
|
|
476
|
+
return input.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/\son\w+="[^"]*"/gi, "").replace(/\son\w+='[^']*'/gi, "").replace(/javascript:/gi, "");
|
|
477
|
+
}
|
|
478
|
+
var FileIconCard = (props) => {
|
|
479
|
+
const {
|
|
480
|
+
file,
|
|
481
|
+
deleteDisabled,
|
|
482
|
+
selected,
|
|
483
|
+
onSelect,
|
|
484
|
+
onDeleteFile,
|
|
485
|
+
onClickFile,
|
|
486
|
+
icon,
|
|
487
|
+
iconHtml,
|
|
488
|
+
title,
|
|
489
|
+
className
|
|
490
|
+
} = props;
|
|
491
|
+
const [deleting, setDeleting] = useState2(false);
|
|
492
|
+
const [error, setError] = useState2(null);
|
|
493
|
+
const safeIconHtml = useMemo(() => {
|
|
494
|
+
if (!iconHtml) return null;
|
|
495
|
+
return sanitizeIconHtml(iconHtml);
|
|
496
|
+
}, [iconHtml]);
|
|
497
|
+
const canDelete = !!onDeleteFile && !deleteDisabled && !deleting;
|
|
498
|
+
const handleClick = () => {
|
|
499
|
+
onSelect?.(file);
|
|
500
|
+
onClickFile?.(file);
|
|
501
|
+
};
|
|
502
|
+
const handleDelete = async (ev) => {
|
|
503
|
+
ev.stopPropagation();
|
|
504
|
+
if (!canDelete) return;
|
|
505
|
+
setError(null);
|
|
506
|
+
setDeleting(true);
|
|
507
|
+
try {
|
|
508
|
+
await onDeleteFile?.(file);
|
|
509
|
+
} catch (e) {
|
|
510
|
+
setError(e instanceof Error ? e.message : "Delete failed");
|
|
511
|
+
} finally {
|
|
512
|
+
setDeleting(false);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
const borderColor = selected ? "rgba(13,110,253,0.8)" : "rgba(0,0,0,0.12)";
|
|
516
|
+
const boxShadow = selected ? "0 0 0 3px rgba(13,110,253,0.2)" : "none";
|
|
517
|
+
return /* @__PURE__ */ jsxs2(
|
|
518
|
+
"div",
|
|
519
|
+
{
|
|
520
|
+
className: [
|
|
521
|
+
"file-icon-card",
|
|
522
|
+
deleteDisabled ? "is-delete-disabled" : "",
|
|
523
|
+
deleting ? "is-deleting" : "",
|
|
524
|
+
className ?? ""
|
|
525
|
+
].join(" "),
|
|
526
|
+
role: "button",
|
|
527
|
+
tabIndex: 0,
|
|
528
|
+
onClick: handleClick,
|
|
529
|
+
onKeyDown: (e) => {
|
|
530
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
531
|
+
e.preventDefault();
|
|
532
|
+
handleClick();
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
title: title ?? file.Name ?? "File",
|
|
536
|
+
style: {
|
|
537
|
+
display: "flex",
|
|
538
|
+
alignItems: "center",
|
|
539
|
+
gap: 12,
|
|
540
|
+
padding: 12,
|
|
541
|
+
border: `1px solid ${borderColor}`,
|
|
542
|
+
boxShadow,
|
|
543
|
+
borderRadius: 12,
|
|
544
|
+
userSelect: "none",
|
|
545
|
+
cursor: "pointer",
|
|
546
|
+
background: "white"
|
|
547
|
+
},
|
|
548
|
+
children: [
|
|
549
|
+
/* @__PURE__ */ jsx2(
|
|
550
|
+
"div",
|
|
551
|
+
{
|
|
552
|
+
style: {
|
|
553
|
+
width: 44,
|
|
554
|
+
height: 44,
|
|
555
|
+
borderRadius: 10,
|
|
556
|
+
display: "grid",
|
|
557
|
+
placeItems: "center",
|
|
558
|
+
background: "rgba(0,0,0,0.04)",
|
|
559
|
+
flex: "0 0 auto"
|
|
560
|
+
},
|
|
561
|
+
children: icon ? icon : safeIconHtml ? /* @__PURE__ */ jsx2("span", { "aria-hidden": true, dangerouslySetInnerHTML: { __html: safeIconHtml } }) : /* @__PURE__ */ jsx2(DefaultFileIcon, {})
|
|
562
|
+
}
|
|
563
|
+
),
|
|
564
|
+
/* @__PURE__ */ jsxs2("div", { style: { minWidth: 0, flex: "1 1 auto" }, children: [
|
|
565
|
+
/* @__PURE__ */ jsx2(
|
|
566
|
+
"div",
|
|
567
|
+
{
|
|
568
|
+
style: {
|
|
569
|
+
fontWeight: 600,
|
|
570
|
+
overflow: "hidden",
|
|
571
|
+
textOverflow: "ellipsis",
|
|
572
|
+
whiteSpace: "nowrap"
|
|
573
|
+
},
|
|
574
|
+
children: title ?? file.Name ?? "Untitled"
|
|
575
|
+
}
|
|
576
|
+
),
|
|
577
|
+
/* @__PURE__ */ jsx2("div", { style: { fontSize: 12, opacity: 0.7 }, children: typeof file.FileSize === "number" ? formatBytes(file.FileSize) : "" }),
|
|
578
|
+
error ? /* @__PURE__ */ jsx2("div", { style: { fontSize: 12, color: "crimson", marginTop: 4 }, children: error }) : null
|
|
579
|
+
] }),
|
|
580
|
+
!deleteDisabled ? /* @__PURE__ */ jsxs2(
|
|
581
|
+
"button",
|
|
582
|
+
{
|
|
583
|
+
type: "button",
|
|
584
|
+
onClick: handleDelete,
|
|
585
|
+
disabled: !canDelete,
|
|
586
|
+
"aria-label": "Delete file",
|
|
587
|
+
style: {
|
|
588
|
+
border: "1px solid rgba(0,0,0,0.18)",
|
|
589
|
+
background: canDelete ? "white" : "rgba(0,0,0,0.04)",
|
|
590
|
+
borderRadius: 10,
|
|
591
|
+
padding: "8px 10px",
|
|
592
|
+
cursor: canDelete ? "pointer" : "not-allowed",
|
|
593
|
+
display: "flex",
|
|
594
|
+
alignItems: "center",
|
|
595
|
+
gap: 8
|
|
596
|
+
},
|
|
597
|
+
children: [
|
|
598
|
+
deleting ? /* @__PURE__ */ jsx2(SmallSpinner, {}) : /* @__PURE__ */ jsx2(TrashIcon, {}),
|
|
599
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: 13 }, children: deleting ? "Deleting\u2026" : "Delete" })
|
|
600
|
+
]
|
|
601
|
+
}
|
|
602
|
+
) : null
|
|
603
|
+
]
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
};
|
|
607
|
+
function formatBytes(bytes) {
|
|
608
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "";
|
|
609
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
610
|
+
let v = bytes;
|
|
611
|
+
let i = 0;
|
|
612
|
+
while (v >= 1024 && i < units.length - 1) {
|
|
613
|
+
v /= 1024;
|
|
614
|
+
i++;
|
|
615
|
+
}
|
|
616
|
+
return `${v.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
|
|
617
|
+
}
|
|
618
|
+
function SmallSpinner() {
|
|
619
|
+
return /* @__PURE__ */ jsx2(
|
|
620
|
+
"span",
|
|
621
|
+
{
|
|
622
|
+
"aria-hidden": true,
|
|
623
|
+
style: {
|
|
624
|
+
width: 14,
|
|
625
|
+
height: 14,
|
|
626
|
+
borderRadius: "50%",
|
|
627
|
+
border: "2px solid rgba(0,0,0,0.2)",
|
|
628
|
+
borderTopColor: "rgba(0,0,0,0.7)",
|
|
629
|
+
display: "inline-block",
|
|
630
|
+
animation: "fileIconSpin 0.8s linear infinite"
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
function DefaultFileIcon() {
|
|
636
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
637
|
+
/* @__PURE__ */ jsx2(
|
|
638
|
+
"path",
|
|
639
|
+
{
|
|
640
|
+
d: "M7 3h7l3 3v15a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z",
|
|
641
|
+
stroke: "currentColor",
|
|
642
|
+
strokeWidth: "2"
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
/* @__PURE__ */ jsx2("path", { d: "M14 3v4a1 1 0 0 0 1 1h4", stroke: "currentColor", strokeWidth: "2" })
|
|
646
|
+
] });
|
|
647
|
+
}
|
|
648
|
+
function TrashIcon() {
|
|
649
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
650
|
+
/* @__PURE__ */ jsx2("path", { d: "M3 6h18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }),
|
|
651
|
+
/* @__PURE__ */ jsx2(
|
|
652
|
+
"path",
|
|
653
|
+
{
|
|
654
|
+
d: "M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2",
|
|
655
|
+
stroke: "currentColor",
|
|
656
|
+
strokeWidth: "2"
|
|
657
|
+
}
|
|
658
|
+
),
|
|
659
|
+
/* @__PURE__ */ jsx2(
|
|
660
|
+
"path",
|
|
661
|
+
{
|
|
662
|
+
d: "M6 6l1 16a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-16",
|
|
663
|
+
stroke: "currentColor",
|
|
664
|
+
strokeWidth: "2"
|
|
665
|
+
}
|
|
666
|
+
),
|
|
667
|
+
/* @__PURE__ */ jsx2(
|
|
668
|
+
"path",
|
|
669
|
+
{
|
|
670
|
+
d: "M10 11v7M14 11v7",
|
|
671
|
+
stroke: "currentColor",
|
|
672
|
+
strokeWidth: "2",
|
|
673
|
+
strokeLinecap: "round"
|
|
674
|
+
}
|
|
675
|
+
)
|
|
676
|
+
] });
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/components/FileIconGrid.tsx
|
|
680
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
681
|
+
function FileIconGrid(props) {
|
|
682
|
+
const {
|
|
683
|
+
files,
|
|
684
|
+
deleteDisabled,
|
|
685
|
+
onDeleted,
|
|
686
|
+
selectedId,
|
|
687
|
+
onSelect,
|
|
688
|
+
icon,
|
|
689
|
+
iconHtml,
|
|
690
|
+
className
|
|
691
|
+
} = props;
|
|
692
|
+
return /* @__PURE__ */ jsx3(
|
|
693
|
+
"div",
|
|
694
|
+
{
|
|
695
|
+
className,
|
|
696
|
+
style: {
|
|
697
|
+
display: "grid",
|
|
698
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
|
|
699
|
+
gap: 12
|
|
700
|
+
},
|
|
701
|
+
children: files.map((f) => /* @__PURE__ */ jsx3(
|
|
702
|
+
FileIconCard,
|
|
703
|
+
{
|
|
704
|
+
file: f,
|
|
705
|
+
deleteDisabled,
|
|
706
|
+
onDeleteFile: onDeleted,
|
|
707
|
+
onSelect,
|
|
708
|
+
selected: selectedId === f.Id,
|
|
709
|
+
icon,
|
|
710
|
+
iconHtml
|
|
711
|
+
},
|
|
712
|
+
f.Id
|
|
713
|
+
))
|
|
714
|
+
}
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// src/components/ContainerIdGridPanel.tsx
|
|
719
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
720
|
+
function ContainerIdGridPanel(props) {
|
|
721
|
+
const {
|
|
722
|
+
containerApiBaseUrl,
|
|
723
|
+
storageApiBaseUrl,
|
|
724
|
+
containerIds,
|
|
725
|
+
onContainerIdsChange,
|
|
726
|
+
accept = "*/*",
|
|
727
|
+
multiple = true,
|
|
728
|
+
selectedId,
|
|
729
|
+
onSelect,
|
|
730
|
+
icon,
|
|
731
|
+
iconHtml,
|
|
732
|
+
deleteDisabled,
|
|
733
|
+
className,
|
|
734
|
+
onDeleted
|
|
735
|
+
} = props;
|
|
736
|
+
const sdkDb = useMemo2(
|
|
737
|
+
() => new SparkStudioStorageSDK(containerApiBaseUrl),
|
|
738
|
+
[containerApiBaseUrl]
|
|
739
|
+
);
|
|
740
|
+
const sdkS3 = useMemo2(
|
|
741
|
+
() => new SparkStudioStorageSDK(storageApiBaseUrl),
|
|
742
|
+
[storageApiBaseUrl]
|
|
743
|
+
);
|
|
744
|
+
const [loading, setLoading] = useState3(false);
|
|
745
|
+
const [files, setFiles] = useState3([]);
|
|
746
|
+
const [dragOver, setDragOver] = useState3(false);
|
|
747
|
+
const [errMsg, setErrMsg] = useState3(null);
|
|
748
|
+
const idsRef = useRef(containerIds);
|
|
749
|
+
useEffect(() => {
|
|
750
|
+
idsRef.current = containerIds;
|
|
751
|
+
}, [containerIds]);
|
|
752
|
+
const createdByFileRef = useRef(/* @__PURE__ */ new WeakMap());
|
|
753
|
+
useEffect(() => {
|
|
754
|
+
let cancelled = false;
|
|
755
|
+
async function loadByIds(ids) {
|
|
756
|
+
setErrMsg(null);
|
|
757
|
+
if (!ids || ids.length === 0) {
|
|
758
|
+
setFiles([]);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
setLoading(true);
|
|
762
|
+
try {
|
|
763
|
+
const results = await Promise.all(
|
|
764
|
+
ids.map(async (id) => {
|
|
765
|
+
try {
|
|
766
|
+
const dto = await sdkDb.container.Read?.(id);
|
|
767
|
+
return dto ?? null;
|
|
768
|
+
} catch {
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
})
|
|
772
|
+
);
|
|
773
|
+
if (cancelled) return;
|
|
774
|
+
const map = /* @__PURE__ */ new Map();
|
|
775
|
+
for (const r of results) if (r?.Id) map.set(r.Id, r);
|
|
776
|
+
setFiles(
|
|
777
|
+
ids.map((id) => map.get(id)).filter(Boolean)
|
|
778
|
+
);
|
|
779
|
+
} catch (e) {
|
|
780
|
+
if (!cancelled)
|
|
781
|
+
setErrMsg(e instanceof Error ? e.message : "Failed to load files");
|
|
782
|
+
} finally {
|
|
783
|
+
if (!cancelled) setLoading(false);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
void loadByIds(containerIds);
|
|
787
|
+
return () => {
|
|
788
|
+
cancelled = true;
|
|
789
|
+
};
|
|
790
|
+
}, [containerIds, sdkDb]);
|
|
791
|
+
const getPresignedUrl = async (file) => {
|
|
792
|
+
const contentType = file.type || "application/octet-stream";
|
|
793
|
+
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
794
|
+
file.name,
|
|
795
|
+
file.size,
|
|
796
|
+
encodeURIComponent(contentType)
|
|
797
|
+
);
|
|
798
|
+
createdByFileRef.current.set(file, containerDTO);
|
|
799
|
+
let lastError;
|
|
800
|
+
for (let i = 1; i <= 3; i++) {
|
|
801
|
+
try {
|
|
802
|
+
return await sdkS3.s3.GetPreSignedUrl(containerDTO);
|
|
803
|
+
} catch (e) {
|
|
804
|
+
lastError = e;
|
|
805
|
+
if (i < 3) await new Promise((r) => setTimeout(r, 500 * i));
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
throw lastError instanceof Error ? lastError : new Error("Failed to fetch presigned URL");
|
|
809
|
+
};
|
|
810
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
811
|
+
autoUpload: true,
|
|
812
|
+
getPresignedUrl,
|
|
813
|
+
onUploadComplete: async (file) => {
|
|
814
|
+
setErrMsg(null);
|
|
815
|
+
const created = createdByFileRef.current.get(file);
|
|
816
|
+
if (created?.Id) {
|
|
817
|
+
const prev = idsRef.current ?? [];
|
|
818
|
+
const next = prev.includes(created.Id) ? prev : [...prev, created.Id];
|
|
819
|
+
onContainerIdsChange(next);
|
|
820
|
+
}
|
|
821
|
+
if (created?.Id) {
|
|
822
|
+
try {
|
|
823
|
+
const refreshed = await sdkDb.container.Read?.(created.Id);
|
|
824
|
+
if (refreshed) {
|
|
825
|
+
setFiles((prevFiles) => {
|
|
826
|
+
const nextFiles = prevFiles.slice();
|
|
827
|
+
const idx = nextFiles.findIndex((x) => x.Id === created.Id);
|
|
828
|
+
if (idx >= 0) nextFiles[idx] = refreshed;
|
|
829
|
+
else nextFiles.push(refreshed);
|
|
830
|
+
return nextFiles;
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
onUploadError: (_file, error) => {
|
|
838
|
+
setErrMsg(error?.message ?? "Upload failed");
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
const handleDelete = async (file) => {
|
|
842
|
+
if (deleteDisabled) return;
|
|
843
|
+
await sdkDb.container.DeleteContainer(file.Id);
|
|
844
|
+
await sdkS3.s3.DeleteS3(file);
|
|
845
|
+
const prev = idsRef.current ?? [];
|
|
846
|
+
onContainerIdsChange(prev.filter((id) => id !== file.Id));
|
|
847
|
+
setFiles((prevFiles) => prevFiles.filter((x) => x.Id !== file.Id));
|
|
848
|
+
onDeleted?.(file);
|
|
849
|
+
};
|
|
850
|
+
const openPicker = () => {
|
|
851
|
+
const input = document.createElement("input");
|
|
852
|
+
input.type = "file";
|
|
853
|
+
input.multiple = multiple;
|
|
854
|
+
input.accept = accept;
|
|
855
|
+
input.onchange = () => {
|
|
856
|
+
if (input.files) startUploadsIfNeeded(input.files);
|
|
857
|
+
};
|
|
858
|
+
input.click();
|
|
859
|
+
};
|
|
860
|
+
const onDrop = (ev) => {
|
|
861
|
+
ev.preventDefault();
|
|
862
|
+
ev.stopPropagation();
|
|
863
|
+
setDragOver(false);
|
|
864
|
+
const list = ev.dataTransfer.files;
|
|
865
|
+
if (!list || list.length === 0) return;
|
|
866
|
+
startUploadsIfNeeded(list);
|
|
867
|
+
};
|
|
868
|
+
return /* @__PURE__ */ jsxs3("div", { className, style: { display: "grid", gap: 12 }, children: [
|
|
869
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
870
|
+
/* @__PURE__ */ jsx4(UploadProgressList, { uploads }),
|
|
871
|
+
errMsg ? /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: "crimson", marginTop: 6 }, children: errMsg }) : null
|
|
872
|
+
] }),
|
|
873
|
+
/* @__PURE__ */ jsxs3(
|
|
874
|
+
"div",
|
|
875
|
+
{
|
|
876
|
+
onDragEnter: (e) => {
|
|
877
|
+
e.preventDefault();
|
|
878
|
+
e.stopPropagation();
|
|
879
|
+
setDragOver(true);
|
|
880
|
+
},
|
|
881
|
+
onDragOver: (e) => {
|
|
882
|
+
e.preventDefault();
|
|
883
|
+
e.stopPropagation();
|
|
884
|
+
setDragOver(true);
|
|
885
|
+
},
|
|
886
|
+
onDragLeave: (e) => {
|
|
887
|
+
e.preventDefault();
|
|
888
|
+
e.stopPropagation();
|
|
889
|
+
setDragOver(false);
|
|
890
|
+
},
|
|
891
|
+
onDrop,
|
|
892
|
+
style: {
|
|
893
|
+
position: "relative",
|
|
894
|
+
borderRadius: 14,
|
|
895
|
+
border: `2px dashed ${dragOver ? "rgba(13,110,253,0.9)" : "rgba(0,0,0,0.15)"}`,
|
|
896
|
+
background: dragOver ? "rgba(13,110,253,0.06)" : "transparent",
|
|
897
|
+
padding: 12
|
|
898
|
+
},
|
|
899
|
+
children: [
|
|
900
|
+
dragOver ? /* @__PURE__ */ jsx4(
|
|
901
|
+
"div",
|
|
902
|
+
{
|
|
903
|
+
style: {
|
|
904
|
+
position: "absolute",
|
|
905
|
+
inset: 0,
|
|
906
|
+
borderRadius: 14,
|
|
907
|
+
display: "grid",
|
|
908
|
+
placeItems: "center",
|
|
909
|
+
pointerEvents: "none",
|
|
910
|
+
background: "rgba(13,110,253,0.10)",
|
|
911
|
+
fontWeight: 800
|
|
912
|
+
},
|
|
913
|
+
children: "Drop files to upload"
|
|
914
|
+
}
|
|
915
|
+
) : null,
|
|
916
|
+
/* @__PURE__ */ jsxs3(
|
|
917
|
+
"div",
|
|
918
|
+
{
|
|
919
|
+
style: {
|
|
920
|
+
display: "flex",
|
|
921
|
+
justifyContent: "space-between",
|
|
922
|
+
marginBottom: 10
|
|
923
|
+
},
|
|
924
|
+
children: [
|
|
925
|
+
/* @__PURE__ */ jsx4("div", { style: { fontWeight: 700 }, children: "Files" }),
|
|
926
|
+
/* @__PURE__ */ jsx4(
|
|
927
|
+
"button",
|
|
928
|
+
{
|
|
929
|
+
type: "button",
|
|
930
|
+
onClick: openPicker,
|
|
931
|
+
style: {
|
|
932
|
+
border: "1px solid rgba(0,0,0,0.18)",
|
|
933
|
+
background: "white",
|
|
934
|
+
borderRadius: 10,
|
|
935
|
+
padding: "8px 10px",
|
|
936
|
+
cursor: "pointer",
|
|
937
|
+
fontWeight: 600
|
|
938
|
+
},
|
|
939
|
+
children: "Browse\u2026"
|
|
940
|
+
}
|
|
941
|
+
)
|
|
942
|
+
]
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
loading ? /* @__PURE__ */ jsx4(
|
|
946
|
+
"div",
|
|
947
|
+
{
|
|
948
|
+
className: "d-flex justify-content-center align-items-center",
|
|
949
|
+
style: { minHeight: 120 },
|
|
950
|
+
children: /* @__PURE__ */ jsx4("div", { className: "spinner-border text-secondary", role: "status" })
|
|
951
|
+
}
|
|
952
|
+
) : /* @__PURE__ */ jsx4(
|
|
953
|
+
FileIconGrid,
|
|
954
|
+
{
|
|
955
|
+
files,
|
|
956
|
+
deleteDisabled,
|
|
957
|
+
onDeleted: handleDelete,
|
|
958
|
+
selectedId,
|
|
959
|
+
onSelect,
|
|
960
|
+
icon,
|
|
961
|
+
iconHtml
|
|
962
|
+
}
|
|
963
|
+
)
|
|
964
|
+
]
|
|
965
|
+
}
|
|
966
|
+
)
|
|
967
|
+
] });
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/components/ContainerUploadPanel.tsx
|
|
971
|
+
import "react";
|
|
972
|
+
|
|
973
|
+
// src/components/UploadContainer.tsx
|
|
974
|
+
import {
|
|
975
|
+
forwardRef,
|
|
976
|
+
useImperativeHandle,
|
|
977
|
+
useMemo as useMemo3,
|
|
978
|
+
useRef as useRef3,
|
|
979
|
+
useState as useState5
|
|
980
|
+
} from "react";
|
|
981
|
+
|
|
982
|
+
// src/components/UploadDropzone.tsx
|
|
983
|
+
import "react";
|
|
984
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
985
|
+
var UploadDropzone = ({
|
|
986
|
+
isDragging,
|
|
987
|
+
onDragOver,
|
|
988
|
+
onDragLeave,
|
|
989
|
+
onDrop,
|
|
990
|
+
className = "",
|
|
991
|
+
style,
|
|
992
|
+
children
|
|
993
|
+
}) => {
|
|
994
|
+
const baseClass = "rounded-3 d-flex flex-column align-items-center justify-content-center";
|
|
995
|
+
const stateClass = isDragging ? "bg-body-secondary border-dashed border-2 border-secondary" : "bg-body-trasparent border-solid border-transparent border-2";
|
|
996
|
+
const combinedClassName = `${baseClass} ${stateClass} ${className}`.trim();
|
|
997
|
+
const handleDragOver = (e) => {
|
|
998
|
+
e.preventDefault();
|
|
999
|
+
onDragOver?.(e);
|
|
1000
|
+
};
|
|
1001
|
+
const handleDragLeave = (e) => {
|
|
1002
|
+
e.preventDefault();
|
|
1003
|
+
onDragLeave?.(e);
|
|
1004
|
+
};
|
|
1005
|
+
const handleDrop = (e) => {
|
|
1006
|
+
e.preventDefault();
|
|
1007
|
+
onDrop?.(e);
|
|
1008
|
+
};
|
|
1009
|
+
return /* @__PURE__ */ jsx5(
|
|
1010
|
+
"div",
|
|
1011
|
+
{
|
|
1012
|
+
className: combinedClassName,
|
|
1013
|
+
style: { minHeight: "140px", ...style },
|
|
1014
|
+
onDragOver: handleDragOver,
|
|
1015
|
+
onDragLeave: handleDragLeave,
|
|
1016
|
+
onDrop: handleDrop,
|
|
1017
|
+
children
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
};
|
|
1021
|
+
|
|
512
1022
|
// src/components/DesktopFileIcon.tsx
|
|
513
1023
|
import {
|
|
514
1024
|
faFile,
|
|
@@ -522,8 +1032,8 @@ import {
|
|
|
522
1032
|
faFileCode
|
|
523
1033
|
} from "@fortawesome/free-solid-svg-icons";
|
|
524
1034
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
525
|
-
import { useEffect, useRef, useState as
|
|
526
|
-
import { Fragment, jsx as
|
|
1035
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
|
|
1036
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
527
1037
|
function getFileExtension(name) {
|
|
528
1038
|
if (!name) return null;
|
|
529
1039
|
const lastDot = name.lastIndexOf(".");
|
|
@@ -602,13 +1112,13 @@ var DesktopFileIcon = ({
|
|
|
602
1112
|
onOpen,
|
|
603
1113
|
onDelete
|
|
604
1114
|
}) => {
|
|
605
|
-
const [contextMenuPos, setContextMenuPos] =
|
|
1115
|
+
const [contextMenuPos, setContextMenuPos] = useState4(
|
|
606
1116
|
null
|
|
607
1117
|
);
|
|
608
|
-
const [isHovered, setIsHovered] =
|
|
609
|
-
const [isDeleting, setIsDeleting] =
|
|
610
|
-
const iconRef =
|
|
611
|
-
const menuRef =
|
|
1118
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
1119
|
+
const [isDeleting, setIsDeleting] = useState4(false);
|
|
1120
|
+
const iconRef = useRef2(null);
|
|
1121
|
+
const menuRef = useRef2(null);
|
|
612
1122
|
const handleDoubleClick = () => {
|
|
613
1123
|
if (isDeleting) return;
|
|
614
1124
|
if (onOpen) {
|
|
@@ -666,7 +1176,7 @@ var DesktopFileIcon = ({
|
|
|
666
1176
|
const formattedSize = typeof sizeBytes === "number" ? `${(sizeBytes / 1024).toFixed(1)} KB` : void 0;
|
|
667
1177
|
const ext = getFileExtension(name);
|
|
668
1178
|
const iconToRender = getIconForExtension(ext);
|
|
669
|
-
|
|
1179
|
+
useEffect2(() => {
|
|
670
1180
|
if (!contextMenuPos) return;
|
|
671
1181
|
const handleGlobalClick = (e) => {
|
|
672
1182
|
const target = e.target;
|
|
@@ -683,8 +1193,8 @@ var DesktopFileIcon = ({
|
|
|
683
1193
|
document.removeEventListener("mousedown", handleGlobalClick);
|
|
684
1194
|
};
|
|
685
1195
|
}, [contextMenuPos]);
|
|
686
|
-
return /* @__PURE__ */
|
|
687
|
-
/* @__PURE__ */
|
|
1196
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1197
|
+
/* @__PURE__ */ jsxs4(
|
|
688
1198
|
"div",
|
|
689
1199
|
{
|
|
690
1200
|
ref: iconRef,
|
|
@@ -705,7 +1215,7 @@ var DesktopFileIcon = ({
|
|
|
705
1215
|
onMouseEnter: () => setIsHovered(true),
|
|
706
1216
|
onMouseLeave: () => setIsHovered(false),
|
|
707
1217
|
children: [
|
|
708
|
-
/* @__PURE__ */
|
|
1218
|
+
/* @__PURE__ */ jsxs4(
|
|
709
1219
|
"div",
|
|
710
1220
|
{
|
|
711
1221
|
className: "border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm position-relative",
|
|
@@ -714,17 +1224,17 @@ var DesktopFileIcon = ({
|
|
|
714
1224
|
height: 64
|
|
715
1225
|
},
|
|
716
1226
|
children: [
|
|
717
|
-
/* @__PURE__ */
|
|
718
|
-
isDeleting && /* @__PURE__ */
|
|
1227
|
+
/* @__PURE__ */ jsx6(FontAwesomeIcon, { icon: iconToRender, className: "fs-2" }),
|
|
1228
|
+
isDeleting && /* @__PURE__ */ jsx6("div", { className: "position-absolute top-50 start-50 translate-middle", children: /* @__PURE__ */ jsx6("div", { className: "spinner-border spinner-border-sm text-danger" }) })
|
|
719
1229
|
]
|
|
720
1230
|
}
|
|
721
1231
|
),
|
|
722
|
-
/* @__PURE__ */
|
|
723
|
-
formattedSize && /* @__PURE__ */
|
|
1232
|
+
/* @__PURE__ */ jsx6("div", { className: "small text-center text-truncate", style: { width: "100%" }, children: name }),
|
|
1233
|
+
formattedSize && /* @__PURE__ */ jsx6("small", { className: "text-muted mt-1", children: formattedSize })
|
|
724
1234
|
]
|
|
725
1235
|
}
|
|
726
1236
|
),
|
|
727
|
-
contextMenuPos && !isDeleting && /* @__PURE__ */
|
|
1237
|
+
contextMenuPos && !isDeleting && /* @__PURE__ */ jsxs4(
|
|
728
1238
|
"div",
|
|
729
1239
|
{
|
|
730
1240
|
ref: menuRef,
|
|
@@ -737,7 +1247,7 @@ var DesktopFileIcon = ({
|
|
|
737
1247
|
},
|
|
738
1248
|
onClick: (e) => e.stopPropagation(),
|
|
739
1249
|
children: [
|
|
740
|
-
/* @__PURE__ */
|
|
1250
|
+
/* @__PURE__ */ jsx6(
|
|
741
1251
|
"button",
|
|
742
1252
|
{
|
|
743
1253
|
type: "button",
|
|
@@ -747,7 +1257,7 @@ var DesktopFileIcon = ({
|
|
|
747
1257
|
children: "Download file"
|
|
748
1258
|
}
|
|
749
1259
|
),
|
|
750
|
-
/* @__PURE__ */
|
|
1260
|
+
/* @__PURE__ */ jsx6(
|
|
751
1261
|
"button",
|
|
752
1262
|
{
|
|
753
1263
|
type: "button",
|
|
@@ -757,8 +1267,8 @@ var DesktopFileIcon = ({
|
|
|
757
1267
|
children: "Copy download URL"
|
|
758
1268
|
}
|
|
759
1269
|
),
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
1270
|
+
/* @__PURE__ */ jsx6("div", { className: "dropdown-divider" }),
|
|
1271
|
+
/* @__PURE__ */ jsx6(
|
|
762
1272
|
"button",
|
|
763
1273
|
{
|
|
764
1274
|
type: "button",
|
|
@@ -774,160 +1284,165 @@ var DesktopFileIcon = ({
|
|
|
774
1284
|
};
|
|
775
1285
|
|
|
776
1286
|
// src/components/UploadContainer.tsx
|
|
777
|
-
import { Fragment as Fragment2, jsx as
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1287
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1288
|
+
function filesToFileList(files) {
|
|
1289
|
+
const dt = new DataTransfer();
|
|
1290
|
+
for (const f of files) dt.items.add(f);
|
|
1291
|
+
return dt.files;
|
|
1292
|
+
}
|
|
1293
|
+
var UploadContainer = forwardRef(
|
|
1294
|
+
({
|
|
1295
|
+
multiple = true,
|
|
1296
|
+
accept = "*/*",
|
|
1297
|
+
onFilesSelected,
|
|
1298
|
+
existingFiles = [],
|
|
1299
|
+
existingFilesLoading = false,
|
|
1300
|
+
onExistingFileClick,
|
|
1301
|
+
onDeleteFile,
|
|
1302
|
+
autoUpload = false,
|
|
792
1303
|
getPresignedUrl,
|
|
793
1304
|
onUploadComplete,
|
|
794
1305
|
onUploadError
|
|
795
|
-
})
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1306
|
+
}, ref) => {
|
|
1307
|
+
const [isDragging, setIsDragging] = useState5(false);
|
|
1308
|
+
const inputId = useMemo3(() => `filePicker_${crypto.randomUUID()}`, []);
|
|
1309
|
+
const inputRef = useRef3(null);
|
|
1310
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
1311
|
+
autoUpload,
|
|
1312
|
+
getPresignedUrl,
|
|
1313
|
+
onUploadComplete,
|
|
1314
|
+
onUploadError
|
|
1315
|
+
});
|
|
1316
|
+
const selectAndUpload = (files) => {
|
|
1317
|
+
if (!files || files.length === 0) return;
|
|
1318
|
+
onFilesSelected?.(files);
|
|
1319
|
+
startUploadsIfNeeded(files);
|
|
1320
|
+
};
|
|
1321
|
+
useImperativeHandle(ref, () => ({
|
|
1322
|
+
enqueueFiles(files) {
|
|
1323
|
+
const list = Array.isArray(files) ? filesToFileList(files) : files;
|
|
1324
|
+
selectAndUpload(list);
|
|
1325
|
+
},
|
|
1326
|
+
openFilePicker() {
|
|
1327
|
+
inputRef.current?.click();
|
|
1328
|
+
}
|
|
1329
|
+
}));
|
|
1330
|
+
const handleDragOver = (e) => {
|
|
1331
|
+
e.preventDefault();
|
|
1332
|
+
setIsDragging(true);
|
|
1333
|
+
};
|
|
1334
|
+
const handleDragLeave = (e) => {
|
|
1335
|
+
e.preventDefault();
|
|
1336
|
+
setIsDragging(false);
|
|
1337
|
+
};
|
|
1338
|
+
const handleDrop = (e) => {
|
|
1339
|
+
e.preventDefault();
|
|
1340
|
+
setIsDragging(false);
|
|
1341
|
+
const files = e.dataTransfer.files;
|
|
1342
|
+
if (!files || files.length === 0) return;
|
|
1343
|
+
selectAndUpload(files);
|
|
1344
|
+
};
|
|
1345
|
+
const handleExistingFileOpen = (file) => {
|
|
1346
|
+
if (onExistingFileClick) {
|
|
1347
|
+
onExistingFileClick(file);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
const a = document.createElement("a");
|
|
1351
|
+
a.href = file.PublicUrl ?? "";
|
|
1352
|
+
a.download = file.Name ?? "";
|
|
1353
|
+
a.target = "_blank";
|
|
1354
|
+
a.rel = "noopener noreferrer";
|
|
1355
|
+
document.body.appendChild(a);
|
|
1356
|
+
a.click();
|
|
1357
|
+
document.body.removeChild(a);
|
|
1358
|
+
};
|
|
1359
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1360
|
+
/* @__PURE__ */ jsxs5("div", { className: "w-100", children: [
|
|
1361
|
+
/* @__PURE__ */ jsx7(
|
|
1362
|
+
"input",
|
|
1363
|
+
{
|
|
1364
|
+
ref: inputRef,
|
|
1365
|
+
id: inputId,
|
|
1366
|
+
type: "file",
|
|
1367
|
+
multiple,
|
|
1368
|
+
accept,
|
|
1369
|
+
className: "d-none",
|
|
1370
|
+
onChange: (e) => {
|
|
1371
|
+
if (!e.target.files) return;
|
|
1372
|
+
selectAndUpload(e.target.files);
|
|
1373
|
+
e.currentTarget.value = "";
|
|
1374
|
+
}
|
|
839
1375
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1376
|
+
),
|
|
1377
|
+
/* @__PURE__ */ jsx7("div", { className: "text-start", children: /* @__PURE__ */ jsx7(
|
|
1378
|
+
"button",
|
|
1379
|
+
{
|
|
1380
|
+
type: "button",
|
|
1381
|
+
className: "btn btn-primary float-start",
|
|
1382
|
+
onClick: () => inputRef.current?.click(),
|
|
1383
|
+
children: "Browse files\u2026"
|
|
1384
|
+
}
|
|
1385
|
+
) })
|
|
1386
|
+
] }),
|
|
1387
|
+
/* @__PURE__ */ jsxs5(
|
|
1388
|
+
UploadDropzone,
|
|
844
1389
|
{
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
transition: "background 0.12s, border-color 0.12s"
|
|
1390
|
+
isDragging,
|
|
1391
|
+
onDragOver: handleDragOver,
|
|
1392
|
+
onDragLeave: handleDragLeave,
|
|
1393
|
+
onDrop: handleDrop,
|
|
1394
|
+
className: "w-100",
|
|
1395
|
+
style: { minHeight: "100px", alignItems: "stretch" },
|
|
1396
|
+
children: [
|
|
1397
|
+
/* @__PURE__ */ jsx7("div", { className: "w-100 mb-3", children: /* @__PURE__ */ jsx7("div", { className: "d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-3", children: /* @__PURE__ */ jsx7("div", { className: "flex-grow-1 w-100", children: /* @__PURE__ */ jsx7(UploadProgressList, { uploads }) }) }) }),
|
|
1398
|
+
/* @__PURE__ */ jsx7(
|
|
1399
|
+
"div",
|
|
1400
|
+
{
|
|
1401
|
+
className: "w-100 d-flex flex-wrap gap-4 align-content-start",
|
|
1402
|
+
style: { minHeight: "140px" },
|
|
1403
|
+
children: existingFilesLoading ? /* @__PURE__ */ jsx7("div", { className: "w-100 d-flex justify-content-center align-items-center", children: /* @__PURE__ */ jsx7("div", { className: "spinner-border text-secondary", role: "status" }) }) : existingFiles.length === 0 ? /* @__PURE__ */ jsxs5(
|
|
1404
|
+
"div",
|
|
1405
|
+
{
|
|
1406
|
+
className: "w-100 d-flex flex-column align-items-center justify-content-center text-muted",
|
|
1407
|
+
style: {
|
|
1408
|
+
minHeight: "160px",
|
|
1409
|
+
padding: "20px",
|
|
1410
|
+
cursor: "pointer",
|
|
1411
|
+
transition: "background 0.12s, border-color 0.12s"
|
|
1412
|
+
},
|
|
1413
|
+
onClick: () => inputRef.current?.click(),
|
|
1414
|
+
children: [
|
|
1415
|
+
/* @__PURE__ */ jsx7("strong", { children: "Drag & drop files here" }),
|
|
1416
|
+
/* @__PURE__ */ jsx7("small", { className: "mt-1", children: "\u2026or click to browse" })
|
|
1417
|
+
]
|
|
1418
|
+
}
|
|
1419
|
+
) : existingFiles.map((file) => /* @__PURE__ */ jsx7(
|
|
1420
|
+
DesktopFileIcon,
|
|
1421
|
+
{
|
|
1422
|
+
name: file.Name,
|
|
1423
|
+
sizeBytes: file.FileSize,
|
|
1424
|
+
downloadUrl: file.PublicUrl,
|
|
1425
|
+
onOpen: () => handleExistingFileOpen(file),
|
|
1426
|
+
onDelete: () => onDeleteFile?.(file)
|
|
883
1427
|
},
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
onChange: (e) => {
|
|
896
|
-
if (!e.target.files) return;
|
|
897
|
-
onFilesSelected?.(e.target.files);
|
|
898
|
-
startUploadsIfNeeded(e.target.files);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
),
|
|
902
|
-
/* @__PURE__ */ jsx4("strong", { children: "Drag & drop files here" }),
|
|
903
|
-
/* @__PURE__ */ jsx4("small", { className: "mt-1", children: "\u2026or click to browse" })
|
|
904
|
-
]
|
|
905
|
-
}
|
|
906
|
-
) : existingFiles.map((file) => /* @__PURE__ */ jsx4(
|
|
907
|
-
DesktopFileIcon,
|
|
908
|
-
{
|
|
909
|
-
name: file.Name,
|
|
910
|
-
sizeBytes: file.FileSize,
|
|
911
|
-
downloadUrl: file.PublicUrl,
|
|
912
|
-
onOpen: () => handleExistingFileOpen(file),
|
|
913
|
-
onDelete: () => onDeleteFile?.(file)
|
|
914
|
-
},
|
|
915
|
-
file.Id
|
|
916
|
-
))
|
|
917
|
-
}
|
|
918
|
-
)
|
|
919
|
-
]
|
|
920
|
-
}
|
|
921
|
-
)
|
|
922
|
-
] });
|
|
923
|
-
};
|
|
1428
|
+
file.Id
|
|
1429
|
+
))
|
|
1430
|
+
}
|
|
1431
|
+
)
|
|
1432
|
+
]
|
|
1433
|
+
}
|
|
1434
|
+
)
|
|
1435
|
+
] });
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
UploadContainer.displayName = "UploadContainer";
|
|
924
1439
|
|
|
925
1440
|
// src/hooks/UseContainers.ts
|
|
926
|
-
import { useEffect as
|
|
1441
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
927
1442
|
function UseContainers({ apiBaseUrl, parentId }) {
|
|
928
|
-
const [containers, setContainers] =
|
|
929
|
-
const [loading, setLoading] =
|
|
930
|
-
const [error, setError] =
|
|
1443
|
+
const [containers, setContainers] = useState6([]);
|
|
1444
|
+
const [loading, setLoading] = useState6(false);
|
|
1445
|
+
const [error, setError] = useState6(null);
|
|
931
1446
|
const load = async () => {
|
|
932
1447
|
setLoading(true);
|
|
933
1448
|
setError(null);
|
|
@@ -943,7 +1458,7 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
943
1458
|
setLoading(false);
|
|
944
1459
|
}
|
|
945
1460
|
};
|
|
946
|
-
|
|
1461
|
+
useEffect3(() => {
|
|
947
1462
|
void load();
|
|
948
1463
|
}, [apiBaseUrl, parentId]);
|
|
949
1464
|
return {
|
|
@@ -956,11 +1471,12 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
956
1471
|
}
|
|
957
1472
|
|
|
958
1473
|
// src/components/ContainerUploadPanel.tsx
|
|
959
|
-
import { jsx as
|
|
1474
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
960
1475
|
var ContainerUploadPanel = ({
|
|
961
1476
|
containerApiBaseUrl,
|
|
962
1477
|
storageApiBaseUrl,
|
|
963
|
-
parentContainerId
|
|
1478
|
+
parentContainerId,
|
|
1479
|
+
uploadRef
|
|
964
1480
|
}) => {
|
|
965
1481
|
const { containers, setContainers, reload, loading } = UseContainers({
|
|
966
1482
|
apiBaseUrl: containerApiBaseUrl,
|
|
@@ -1015,9 +1531,10 @@ var ContainerUploadPanel = ({
|
|
|
1015
1531
|
await sdkS3.s3.DeleteS3(file);
|
|
1016
1532
|
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
1017
1533
|
};
|
|
1018
|
-
return /* @__PURE__ */
|
|
1534
|
+
return /* @__PURE__ */ jsx8(
|
|
1019
1535
|
UploadContainer,
|
|
1020
1536
|
{
|
|
1537
|
+
ref: uploadRef,
|
|
1021
1538
|
existingFiles: containers,
|
|
1022
1539
|
existingFilesLoading: loading,
|
|
1023
1540
|
onExistingFileClick: handleExistingFileClick,
|
|
@@ -1030,9 +1547,172 @@ var ContainerUploadPanel = ({
|
|
|
1030
1547
|
);
|
|
1031
1548
|
};
|
|
1032
1549
|
|
|
1550
|
+
// src/components/FileGridUploadPanel.tsx
|
|
1551
|
+
import { useMemo as useMemo4, useState as useState7 } from "react";
|
|
1552
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1553
|
+
function FileGridUploadPanel(props) {
|
|
1554
|
+
const {
|
|
1555
|
+
containerApiBaseUrl,
|
|
1556
|
+
storageApiBaseUrl,
|
|
1557
|
+
parentContainerId,
|
|
1558
|
+
accept = "*/*",
|
|
1559
|
+
multiple = true,
|
|
1560
|
+
selectedId,
|
|
1561
|
+
onSelect,
|
|
1562
|
+
icon,
|
|
1563
|
+
iconHtml,
|
|
1564
|
+
deleteDisabled
|
|
1565
|
+
} = props;
|
|
1566
|
+
const { containers, setContainers, reload, loading } = UseContainers({
|
|
1567
|
+
apiBaseUrl: containerApiBaseUrl,
|
|
1568
|
+
parentId: parentContainerId
|
|
1569
|
+
});
|
|
1570
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
1571
|
+
const [error, setError] = useState7(null);
|
|
1572
|
+
const sdkDb = useMemo4(() => new SparkStudioStorageSDK(containerApiBaseUrl), [containerApiBaseUrl]);
|
|
1573
|
+
const sdkS3 = useMemo4(() => new SparkStudioStorageSDK(storageApiBaseUrl), [storageApiBaseUrl]);
|
|
1574
|
+
const getPresignedUrl = async (file) => {
|
|
1575
|
+
const contentType = file.type || "application/octet-stream";
|
|
1576
|
+
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
1577
|
+
file.name,
|
|
1578
|
+
file.size,
|
|
1579
|
+
encodeURIComponent(contentType)
|
|
1580
|
+
);
|
|
1581
|
+
let lastError;
|
|
1582
|
+
for (let i = 1; i <= 3; i++) {
|
|
1583
|
+
try {
|
|
1584
|
+
return await sdkS3.s3.GetPreSignedUrl(containerDTO);
|
|
1585
|
+
} catch (e) {
|
|
1586
|
+
lastError = e;
|
|
1587
|
+
if (i < 3) await new Promise((r) => setTimeout(r, 500 * i));
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
throw lastError instanceof Error ? lastError : new Error("Failed to fetch presigned URL");
|
|
1591
|
+
};
|
|
1592
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
1593
|
+
autoUpload: true,
|
|
1594
|
+
getPresignedUrl,
|
|
1595
|
+
onUploadComplete: async () => {
|
|
1596
|
+
setError(null);
|
|
1597
|
+
await reload();
|
|
1598
|
+
},
|
|
1599
|
+
onUploadError: (_file, err) => {
|
|
1600
|
+
setError(err.message ?? "Upload failed");
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
const handleDeleteFile = async (file) => {
|
|
1604
|
+
const sdkDb2 = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
1605
|
+
const sdkS32 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
1606
|
+
await sdkDb2.container.DeleteContainer(file.Id);
|
|
1607
|
+
await sdkS32.s3.DeleteS3(file);
|
|
1608
|
+
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
1609
|
+
};
|
|
1610
|
+
const openPicker = () => {
|
|
1611
|
+
const input = document.createElement("input");
|
|
1612
|
+
input.type = "file";
|
|
1613
|
+
input.multiple = multiple;
|
|
1614
|
+
input.accept = accept;
|
|
1615
|
+
input.onchange = () => {
|
|
1616
|
+
if (!input.files || input.files.length === 0) return;
|
|
1617
|
+
startUploadsIfNeeded(input.files);
|
|
1618
|
+
};
|
|
1619
|
+
input.click();
|
|
1620
|
+
};
|
|
1621
|
+
return /* @__PURE__ */ jsxs6("div", { style: { display: "grid", gap: 12 }, children: [
|
|
1622
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1623
|
+
/* @__PURE__ */ jsx9(UploadProgressList, { uploads }),
|
|
1624
|
+
error ? /* @__PURE__ */ jsx9("div", { style: { fontSize: 12, color: "crimson", marginTop: 6 }, children: error }) : null
|
|
1625
|
+
] }),
|
|
1626
|
+
/* @__PURE__ */ jsxs6(
|
|
1627
|
+
"div",
|
|
1628
|
+
{
|
|
1629
|
+
onDragEnter: (e) => {
|
|
1630
|
+
e.preventDefault();
|
|
1631
|
+
e.stopPropagation();
|
|
1632
|
+
setIsDragging(true);
|
|
1633
|
+
},
|
|
1634
|
+
onDragOver: (e) => {
|
|
1635
|
+
e.preventDefault();
|
|
1636
|
+
e.stopPropagation();
|
|
1637
|
+
setIsDragging(true);
|
|
1638
|
+
},
|
|
1639
|
+
onDragLeave: (e) => {
|
|
1640
|
+
e.preventDefault();
|
|
1641
|
+
e.stopPropagation();
|
|
1642
|
+
setIsDragging(false);
|
|
1643
|
+
},
|
|
1644
|
+
onDrop: (e) => {
|
|
1645
|
+
e.preventDefault();
|
|
1646
|
+
e.stopPropagation();
|
|
1647
|
+
setIsDragging(false);
|
|
1648
|
+
const files = e.dataTransfer.files;
|
|
1649
|
+
if (!files || files.length === 0) return;
|
|
1650
|
+
startUploadsIfNeeded(files);
|
|
1651
|
+
},
|
|
1652
|
+
style: {
|
|
1653
|
+
position: "relative",
|
|
1654
|
+
borderRadius: 14,
|
|
1655
|
+
border: isDragging ? "2px dashed rgba(13,110,253,0.9)" : "2px dashed rgba(0,0,0,0.15)",
|
|
1656
|
+
background: isDragging ? "rgba(13,110,253,0.06)" : "transparent",
|
|
1657
|
+
padding: 12
|
|
1658
|
+
},
|
|
1659
|
+
children: [
|
|
1660
|
+
isDragging ? /* @__PURE__ */ jsx9(
|
|
1661
|
+
"div",
|
|
1662
|
+
{
|
|
1663
|
+
style: {
|
|
1664
|
+
position: "absolute",
|
|
1665
|
+
inset: 0,
|
|
1666
|
+
borderRadius: 14,
|
|
1667
|
+
display: "grid",
|
|
1668
|
+
placeItems: "center",
|
|
1669
|
+
pointerEvents: "none",
|
|
1670
|
+
background: "rgba(13,110,253,0.08)",
|
|
1671
|
+
fontWeight: 800
|
|
1672
|
+
},
|
|
1673
|
+
children: "Drop files to upload"
|
|
1674
|
+
}
|
|
1675
|
+
) : null,
|
|
1676
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 10 }, children: [
|
|
1677
|
+
/* @__PURE__ */ jsx9("div", { style: { fontWeight: 700 }, children: "Files" }),
|
|
1678
|
+
/* @__PURE__ */ jsx9(
|
|
1679
|
+
"button",
|
|
1680
|
+
{
|
|
1681
|
+
type: "button",
|
|
1682
|
+
onClick: openPicker,
|
|
1683
|
+
style: {
|
|
1684
|
+
border: "1px solid rgba(0,0,0,0.18)",
|
|
1685
|
+
background: "white",
|
|
1686
|
+
borderRadius: 10,
|
|
1687
|
+
padding: "8px 10px",
|
|
1688
|
+
cursor: "pointer",
|
|
1689
|
+
fontWeight: 600
|
|
1690
|
+
},
|
|
1691
|
+
children: "Browse\u2026"
|
|
1692
|
+
}
|
|
1693
|
+
)
|
|
1694
|
+
] }),
|
|
1695
|
+
loading ? /* @__PURE__ */ jsx9("div", { className: "d-flex justify-content-center align-items-center", style: { minHeight: 120 }, children: /* @__PURE__ */ jsx9("div", { className: "spinner-border text-secondary", role: "status" }) }) : /* @__PURE__ */ jsx9(
|
|
1696
|
+
FileIconGrid,
|
|
1697
|
+
{
|
|
1698
|
+
files: containers,
|
|
1699
|
+
deleteDisabled,
|
|
1700
|
+
onDeleted: handleDeleteFile,
|
|
1701
|
+
selectedId,
|
|
1702
|
+
onSelect,
|
|
1703
|
+
icon,
|
|
1704
|
+
iconHtml
|
|
1705
|
+
}
|
|
1706
|
+
)
|
|
1707
|
+
]
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1710
|
+
] });
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1033
1713
|
// src/components/SingleFileProcessUploader.tsx
|
|
1034
|
-
import { useCallback as useCallback2, useRef as
|
|
1035
|
-
import { jsx as
|
|
1714
|
+
import { useCallback as useCallback2, useRef as useRef4, useState as useState8 } from "react";
|
|
1715
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1036
1716
|
var SingleFileProcessUploader = ({
|
|
1037
1717
|
getPresignedUrl,
|
|
1038
1718
|
onUploadComplete,
|
|
@@ -1041,11 +1721,11 @@ var SingleFileProcessUploader = ({
|
|
|
1041
1721
|
disabled,
|
|
1042
1722
|
uploadOnDrop = false
|
|
1043
1723
|
}) => {
|
|
1044
|
-
const [selectedFile, setSelectedFile] =
|
|
1045
|
-
const [isDragging, setIsDragging] =
|
|
1046
|
-
const [progress, setProgress] =
|
|
1047
|
-
const [status, setStatus] =
|
|
1048
|
-
const fileInputRef =
|
|
1724
|
+
const [selectedFile, setSelectedFile] = useState8(null);
|
|
1725
|
+
const [isDragging, setIsDragging] = useState8(false);
|
|
1726
|
+
const [progress, setProgress] = useState8(null);
|
|
1727
|
+
const [status, setStatus] = useState8("idle");
|
|
1728
|
+
const fileInputRef = useRef4(null);
|
|
1049
1729
|
function getErrorMessage(err) {
|
|
1050
1730
|
if (err instanceof Error) return err.message;
|
|
1051
1731
|
if (typeof err === "string") return err;
|
|
@@ -1131,8 +1811,8 @@ var SingleFileProcessUploader = ({
|
|
|
1131
1811
|
disabled ? "opacity-50" : "cursor-pointer",
|
|
1132
1812
|
isDragging ? "bg-body-secondary border-dashed border-2 border-secondary" : "bg-body-trasparent border-dashed border-2"
|
|
1133
1813
|
].join(" ");
|
|
1134
|
-
return /* @__PURE__ */
|
|
1135
|
-
isUploading ? /* @__PURE__ */
|
|
1814
|
+
return /* @__PURE__ */ jsxs7("div", { className: "d-flex flex-column gap-2", children: [
|
|
1815
|
+
isUploading ? /* @__PURE__ */ jsx10("div", { className: "small", children: /* @__PURE__ */ jsx10("div", { className: "progress", children: /* @__PURE__ */ jsx10(
|
|
1136
1816
|
"div",
|
|
1137
1817
|
{
|
|
1138
1818
|
className: "progress-bar progress-bar-striped progress-bar-animated",
|
|
@@ -1142,7 +1822,7 @@ var SingleFileProcessUploader = ({
|
|
|
1142
1822
|
"aria-valuenow": progress ?? 0,
|
|
1143
1823
|
style: { width: `${progress ?? 0}%` }
|
|
1144
1824
|
}
|
|
1145
|
-
) }) }) : /* @__PURE__ */
|
|
1825
|
+
) }) }) : /* @__PURE__ */ jsxs7(
|
|
1146
1826
|
"div",
|
|
1147
1827
|
{
|
|
1148
1828
|
className: dropzoneClasses,
|
|
@@ -1153,7 +1833,7 @@ var SingleFileProcessUploader = ({
|
|
|
1153
1833
|
role: "button",
|
|
1154
1834
|
"aria-disabled": disabled,
|
|
1155
1835
|
children: [
|
|
1156
|
-
/* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsx10(
|
|
1157
1837
|
"input",
|
|
1158
1838
|
{
|
|
1159
1839
|
ref: fileInputRef,
|
|
@@ -1164,8 +1844,8 @@ var SingleFileProcessUploader = ({
|
|
|
1164
1844
|
disabled: disabled || isUploading
|
|
1165
1845
|
}
|
|
1166
1846
|
),
|
|
1167
|
-
selectedFile ? /* @__PURE__ */
|
|
1168
|
-
/* @__PURE__ */
|
|
1847
|
+
selectedFile ? /* @__PURE__ */ jsxs7("div", { className: "small", children: [
|
|
1848
|
+
/* @__PURE__ */ jsx10(
|
|
1169
1849
|
"button",
|
|
1170
1850
|
{
|
|
1171
1851
|
type: "button",
|
|
@@ -1174,15 +1854,15 @@ var SingleFileProcessUploader = ({
|
|
|
1174
1854
|
children: "Browse file\u2026"
|
|
1175
1855
|
}
|
|
1176
1856
|
),
|
|
1177
|
-
/* @__PURE__ */
|
|
1178
|
-
/* @__PURE__ */
|
|
1857
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1858
|
+
/* @__PURE__ */ jsx10("strong", { children: "Selected file:" }),
|
|
1179
1859
|
" ",
|
|
1180
1860
|
selectedFile.name
|
|
1181
1861
|
] }),
|
|
1182
|
-
/* @__PURE__ */
|
|
1183
|
-
uploadOnDrop && /* @__PURE__ */
|
|
1184
|
-
] }) : /* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1862
|
+
/* @__PURE__ */ jsx10("div", { className: "text-muted", children: "Click here to change file or drag a new one." }),
|
|
1863
|
+
uploadOnDrop && /* @__PURE__ */ jsx10("div", { className: "text-muted", children: "Upload starts automatically." })
|
|
1864
|
+
] }) : /* @__PURE__ */ jsxs7("div", { className: "small", children: [
|
|
1865
|
+
/* @__PURE__ */ jsx10(
|
|
1186
1866
|
"button",
|
|
1187
1867
|
{
|
|
1188
1868
|
type: "button",
|
|
@@ -1191,13 +1871,13 @@ var SingleFileProcessUploader = ({
|
|
|
1191
1871
|
children: "Browse file\u2026"
|
|
1192
1872
|
}
|
|
1193
1873
|
),
|
|
1194
|
-
/* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1874
|
+
/* @__PURE__ */ jsx10("div", { children: "Drag & drop a file here" }),
|
|
1875
|
+
/* @__PURE__ */ jsx10("div", { className: "text-muted", children: "or click to browse" })
|
|
1196
1876
|
] })
|
|
1197
1877
|
]
|
|
1198
1878
|
}
|
|
1199
1879
|
),
|
|
1200
|
-
!uploadOnDrop && /* @__PURE__ */
|
|
1880
|
+
!uploadOnDrop && /* @__PURE__ */ jsx10(
|
|
1201
1881
|
"button",
|
|
1202
1882
|
{
|
|
1203
1883
|
type: "button",
|
|
@@ -1211,39 +1891,49 @@ var SingleFileProcessUploader = ({
|
|
|
1211
1891
|
};
|
|
1212
1892
|
|
|
1213
1893
|
// src/views/HomeView.tsx
|
|
1894
|
+
import { useEffect as useEffect4, useState as useState9 } from "react";
|
|
1214
1895
|
import {
|
|
1215
1896
|
AppSettings,
|
|
1216
1897
|
AuthenticatorProvider,
|
|
1217
1898
|
UserInfoCard,
|
|
1218
1899
|
useUser
|
|
1219
1900
|
} from "@sparkstudio/authentication-ui";
|
|
1220
|
-
import { Fragment as Fragment3, jsx as
|
|
1901
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1902
|
+
var CONTAINER_API = "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod";
|
|
1903
|
+
var STORAGE_API = "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod";
|
|
1221
1904
|
function HomeView() {
|
|
1222
|
-
return /* @__PURE__ */
|
|
1905
|
+
return /* @__PURE__ */ jsx11(
|
|
1223
1906
|
AuthenticatorProvider,
|
|
1224
1907
|
{
|
|
1225
1908
|
googleClientId: AppSettings.GoogleClientId,
|
|
1226
1909
|
authenticationUrl: AppSettings.AuthenticationUrl,
|
|
1227
1910
|
accountsUrl: AppSettings.AccountsUrl,
|
|
1228
|
-
children: /* @__PURE__ */
|
|
1911
|
+
children: /* @__PURE__ */ jsx11(HomeContent, {})
|
|
1229
1912
|
}
|
|
1230
1913
|
);
|
|
1231
1914
|
}
|
|
1232
1915
|
function HomeContent() {
|
|
1233
1916
|
const { user } = useUser();
|
|
1917
|
+
const [ids, setIds] = useState9([]);
|
|
1918
|
+
const [selectedId, setSelectedId] = useState9(void 0);
|
|
1919
|
+
const [selectedFile, setSelectedFile] = useState9(null);
|
|
1920
|
+
useEffect4(() => {
|
|
1921
|
+
if (selectedId && !ids.includes(selectedId)) {
|
|
1922
|
+
setSelectedId(void 0);
|
|
1923
|
+
setSelectedFile(null);
|
|
1924
|
+
}
|
|
1925
|
+
}, [ids, selectedId]);
|
|
1234
1926
|
async function getPresignedUrlFromApi(file) {
|
|
1235
|
-
const
|
|
1236
|
-
"https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1237
|
-
//"https://localhost:5001"
|
|
1238
|
-
);
|
|
1927
|
+
const sdk = new SparkStudioStorageSDK(STORAGE_API);
|
|
1239
1928
|
const contentType = file.type || "application/octet-stream";
|
|
1240
|
-
|
|
1241
|
-
|
|
1929
|
+
return sdk.s3.GetTemporaryPreSignedUrl(
|
|
1930
|
+
new TemporaryFileDTO({ Name: file.name, ContentType: contentType })
|
|
1931
|
+
);
|
|
1242
1932
|
}
|
|
1243
|
-
return /* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */
|
|
1245
|
-
user
|
|
1246
|
-
/* @__PURE__ */
|
|
1933
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
1934
|
+
/* @__PURE__ */ jsx11(UserInfoCard, {}),
|
|
1935
|
+
user ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
1936
|
+
/* @__PURE__ */ jsx11(
|
|
1247
1937
|
SingleFileProcessUploader,
|
|
1248
1938
|
{
|
|
1249
1939
|
uploadOnDrop: true,
|
|
@@ -1254,23 +1944,59 @@ function HomeContent() {
|
|
|
1254
1944
|
}
|
|
1255
1945
|
}
|
|
1256
1946
|
),
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
|
|
1947
|
+
/* @__PURE__ */ jsx11(
|
|
1948
|
+
ContainerIdGridPanel,
|
|
1949
|
+
{
|
|
1950
|
+
containerApiBaseUrl: CONTAINER_API,
|
|
1951
|
+
storageApiBaseUrl: STORAGE_API,
|
|
1952
|
+
containerIds: ids,
|
|
1953
|
+
onContainerIdsChange: setIds,
|
|
1954
|
+
multiple: true,
|
|
1955
|
+
accept: "*/*",
|
|
1956
|
+
selectedId,
|
|
1957
|
+
onSelect: (file) => {
|
|
1958
|
+
setSelectedId(file.Id);
|
|
1959
|
+
setSelectedFile(file);
|
|
1960
|
+
},
|
|
1961
|
+
onDeleted: (file) => {
|
|
1962
|
+
console.log("Deleted:", file);
|
|
1963
|
+
if (selectedId === file.Id) {
|
|
1964
|
+
setSelectedId(void 0);
|
|
1965
|
+
setSelectedFile(null);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
),
|
|
1970
|
+
selectedFile ? /* @__PURE__ */ jsxs8(
|
|
1971
|
+
"div",
|
|
1259
1972
|
{
|
|
1260
|
-
|
|
1261
|
-
|
|
1973
|
+
style: {
|
|
1974
|
+
marginTop: 12,
|
|
1975
|
+
padding: 12,
|
|
1976
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
1977
|
+
borderRadius: 12
|
|
1978
|
+
},
|
|
1979
|
+
children: [
|
|
1980
|
+
/* @__PURE__ */ jsx11("div", { style: { fontWeight: 700 }, children: "Selected file" }),
|
|
1981
|
+
/* @__PURE__ */ jsx11("div", { children: selectedFile.Name ?? "(no name)" }),
|
|
1982
|
+
/* @__PURE__ */ jsx11("div", { style: { fontSize: 12, opacity: 0.7 }, children: selectedFile.PublicUrl ?? "(no public url)" })
|
|
1983
|
+
]
|
|
1262
1984
|
}
|
|
1263
|
-
)
|
|
1264
|
-
] })
|
|
1985
|
+
) : null
|
|
1986
|
+
] }) : null
|
|
1265
1987
|
] });
|
|
1266
1988
|
}
|
|
1267
1989
|
export {
|
|
1268
1990
|
AWSPresignedUrlDTO,
|
|
1269
1991
|
Container,
|
|
1270
1992
|
ContainerDTO,
|
|
1993
|
+
ContainerIdGridPanel,
|
|
1271
1994
|
ContainerType,
|
|
1272
1995
|
ContainerUploadPanel,
|
|
1273
1996
|
DesktopFileIcon,
|
|
1997
|
+
FileGridUploadPanel,
|
|
1998
|
+
FileIconCard,
|
|
1999
|
+
FileIconGrid,
|
|
1274
2000
|
Home,
|
|
1275
2001
|
HomeView,
|
|
1276
2002
|
S3,
|