@sparkstudio/storage-ui 1.0.27 → 1.0.29
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 -297
- package/dist/index.d.cts +84 -18
- package/dist/index.d.ts +84 -18
- package/dist/index.js +990 -286
- 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,557 @@ 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
|
+
} = props;
|
|
735
|
+
const sdkDb = useMemo2(
|
|
736
|
+
() => new SparkStudioStorageSDK(containerApiBaseUrl),
|
|
737
|
+
[containerApiBaseUrl]
|
|
738
|
+
);
|
|
739
|
+
const sdkS3 = useMemo2(
|
|
740
|
+
() => new SparkStudioStorageSDK(storageApiBaseUrl),
|
|
741
|
+
[storageApiBaseUrl]
|
|
742
|
+
);
|
|
743
|
+
const [loading, setLoading] = useState3(false);
|
|
744
|
+
const [files, setFiles] = useState3([]);
|
|
745
|
+
const [dragOver, setDragOver] = useState3(false);
|
|
746
|
+
const [errMsg, setErrMsg] = useState3(null);
|
|
747
|
+
const idsRef = useRef(containerIds);
|
|
748
|
+
useEffect(() => {
|
|
749
|
+
idsRef.current = containerIds;
|
|
750
|
+
}, [containerIds]);
|
|
751
|
+
const createdByFileRef = useRef(/* @__PURE__ */ new WeakMap());
|
|
752
|
+
useEffect(() => {
|
|
753
|
+
let cancelled = false;
|
|
754
|
+
async function loadByIds(ids) {
|
|
755
|
+
setErrMsg(null);
|
|
756
|
+
if (!ids || ids.length === 0) {
|
|
757
|
+
setFiles([]);
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
setLoading(true);
|
|
761
|
+
try {
|
|
762
|
+
const results = await Promise.all(
|
|
763
|
+
ids.map(async (id) => {
|
|
764
|
+
try {
|
|
765
|
+
const dto = await sdkDb.container.Read?.(id);
|
|
766
|
+
return dto ?? null;
|
|
767
|
+
} catch {
|
|
768
|
+
return null;
|
|
769
|
+
}
|
|
770
|
+
})
|
|
771
|
+
);
|
|
772
|
+
if (cancelled) return;
|
|
773
|
+
const map = /* @__PURE__ */ new Map();
|
|
774
|
+
for (const r of results) if (r?.Id) map.set(r.Id, r);
|
|
775
|
+
setFiles(
|
|
776
|
+
ids.map((id) => map.get(id)).filter(Boolean)
|
|
777
|
+
);
|
|
778
|
+
} catch (e) {
|
|
779
|
+
if (!cancelled)
|
|
780
|
+
setErrMsg(e instanceof Error ? e.message : "Failed to load files");
|
|
781
|
+
} finally {
|
|
782
|
+
if (!cancelled) setLoading(false);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
void loadByIds(containerIds);
|
|
786
|
+
return () => {
|
|
787
|
+
cancelled = true;
|
|
788
|
+
};
|
|
789
|
+
}, [containerIds, sdkDb]);
|
|
790
|
+
const getPresignedUrl = async (file) => {
|
|
791
|
+
const contentType = file.type || "application/octet-stream";
|
|
792
|
+
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
793
|
+
file.name,
|
|
794
|
+
file.size,
|
|
795
|
+
encodeURIComponent(contentType)
|
|
796
|
+
);
|
|
797
|
+
createdByFileRef.current.set(file, containerDTO);
|
|
798
|
+
let lastError;
|
|
799
|
+
for (let i = 1; i <= 3; i++) {
|
|
800
|
+
try {
|
|
801
|
+
return await sdkS3.s3.GetPreSignedUrl(containerDTO);
|
|
802
|
+
} catch (e) {
|
|
803
|
+
lastError = e;
|
|
804
|
+
if (i < 3) await new Promise((r) => setTimeout(r, 500 * i));
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
throw lastError instanceof Error ? lastError : new Error("Failed to fetch presigned URL");
|
|
808
|
+
};
|
|
809
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
810
|
+
autoUpload: true,
|
|
811
|
+
getPresignedUrl,
|
|
812
|
+
onUploadComplete: async (file) => {
|
|
813
|
+
setErrMsg(null);
|
|
814
|
+
const created = createdByFileRef.current.get(file);
|
|
815
|
+
if (created?.Id) {
|
|
816
|
+
const prev = idsRef.current ?? [];
|
|
817
|
+
const next = prev.includes(created.Id) ? prev : [...prev, created.Id];
|
|
818
|
+
onContainerIdsChange(next);
|
|
819
|
+
}
|
|
820
|
+
if (created?.Id) {
|
|
821
|
+
try {
|
|
822
|
+
const refreshed = await sdkDb.container.Read?.(created.Id);
|
|
823
|
+
if (refreshed) {
|
|
824
|
+
setFiles((prevFiles) => {
|
|
825
|
+
const nextFiles = prevFiles.slice();
|
|
826
|
+
const idx = nextFiles.findIndex((x) => x.Id === created.Id);
|
|
827
|
+
if (idx >= 0) nextFiles[idx] = refreshed;
|
|
828
|
+
else nextFiles.push(refreshed);
|
|
829
|
+
return nextFiles;
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
onUploadError: (_file, error) => {
|
|
837
|
+
setErrMsg(error?.message ?? "Upload failed");
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
const handleDelete = async (file) => {
|
|
841
|
+
if (deleteDisabled) return;
|
|
842
|
+
await sdkDb.container.DeleteContainer(file.Id);
|
|
843
|
+
await sdkS3.s3.DeleteS3(file);
|
|
844
|
+
const prev = idsRef.current ?? [];
|
|
845
|
+
onContainerIdsChange(prev.filter((id) => id !== file.Id));
|
|
846
|
+
setFiles((prevFiles) => prevFiles.filter((x) => x.Id !== file.Id));
|
|
847
|
+
};
|
|
848
|
+
const openPicker = () => {
|
|
849
|
+
const input = document.createElement("input");
|
|
850
|
+
input.type = "file";
|
|
851
|
+
input.multiple = multiple;
|
|
852
|
+
input.accept = accept;
|
|
853
|
+
input.onchange = () => {
|
|
854
|
+
if (input.files) startUploadsIfNeeded(input.files);
|
|
855
|
+
};
|
|
856
|
+
input.click();
|
|
857
|
+
};
|
|
858
|
+
const onDrop = (ev) => {
|
|
859
|
+
ev.preventDefault();
|
|
860
|
+
ev.stopPropagation();
|
|
861
|
+
setDragOver(false);
|
|
862
|
+
const list = ev.dataTransfer.files;
|
|
863
|
+
if (!list || list.length === 0) return;
|
|
864
|
+
startUploadsIfNeeded(list);
|
|
865
|
+
};
|
|
866
|
+
return /* @__PURE__ */ jsxs3("div", { className, style: { display: "grid", gap: 12 }, children: [
|
|
867
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
868
|
+
/* @__PURE__ */ jsx4(UploadProgressList, { uploads }),
|
|
869
|
+
errMsg ? /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: "crimson", marginTop: 6 }, children: errMsg }) : null
|
|
870
|
+
] }),
|
|
871
|
+
/* @__PURE__ */ jsxs3(
|
|
872
|
+
"div",
|
|
873
|
+
{
|
|
874
|
+
onDragEnter: (e) => {
|
|
875
|
+
e.preventDefault();
|
|
876
|
+
e.stopPropagation();
|
|
877
|
+
setDragOver(true);
|
|
878
|
+
},
|
|
879
|
+
onDragOver: (e) => {
|
|
880
|
+
e.preventDefault();
|
|
881
|
+
e.stopPropagation();
|
|
882
|
+
setDragOver(true);
|
|
883
|
+
},
|
|
884
|
+
onDragLeave: (e) => {
|
|
885
|
+
e.preventDefault();
|
|
886
|
+
e.stopPropagation();
|
|
887
|
+
setDragOver(false);
|
|
888
|
+
},
|
|
889
|
+
onDrop,
|
|
890
|
+
style: {
|
|
891
|
+
position: "relative",
|
|
892
|
+
borderRadius: 14,
|
|
893
|
+
border: `2px dashed ${dragOver ? "rgba(13,110,253,0.9)" : "rgba(0,0,0,0.15)"}`,
|
|
894
|
+
background: dragOver ? "rgba(13,110,253,0.06)" : "transparent",
|
|
895
|
+
padding: 12
|
|
896
|
+
},
|
|
897
|
+
children: [
|
|
898
|
+
dragOver ? /* @__PURE__ */ jsx4(
|
|
899
|
+
"div",
|
|
900
|
+
{
|
|
901
|
+
style: {
|
|
902
|
+
position: "absolute",
|
|
903
|
+
inset: 0,
|
|
904
|
+
borderRadius: 14,
|
|
905
|
+
display: "grid",
|
|
906
|
+
placeItems: "center",
|
|
907
|
+
pointerEvents: "none",
|
|
908
|
+
background: "rgba(13,110,253,0.10)",
|
|
909
|
+
fontWeight: 800
|
|
910
|
+
},
|
|
911
|
+
children: "Drop files to upload"
|
|
912
|
+
}
|
|
913
|
+
) : null,
|
|
914
|
+
/* @__PURE__ */ jsxs3(
|
|
915
|
+
"div",
|
|
916
|
+
{
|
|
917
|
+
style: {
|
|
918
|
+
display: "flex",
|
|
919
|
+
justifyContent: "space-between",
|
|
920
|
+
marginBottom: 10
|
|
921
|
+
},
|
|
922
|
+
children: [
|
|
923
|
+
/* @__PURE__ */ jsx4("div", { style: { fontWeight: 700 }, children: "Files" }),
|
|
924
|
+
/* @__PURE__ */ jsx4(
|
|
925
|
+
"button",
|
|
926
|
+
{
|
|
927
|
+
type: "button",
|
|
928
|
+
onClick: openPicker,
|
|
929
|
+
style: {
|
|
930
|
+
border: "1px solid rgba(0,0,0,0.18)",
|
|
931
|
+
background: "white",
|
|
932
|
+
borderRadius: 10,
|
|
933
|
+
padding: "8px 10px",
|
|
934
|
+
cursor: "pointer",
|
|
935
|
+
fontWeight: 600
|
|
936
|
+
},
|
|
937
|
+
children: "Browse\u2026"
|
|
938
|
+
}
|
|
939
|
+
)
|
|
940
|
+
]
|
|
941
|
+
}
|
|
942
|
+
),
|
|
943
|
+
loading ? /* @__PURE__ */ jsx4(
|
|
944
|
+
"div",
|
|
945
|
+
{
|
|
946
|
+
className: "d-flex justify-content-center align-items-center",
|
|
947
|
+
style: { minHeight: 120 },
|
|
948
|
+
children: /* @__PURE__ */ jsx4("div", { className: "spinner-border text-secondary", role: "status" })
|
|
949
|
+
}
|
|
950
|
+
) : /* @__PURE__ */ jsx4(
|
|
951
|
+
FileIconGrid,
|
|
952
|
+
{
|
|
953
|
+
files,
|
|
954
|
+
deleteDisabled,
|
|
955
|
+
onDeleted: handleDelete,
|
|
956
|
+
selectedId,
|
|
957
|
+
onSelect,
|
|
958
|
+
icon,
|
|
959
|
+
iconHtml
|
|
960
|
+
}
|
|
961
|
+
)
|
|
962
|
+
]
|
|
963
|
+
}
|
|
964
|
+
)
|
|
965
|
+
] });
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/components/ContainerUploadPanel.tsx
|
|
969
|
+
import "react";
|
|
970
|
+
|
|
971
|
+
// src/components/UploadContainer.tsx
|
|
972
|
+
import {
|
|
973
|
+
forwardRef,
|
|
974
|
+
useImperativeHandle,
|
|
975
|
+
useMemo as useMemo3,
|
|
976
|
+
useRef as useRef3,
|
|
977
|
+
useState as useState5
|
|
978
|
+
} from "react";
|
|
979
|
+
|
|
980
|
+
// src/components/UploadDropzone.tsx
|
|
981
|
+
import "react";
|
|
982
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
983
|
+
var UploadDropzone = ({
|
|
984
|
+
isDragging,
|
|
985
|
+
onDragOver,
|
|
986
|
+
onDragLeave,
|
|
987
|
+
onDrop,
|
|
988
|
+
className = "",
|
|
989
|
+
style,
|
|
990
|
+
children
|
|
991
|
+
}) => {
|
|
992
|
+
const baseClass = "rounded-3 d-flex flex-column align-items-center justify-content-center";
|
|
993
|
+
const stateClass = isDragging ? "bg-body-secondary border-dashed border-2 border-secondary" : "bg-body-trasparent border-solid border-transparent border-2";
|
|
994
|
+
const combinedClassName = `${baseClass} ${stateClass} ${className}`.trim();
|
|
995
|
+
const handleDragOver = (e) => {
|
|
996
|
+
e.preventDefault();
|
|
997
|
+
onDragOver?.(e);
|
|
998
|
+
};
|
|
999
|
+
const handleDragLeave = (e) => {
|
|
1000
|
+
e.preventDefault();
|
|
1001
|
+
onDragLeave?.(e);
|
|
1002
|
+
};
|
|
1003
|
+
const handleDrop = (e) => {
|
|
1004
|
+
e.preventDefault();
|
|
1005
|
+
onDrop?.(e);
|
|
1006
|
+
};
|
|
1007
|
+
return /* @__PURE__ */ jsx5(
|
|
1008
|
+
"div",
|
|
1009
|
+
{
|
|
1010
|
+
className: combinedClassName,
|
|
1011
|
+
style: { minHeight: "140px", ...style },
|
|
1012
|
+
onDragOver: handleDragOver,
|
|
1013
|
+
onDragLeave: handleDragLeave,
|
|
1014
|
+
onDrop: handleDrop,
|
|
1015
|
+
children
|
|
1016
|
+
}
|
|
1017
|
+
);
|
|
1018
|
+
};
|
|
1019
|
+
|
|
512
1020
|
// src/components/DesktopFileIcon.tsx
|
|
513
1021
|
import {
|
|
514
1022
|
faFile,
|
|
@@ -522,8 +1030,8 @@ import {
|
|
|
522
1030
|
faFileCode
|
|
523
1031
|
} from "@fortawesome/free-solid-svg-icons";
|
|
524
1032
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
525
|
-
import { useEffect, useRef, useState as
|
|
526
|
-
import { Fragment, jsx as
|
|
1033
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
|
|
1034
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
527
1035
|
function getFileExtension(name) {
|
|
528
1036
|
if (!name) return null;
|
|
529
1037
|
const lastDot = name.lastIndexOf(".");
|
|
@@ -602,13 +1110,13 @@ var DesktopFileIcon = ({
|
|
|
602
1110
|
onOpen,
|
|
603
1111
|
onDelete
|
|
604
1112
|
}) => {
|
|
605
|
-
const [contextMenuPos, setContextMenuPos] =
|
|
1113
|
+
const [contextMenuPos, setContextMenuPos] = useState4(
|
|
606
1114
|
null
|
|
607
1115
|
);
|
|
608
|
-
const [isHovered, setIsHovered] =
|
|
609
|
-
const [isDeleting, setIsDeleting] =
|
|
610
|
-
const iconRef =
|
|
611
|
-
const menuRef =
|
|
1116
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
1117
|
+
const [isDeleting, setIsDeleting] = useState4(false);
|
|
1118
|
+
const iconRef = useRef2(null);
|
|
1119
|
+
const menuRef = useRef2(null);
|
|
612
1120
|
const handleDoubleClick = () => {
|
|
613
1121
|
if (isDeleting) return;
|
|
614
1122
|
if (onOpen) {
|
|
@@ -666,7 +1174,7 @@ var DesktopFileIcon = ({
|
|
|
666
1174
|
const formattedSize = typeof sizeBytes === "number" ? `${(sizeBytes / 1024).toFixed(1)} KB` : void 0;
|
|
667
1175
|
const ext = getFileExtension(name);
|
|
668
1176
|
const iconToRender = getIconForExtension(ext);
|
|
669
|
-
|
|
1177
|
+
useEffect2(() => {
|
|
670
1178
|
if (!contextMenuPos) return;
|
|
671
1179
|
const handleGlobalClick = (e) => {
|
|
672
1180
|
const target = e.target;
|
|
@@ -683,8 +1191,8 @@ var DesktopFileIcon = ({
|
|
|
683
1191
|
document.removeEventListener("mousedown", handleGlobalClick);
|
|
684
1192
|
};
|
|
685
1193
|
}, [contextMenuPos]);
|
|
686
|
-
return /* @__PURE__ */
|
|
687
|
-
/* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1195
|
+
/* @__PURE__ */ jsxs4(
|
|
688
1196
|
"div",
|
|
689
1197
|
{
|
|
690
1198
|
ref: iconRef,
|
|
@@ -705,7 +1213,7 @@ var DesktopFileIcon = ({
|
|
|
705
1213
|
onMouseEnter: () => setIsHovered(true),
|
|
706
1214
|
onMouseLeave: () => setIsHovered(false),
|
|
707
1215
|
children: [
|
|
708
|
-
/* @__PURE__ */
|
|
1216
|
+
/* @__PURE__ */ jsxs4(
|
|
709
1217
|
"div",
|
|
710
1218
|
{
|
|
711
1219
|
className: "border rounded-3 d-flex align-items-center justify-content-center mb-1 shadow-sm position-relative",
|
|
@@ -714,17 +1222,17 @@ var DesktopFileIcon = ({
|
|
|
714
1222
|
height: 64
|
|
715
1223
|
},
|
|
716
1224
|
children: [
|
|
717
|
-
/* @__PURE__ */
|
|
718
|
-
isDeleting && /* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsx6(FontAwesomeIcon, { icon: iconToRender, className: "fs-2" }),
|
|
1226
|
+
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
1227
|
]
|
|
720
1228
|
}
|
|
721
1229
|
),
|
|
722
|
-
/* @__PURE__ */
|
|
723
|
-
formattedSize && /* @__PURE__ */
|
|
1230
|
+
/* @__PURE__ */ jsx6("div", { className: "small text-center text-truncate", style: { width: "100%" }, children: name }),
|
|
1231
|
+
formattedSize && /* @__PURE__ */ jsx6("small", { className: "text-muted mt-1", children: formattedSize })
|
|
724
1232
|
]
|
|
725
1233
|
}
|
|
726
1234
|
),
|
|
727
|
-
contextMenuPos && !isDeleting && /* @__PURE__ */
|
|
1235
|
+
contextMenuPos && !isDeleting && /* @__PURE__ */ jsxs4(
|
|
728
1236
|
"div",
|
|
729
1237
|
{
|
|
730
1238
|
ref: menuRef,
|
|
@@ -737,7 +1245,7 @@ var DesktopFileIcon = ({
|
|
|
737
1245
|
},
|
|
738
1246
|
onClick: (e) => e.stopPropagation(),
|
|
739
1247
|
children: [
|
|
740
|
-
/* @__PURE__ */
|
|
1248
|
+
/* @__PURE__ */ jsx6(
|
|
741
1249
|
"button",
|
|
742
1250
|
{
|
|
743
1251
|
type: "button",
|
|
@@ -747,7 +1255,7 @@ var DesktopFileIcon = ({
|
|
|
747
1255
|
children: "Download file"
|
|
748
1256
|
}
|
|
749
1257
|
),
|
|
750
|
-
/* @__PURE__ */
|
|
1258
|
+
/* @__PURE__ */ jsx6(
|
|
751
1259
|
"button",
|
|
752
1260
|
{
|
|
753
1261
|
type: "button",
|
|
@@ -757,8 +1265,8 @@ var DesktopFileIcon = ({
|
|
|
757
1265
|
children: "Copy download URL"
|
|
758
1266
|
}
|
|
759
1267
|
),
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
1268
|
+
/* @__PURE__ */ jsx6("div", { className: "dropdown-divider" }),
|
|
1269
|
+
/* @__PURE__ */ jsx6(
|
|
762
1270
|
"button",
|
|
763
1271
|
{
|
|
764
1272
|
type: "button",
|
|
@@ -774,160 +1282,165 @@ var DesktopFileIcon = ({
|
|
|
774
1282
|
};
|
|
775
1283
|
|
|
776
1284
|
// 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
|
-
|
|
1285
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1286
|
+
function filesToFileList(files) {
|
|
1287
|
+
const dt = new DataTransfer();
|
|
1288
|
+
for (const f of files) dt.items.add(f);
|
|
1289
|
+
return dt.files;
|
|
1290
|
+
}
|
|
1291
|
+
var UploadContainer = forwardRef(
|
|
1292
|
+
({
|
|
1293
|
+
multiple = true,
|
|
1294
|
+
accept = "*/*",
|
|
1295
|
+
onFilesSelected,
|
|
1296
|
+
existingFiles = [],
|
|
1297
|
+
existingFilesLoading = false,
|
|
1298
|
+
onExistingFileClick,
|
|
1299
|
+
onDeleteFile,
|
|
1300
|
+
autoUpload = false,
|
|
792
1301
|
getPresignedUrl,
|
|
793
1302
|
onUploadComplete,
|
|
794
1303
|
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
|
-
|
|
1304
|
+
}, ref) => {
|
|
1305
|
+
const [isDragging, setIsDragging] = useState5(false);
|
|
1306
|
+
const inputId = useMemo3(() => `filePicker_${crypto.randomUUID()}`, []);
|
|
1307
|
+
const inputRef = useRef3(null);
|
|
1308
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
1309
|
+
autoUpload,
|
|
1310
|
+
getPresignedUrl,
|
|
1311
|
+
onUploadComplete,
|
|
1312
|
+
onUploadError
|
|
1313
|
+
});
|
|
1314
|
+
const selectAndUpload = (files) => {
|
|
1315
|
+
if (!files || files.length === 0) return;
|
|
1316
|
+
onFilesSelected?.(files);
|
|
1317
|
+
startUploadsIfNeeded(files);
|
|
1318
|
+
};
|
|
1319
|
+
useImperativeHandle(ref, () => ({
|
|
1320
|
+
enqueueFiles(files) {
|
|
1321
|
+
const list = Array.isArray(files) ? filesToFileList(files) : files;
|
|
1322
|
+
selectAndUpload(list);
|
|
1323
|
+
},
|
|
1324
|
+
openFilePicker() {
|
|
1325
|
+
inputRef.current?.click();
|
|
1326
|
+
}
|
|
1327
|
+
}));
|
|
1328
|
+
const handleDragOver = (e) => {
|
|
1329
|
+
e.preventDefault();
|
|
1330
|
+
setIsDragging(true);
|
|
1331
|
+
};
|
|
1332
|
+
const handleDragLeave = (e) => {
|
|
1333
|
+
e.preventDefault();
|
|
1334
|
+
setIsDragging(false);
|
|
1335
|
+
};
|
|
1336
|
+
const handleDrop = (e) => {
|
|
1337
|
+
e.preventDefault();
|
|
1338
|
+
setIsDragging(false);
|
|
1339
|
+
const files = e.dataTransfer.files;
|
|
1340
|
+
if (!files || files.length === 0) return;
|
|
1341
|
+
selectAndUpload(files);
|
|
1342
|
+
};
|
|
1343
|
+
const handleExistingFileOpen = (file) => {
|
|
1344
|
+
if (onExistingFileClick) {
|
|
1345
|
+
onExistingFileClick(file);
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const a = document.createElement("a");
|
|
1349
|
+
a.href = file.PublicUrl ?? "";
|
|
1350
|
+
a.download = file.Name ?? "";
|
|
1351
|
+
a.target = "_blank";
|
|
1352
|
+
a.rel = "noopener noreferrer";
|
|
1353
|
+
document.body.appendChild(a);
|
|
1354
|
+
a.click();
|
|
1355
|
+
document.body.removeChild(a);
|
|
1356
|
+
};
|
|
1357
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1358
|
+
/* @__PURE__ */ jsxs5("div", { className: "w-100", children: [
|
|
1359
|
+
/* @__PURE__ */ jsx7(
|
|
1360
|
+
"input",
|
|
1361
|
+
{
|
|
1362
|
+
ref: inputRef,
|
|
1363
|
+
id: inputId,
|
|
1364
|
+
type: "file",
|
|
1365
|
+
multiple,
|
|
1366
|
+
accept,
|
|
1367
|
+
className: "d-none",
|
|
1368
|
+
onChange: (e) => {
|
|
1369
|
+
if (!e.target.files) return;
|
|
1370
|
+
selectAndUpload(e.target.files);
|
|
1371
|
+
e.currentTarget.value = "";
|
|
1372
|
+
}
|
|
839
1373
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1374
|
+
),
|
|
1375
|
+
/* @__PURE__ */ jsx7("div", { className: "text-start", children: /* @__PURE__ */ jsx7(
|
|
1376
|
+
"button",
|
|
1377
|
+
{
|
|
1378
|
+
type: "button",
|
|
1379
|
+
className: "btn btn-primary float-start",
|
|
1380
|
+
onClick: () => inputRef.current?.click(),
|
|
1381
|
+
children: "Browse files\u2026"
|
|
1382
|
+
}
|
|
1383
|
+
) })
|
|
1384
|
+
] }),
|
|
1385
|
+
/* @__PURE__ */ jsxs5(
|
|
1386
|
+
UploadDropzone,
|
|
844
1387
|
{
|
|
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"
|
|
1388
|
+
isDragging,
|
|
1389
|
+
onDragOver: handleDragOver,
|
|
1390
|
+
onDragLeave: handleDragLeave,
|
|
1391
|
+
onDrop: handleDrop,
|
|
1392
|
+
className: "w-100",
|
|
1393
|
+
style: { minHeight: "100px", alignItems: "stretch" },
|
|
1394
|
+
children: [
|
|
1395
|
+
/* @__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 }) }) }) }),
|
|
1396
|
+
/* @__PURE__ */ jsx7(
|
|
1397
|
+
"div",
|
|
1398
|
+
{
|
|
1399
|
+
className: "w-100 d-flex flex-wrap gap-4 align-content-start",
|
|
1400
|
+
style: { minHeight: "140px" },
|
|
1401
|
+
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(
|
|
1402
|
+
"div",
|
|
1403
|
+
{
|
|
1404
|
+
className: "w-100 d-flex flex-column align-items-center justify-content-center text-muted",
|
|
1405
|
+
style: {
|
|
1406
|
+
minHeight: "160px",
|
|
1407
|
+
padding: "20px",
|
|
1408
|
+
cursor: "pointer",
|
|
1409
|
+
transition: "background 0.12s, border-color 0.12s"
|
|
1410
|
+
},
|
|
1411
|
+
onClick: () => inputRef.current?.click(),
|
|
1412
|
+
children: [
|
|
1413
|
+
/* @__PURE__ */ jsx7("strong", { children: "Drag & drop files here" }),
|
|
1414
|
+
/* @__PURE__ */ jsx7("small", { className: "mt-1", children: "\u2026or click to browse" })
|
|
1415
|
+
]
|
|
1416
|
+
}
|
|
1417
|
+
) : existingFiles.map((file) => /* @__PURE__ */ jsx7(
|
|
1418
|
+
DesktopFileIcon,
|
|
1419
|
+
{
|
|
1420
|
+
name: file.Name,
|
|
1421
|
+
sizeBytes: file.FileSize,
|
|
1422
|
+
downloadUrl: file.PublicUrl,
|
|
1423
|
+
onOpen: () => handleExistingFileOpen(file),
|
|
1424
|
+
onDelete: () => onDeleteFile?.(file)
|
|
883
1425
|
},
|
|
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
|
-
};
|
|
1426
|
+
file.Id
|
|
1427
|
+
))
|
|
1428
|
+
}
|
|
1429
|
+
)
|
|
1430
|
+
]
|
|
1431
|
+
}
|
|
1432
|
+
)
|
|
1433
|
+
] });
|
|
1434
|
+
}
|
|
1435
|
+
);
|
|
1436
|
+
UploadContainer.displayName = "UploadContainer";
|
|
924
1437
|
|
|
925
1438
|
// src/hooks/UseContainers.ts
|
|
926
|
-
import { useEffect as
|
|
1439
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
927
1440
|
function UseContainers({ apiBaseUrl, parentId }) {
|
|
928
|
-
const [containers, setContainers] =
|
|
929
|
-
const [loading, setLoading] =
|
|
930
|
-
const [error, setError] =
|
|
1441
|
+
const [containers, setContainers] = useState6([]);
|
|
1442
|
+
const [loading, setLoading] = useState6(false);
|
|
1443
|
+
const [error, setError] = useState6(null);
|
|
931
1444
|
const load = async () => {
|
|
932
1445
|
setLoading(true);
|
|
933
1446
|
setError(null);
|
|
@@ -943,7 +1456,7 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
943
1456
|
setLoading(false);
|
|
944
1457
|
}
|
|
945
1458
|
};
|
|
946
|
-
|
|
1459
|
+
useEffect3(() => {
|
|
947
1460
|
void load();
|
|
948
1461
|
}, [apiBaseUrl, parentId]);
|
|
949
1462
|
return {
|
|
@@ -956,11 +1469,12 @@ function UseContainers({ apiBaseUrl, parentId }) {
|
|
|
956
1469
|
}
|
|
957
1470
|
|
|
958
1471
|
// src/components/ContainerUploadPanel.tsx
|
|
959
|
-
import { jsx as
|
|
1472
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
960
1473
|
var ContainerUploadPanel = ({
|
|
961
1474
|
containerApiBaseUrl,
|
|
962
1475
|
storageApiBaseUrl,
|
|
963
|
-
parentContainerId
|
|
1476
|
+
parentContainerId,
|
|
1477
|
+
uploadRef
|
|
964
1478
|
}) => {
|
|
965
1479
|
const { containers, setContainers, reload, loading } = UseContainers({
|
|
966
1480
|
apiBaseUrl: containerApiBaseUrl,
|
|
@@ -1015,9 +1529,10 @@ var ContainerUploadPanel = ({
|
|
|
1015
1529
|
await sdkS3.s3.DeleteS3(file);
|
|
1016
1530
|
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
1017
1531
|
};
|
|
1018
|
-
return /* @__PURE__ */
|
|
1532
|
+
return /* @__PURE__ */ jsx8(
|
|
1019
1533
|
UploadContainer,
|
|
1020
1534
|
{
|
|
1535
|
+
ref: uploadRef,
|
|
1021
1536
|
existingFiles: containers,
|
|
1022
1537
|
existingFilesLoading: loading,
|
|
1023
1538
|
onExistingFileClick: handleExistingFileClick,
|
|
@@ -1030,9 +1545,172 @@ var ContainerUploadPanel = ({
|
|
|
1030
1545
|
);
|
|
1031
1546
|
};
|
|
1032
1547
|
|
|
1548
|
+
// src/components/FileGridUploadPanel.tsx
|
|
1549
|
+
import { useMemo as useMemo4, useState as useState7 } from "react";
|
|
1550
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1551
|
+
function FileGridUploadPanel(props) {
|
|
1552
|
+
const {
|
|
1553
|
+
containerApiBaseUrl,
|
|
1554
|
+
storageApiBaseUrl,
|
|
1555
|
+
parentContainerId,
|
|
1556
|
+
accept = "*/*",
|
|
1557
|
+
multiple = true,
|
|
1558
|
+
selectedId,
|
|
1559
|
+
onSelect,
|
|
1560
|
+
icon,
|
|
1561
|
+
iconHtml,
|
|
1562
|
+
deleteDisabled
|
|
1563
|
+
} = props;
|
|
1564
|
+
const { containers, setContainers, reload, loading } = UseContainers({
|
|
1565
|
+
apiBaseUrl: containerApiBaseUrl,
|
|
1566
|
+
parentId: parentContainerId
|
|
1567
|
+
});
|
|
1568
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
1569
|
+
const [error, setError] = useState7(null);
|
|
1570
|
+
const sdkDb = useMemo4(() => new SparkStudioStorageSDK(containerApiBaseUrl), [containerApiBaseUrl]);
|
|
1571
|
+
const sdkS3 = useMemo4(() => new SparkStudioStorageSDK(storageApiBaseUrl), [storageApiBaseUrl]);
|
|
1572
|
+
const getPresignedUrl = async (file) => {
|
|
1573
|
+
const contentType = file.type || "application/octet-stream";
|
|
1574
|
+
const containerDTO = await sdkDb.container.CreateFileContainer(
|
|
1575
|
+
file.name,
|
|
1576
|
+
file.size,
|
|
1577
|
+
encodeURIComponent(contentType)
|
|
1578
|
+
);
|
|
1579
|
+
let lastError;
|
|
1580
|
+
for (let i = 1; i <= 3; i++) {
|
|
1581
|
+
try {
|
|
1582
|
+
return await sdkS3.s3.GetPreSignedUrl(containerDTO);
|
|
1583
|
+
} catch (e) {
|
|
1584
|
+
lastError = e;
|
|
1585
|
+
if (i < 3) await new Promise((r) => setTimeout(r, 500 * i));
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
throw lastError instanceof Error ? lastError : new Error("Failed to fetch presigned URL");
|
|
1589
|
+
};
|
|
1590
|
+
const { uploads, startUploadsIfNeeded } = UseUploadManager({
|
|
1591
|
+
autoUpload: true,
|
|
1592
|
+
getPresignedUrl,
|
|
1593
|
+
onUploadComplete: async () => {
|
|
1594
|
+
setError(null);
|
|
1595
|
+
await reload();
|
|
1596
|
+
},
|
|
1597
|
+
onUploadError: (_file, err) => {
|
|
1598
|
+
setError(err.message ?? "Upload failed");
|
|
1599
|
+
}
|
|
1600
|
+
});
|
|
1601
|
+
const handleDeleteFile = async (file) => {
|
|
1602
|
+
const sdkDb2 = new SparkStudioStorageSDK(containerApiBaseUrl);
|
|
1603
|
+
const sdkS32 = new SparkStudioStorageSDK(storageApiBaseUrl);
|
|
1604
|
+
await sdkDb2.container.DeleteContainer(file.Id);
|
|
1605
|
+
await sdkS32.s3.DeleteS3(file);
|
|
1606
|
+
setContainers((prev) => prev.filter((c) => c.Id !== file.Id));
|
|
1607
|
+
};
|
|
1608
|
+
const openPicker = () => {
|
|
1609
|
+
const input = document.createElement("input");
|
|
1610
|
+
input.type = "file";
|
|
1611
|
+
input.multiple = multiple;
|
|
1612
|
+
input.accept = accept;
|
|
1613
|
+
input.onchange = () => {
|
|
1614
|
+
if (!input.files || input.files.length === 0) return;
|
|
1615
|
+
startUploadsIfNeeded(input.files);
|
|
1616
|
+
};
|
|
1617
|
+
input.click();
|
|
1618
|
+
};
|
|
1619
|
+
return /* @__PURE__ */ jsxs6("div", { style: { display: "grid", gap: 12 }, children: [
|
|
1620
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1621
|
+
/* @__PURE__ */ jsx9(UploadProgressList, { uploads }),
|
|
1622
|
+
error ? /* @__PURE__ */ jsx9("div", { style: { fontSize: 12, color: "crimson", marginTop: 6 }, children: error }) : null
|
|
1623
|
+
] }),
|
|
1624
|
+
/* @__PURE__ */ jsxs6(
|
|
1625
|
+
"div",
|
|
1626
|
+
{
|
|
1627
|
+
onDragEnter: (e) => {
|
|
1628
|
+
e.preventDefault();
|
|
1629
|
+
e.stopPropagation();
|
|
1630
|
+
setIsDragging(true);
|
|
1631
|
+
},
|
|
1632
|
+
onDragOver: (e) => {
|
|
1633
|
+
e.preventDefault();
|
|
1634
|
+
e.stopPropagation();
|
|
1635
|
+
setIsDragging(true);
|
|
1636
|
+
},
|
|
1637
|
+
onDragLeave: (e) => {
|
|
1638
|
+
e.preventDefault();
|
|
1639
|
+
e.stopPropagation();
|
|
1640
|
+
setIsDragging(false);
|
|
1641
|
+
},
|
|
1642
|
+
onDrop: (e) => {
|
|
1643
|
+
e.preventDefault();
|
|
1644
|
+
e.stopPropagation();
|
|
1645
|
+
setIsDragging(false);
|
|
1646
|
+
const files = e.dataTransfer.files;
|
|
1647
|
+
if (!files || files.length === 0) return;
|
|
1648
|
+
startUploadsIfNeeded(files);
|
|
1649
|
+
},
|
|
1650
|
+
style: {
|
|
1651
|
+
position: "relative",
|
|
1652
|
+
borderRadius: 14,
|
|
1653
|
+
border: isDragging ? "2px dashed rgba(13,110,253,0.9)" : "2px dashed rgba(0,0,0,0.15)",
|
|
1654
|
+
background: isDragging ? "rgba(13,110,253,0.06)" : "transparent",
|
|
1655
|
+
padding: 12
|
|
1656
|
+
},
|
|
1657
|
+
children: [
|
|
1658
|
+
isDragging ? /* @__PURE__ */ jsx9(
|
|
1659
|
+
"div",
|
|
1660
|
+
{
|
|
1661
|
+
style: {
|
|
1662
|
+
position: "absolute",
|
|
1663
|
+
inset: 0,
|
|
1664
|
+
borderRadius: 14,
|
|
1665
|
+
display: "grid",
|
|
1666
|
+
placeItems: "center",
|
|
1667
|
+
pointerEvents: "none",
|
|
1668
|
+
background: "rgba(13,110,253,0.08)",
|
|
1669
|
+
fontWeight: 800
|
|
1670
|
+
},
|
|
1671
|
+
children: "Drop files to upload"
|
|
1672
|
+
}
|
|
1673
|
+
) : null,
|
|
1674
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 10 }, children: [
|
|
1675
|
+
/* @__PURE__ */ jsx9("div", { style: { fontWeight: 700 }, children: "Files" }),
|
|
1676
|
+
/* @__PURE__ */ jsx9(
|
|
1677
|
+
"button",
|
|
1678
|
+
{
|
|
1679
|
+
type: "button",
|
|
1680
|
+
onClick: openPicker,
|
|
1681
|
+
style: {
|
|
1682
|
+
border: "1px solid rgba(0,0,0,0.18)",
|
|
1683
|
+
background: "white",
|
|
1684
|
+
borderRadius: 10,
|
|
1685
|
+
padding: "8px 10px",
|
|
1686
|
+
cursor: "pointer",
|
|
1687
|
+
fontWeight: 600
|
|
1688
|
+
},
|
|
1689
|
+
children: "Browse\u2026"
|
|
1690
|
+
}
|
|
1691
|
+
)
|
|
1692
|
+
] }),
|
|
1693
|
+
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(
|
|
1694
|
+
FileIconGrid,
|
|
1695
|
+
{
|
|
1696
|
+
files: containers,
|
|
1697
|
+
deleteDisabled,
|
|
1698
|
+
onDeleted: handleDeleteFile,
|
|
1699
|
+
selectedId,
|
|
1700
|
+
onSelect,
|
|
1701
|
+
icon,
|
|
1702
|
+
iconHtml
|
|
1703
|
+
}
|
|
1704
|
+
)
|
|
1705
|
+
]
|
|
1706
|
+
}
|
|
1707
|
+
)
|
|
1708
|
+
] });
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1033
1711
|
// src/components/SingleFileProcessUploader.tsx
|
|
1034
|
-
import { useCallback as useCallback2, useRef as
|
|
1035
|
-
import { jsx as
|
|
1712
|
+
import { useCallback as useCallback2, useRef as useRef4, useState as useState8 } from "react";
|
|
1713
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1036
1714
|
var SingleFileProcessUploader = ({
|
|
1037
1715
|
getPresignedUrl,
|
|
1038
1716
|
onUploadComplete,
|
|
@@ -1041,11 +1719,11 @@ var SingleFileProcessUploader = ({
|
|
|
1041
1719
|
disabled,
|
|
1042
1720
|
uploadOnDrop = false
|
|
1043
1721
|
}) => {
|
|
1044
|
-
const [selectedFile, setSelectedFile] =
|
|
1045
|
-
const [isDragging, setIsDragging] =
|
|
1046
|
-
const [progress, setProgress] =
|
|
1047
|
-
const [status, setStatus] =
|
|
1048
|
-
const fileInputRef =
|
|
1722
|
+
const [selectedFile, setSelectedFile] = useState8(null);
|
|
1723
|
+
const [isDragging, setIsDragging] = useState8(false);
|
|
1724
|
+
const [progress, setProgress] = useState8(null);
|
|
1725
|
+
const [status, setStatus] = useState8("idle");
|
|
1726
|
+
const fileInputRef = useRef4(null);
|
|
1049
1727
|
function getErrorMessage(err) {
|
|
1050
1728
|
if (err instanceof Error) return err.message;
|
|
1051
1729
|
if (typeof err === "string") return err;
|
|
@@ -1131,31 +1809,18 @@ var SingleFileProcessUploader = ({
|
|
|
1131
1809
|
disabled ? "opacity-50" : "cursor-pointer",
|
|
1132
1810
|
isDragging ? "bg-body-secondary border-dashed border-2 border-secondary" : "bg-body-trasparent border-dashed border-2"
|
|
1133
1811
|
].join(" ");
|
|
1134
|
-
return /* @__PURE__ */
|
|
1135
|
-
isUploading ? /* @__PURE__ */
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
] }),
|
|
1147
|
-
/* @__PURE__ */ jsx6("div", { className: "progress", children: /* @__PURE__ */ jsx6(
|
|
1148
|
-
"div",
|
|
1149
|
-
{
|
|
1150
|
-
className: "progress-bar progress-bar-striped progress-bar-animated",
|
|
1151
|
-
role: "progressbar",
|
|
1152
|
-
"aria-valuemin": 0,
|
|
1153
|
-
"aria-valuemax": 100,
|
|
1154
|
-
"aria-valuenow": progress ?? 0,
|
|
1155
|
-
style: { width: `${progress ?? 0}%` }
|
|
1156
|
-
}
|
|
1157
|
-
) })
|
|
1158
|
-
] }) : /* @__PURE__ */ jsxs4(
|
|
1812
|
+
return /* @__PURE__ */ jsxs7("div", { className: "d-flex flex-column gap-2", children: [
|
|
1813
|
+
isUploading ? /* @__PURE__ */ jsx10("div", { className: "small", children: /* @__PURE__ */ jsx10("div", { className: "progress", children: /* @__PURE__ */ jsx10(
|
|
1814
|
+
"div",
|
|
1815
|
+
{
|
|
1816
|
+
className: "progress-bar progress-bar-striped progress-bar-animated",
|
|
1817
|
+
role: "progressbar",
|
|
1818
|
+
"aria-valuemin": 0,
|
|
1819
|
+
"aria-valuemax": 100,
|
|
1820
|
+
"aria-valuenow": progress ?? 0,
|
|
1821
|
+
style: { width: `${progress ?? 0}%` }
|
|
1822
|
+
}
|
|
1823
|
+
) }) }) : /* @__PURE__ */ jsxs7(
|
|
1159
1824
|
"div",
|
|
1160
1825
|
{
|
|
1161
1826
|
className: dropzoneClasses,
|
|
@@ -1166,7 +1831,7 @@ var SingleFileProcessUploader = ({
|
|
|
1166
1831
|
role: "button",
|
|
1167
1832
|
"aria-disabled": disabled,
|
|
1168
1833
|
children: [
|
|
1169
|
-
/* @__PURE__ */
|
|
1834
|
+
/* @__PURE__ */ jsx10(
|
|
1170
1835
|
"input",
|
|
1171
1836
|
{
|
|
1172
1837
|
ref: fileInputRef,
|
|
@@ -1177,8 +1842,8 @@ var SingleFileProcessUploader = ({
|
|
|
1177
1842
|
disabled: disabled || isUploading
|
|
1178
1843
|
}
|
|
1179
1844
|
),
|
|
1180
|
-
selectedFile ? /* @__PURE__ */
|
|
1181
|
-
/* @__PURE__ */
|
|
1845
|
+
selectedFile ? /* @__PURE__ */ jsxs7("div", { className: "small", children: [
|
|
1846
|
+
/* @__PURE__ */ jsx10(
|
|
1182
1847
|
"button",
|
|
1183
1848
|
{
|
|
1184
1849
|
type: "button",
|
|
@@ -1187,15 +1852,15 @@ var SingleFileProcessUploader = ({
|
|
|
1187
1852
|
children: "Browse file\u2026"
|
|
1188
1853
|
}
|
|
1189
1854
|
),
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1855
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
1856
|
+
/* @__PURE__ */ jsx10("strong", { children: "Selected file:" }),
|
|
1192
1857
|
" ",
|
|
1193
1858
|
selectedFile.name
|
|
1194
1859
|
] }),
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
uploadOnDrop && /* @__PURE__ */
|
|
1197
|
-
] }) : /* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */
|
|
1860
|
+
/* @__PURE__ */ jsx10("div", { className: "text-muted", children: "Click here to change file or drag a new one." }),
|
|
1861
|
+
uploadOnDrop && /* @__PURE__ */ jsx10("div", { className: "text-muted", children: "Upload starts automatically." })
|
|
1862
|
+
] }) : /* @__PURE__ */ jsxs7("div", { className: "small", children: [
|
|
1863
|
+
/* @__PURE__ */ jsx10(
|
|
1199
1864
|
"button",
|
|
1200
1865
|
{
|
|
1201
1866
|
type: "button",
|
|
@@ -1204,13 +1869,13 @@ var SingleFileProcessUploader = ({
|
|
|
1204
1869
|
children: "Browse file\u2026"
|
|
1205
1870
|
}
|
|
1206
1871
|
),
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1872
|
+
/* @__PURE__ */ jsx10("div", { children: "Drag & drop a file here" }),
|
|
1873
|
+
/* @__PURE__ */ jsx10("div", { className: "text-muted", children: "or click to browse" })
|
|
1209
1874
|
] })
|
|
1210
1875
|
]
|
|
1211
1876
|
}
|
|
1212
1877
|
),
|
|
1213
|
-
!uploadOnDrop && /* @__PURE__ */
|
|
1878
|
+
!uploadOnDrop && /* @__PURE__ */ jsx10(
|
|
1214
1879
|
"button",
|
|
1215
1880
|
{
|
|
1216
1881
|
type: "button",
|
|
@@ -1224,39 +1889,49 @@ var SingleFileProcessUploader = ({
|
|
|
1224
1889
|
};
|
|
1225
1890
|
|
|
1226
1891
|
// src/views/HomeView.tsx
|
|
1892
|
+
import { useEffect as useEffect4, useState as useState9 } from "react";
|
|
1227
1893
|
import {
|
|
1228
1894
|
AppSettings,
|
|
1229
1895
|
AuthenticatorProvider,
|
|
1230
1896
|
UserInfoCard,
|
|
1231
1897
|
useUser
|
|
1232
1898
|
} from "@sparkstudio/authentication-ui";
|
|
1233
|
-
import { Fragment as Fragment3, jsx as
|
|
1899
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1900
|
+
var CONTAINER_API = "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod";
|
|
1901
|
+
var STORAGE_API = "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod";
|
|
1234
1902
|
function HomeView() {
|
|
1235
|
-
return /* @__PURE__ */
|
|
1903
|
+
return /* @__PURE__ */ jsx11(
|
|
1236
1904
|
AuthenticatorProvider,
|
|
1237
1905
|
{
|
|
1238
1906
|
googleClientId: AppSettings.GoogleClientId,
|
|
1239
1907
|
authenticationUrl: AppSettings.AuthenticationUrl,
|
|
1240
1908
|
accountsUrl: AppSettings.AccountsUrl,
|
|
1241
|
-
children: /* @__PURE__ */
|
|
1909
|
+
children: /* @__PURE__ */ jsx11(HomeContent, {})
|
|
1242
1910
|
}
|
|
1243
1911
|
);
|
|
1244
1912
|
}
|
|
1245
1913
|
function HomeContent() {
|
|
1246
1914
|
const { user } = useUser();
|
|
1915
|
+
const [ids, setIds] = useState9([]);
|
|
1916
|
+
const [selectedId, setSelectedId] = useState9(void 0);
|
|
1917
|
+
const [selectedFile, setSelectedFile] = useState9(null);
|
|
1918
|
+
useEffect4(() => {
|
|
1919
|
+
if (selectedId && !ids.includes(selectedId)) {
|
|
1920
|
+
setSelectedId(void 0);
|
|
1921
|
+
setSelectedFile(null);
|
|
1922
|
+
}
|
|
1923
|
+
}, [ids, selectedId]);
|
|
1247
1924
|
async function getPresignedUrlFromApi(file) {
|
|
1248
|
-
const
|
|
1249
|
-
"https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
|
|
1250
|
-
//"https://localhost:5001"
|
|
1251
|
-
);
|
|
1925
|
+
const sdk = new SparkStudioStorageSDK(STORAGE_API);
|
|
1252
1926
|
const contentType = file.type || "application/octet-stream";
|
|
1253
|
-
|
|
1254
|
-
|
|
1927
|
+
return sdk.s3.GetTemporaryPreSignedUrl(
|
|
1928
|
+
new TemporaryFileDTO({ Name: file.name, ContentType: contentType })
|
|
1929
|
+
);
|
|
1255
1930
|
}
|
|
1256
|
-
return /* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
user
|
|
1259
|
-
/* @__PURE__ */
|
|
1931
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
1932
|
+
/* @__PURE__ */ jsx11(UserInfoCard, {}),
|
|
1933
|
+
user ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
1934
|
+
/* @__PURE__ */ jsx11(
|
|
1260
1935
|
SingleFileProcessUploader,
|
|
1261
1936
|
{
|
|
1262
1937
|
uploadOnDrop: true,
|
|
@@ -1267,23 +1942,52 @@ function HomeContent() {
|
|
|
1267
1942
|
}
|
|
1268
1943
|
}
|
|
1269
1944
|
),
|
|
1270
|
-
/* @__PURE__ */
|
|
1271
|
-
|
|
1945
|
+
/* @__PURE__ */ jsx11(
|
|
1946
|
+
ContainerIdGridPanel,
|
|
1272
1947
|
{
|
|
1273
|
-
containerApiBaseUrl:
|
|
1274
|
-
storageApiBaseUrl:
|
|
1948
|
+
containerApiBaseUrl: CONTAINER_API,
|
|
1949
|
+
storageApiBaseUrl: STORAGE_API,
|
|
1950
|
+
containerIds: ids,
|
|
1951
|
+
onContainerIdsChange: setIds,
|
|
1952
|
+
multiple: true,
|
|
1953
|
+
accept: "*/*",
|
|
1954
|
+
selectedId,
|
|
1955
|
+
onSelect: (file) => {
|
|
1956
|
+
setSelectedId(file.Id);
|
|
1957
|
+
setSelectedFile(file);
|
|
1958
|
+
}
|
|
1275
1959
|
}
|
|
1276
|
-
)
|
|
1277
|
-
|
|
1960
|
+
),
|
|
1961
|
+
selectedFile ? /* @__PURE__ */ jsxs8(
|
|
1962
|
+
"div",
|
|
1963
|
+
{
|
|
1964
|
+
style: {
|
|
1965
|
+
marginTop: 12,
|
|
1966
|
+
padding: 12,
|
|
1967
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
1968
|
+
borderRadius: 12
|
|
1969
|
+
},
|
|
1970
|
+
children: [
|
|
1971
|
+
/* @__PURE__ */ jsx11("div", { style: { fontWeight: 700 }, children: "Selected file" }),
|
|
1972
|
+
/* @__PURE__ */ jsx11("div", { children: selectedFile.Name ?? "(no name)" }),
|
|
1973
|
+
/* @__PURE__ */ jsx11("div", { style: { fontSize: 12, opacity: 0.7 }, children: selectedFile.PublicUrl ?? "(no public url)" })
|
|
1974
|
+
]
|
|
1975
|
+
}
|
|
1976
|
+
) : null
|
|
1977
|
+
] }) : null
|
|
1278
1978
|
] });
|
|
1279
1979
|
}
|
|
1280
1980
|
export {
|
|
1281
1981
|
AWSPresignedUrlDTO,
|
|
1282
1982
|
Container,
|
|
1283
1983
|
ContainerDTO,
|
|
1984
|
+
ContainerIdGridPanel,
|
|
1284
1985
|
ContainerType,
|
|
1285
1986
|
ContainerUploadPanel,
|
|
1286
1987
|
DesktopFileIcon,
|
|
1988
|
+
FileGridUploadPanel,
|
|
1989
|
+
FileIconCard,
|
|
1990
|
+
FileIconGrid,
|
|
1287
1991
|
Home,
|
|
1288
1992
|
HomeView,
|
|
1289
1993
|
S3,
|