@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.mjs CHANGED
@@ -748,8 +748,8 @@ var CREATE_BOARD = gql`
748
748
  `;
749
749
  var UPDATE_BOARD = gql`
750
750
  ${BOARD_FRAGMENT}
751
- mutation UpdateBoard($id: UUID!, $input: UpdateBoardInput!) {
752
- updateBoard(id: $id, input: $input) {
751
+ mutation UpdateBoard($input: UpdateBoardInput!) {
752
+ updateBoard(input: $input) {
753
753
  ...BoardFragment
754
754
  }
755
755
  }
@@ -815,6 +815,11 @@ var RETRY_GENERATION = gql`
815
815
  }
816
816
  }
817
817
  `;
818
+ var DELETE_GENERATION = gql`
819
+ mutation DeleteGeneration($id: UUID!) {
820
+ deleteGeneration(id: $id)
821
+ }
822
+ `;
818
823
  var UPLOAD_ARTIFACT_FROM_URL = gql`
819
824
  ${GENERATION_FRAGMENT}
820
825
  mutation UploadArtifactFromUrl($input: UploadArtifactInput!) {
@@ -977,8 +982,10 @@ function useBoard(boardId, options) {
977
982
  throw new Error("Board ID is required");
978
983
  }
979
984
  const result = await updateBoardMutation({
980
- id: boardId,
981
- input: updates
985
+ input: {
986
+ id: boardId,
987
+ ...updates
988
+ }
982
989
  });
983
990
  if (result.error) {
984
991
  throw new Error(result.error.message);
@@ -1101,6 +1108,7 @@ function useGeneration() {
1101
1108
  const [, createGenerationMutation] = useMutation3(CREATE_GENERATION);
1102
1109
  const [, cancelGenerationMutation] = useMutation3(CANCEL_GENERATION);
1103
1110
  const [, retryGenerationMutation] = useMutation3(RETRY_GENERATION);
1111
+ const [, deleteGenerationMutation] = useMutation3(DELETE_GENERATION);
1104
1112
  useEffect2(() => {
1105
1113
  return () => {
1106
1114
  abortControllers.current.forEach((controller) => {
@@ -1310,6 +1318,36 @@ function useGeneration() {
1310
1318
  },
1311
1319
  [retryGenerationMutation, connectToSSE]
1312
1320
  );
1321
+ const deleteGeneration = useCallback5(
1322
+ async (jobId) => {
1323
+ try {
1324
+ const result2 = await deleteGenerationMutation({ id: jobId });
1325
+ if (result2.error) {
1326
+ throw new Error(result2.error.message);
1327
+ }
1328
+ if (!result2.data?.deleteGeneration) {
1329
+ throw new Error("Failed to delete generation");
1330
+ }
1331
+ const controller = abortControllers.current.get(jobId);
1332
+ if (controller) {
1333
+ controller.abort();
1334
+ abortControllers.current.delete(jobId);
1335
+ }
1336
+ if (progress?.jobId === jobId) {
1337
+ setProgress(null);
1338
+ setResult(null);
1339
+ setIsGenerating(false);
1340
+ }
1341
+ setHistory((prev) => prev.filter((item) => item.jobId !== jobId));
1342
+ } catch (err) {
1343
+ setError(
1344
+ err instanceof Error ? err : new Error("Failed to delete generation")
1345
+ );
1346
+ throw err;
1347
+ }
1348
+ },
1349
+ [deleteGenerationMutation, progress]
1350
+ );
1313
1351
  const clearHistory = useCallback5(() => {
1314
1352
  setHistory([]);
1315
1353
  }, []);
@@ -1321,6 +1359,7 @@ function useGeneration() {
1321
1359
  submit,
1322
1360
  cancel,
1323
1361
  retry,
1362
+ deleteGeneration,
1324
1363
  history,
1325
1364
  clearHistory
1326
1365
  };
@@ -1343,21 +1382,44 @@ function useGenerators(options = {}) {
1343
1382
  };
1344
1383
  }
1345
1384
 
1346
- // src/hooks/useUpload.ts
1347
- import { useCallback as useCallback6, useState as useState5 } from "react";
1385
+ // src/hooks/useMultiUpload.ts
1386
+ import { useCallback as useCallback6, useState as useState5, useRef as useRef2 } from "react";
1348
1387
  import { useMutation as useMutation4 } from "urql";
1349
- function useUpload() {
1350
- const [isUploading, setIsUploading] = useState5(false);
1351
- const [progress, setProgress] = useState5(0);
1352
- const [error, setError] = useState5(null);
1388
+ var uploadIdCounter = 0;
1389
+ function generateUploadId() {
1390
+ return `upload-${Date.now()}-${++uploadIdCounter}`;
1391
+ }
1392
+ function getFileName(source) {
1393
+ if (typeof source === "string") {
1394
+ try {
1395
+ const url = new URL(source);
1396
+ const pathParts = url.pathname.split("/");
1397
+ return pathParts[pathParts.length - 1] || source;
1398
+ } catch {
1399
+ return source;
1400
+ }
1401
+ }
1402
+ return source.name;
1403
+ }
1404
+ function useMultiUpload() {
1405
+ const [uploads, setUploads] = useState5([]);
1406
+ const abortControllersRef = useRef2(/* @__PURE__ */ new Map());
1353
1407
  const { apiUrl } = useApiConfig();
1354
1408
  const auth = useAuth();
1355
1409
  const [, uploadFromUrlMutation] = useMutation4(UPLOAD_ARTIFACT_FROM_URL);
1356
- const upload = useCallback6(
1357
- async (request) => {
1358
- setError(null);
1359
- setProgress(0);
1360
- setIsUploading(true);
1410
+ const updateUpload = useCallback6(
1411
+ (uploadId, updates) => {
1412
+ setUploads(
1413
+ (prev) => prev.map(
1414
+ (item) => item.id === uploadId ? { ...item, ...updates } : item
1415
+ )
1416
+ );
1417
+ },
1418
+ []
1419
+ );
1420
+ const uploadSingle = useCallback6(
1421
+ async (uploadId, request) => {
1422
+ updateUpload(uploadId, { status: "uploading", progress: 0 });
1361
1423
  try {
1362
1424
  if (typeof request.source === "string") {
1363
1425
  const result2 = await uploadFromUrlMutation({
@@ -1375,9 +1437,7 @@ function useUpload() {
1375
1437
  if (!result2.data?.uploadArtifact) {
1376
1438
  throw new Error("Upload failed");
1377
1439
  }
1378
- setProgress(100);
1379
- setIsUploading(false);
1380
- return {
1440
+ const uploadResult = {
1381
1441
  id: result2.data.uploadArtifact.id,
1382
1442
  storageUrl: result2.data.uploadArtifact.storageUrl,
1383
1443
  thumbnailUrl: result2.data.uploadArtifact.thumbnailUrl,
@@ -1385,6 +1445,12 @@ function useUpload() {
1385
1445
  artifactType: result2.data.uploadArtifact.artifactType,
1386
1446
  generatorName: result2.data.uploadArtifact.generatorName
1387
1447
  };
1448
+ updateUpload(uploadId, {
1449
+ status: "completed",
1450
+ progress: 100,
1451
+ result: uploadResult
1452
+ });
1453
+ return uploadResult;
1388
1454
  }
1389
1455
  const formData = new FormData();
1390
1456
  formData.append("board_id", request.boardId);
@@ -1401,68 +1467,128 @@ function useUpload() {
1401
1467
  if (token) {
1402
1468
  headers.Authorization = `Bearer ${token}`;
1403
1469
  }
1404
- const result = await new Promise((resolve, reject) => {
1405
- const xhr = new XMLHttpRequest();
1406
- xhr.upload.addEventListener("progress", (e) => {
1407
- if (e.lengthComputable) {
1408
- const percentComplete = e.loaded / e.total * 100;
1409
- setProgress(percentComplete);
1410
- }
1411
- });
1412
- xhr.addEventListener("load", () => {
1413
- if (xhr.status === 200) {
1414
- try {
1415
- const data = JSON.parse(xhr.responseText);
1416
- resolve({
1417
- id: data.id,
1418
- storageUrl: data.storageUrl,
1419
- thumbnailUrl: data.thumbnailUrl,
1420
- status: "completed",
1421
- artifactType: data.artifactType,
1422
- generatorName: data.generatorName
1423
- });
1424
- } catch (err) {
1425
- reject(new Error("Failed to parse response"));
1470
+ const result = await new Promise(
1471
+ (resolve, reject) => {
1472
+ const xhr = new XMLHttpRequest();
1473
+ abortControllersRef.current.set(uploadId, () => xhr.abort());
1474
+ const cleanup = () => {
1475
+ abortControllersRef.current.delete(uploadId);
1476
+ };
1477
+ xhr.upload.addEventListener("progress", (e) => {
1478
+ if (e.lengthComputable) {
1479
+ const percentComplete = e.loaded / e.total * 100;
1480
+ updateUpload(uploadId, { progress: percentComplete });
1426
1481
  }
1427
- } else {
1428
- try {
1429
- const errorData = JSON.parse(xhr.responseText);
1430
- reject(new Error(errorData.detail || `Upload failed: ${xhr.statusText}`));
1431
- } catch {
1432
- reject(new Error(`Upload failed: ${xhr.statusText}`));
1482
+ });
1483
+ xhr.addEventListener("load", () => {
1484
+ cleanup();
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"));
1498
+ }
1499
+ } else {
1500
+ try {
1501
+ const errorData = JSON.parse(xhr.responseText);
1502
+ reject(
1503
+ new Error(
1504
+ errorData.detail || `Upload failed: ${xhr.statusText}`
1505
+ )
1506
+ );
1507
+ } catch {
1508
+ reject(new Error(`Upload failed: ${xhr.statusText}`));
1509
+ }
1433
1510
  }
1434
- }
1435
- });
1436
- xhr.addEventListener("error", () => {
1437
- reject(new Error("Upload failed: Network error"));
1438
- });
1439
- xhr.addEventListener("abort", () => {
1440
- reject(new Error("Upload cancelled"));
1441
- });
1442
- xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1443
- Object.entries(headers).forEach(([key, value]) => {
1444
- xhr.setRequestHeader(key, value);
1445
- });
1446
- xhr.send(formData);
1511
+ });
1512
+ xhr.addEventListener("error", () => {
1513
+ cleanup();
1514
+ reject(new Error("Upload failed: Network error"));
1515
+ });
1516
+ xhr.addEventListener("abort", () => {
1517
+ cleanup();
1518
+ reject(new Error("Upload cancelled"));
1519
+ });
1520
+ xhr.addEventListener("loadend", () => {
1521
+ cleanup();
1522
+ });
1523
+ xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
1524
+ Object.entries(headers).forEach(([key, value]) => {
1525
+ xhr.setRequestHeader(key, value);
1526
+ });
1527
+ xhr.send(formData);
1528
+ }
1529
+ );
1530
+ updateUpload(uploadId, {
1531
+ status: "completed",
1532
+ progress: 100,
1533
+ result
1447
1534
  });
1448
- setProgress(100);
1449
- setIsUploading(false);
1450
1535
  return result;
1451
1536
  } catch (err) {
1452
1537
  const uploadError = err instanceof Error ? err : new Error("Upload failed");
1453
- setError(uploadError);
1454
- setIsUploading(false);
1455
- setProgress(0);
1538
+ updateUpload(uploadId, {
1539
+ status: "failed",
1540
+ error: uploadError
1541
+ });
1456
1542
  throw uploadError;
1457
1543
  }
1458
1544
  },
1459
- [uploadFromUrlMutation, apiUrl, auth]
1545
+ [uploadFromUrlMutation, apiUrl, auth, updateUpload]
1546
+ );
1547
+ const uploadMultiple = useCallback6(
1548
+ async (requests) => {
1549
+ const newUploads = requests.map((request) => ({
1550
+ id: generateUploadId(),
1551
+ file: request.source,
1552
+ fileName: getFileName(request.source),
1553
+ status: "pending",
1554
+ progress: 0
1555
+ }));
1556
+ setUploads((prev) => [...prev, ...newUploads]);
1557
+ const results = await Promise.allSettled(
1558
+ requests.map(
1559
+ (request, index) => uploadSingle(newUploads[index].id, request)
1560
+ )
1561
+ );
1562
+ const successfulResults = [];
1563
+ results.forEach((result) => {
1564
+ if (result.status === "fulfilled") {
1565
+ successfulResults.push(result.value);
1566
+ }
1567
+ });
1568
+ return successfulResults;
1569
+ },
1570
+ [uploadSingle]
1460
1571
  );
1572
+ const clearUploads = useCallback6(() => {
1573
+ abortControllersRef.current.forEach((abort) => abort());
1574
+ abortControllersRef.current.clear();
1575
+ setUploads([]);
1576
+ }, []);
1577
+ const cancelUpload = useCallback6((uploadId) => {
1578
+ const abort = abortControllersRef.current.get(uploadId);
1579
+ if (abort) {
1580
+ abort();
1581
+ }
1582
+ }, []);
1583
+ const isUploading = uploads.some((u) => u.status === "uploading");
1584
+ const overallProgress = uploads.length > 0 ? uploads.reduce((sum, u) => sum + u.progress, 0) / uploads.length : 0;
1461
1585
  return {
1462
- upload,
1586
+ uploadMultiple,
1587
+ uploads,
1463
1588
  isUploading,
1464
- progress,
1465
- error
1589
+ overallProgress,
1590
+ clearUploads,
1591
+ cancelUpload
1466
1592
  };
1467
1593
  }
1468
1594
 
@@ -1579,6 +1705,7 @@ export {
1579
1705
  CREATE_BOARD,
1580
1706
  CREATE_GENERATION,
1581
1707
  DELETE_BOARD,
1708
+ DELETE_GENERATION,
1582
1709
  DESCENDANT_NODE_FRAGMENT,
1583
1710
  GENERATION_FRAGMENT,
1584
1711
  GET_ANCESTRY,
@@ -1618,6 +1745,6 @@ export {
1618
1745
  useGenerators,
1619
1746
  useInputArtifacts,
1620
1747
  useLineage,
1621
- useUpload
1748
+ useMultiUpload
1622
1749
  };
1623
1750
  //# sourceMappingURL=index.mjs.map