@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 +24 -9
- package/dist/index.d.ts +24 -9
- package/dist/index.js +197 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +196 -69
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
- package/src/graphql/__tests__/operations.test.ts +53 -0
- package/src/graphql/operations.ts +9 -2
- package/src/hooks/__tests__/useMultiUpload.test.ts +238 -0
- package/src/hooks/useBoard.ts +4 -2
- package/src/hooks/useGeneration.ts +44 -0
- package/src/hooks/useMultiUpload.ts +309 -0
- package/src/index.ts +7 -5
- package/src/hooks/useUpload.ts +0 -175
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($
|
|
752
|
-
updateBoard(
|
|
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
|
-
|
|
981
|
-
|
|
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/
|
|
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
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
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
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
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
|
-
|
|
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(
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
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
|
-
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
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
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
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
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
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
|
-
|
|
1586
|
+
uploadMultiple,
|
|
1587
|
+
uploads,
|
|
1463
1588
|
isUploading,
|
|
1464
|
-
|
|
1465
|
-
|
|
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
|
-
|
|
1748
|
+
useMultiUpload
|
|
1622
1749
|
};
|
|
1623
1750
|
//# sourceMappingURL=index.mjs.map
|