@weirdfingers/boards 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -389,6 +389,7 @@ declare const REMOVE_BOARD_MEMBER: urql.TypedDocumentNode<any, urql.AnyVariables
389
389
  declare const CREATE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
390
390
  declare const CANCEL_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
391
391
  declare const RETRY_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
+ declare const DELETE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
393
  declare const UPLOAD_ARTIFACT_FROM_URL: urql.TypedDocumentNode<any, urql.AnyVariables>;
393
394
  interface CreateBoardInput {
394
395
  title: string;
@@ -398,6 +399,7 @@ interface CreateBoardInput {
398
399
  metadata?: Record<string, unknown>;
399
400
  }
400
401
  interface UpdateBoardInput {
402
+ id: string;
401
403
  title?: string;
402
404
  description?: string;
403
405
  isPublic?: boolean;
@@ -651,6 +653,7 @@ interface GenerationHook {
651
653
  submit: (request: GenerationRequest) => Promise<string>;
652
654
  cancel: (jobId: string) => Promise<void>;
653
655
  retry: (jobId: string) => Promise<void>;
656
+ deleteGeneration: (jobId: string) => Promise<void>;
654
657
  history: GenerationResult[];
655
658
  clearHistory: () => void;
656
659
  }
@@ -678,17 +681,17 @@ interface GeneratorsHook {
678
681
  declare function useGenerators(options?: UseGeneratorsOptions): GeneratorsHook;
679
682
 
680
683
  /**
681
- * Hook for uploading artifacts (images, videos, audio, text).
684
+ * Hook for uploading multiple artifacts concurrently with individual progress tracking.
682
685
  */
683
686
 
684
- interface UploadRequest {
687
+ interface MultiUploadRequest {
685
688
  boardId: string;
686
689
  artifactType: ArtifactType;
687
690
  source: File | string;
688
691
  userDescription?: string;
689
692
  parentGenerationId?: string;
690
693
  }
691
- interface UploadResult {
694
+ interface MultiUploadResult {
692
695
  id: string;
693
696
  storageUrl: string;
694
697
  thumbnailUrl?: string;
@@ -696,13 +699,25 @@ interface UploadResult {
696
699
  artifactType: ArtifactType;
697
700
  generatorName: string;
698
701
  }
699
- interface UploadHook {
700
- upload: (request: UploadRequest) => Promise<UploadResult>;
701
- isUploading: boolean;
702
+ type UploadStatus = "pending" | "uploading" | "completed" | "failed";
703
+ interface UploadItem {
704
+ id: string;
705
+ file: File | string;
706
+ fileName: string;
707
+ status: UploadStatus;
702
708
  progress: number;
703
- error: Error | null;
709
+ result?: MultiUploadResult;
710
+ error?: Error;
711
+ }
712
+ interface MultiUploadHook {
713
+ uploadMultiple: (requests: MultiUploadRequest[]) => Promise<MultiUploadResult[]>;
714
+ uploads: UploadItem[];
715
+ isUploading: boolean;
716
+ overallProgress: number;
717
+ clearUploads: () => void;
718
+ cancelUpload: (uploadId: string) => void;
704
719
  }
705
- declare function useUpload(): UploadHook;
720
+ declare function useMultiUpload(): MultiUploadHook;
706
721
 
707
722
  /**
708
723
  * Hook for accessing generation lineage (ancestry and descendants).
@@ -907,4 +922,4 @@ declare function BoardsProvider({ children, apiUrl, graphqlUrl, subscriptionUrl,
907
922
 
908
923
  declare const VERSION = "0.1.0";
909
924
 
910
- export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadHook, type UploadRequest, type UploadResult, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useUpload };
925
+ export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DELETE_GENERATION, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, type MultiUploadHook, type MultiUploadRequest, type MultiUploadResult, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadItem, type UploadStatus, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useMultiUpload };
package/dist/index.d.ts CHANGED
@@ -389,6 +389,7 @@ declare const REMOVE_BOARD_MEMBER: urql.TypedDocumentNode<any, urql.AnyVariables
389
389
  declare const CREATE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
390
390
  declare const CANCEL_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
391
391
  declare const RETRY_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
+ declare const DELETE_GENERATION: urql.TypedDocumentNode<any, urql.AnyVariables>;
392
393
  declare const UPLOAD_ARTIFACT_FROM_URL: urql.TypedDocumentNode<any, urql.AnyVariables>;
393
394
  interface CreateBoardInput {
394
395
  title: string;
@@ -398,6 +399,7 @@ interface CreateBoardInput {
398
399
  metadata?: Record<string, unknown>;
399
400
  }
400
401
  interface UpdateBoardInput {
402
+ id: string;
401
403
  title?: string;
402
404
  description?: string;
403
405
  isPublic?: boolean;
@@ -651,6 +653,7 @@ interface GenerationHook {
651
653
  submit: (request: GenerationRequest) => Promise<string>;
652
654
  cancel: (jobId: string) => Promise<void>;
653
655
  retry: (jobId: string) => Promise<void>;
656
+ deleteGeneration: (jobId: string) => Promise<void>;
654
657
  history: GenerationResult[];
655
658
  clearHistory: () => void;
656
659
  }
@@ -678,17 +681,17 @@ interface GeneratorsHook {
678
681
  declare function useGenerators(options?: UseGeneratorsOptions): GeneratorsHook;
679
682
 
680
683
  /**
681
- * Hook for uploading artifacts (images, videos, audio, text).
684
+ * Hook for uploading multiple artifacts concurrently with individual progress tracking.
682
685
  */
683
686
 
684
- interface UploadRequest {
687
+ interface MultiUploadRequest {
685
688
  boardId: string;
686
689
  artifactType: ArtifactType;
687
690
  source: File | string;
688
691
  userDescription?: string;
689
692
  parentGenerationId?: string;
690
693
  }
691
- interface UploadResult {
694
+ interface MultiUploadResult {
692
695
  id: string;
693
696
  storageUrl: string;
694
697
  thumbnailUrl?: string;
@@ -696,13 +699,25 @@ interface UploadResult {
696
699
  artifactType: ArtifactType;
697
700
  generatorName: string;
698
701
  }
699
- interface UploadHook {
700
- upload: (request: UploadRequest) => Promise<UploadResult>;
701
- isUploading: boolean;
702
+ type UploadStatus = "pending" | "uploading" | "completed" | "failed";
703
+ interface UploadItem {
704
+ id: string;
705
+ file: File | string;
706
+ fileName: string;
707
+ status: UploadStatus;
702
708
  progress: number;
703
- error: Error | null;
709
+ result?: MultiUploadResult;
710
+ error?: Error;
711
+ }
712
+ interface MultiUploadHook {
713
+ uploadMultiple: (requests: MultiUploadRequest[]) => Promise<MultiUploadResult[]>;
714
+ uploads: UploadItem[];
715
+ isUploading: boolean;
716
+ overallProgress: number;
717
+ clearUploads: () => void;
718
+ cancelUpload: (uploadId: string) => void;
704
719
  }
705
- declare function useUpload(): UploadHook;
720
+ declare function useMultiUpload(): MultiUploadHook;
706
721
 
707
722
  /**
708
723
  * Hook for accessing generation lineage (ancestry and descendants).
@@ -907,4 +922,4 @@ declare function BoardsProvider({ children, apiUrl, graphqlUrl, subscriptionUrl,
907
922
 
908
923
  declare const VERSION = "0.1.0";
909
924
 
910
- export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadHook, type UploadRequest, type UploadResult, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useUpload };
925
+ export { ADD_BOARD_MEMBER, ANCESTRY_NODE_FRAGMENT, ARTIFACT_LINEAGE_FRAGMENT, type AncestryNode, type ApiConfig, type Artifact$1 as Artifact, type ArtifactLineage, type ArtifactSlot, type ArtifactSlotInfo, ArtifactType, type AuthContextValue, AuthProvider, type AuthProviderConfig, type AuthState$1 as AuthState, BOARD_FRAGMENT, BaseAuthProvider, BoardRole, BoardsProvider, CANCEL_GENERATION, CREATE_BOARD, CREATE_GENERATION, type CreateBoardInput, type CreateGenerationInput, DELETE_BOARD, DELETE_GENERATION, DESCENDANT_NODE_FRAGMENT, type DescendantNode, type DropdownField, GENERATION_FRAGMENT, GET_ANCESTRY, GET_BOARD, GET_BOARDS, GET_CURRENT_USER, GET_DESCENDANTS, GET_GENERATION, GET_GENERATIONS, GET_GENERATORS, GET_INPUT_ARTIFACTS, GenerationStatus, type Generator, type GeneratorInfo, type GeneratorSelectionContextValue, GeneratorSelectionProvider, type MultiUploadHook, type MultiUploadRequest, type MultiUploadResult, NoAuthProvider, type NumberInputField, type ParsedGeneratorSchema, type PromptField, REMOVE_BOARD_MEMBER, RETRY_GENERATION, type SettingsField, type SignInOptions, type SliderField, type TextInputField, UPDATE_BOARD, UPDATE_BOARD_MEMBER_ROLE, UPLOAD_ARTIFACT_FROM_URL, USER_FRAGMENT, type UpdateBoardInput, type UploadArtifactInput, type UploadItem, type UploadStatus, type User$1 as User, VERSION, createGraphQLClient, getArtifactType, isArtifactReference, parseArtifactSlot, parseGeneratorSchema, parseSettingsField, useAncestry, useApiConfig, useAuth, useAuthOptional, useBoard, useBoards, useDescendants, useGeneration, useGeneratorSelection, useGenerators, useInputArtifacts, useLineage, useMultiUpload };
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  CREATE_BOARD: () => CREATE_BOARD,
34
34
  CREATE_GENERATION: () => CREATE_GENERATION,
35
35
  DELETE_BOARD: () => DELETE_BOARD,
36
+ DELETE_GENERATION: () => DELETE_GENERATION,
36
37
  DESCENDANT_NODE_FRAGMENT: () => DESCENDANT_NODE_FRAGMENT,
37
38
  GENERATION_FRAGMENT: () => GENERATION_FRAGMENT,
38
39
  GET_ANCESTRY: () => GET_ANCESTRY,
@@ -72,7 +73,7 @@ __export(index_exports, {
72
73
  useGenerators: () => useGenerators,
73
74
  useInputArtifacts: () => useInputArtifacts,
74
75
  useLineage: () => useLineage,
75
- useUpload: () => useUpload
76
+ useMultiUpload: () => useMultiUpload
76
77
  });
77
78
  module.exports = __toCommonJS(index_exports);
78
79
 
@@ -820,8 +821,8 @@ var CREATE_BOARD = import_urql2.gql`
820
821
  `;
821
822
  var UPDATE_BOARD = import_urql2.gql`
822
823
  ${BOARD_FRAGMENT}
823
- mutation UpdateBoard($id: UUID!, $input: UpdateBoardInput!) {
824
- updateBoard(id: $id, input: $input) {
824
+ mutation UpdateBoard($input: UpdateBoardInput!) {
825
+ updateBoard(input: $input) {
825
826
  ...BoardFragment
826
827
  }
827
828
  }
@@ -887,6 +888,11 @@ var RETRY_GENERATION = import_urql2.gql`
887
888
  }
888
889
  }
889
890
  `;
891
+ var DELETE_GENERATION = import_urql2.gql`
892
+ mutation DeleteGeneration($id: UUID!) {
893
+ deleteGeneration(id: $id)
894
+ }
895
+ `;
890
896
  var UPLOAD_ARTIFACT_FROM_URL = import_urql2.gql`
891
897
  ${GENERATION_FRAGMENT}
892
898
  mutation UploadArtifactFromUrl($input: UploadArtifactInput!) {
@@ -1049,8 +1055,10 @@ function useBoard(boardId, options) {
1049
1055
  throw new Error("Board ID is required");
1050
1056
  }
1051
1057
  const result = await updateBoardMutation({
1052
- id: boardId,
1053
- input: updates
1058
+ input: {
1059
+ id: boardId,
1060
+ ...updates
1061
+ }
1054
1062
  });
1055
1063
  if (result.error) {
1056
1064
  throw new Error(result.error.message);
@@ -1173,6 +1181,7 @@ function useGeneration() {
1173
1181
  const [, createGenerationMutation] = (0, import_urql5.useMutation)(CREATE_GENERATION);
1174
1182
  const [, cancelGenerationMutation] = (0, import_urql5.useMutation)(CANCEL_GENERATION);
1175
1183
  const [, retryGenerationMutation] = (0, import_urql5.useMutation)(RETRY_GENERATION);
1184
+ const [, deleteGenerationMutation] = (0, import_urql5.useMutation)(DELETE_GENERATION);
1176
1185
  (0, import_react6.useEffect)(() => {
1177
1186
  return () => {
1178
1187
  abortControllers.current.forEach((controller) => {
@@ -1382,6 +1391,36 @@ function useGeneration() {
1382
1391
  },
1383
1392
  [retryGenerationMutation, connectToSSE]
1384
1393
  );
1394
+ const deleteGeneration = (0, import_react6.useCallback)(
1395
+ async (jobId) => {
1396
+ try {
1397
+ const result2 = await deleteGenerationMutation({ id: jobId });
1398
+ if (result2.error) {
1399
+ throw new Error(result2.error.message);
1400
+ }
1401
+ if (!result2.data?.deleteGeneration) {
1402
+ throw new Error("Failed to delete generation");
1403
+ }
1404
+ const controller = abortControllers.current.get(jobId);
1405
+ if (controller) {
1406
+ controller.abort();
1407
+ abortControllers.current.delete(jobId);
1408
+ }
1409
+ if (progress?.jobId === jobId) {
1410
+ setProgress(null);
1411
+ setResult(null);
1412
+ setIsGenerating(false);
1413
+ }
1414
+ setHistory((prev) => prev.filter((item) => item.jobId !== jobId));
1415
+ } catch (err) {
1416
+ setError(
1417
+ err instanceof Error ? err : new Error("Failed to delete generation")
1418
+ );
1419
+ throw err;
1420
+ }
1421
+ },
1422
+ [deleteGenerationMutation, progress]
1423
+ );
1385
1424
  const clearHistory = (0, import_react6.useCallback)(() => {
1386
1425
  setHistory([]);
1387
1426
  }, []);
@@ -1393,6 +1432,7 @@ function useGeneration() {
1393
1432
  submit,
1394
1433
  cancel,
1395
1434
  retry,
1435
+ deleteGeneration,
1396
1436
  history,
1397
1437
  clearHistory
1398
1438
  };
@@ -1415,21 +1455,44 @@ function useGenerators(options = {}) {
1415
1455
  };
1416
1456
  }
1417
1457
 
1418
- // src/hooks/useUpload.ts
1458
+ // src/hooks/useMultiUpload.ts
1419
1459
  var import_react8 = require("react");
1420
1460
  var import_urql7 = require("urql");
1421
- function useUpload() {
1422
- const [isUploading, setIsUploading] = (0, import_react8.useState)(false);
1423
- const [progress, setProgress] = (0, import_react8.useState)(0);
1424
- const [error, setError] = (0, import_react8.useState)(null);
1461
+ var uploadIdCounter = 0;
1462
+ function generateUploadId() {
1463
+ return `upload-${Date.now()}-${++uploadIdCounter}`;
1464
+ }
1465
+ function getFileName(source) {
1466
+ if (typeof source === "string") {
1467
+ try {
1468
+ const url = new URL(source);
1469
+ const pathParts = url.pathname.split("/");
1470
+ return pathParts[pathParts.length - 1] || source;
1471
+ } catch {
1472
+ return source;
1473
+ }
1474
+ }
1475
+ return source.name;
1476
+ }
1477
+ function useMultiUpload() {
1478
+ const [uploads, setUploads] = (0, import_react8.useState)([]);
1479
+ const abortControllersRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
1425
1480
  const { apiUrl } = useApiConfig();
1426
1481
  const auth = useAuth();
1427
1482
  const [, uploadFromUrlMutation] = (0, import_urql7.useMutation)(UPLOAD_ARTIFACT_FROM_URL);
1428
- const upload = (0, import_react8.useCallback)(
1429
- async (request) => {
1430
- setError(null);
1431
- setProgress(0);
1432
- setIsUploading(true);
1483
+ const updateUpload = (0, import_react8.useCallback)(
1484
+ (uploadId, updates) => {
1485
+ setUploads(
1486
+ (prev) => prev.map(
1487
+ (item) => item.id === uploadId ? { ...item, ...updates } : item
1488
+ )
1489
+ );
1490
+ },
1491
+ []
1492
+ );
1493
+ const uploadSingle = (0, import_react8.useCallback)(
1494
+ async (uploadId, request) => {
1495
+ updateUpload(uploadId, { status: "uploading", progress: 0 });
1433
1496
  try {
1434
1497
  if (typeof request.source === "string") {
1435
1498
  const result2 = await uploadFromUrlMutation({
@@ -1447,9 +1510,7 @@ function useUpload() {
1447
1510
  if (!result2.data?.uploadArtifact) {
1448
1511
  throw new Error("Upload failed");
1449
1512
  }
1450
- setProgress(100);
1451
- setIsUploading(false);
1452
- return {
1513
+ const uploadResult = {
1453
1514
  id: result2.data.uploadArtifact.id,
1454
1515
  storageUrl: result2.data.uploadArtifact.storageUrl,
1455
1516
  thumbnailUrl: result2.data.uploadArtifact.thumbnailUrl,
@@ -1457,6 +1518,12 @@ function useUpload() {
1457
1518
  artifactType: result2.data.uploadArtifact.artifactType,
1458
1519
  generatorName: result2.data.uploadArtifact.generatorName
1459
1520
  };
1521
+ updateUpload(uploadId, {
1522
+ status: "completed",
1523
+ progress: 100,
1524
+ result: uploadResult
1525
+ });
1526
+ return uploadResult;
1460
1527
  }
1461
1528
  const formData = new FormData();
1462
1529
  formData.append("board_id", request.boardId);
@@ -1473,68 +1540,128 @@ function useUpload() {
1473
1540
  if (token) {
1474
1541
  headers.Authorization = `Bearer ${token}`;
1475
1542
  }
1476
- const result = await new Promise((resolve, reject) => {
1477
- const xhr = new XMLHttpRequest();
1478
- xhr.upload.addEventListener("progress", (e) => {
1479
- if (e.lengthComputable) {
1480
- const percentComplete = e.loaded / e.total * 100;
1481
- setProgress(percentComplete);
1482
- }
1483
- });
1484
- xhr.addEventListener("load", () => {
1485
- if (xhr.status === 200) {
1486
- try {
1487
- const data = JSON.parse(xhr.responseText);
1488
- resolve({
1489
- id: data.id,
1490
- storageUrl: data.storageUrl,
1491
- thumbnailUrl: data.thumbnailUrl,
1492
- status: "completed",
1493
- artifactType: data.artifactType,
1494
- generatorName: data.generatorName
1495
- });
1496
- } catch (err) {
1497
- reject(new Error("Failed to parse response"));
1543
+ const result = await new Promise(
1544
+ (resolve, reject) => {
1545
+ const xhr = new XMLHttpRequest();
1546
+ abortControllersRef.current.set(uploadId, () => xhr.abort());
1547
+ const cleanup = () => {
1548
+ abortControllersRef.current.delete(uploadId);
1549
+ };
1550
+ xhr.upload.addEventListener("progress", (e) => {
1551
+ if (e.lengthComputable) {
1552
+ const percentComplete = e.loaded / e.total * 100;
1553
+ updateUpload(uploadId, { progress: percentComplete });
1498
1554
  }
1499
- } else {
1500
- try {
1501
- const errorData = JSON.parse(xhr.responseText);
1502
- reject(new Error(errorData.detail || `Upload failed: ${xhr.statusText}`));
1503
- } catch {
1504
- reject(new Error(`Upload failed: ${xhr.statusText}`));
1555
+ });
1556
+ xhr.addEventListener("load", () => {
1557
+ cleanup();
1558
+ if (xhr.status === 200) {
1559
+ try {
1560
+ const data = JSON.parse(xhr.responseText);
1561
+ resolve({
1562
+ id: data.id,
1563
+ storageUrl: data.storageUrl,
1564
+ thumbnailUrl: data.thumbnailUrl,
1565
+ status: "completed",
1566
+ artifactType: data.artifactType,
1567
+ generatorName: data.generatorName
1568
+ });
1569
+ } catch (err) {
1570
+ reject(new Error("Failed to parse response"));
1571
+ }
1572
+ } else {
1573
+ try {
1574
+ const errorData = JSON.parse(xhr.responseText);
1575
+ reject(
1576
+ new Error(
1577
+ errorData.detail || `Upload failed: ${xhr.statusText}`
1578
+ )
1579
+ );
1580
+ } catch {
1581
+ reject(new Error(`Upload failed: ${xhr.statusText}`));
1582
+ }
1505
1583
  }
1506
- }
1507
- });
1508
- xhr.addEventListener("error", () => {
1509
- reject(new Error("Upload failed: Network error"));
1510
- });
1511
- xhr.addEventListener("abort", () => {
1512
- reject(new Error("Upload cancelled"));
1513
- });
1514
- xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1515
- Object.entries(headers).forEach(([key, value]) => {
1516
- xhr.setRequestHeader(key, value);
1517
- });
1518
- xhr.send(formData);
1584
+ });
1585
+ xhr.addEventListener("error", () => {
1586
+ cleanup();
1587
+ reject(new Error("Upload failed: Network error"));
1588
+ });
1589
+ xhr.addEventListener("abort", () => {
1590
+ cleanup();
1591
+ reject(new Error("Upload cancelled"));
1592
+ });
1593
+ xhr.addEventListener("loadend", () => {
1594
+ cleanup();
1595
+ });
1596
+ xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1597
+ Object.entries(headers).forEach(([key, value]) => {
1598
+ xhr.setRequestHeader(key, value);
1599
+ });
1600
+ xhr.send(formData);
1601
+ }
1602
+ );
1603
+ updateUpload(uploadId, {
1604
+ status: "completed",
1605
+ progress: 100,
1606
+ result
1519
1607
  });
1520
- setProgress(100);
1521
- setIsUploading(false);
1522
1608
  return result;
1523
1609
  } catch (err) {
1524
1610
  const uploadError = err instanceof Error ? err : new Error("Upload failed");
1525
- setError(uploadError);
1526
- setIsUploading(false);
1527
- setProgress(0);
1611
+ updateUpload(uploadId, {
1612
+ status: "failed",
1613
+ error: uploadError
1614
+ });
1528
1615
  throw uploadError;
1529
1616
  }
1530
1617
  },
1531
- [uploadFromUrlMutation, apiUrl, auth]
1618
+ [uploadFromUrlMutation, apiUrl, auth, updateUpload]
1619
+ );
1620
+ const uploadMultiple = (0, import_react8.useCallback)(
1621
+ async (requests) => {
1622
+ const newUploads = requests.map((request) => ({
1623
+ id: generateUploadId(),
1624
+ file: request.source,
1625
+ fileName: getFileName(request.source),
1626
+ status: "pending",
1627
+ progress: 0
1628
+ }));
1629
+ setUploads((prev) => [...prev, ...newUploads]);
1630
+ const results = await Promise.allSettled(
1631
+ requests.map(
1632
+ (request, index) => uploadSingle(newUploads[index].id, request)
1633
+ )
1634
+ );
1635
+ const successfulResults = [];
1636
+ results.forEach((result) => {
1637
+ if (result.status === "fulfilled") {
1638
+ successfulResults.push(result.value);
1639
+ }
1640
+ });
1641
+ return successfulResults;
1642
+ },
1643
+ [uploadSingle]
1532
1644
  );
1645
+ const clearUploads = (0, import_react8.useCallback)(() => {
1646
+ abortControllersRef.current.forEach((abort) => abort());
1647
+ abortControllersRef.current.clear();
1648
+ setUploads([]);
1649
+ }, []);
1650
+ const cancelUpload = (0, import_react8.useCallback)((uploadId) => {
1651
+ const abort = abortControllersRef.current.get(uploadId);
1652
+ if (abort) {
1653
+ abort();
1654
+ }
1655
+ }, []);
1656
+ const isUploading = uploads.some((u) => u.status === "uploading");
1657
+ const overallProgress = uploads.length > 0 ? uploads.reduce((sum, u) => sum + u.progress, 0) / uploads.length : 0;
1533
1658
  return {
1534
- upload,
1659
+ uploadMultiple,
1660
+ uploads,
1535
1661
  isUploading,
1536
- progress,
1537
- error
1662
+ overallProgress,
1663
+ clearUploads,
1664
+ cancelUpload
1538
1665
  };
1539
1666
  }
1540
1667
 
@@ -1652,6 +1779,7 @@ var VERSION = "0.1.0";
1652
1779
  CREATE_BOARD,
1653
1780
  CREATE_GENERATION,
1654
1781
  DELETE_BOARD,
1782
+ DELETE_GENERATION,
1655
1783
  DESCENDANT_NODE_FRAGMENT,
1656
1784
  GENERATION_FRAGMENT,
1657
1785
  GET_ANCESTRY,
@@ -1691,6 +1819,6 @@ var VERSION = "0.1.0";
1691
1819
  useGenerators,
1692
1820
  useInputArtifacts,
1693
1821
  useLineage,
1694
- useUpload
1822
+ useMultiUpload
1695
1823
  });
1696
1824
  //# sourceMappingURL=index.js.map