@sparkstudio/storage-ui 1.0.11 → 1.0.13

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.js CHANGED
@@ -76,23 +76,22 @@ var Container = class {
76
76
  if (!response.ok) throw new Error(await response.text());
77
77
  return await response.json();
78
78
  }
79
- async DeleteS3(containerDTO) {
80
- const url = `${this.baseUrl}/api/Container/DeleteS3`;
79
+ async DeleteContainer(id) {
80
+ const url = `${this.baseUrl}/api/Container/DeleteContainer/` + id;
81
81
  const token = localStorage.getItem("auth_token");
82
82
  const requestOptions = {
83
- method: "POST",
83
+ method: "GET",
84
84
  headers: {
85
85
  "Content-Type": "application/json",
86
86
  ...token && { Authorization: `Bearer ${token}` }
87
- },
88
- body: JSON.stringify(containerDTO)
87
+ }
89
88
  };
90
89
  const response = await fetch(url, requestOptions);
91
90
  if (!response.ok) throw new Error(await response.text());
92
91
  return await response.json();
93
92
  }
94
- async DeleteContainer(id) {
95
- const url = `${this.baseUrl}/api/Container/DeleteContainer/` + id;
93
+ async CreateFileContainer(fileName, size, contentType) {
94
+ const url = `${this.baseUrl}/api/Container/CreateFileContainer/` + fileName + `/` + size + `/` + contentType;
96
95
  const token = localStorage.getItem("auth_token");
97
96
  const requestOptions = {
98
97
  method: "GET",
@@ -105,22 +104,39 @@ var Container = class {
105
104
  if (!response.ok) throw new Error(await response.text());
106
105
  return await response.json();
107
106
  }
108
- async CreateFileContainer(fileName, size, contentType) {
109
- const url = `${this.baseUrl}/api/Container/CreateFileContainer/` + fileName + `/` + size + `/` + contentType;
107
+ };
108
+
109
+ // src/api/Controllers/Home.ts
110
+ var Home = class {
111
+ baseUrl;
112
+ constructor(baseUrl) {
113
+ this.baseUrl = baseUrl;
114
+ }
115
+ };
116
+
117
+ // src/api/Controllers/S3.ts
118
+ var S3 = class {
119
+ baseUrl;
120
+ constructor(baseUrl) {
121
+ this.baseUrl = baseUrl;
122
+ }
123
+ async DeleteS3(containerDTO) {
124
+ const url = `${this.baseUrl}/api/S3/DeleteS3`;
110
125
  const token = localStorage.getItem("auth_token");
111
126
  const requestOptions = {
112
- method: "GET",
127
+ method: "POST",
113
128
  headers: {
114
129
  "Content-Type": "application/json",
115
130
  ...token && { Authorization: `Bearer ${token}` }
116
- }
131
+ },
132
+ body: JSON.stringify(containerDTO)
117
133
  };
118
134
  const response = await fetch(url, requestOptions);
119
135
  if (!response.ok) throw new Error(await response.text());
120
136
  return await response.json();
121
137
  }
122
138
  async GetPreSignedUrl(containerDTO) {
123
- const url = `${this.baseUrl}/api/Container/GetPreSignedUrl`;
139
+ const url = `${this.baseUrl}/api/S3/GetPreSignedUrl`;
124
140
  const token = localStorage.getItem("auth_token");
125
141
  const requestOptions = {
126
142
  method: "POST",
@@ -136,21 +152,15 @@ var Container = class {
136
152
  }
137
153
  };
138
154
 
139
- // src/api/Controllers/Home.ts
140
- var Home = class {
141
- baseUrl;
142
- constructor(baseUrl) {
143
- this.baseUrl = baseUrl;
144
- }
145
- };
146
-
147
155
  // src/api/SparkStudioStorageSDK.ts
148
156
  var SparkStudioStorageSDK = class {
149
157
  container;
150
158
  home;
159
+ s3;
151
160
  constructor(baseUrl) {
152
161
  this.container = new Container(baseUrl);
153
162
  this.home = new Home(baseUrl);
163
+ this.s3 = new S3(baseUrl);
154
164
  }
155
165
  };
156
166
 
@@ -196,75 +206,246 @@ var ContainerType = /* @__PURE__ */ ((ContainerType2) => {
196
206
  return ContainerType2;
197
207
  })(ContainerType || {});
198
208
 
209
+ // src/components/ContainerUploadPanel.tsx
210
+ import "react";
211
+
199
212
  // src/components/UploadContainer.tsx
200
- import { useState } from "react";
213
+ import { useState as useState2 } from "react";
214
+
215
+ // src/components/UploadDropzone.tsx
216
+ import "react";
201
217
  import { jsx, jsxs } from "react/jsx-runtime";
202
- var UploadContainer = ({
203
- title = "Upload files",
204
- description = "Drag and drop files here, or click the button to browse.",
205
- multiple = true,
218
+ var UploadDropzone = ({
219
+ isDragging,
220
+ onDragOver,
221
+ onDragLeave,
222
+ onDrop
223
+ }) => {
224
+ return /* @__PURE__ */ jsxs(
225
+ "div",
226
+ {
227
+ className: "border rounded-3 p-4 text-center mb-3 d-flex flex-column align-items-center justify-content-center " + (isDragging ? "bg-light border-primary" : "border-secondary border-dashed"),
228
+ style: { cursor: "pointer", minHeight: "140px" },
229
+ onDragOver,
230
+ onDragLeave,
231
+ onDrop,
232
+ children: [
233
+ /* @__PURE__ */ jsx("i", { className: "bi bi-cloud-arrow-up fs-1 mb-2" }),
234
+ /* @__PURE__ */ jsx("p", { className: "mb-2", children: "Drop files here" }),
235
+ /* @__PURE__ */ jsx("small", { className: "text-muted", children: "or click the button below" })
236
+ ]
237
+ }
238
+ );
239
+ };
240
+
241
+ // src/components/UploadFilePicker.tsx
242
+ import "react";
243
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
244
+ var UploadFilePicker = ({
245
+ multiple,
206
246
  accept,
207
- onFilesSelected,
208
- autoUpload = false,
209
- getPresignedUrl,
210
- onUploadComplete,
211
- onUploadError
247
+ fileNames,
248
+ onFileChange
212
249
  }) => {
213
- const [isDragging, setIsDragging] = useState(false);
214
- const [fileNames, setFileNames] = useState([]);
215
- const [uploads, setUploads] = useState([]);
216
- const startUploadsIfNeeded = (files) => {
217
- if (!autoUpload || !getPresignedUrl) return;
218
- const newUploads = Array.from(files).map((file) => ({
219
- id: `${file.name}-${file.size}-${file.lastModified}-${Math.random()}`,
220
- file,
221
- progress: 0,
222
- status: "pending"
223
- }));
224
- setUploads((prev) => [...prev, ...newUploads]);
225
- newUploads.forEach((upload) => {
226
- uploadFile(upload);
227
- });
228
- };
229
- const uploadFile = async (upload) => {
230
- setUploads(
231
- (prev) => prev.map(
232
- (u) => u.id === upload.id ? { ...u, status: "uploading", progress: 0 } : u
250
+ return /* @__PURE__ */ jsxs2("div", { className: "d-flex gap-2 align-items-center", children: [
251
+ /* @__PURE__ */ jsxs2("label", { className: "btn btn-primary mb-0", children: [
252
+ /* @__PURE__ */ jsx2("i", { className: "bi bi-folder2-open me-2" }),
253
+ "Browse files",
254
+ /* @__PURE__ */ jsx2(
255
+ "input",
256
+ {
257
+ type: "file",
258
+ className: "d-none",
259
+ multiple,
260
+ accept,
261
+ onChange: onFileChange
262
+ }
233
263
  )
234
- );
235
- try {
236
- if (!getPresignedUrl) {
237
- throw new Error("getPresignedUrl is not provided.");
264
+ ] }),
265
+ fileNames.length > 0 && /* @__PURE__ */ jsxs2("div", { className: "flex-grow-1", children: [
266
+ /* @__PURE__ */ jsx2("div", { className: "small text-muted", children: "Selected:" }),
267
+ /* @__PURE__ */ jsx2("ul", { className: "mb-0 small", children: fileNames.map((name) => /* @__PURE__ */ jsx2("li", { children: name }, name)) })
268
+ ] })
269
+ ] });
270
+ };
271
+
272
+ // src/components/UploadProgressList.tsx
273
+ import "react";
274
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
275
+ var UploadProgressList = ({
276
+ uploads
277
+ }) => {
278
+ if (uploads.length === 0) return null;
279
+ return /* @__PURE__ */ jsx3("div", { className: "mt-3", children: uploads.map((u) => /* @__PURE__ */ jsxs3("div", { className: "mb-2", children: [
280
+ /* @__PURE__ */ jsxs3("div", { className: "d-flex justify-content-between small mb-1", children: [
281
+ /* @__PURE__ */ jsxs3("span", { children: [
282
+ u.file.name,
283
+ " - ",
284
+ u?.publicUrl ?? ""
285
+ ] }),
286
+ /* @__PURE__ */ jsx3("span", { children: u.status === "success" ? "Completed" : u.status === "error" ? "Error" : `${u.progress}%` })
287
+ ] }),
288
+ /* @__PURE__ */ jsx3("div", { className: "progress", style: { height: "6px" }, children: /* @__PURE__ */ jsx3(
289
+ "div",
290
+ {
291
+ className: "progress-bar " + (u.status === "success" ? "bg-success" : u.status === "error" ? "bg-danger" : ""),
292
+ role: "progressbar",
293
+ style: { width: `${u.progress}%` },
294
+ "aria-valuenow": u.progress,
295
+ "aria-valuemin": 0,
296
+ "aria-valuemax": 100
238
297
  }
239
- const presignedUrl = await getPresignedUrl(upload.file);
240
- const url = presignedUrl?.PresignedUrl ?? "";
241
- await uploadFileToS3(upload.file, url, (progress) => {
242
- setUploads(
243
- (prev) => prev.map(
244
- (u) => u.id === upload.id ? { ...u, progress } : u
298
+ ) }),
299
+ u.status === "error" && /* @__PURE__ */ jsx3("div", { className: "text-danger small mt-1", children: u.error ?? "Upload failed" })
300
+ ] }, u.id)) });
301
+ };
302
+
303
+ // src/hooks/UseUploadManager.ts
304
+ import { useState, useCallback } from "react";
305
+
306
+ // src/engines/UploadFileToS3.ts
307
+ async function UploadFileToS3(file, presignedUrl, onProgress) {
308
+ return new Promise((resolve, reject) => {
309
+ const xhr = new XMLHttpRequest();
310
+ xhr.open("PUT", presignedUrl);
311
+ xhr.upload.onprogress = (event) => {
312
+ if (!event.lengthComputable) return;
313
+ const percent = Math.round(event.loaded / event.total * 100);
314
+ onProgress(percent);
315
+ };
316
+ xhr.onload = () => {
317
+ if (xhr.status >= 200 && xhr.status < 300) {
318
+ onProgress(100);
319
+ resolve();
320
+ } else {
321
+ reject(
322
+ new Error(
323
+ `S3 upload failed with status ${xhr.status}: ${xhr.statusText}`
245
324
  )
246
325
  );
247
- });
248
- const fileUrl = url.split("?")[0];
249
- setUploads(
250
- (prev) => prev.map(
251
- (u) => u.id === upload.id ? { ...u, status: "success", progress: 100, s3Url: fileUrl, publicUrl: presignedUrl.PublicUrl } : u
252
- )
253
- );
254
- onUploadComplete?.(upload.file, fileUrl);
255
- } catch (err) {
256
- let message = "Upload failed";
257
- if (err instanceof Error) {
258
- message = err.message;
259
326
  }
327
+ };
328
+ xhr.onerror = () => {
329
+ reject(new Error("Network error while uploading to S3"));
330
+ };
331
+ xhr.setRequestHeader(
332
+ "Content-Type",
333
+ file.type || "application/octet-stream"
334
+ );
335
+ xhr.send(file);
336
+ });
337
+ }
338
+
339
+ // src/hooks/UseUploadManager.ts
340
+ function UseUploadManager({
341
+ autoUpload = false,
342
+ getPresignedUrl,
343
+ onUploadComplete,
344
+ onUploadError
345
+ }) {
346
+ const [uploads, setUploads] = useState([]);
347
+ const createUploadStates = (files) => Array.from(files).map((file) => ({
348
+ id: `${file.name}-${file.size}-${file.lastModified}-${Math.random()}`,
349
+ file,
350
+ progress: 0,
351
+ status: "pending"
352
+ }));
353
+ const uploadFile = useCallback(
354
+ async (upload) => {
260
355
  setUploads(
261
356
  (prev) => prev.map(
262
- (u) => u.id === upload.id ? { ...u, status: "error", error: message } : u
357
+ (u) => u.id === upload.id ? { ...u, status: "uploading", progress: 0 } : u
263
358
  )
264
359
  );
265
- onUploadError?.(upload.file, err instanceof Error ? err : new Error(message));
266
- }
360
+ try {
361
+ if (!getPresignedUrl) {
362
+ throw new Error("getPresignedUrl is not provided.");
363
+ }
364
+ const presignedUrl = await getPresignedUrl(
365
+ upload.file
366
+ );
367
+ const url = presignedUrl?.PresignedUrl ?? "";
368
+ await UploadFileToS3(upload.file, url, (progress) => {
369
+ setUploads(
370
+ (prev) => prev.map(
371
+ (u) => u.id === upload.id ? { ...u, progress } : u
372
+ )
373
+ );
374
+ });
375
+ const fileUrl = url.split("?")[0];
376
+ setUploads(
377
+ (prev) => prev.map(
378
+ (u) => u.id === upload.id ? {
379
+ ...u,
380
+ status: "success",
381
+ progress: 100,
382
+ s3Url: fileUrl,
383
+ // assumes your DTO has PublicUrl
384
+ publicUrl: presignedUrl.PublicUrl
385
+ } : u
386
+ )
387
+ );
388
+ onUploadComplete?.(upload.file, fileUrl);
389
+ } catch (err) {
390
+ let message = "Upload failed";
391
+ if (err instanceof Error) {
392
+ message = err.message;
393
+ }
394
+ setUploads(
395
+ (prev) => prev.map(
396
+ (u) => u.id === upload.id ? { ...u, status: "error", error: message } : u
397
+ )
398
+ );
399
+ onUploadError?.(
400
+ upload.file,
401
+ err instanceof Error ? err : new Error(message)
402
+ );
403
+ }
404
+ },
405
+ [getPresignedUrl, onUploadComplete, onUploadError]
406
+ );
407
+ const startUploadsIfNeeded = useCallback(
408
+ (files) => {
409
+ if (!autoUpload || !getPresignedUrl) return;
410
+ const newUploads = createUploadStates(files);
411
+ setUploads((prev) => [...prev, ...newUploads]);
412
+ newUploads.forEach((upload) => {
413
+ void uploadFile(upload);
414
+ });
415
+ },
416
+ [autoUpload, getPresignedUrl, uploadFile]
417
+ );
418
+ const resetUploads = useCallback(() => setUploads([]), []);
419
+ return {
420
+ uploads,
421
+ startUploadsIfNeeded,
422
+ resetUploads
267
423
  };
424
+ }
425
+
426
+ // src/components/UploadContainer.tsx
427
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
428
+ var UploadContainer = ({
429
+ title = "Upload files",
430
+ description = "Drag and drop files here, or click the button to browse.",
431
+ multiple = true,
432
+ accept,
433
+ onFilesSelected,
434
+ existingFiles = [],
435
+ onExistingFileClick,
436
+ autoUpload = false,
437
+ getPresignedUrl,
438
+ onUploadComplete,
439
+ onUploadError
440
+ }) => {
441
+ const [isDragging, setIsDragging] = useState2(false);
442
+ const [fileNames, setFileNames] = useState2([]);
443
+ const { uploads, startUploadsIfNeeded } = UseUploadManager({
444
+ autoUpload,
445
+ getPresignedUrl,
446
+ onUploadComplete,
447
+ onUploadError
448
+ });
268
449
  const handleDragOver = (e) => {
269
450
  e.preventDefault();
270
451
  setIsDragging(true);
@@ -289,149 +470,209 @@ var UploadContainer = ({
289
470
  onFilesSelected?.(files);
290
471
  startUploadsIfNeeded(files);
291
472
  };
292
- return /* @__PURE__ */ jsx("div", { className: "container my-3", children: /* @__PURE__ */ jsx("div", { className: "card shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "card-body", children: [
293
- /* @__PURE__ */ jsx("h5", { className: "card-title mb-2", children: title }),
294
- /* @__PURE__ */ jsx("p", { className: "card-text text-muted", children: description }),
295
- /* @__PURE__ */ jsxs(
296
- "div",
473
+ const handleExistingFileClickInternal = (file) => {
474
+ if (onExistingFileClick) {
475
+ onExistingFileClick(file);
476
+ return;
477
+ }
478
+ const a = document.createElement("a");
479
+ a.download = file.Name ?? "";
480
+ a.target = "_blank";
481
+ a.rel = "noopener noreferrer";
482
+ document.body.appendChild(a);
483
+ a.click();
484
+ document.body.removeChild(a);
485
+ };
486
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
487
+ /* @__PURE__ */ jsx4("h5", { className: "card-title mb-2", children: title }),
488
+ /* @__PURE__ */ jsx4("p", { className: "card-text text-muted", children: description }),
489
+ existingFiles.length > 0 && /* @__PURE__ */ jsxs4("div", { className: "mb-3", children: [
490
+ /* @__PURE__ */ jsx4("h6", { className: "mb-2", children: "Existing files" }),
491
+ /* @__PURE__ */ jsx4("ul", { className: "list-group", children: existingFiles.map((file) => /* @__PURE__ */ jsxs4(
492
+ "li",
493
+ {
494
+ className: "list-group-item d-flex justify-content-between align-items-center",
495
+ style: { cursor: "pointer" },
496
+ onClick: () => handleExistingFileClickInternal(file),
497
+ children: [
498
+ /* @__PURE__ */ jsx4("span", { children: file.Name }),
499
+ typeof file.FileSize === "number" && /* @__PURE__ */ jsxs4("small", { className: "text-muted", children: [
500
+ (file.FileSize / 1024).toFixed(1),
501
+ " KB"
502
+ ] })
503
+ ]
504
+ },
505
+ file.Id
506
+ )) })
507
+ ] }),
508
+ /* @__PURE__ */ jsx4(
509
+ UploadDropzone,
297
510
  {
298
- className: "border rounded-3 p-4 text-center mb-3 d-flex flex-column align-items-center justify-content-center " + (isDragging ? "bg-light border-primary" : "border-secondary border-dashed"),
299
- style: { cursor: "pointer", minHeight: "140px" },
511
+ isDragging,
300
512
  onDragOver: handleDragOver,
301
513
  onDragLeave: handleDragLeave,
302
- onDrop: handleDrop,
303
- children: [
304
- /* @__PURE__ */ jsx("i", { className: "bi bi-cloud-arrow-up fs-1 mb-2" }),
305
- /* @__PURE__ */ jsx("p", { className: "mb-2", children: "Drop files here" }),
306
- /* @__PURE__ */ jsx("small", { className: "text-muted", children: "or click the button below" })
307
- ]
514
+ onDrop: handleDrop
308
515
  }
309
516
  ),
310
- /* @__PURE__ */ jsxs("div", { className: "d-flex gap-2 align-items-center", children: [
311
- /* @__PURE__ */ jsxs("label", { className: "btn btn-primary mb-0", children: [
312
- /* @__PURE__ */ jsx("i", { className: "bi bi-folder2-open me-2" }),
313
- "Browse files",
314
- /* @__PURE__ */ jsx(
315
- "input",
316
- {
317
- type: "file",
318
- className: "d-none",
319
- multiple,
320
- accept,
321
- onChange: handleFileChange
322
- }
323
- )
324
- ] }),
325
- fileNames.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex-grow-1", children: [
326
- /* @__PURE__ */ jsx("div", { className: "small text-muted", children: "Selected:" }),
327
- /* @__PURE__ */ jsx("ul", { className: "mb-0 small", children: fileNames.map((name) => /* @__PURE__ */ jsx("li", { children: name }, name)) })
328
- ] })
329
- ] }),
330
- uploads.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3", children: uploads.map((u) => /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
331
- /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between small mb-1", children: [
332
- /* @__PURE__ */ jsxs("span", { children: [
333
- u.file.name,
334
- " - ",
335
- u?.publicUrl ?? ""
336
- ] }),
337
- /* @__PURE__ */ jsx("span", { children: u.status === "success" ? "Completed" : u.status === "error" ? "Error" : `${u.progress}%` })
338
- ] }),
339
- /* @__PURE__ */ jsx("div", { className: "progress", style: { height: "6px" }, children: /* @__PURE__ */ jsx(
340
- "div",
341
- {
342
- className: "progress-bar " + (u.status === "success" ? "bg-success" : u.status === "error" ? "bg-danger" : ""),
343
- role: "progressbar",
344
- style: { width: `${u.progress}%` },
345
- "aria-valuenow": u.progress,
346
- "aria-valuemin": 0,
347
- "aria-valuemax": 100
348
- }
349
- ) }),
350
- u.status === "error" && /* @__PURE__ */ jsx("div", { className: "text-danger small mt-1", children: u.error ?? "Upload failed" })
351
- ] }, u.id)) })
352
- ] }) }) });
353
- };
354
- async function uploadFileToS3(file, presignedUrl, onProgress) {
355
- return new Promise((resolve, reject) => {
356
- const xhr = new XMLHttpRequest();
357
- xhr.open("PUT", presignedUrl);
358
- xhr.upload.onprogress = (event) => {
359
- if (!event.lengthComputable) return;
360
- const percent = Math.round(event.loaded / event.total * 100);
361
- onProgress(percent);
362
- };
363
- xhr.onload = () => {
364
- if (xhr.status >= 200 && xhr.status < 300) {
365
- onProgress(100);
366
- resolve();
367
- } else {
368
- reject(
369
- new Error(`S3 upload failed with status ${xhr.status}: ${xhr.statusText}`)
370
- );
517
+ /* @__PURE__ */ jsx4(
518
+ UploadFilePicker,
519
+ {
520
+ multiple,
521
+ accept,
522
+ fileNames,
523
+ onFileChange: handleFileChange
371
524
  }
372
- };
373
- xhr.onerror = () => {
374
- reject(new Error("Network error while uploading to S3"));
375
- };
376
- xhr.setRequestHeader(
377
- "Content-Type",
378
- file.type || "application/octet-stream"
379
- );
380
- xhr.send(file);
381
- });
525
+ ),
526
+ /* @__PURE__ */ jsx4(UploadProgressList, { uploads })
527
+ ] });
528
+ };
529
+
530
+ // src/hooks/UseContainers.ts
531
+ import { useEffect, useState as useState3 } from "react";
532
+ function UseContainers({ apiBaseUrl, parentId }) {
533
+ const [containers, setContainers] = useState3([]);
534
+ const [loading, setLoading] = useState3(false);
535
+ const [error, setError] = useState3(null);
536
+ const load = async () => {
537
+ setLoading(true);
538
+ setError(null);
539
+ try {
540
+ const sdkDb = new SparkStudioStorageSDK(
541
+ "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod"
542
+ );
543
+ const result = await sdkDb.container.ReadRootContainers();
544
+ setContainers(result);
545
+ } catch (err) {
546
+ setError(err);
547
+ } finally {
548
+ setLoading(false);
549
+ }
550
+ };
551
+ useEffect(() => {
552
+ void load();
553
+ }, [apiBaseUrl, parentId]);
554
+ return {
555
+ containers,
556
+ loading,
557
+ error,
558
+ reload: load
559
+ };
382
560
  }
383
561
 
384
- // src/views/HomeView.tsx
385
- import { AppSettings, AuthenticatorProvider, UserInfoCard } from "@sparkstudio/authentication-ui";
386
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
387
- function HomeView() {
388
- function handleOnLoginSuccess(user) {
389
- alert(user?.Id);
390
- }
562
+ // src/components/ContainerUploadPanel.tsx
563
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
564
+ var ContainerUploadPanel = ({
565
+ containerApiBaseUrl,
566
+ parentContainerId,
567
+ title = "Upload files",
568
+ description = "Drop files to upload. Existing files are listed below."
569
+ }) => {
570
+ const { containers, loading, error, reload } = UseContainers({
571
+ apiBaseUrl: containerApiBaseUrl,
572
+ parentId: parentContainerId
573
+ });
391
574
  const getPresignedUrl = async (file) => {
392
- const sdkDb = new SparkStudioStorageSDK("https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod");
393
- const sdkS3 = new SparkStudioStorageSDK("https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod");
394
- const containerDTO = await sdkDb.container.CreateFileContainer(file.name, file.size, encodeURIComponent(file.type));
395
- const resultS3 = await sdkS3.container.GetPreSignedUrl(containerDTO);
575
+ const sdkDb = new SparkStudioStorageSDK(
576
+ "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod"
577
+ );
578
+ const sdkS3 = new SparkStudioStorageSDK(
579
+ "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
580
+ );
581
+ const containerDTO = await sdkDb.container.CreateFileContainer(
582
+ file.name,
583
+ file.size,
584
+ encodeURIComponent(file.type)
585
+ );
586
+ const resultS3 = await sdkS3.s3.GetPreSignedUrl(containerDTO);
396
587
  return resultS3;
397
588
  };
398
- return /* @__PURE__ */ jsxs2(
589
+ const handleUploadComplete = async (file, s3Url) => {
590
+ console.log("Upload complete:", file.name, s3Url);
591
+ await reload();
592
+ };
593
+ const handleUploadError = (file, err) => {
594
+ console.error("Upload failed:", file.name, err);
595
+ };
596
+ const handleExistingFileClick = (file) => {
597
+ const downloadUrl = `${containerApiBaseUrl}/api/Container/Download/${file.Id}`;
598
+ const a = document.createElement("a");
599
+ a.href = downloadUrl;
600
+ a.download = file.Name ?? "";
601
+ a.target = "_blank";
602
+ a.rel = "noopener noreferrer";
603
+ document.body.appendChild(a);
604
+ a.click();
605
+ document.body.removeChild(a);
606
+ };
607
+ return /* @__PURE__ */ jsxs5("div", { children: [
608
+ loading && /* @__PURE__ */ jsx5("p", { children: "Loading existing files\u2026" }),
609
+ error && /* @__PURE__ */ jsxs5("p", { className: "text-danger", children: [
610
+ "Failed to load containers: ",
611
+ error.message
612
+ ] }),
613
+ /* @__PURE__ */ jsx5(
614
+ UploadContainer,
615
+ {
616
+ title,
617
+ description,
618
+ existingFiles: containers,
619
+ onExistingFileClick: handleExistingFileClick,
620
+ autoUpload: true,
621
+ getPresignedUrl,
622
+ onUploadComplete: handleUploadComplete,
623
+ onUploadError: handleUploadError
624
+ }
625
+ )
626
+ ] });
627
+ };
628
+
629
+ // src/views/HomeView.tsx
630
+ import {
631
+ AppSettings,
632
+ AuthenticatorProvider,
633
+ UserInfoCard,
634
+ useUser
635
+ } from "@sparkstudio/authentication-ui";
636
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
637
+ function HomeView() {
638
+ return /* @__PURE__ */ jsx6(
399
639
  AuthenticatorProvider,
400
640
  {
401
641
  googleClientId: AppSettings.GoogleClientId,
402
642
  authenticationUrl: AppSettings.AuthenticationUrl,
403
643
  accountsUrl: AppSettings.AccountsUrl,
404
- onLoginSuccess: handleOnLoginSuccess,
405
- children: [
406
- /* @__PURE__ */ jsx2(UserInfoCard, {}),
407
- /* @__PURE__ */ jsx2(
408
- UploadContainer,
409
- {
410
- title: "Upload your files to S3",
411
- description: "Drag & drop or browse files. Each file will upload with its own progress bar.",
412
- multiple: true,
413
- accept: "*/*",
414
- autoUpload: true,
415
- getPresignedUrl,
416
- onUploadComplete: (file, s3Url) => {
417
- console.log("Uploaded", file.name, "to", s3Url);
418
- },
419
- onUploadError: (file, error) => {
420
- console.error("Failed to upload", file.name, error);
421
- }
422
- }
423
- )
424
- ]
644
+ children: /* @__PURE__ */ jsx6(HomeContent, {})
425
645
  }
426
646
  );
427
647
  }
648
+ function HomeContent() {
649
+ const { user } = useUser();
650
+ return /* @__PURE__ */ jsxs6(Fragment2, { children: [
651
+ /* @__PURE__ */ jsx6(UserInfoCard, {}),
652
+ user && /* @__PURE__ */ jsx6(
653
+ ContainerUploadPanel,
654
+ {
655
+ containerApiBaseUrl: "https://lf9zyufpuk.execute-api.us-east-2.amazonaws.com/Prod",
656
+ storageApiBaseUrl: "https://iq0gmcn0pd.execute-api.us-east-2.amazonaws.com/Prod"
657
+ }
658
+ )
659
+ ] });
660
+ }
428
661
  export {
429
662
  AWSPresignedUrlDTO,
430
663
  Container,
431
664
  ContainerDTO,
432
665
  ContainerType,
666
+ ContainerUploadPanel,
433
667
  Home,
434
668
  HomeView,
669
+ S3,
435
670
  SparkStudioStorageSDK,
436
- UploadContainer
671
+ UploadContainer,
672
+ UploadDropzone,
673
+ UploadFilePicker,
674
+ UploadFileToS3,
675
+ UploadProgressList,
676
+ UseContainers,
677
+ UseUploadManager
437
678
  };