@gallop.software/studio 0.1.85 → 0.1.86
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/{StudioUI-P4TLZNF7.js → StudioUI-PH265HCB.js} +163 -67
- package/dist/StudioUI-PH265HCB.js.map +1 -0
- package/dist/{StudioUI-PPX6VKNU.mjs → StudioUI-QTKNMFLF.mjs} +159 -63
- package/dist/StudioUI-QTKNMFLF.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/StudioUI-P4TLZNF7.js.map +0 -1
- package/dist/StudioUI-PPX6VKNU.mjs.map +0 -1
|
@@ -1294,39 +1294,92 @@ function StudioToolbar() {
|
|
|
1294
1294
|
const handleFileChange = useCallback(async (e) => {
|
|
1295
1295
|
const files = e.target.files;
|
|
1296
1296
|
if (!files || files.length === 0) return;
|
|
1297
|
-
|
|
1297
|
+
const fileList = Array.from(files);
|
|
1298
|
+
if (fileList.length > 1) {
|
|
1299
|
+
setProgressState({
|
|
1300
|
+
current: 0,
|
|
1301
|
+
total: fileList.length,
|
|
1302
|
+
percent: 0,
|
|
1303
|
+
status: "processing",
|
|
1304
|
+
message: "Uploading files..."
|
|
1305
|
+
});
|
|
1306
|
+
setShowProgress(true);
|
|
1307
|
+
} else {
|
|
1308
|
+
setUploading(true);
|
|
1309
|
+
}
|
|
1310
|
+
let uploaded = 0;
|
|
1311
|
+
let errors = 0;
|
|
1298
1312
|
try {
|
|
1299
|
-
for (
|
|
1313
|
+
for (let i = 0; i < fileList.length; i++) {
|
|
1314
|
+
const file = fileList[i];
|
|
1315
|
+
if (fileList.length > 1) {
|
|
1316
|
+
setProgressState({
|
|
1317
|
+
current: i + 1,
|
|
1318
|
+
total: fileList.length,
|
|
1319
|
+
percent: Math.round((i + 1) / fileList.length * 100),
|
|
1320
|
+
status: "processing",
|
|
1321
|
+
currentFile: file.name
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1300
1324
|
const formData = new FormData();
|
|
1301
1325
|
formData.append("file", file);
|
|
1302
1326
|
formData.append("path", currentPath);
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1327
|
+
try {
|
|
1328
|
+
const response = await fetch("/api/studio/upload", {
|
|
1329
|
+
method: "POST",
|
|
1330
|
+
body: formData
|
|
1331
|
+
});
|
|
1332
|
+
if (!response.ok) {
|
|
1333
|
+
const error = await response.json();
|
|
1334
|
+
errors++;
|
|
1335
|
+
if (fileList.length === 1) {
|
|
1336
|
+
if (response.status >= 500) {
|
|
1337
|
+
console.error("Upload error:", error);
|
|
1338
|
+
setAlertMessage({
|
|
1339
|
+
title: "Upload Failed",
|
|
1340
|
+
message: `Failed to upload ${file.name}: ${error.error || "Unknown error"}`
|
|
1341
|
+
});
|
|
1342
|
+
} else {
|
|
1343
|
+
setAlertMessage({
|
|
1344
|
+
title: "Cannot Upload Here",
|
|
1345
|
+
message: error.error || "Upload not allowed in this location."
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1315
1349
|
} else {
|
|
1316
|
-
|
|
1317
|
-
title: "Cannot Upload Here",
|
|
1318
|
-
message: error.error || "Upload not allowed in this location."
|
|
1319
|
-
});
|
|
1350
|
+
uploaded++;
|
|
1320
1351
|
}
|
|
1352
|
+
} catch {
|
|
1353
|
+
errors++;
|
|
1321
1354
|
}
|
|
1322
1355
|
}
|
|
1356
|
+
if (fileList.length > 1) {
|
|
1357
|
+
setProgressState({
|
|
1358
|
+
current: fileList.length,
|
|
1359
|
+
total: fileList.length,
|
|
1360
|
+
percent: 100,
|
|
1361
|
+
status: "complete",
|
|
1362
|
+
processed: uploaded,
|
|
1363
|
+
errors
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1323
1366
|
triggerRefresh();
|
|
1324
1367
|
} catch (error) {
|
|
1325
1368
|
console.error("Upload error:", error);
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1369
|
+
if (fileList.length > 1) {
|
|
1370
|
+
setProgressState({
|
|
1371
|
+
current: 0,
|
|
1372
|
+
total: 0,
|
|
1373
|
+
percent: 0,
|
|
1374
|
+
status: "error",
|
|
1375
|
+
message: "Upload failed."
|
|
1376
|
+
});
|
|
1377
|
+
} else {
|
|
1378
|
+
setAlertMessage({
|
|
1379
|
+
title: "Upload Failed",
|
|
1380
|
+
message: "Upload failed. Check console for details."
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1330
1383
|
} finally {
|
|
1331
1384
|
setUploading(false);
|
|
1332
1385
|
if (fileInputRef.current) {
|
|
@@ -1580,56 +1633,99 @@ function StudioToolbar() {
|
|
|
1580
1633
|
}, [selectedItems, clearSelection, triggerRefresh]);
|
|
1581
1634
|
const handleSyncCdn = useCallback(async () => {
|
|
1582
1635
|
if (selectedItems.size === 0) return;
|
|
1583
|
-
const
|
|
1636
|
+
const selectedPaths2 = Array.from(selectedItems);
|
|
1637
|
+
const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
|
|
1638
|
+
const selectedImagePaths = selectedPaths2.filter((p) => {
|
|
1639
|
+
const ext = p.split(".").pop()?.toLowerCase() || "";
|
|
1640
|
+
return imageExtensions.includes(ext);
|
|
1641
|
+
});
|
|
1642
|
+
const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
|
|
1643
|
+
if (selectedFolders.length > 0) {
|
|
1644
|
+
try {
|
|
1645
|
+
const response = await fetch(`/api/studio/folder-images?folders=${encodeURIComponent(selectedFolders.join(","))}`);
|
|
1646
|
+
const data = await response.json();
|
|
1647
|
+
if (data.images) {
|
|
1648
|
+
for (const img of data.images) {
|
|
1649
|
+
const fullPath = `public/${img}`;
|
|
1650
|
+
if (!selectedImagePaths.includes(fullPath)) {
|
|
1651
|
+
selectedImagePaths.push(fullPath);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
console.error("Failed to get folder images:", error);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
const imageKeys = selectedImagePaths.map((p) => "/" + p.replace(/^public\//, ""));
|
|
1584
1660
|
if (imageKeys.length === 0) {
|
|
1585
1661
|
setAlertMessage({
|
|
1586
|
-
title: "No Images
|
|
1587
|
-
message: "
|
|
1662
|
+
title: "No Images Found",
|
|
1663
|
+
message: "No images found in the selected items."
|
|
1588
1664
|
});
|
|
1589
1665
|
return;
|
|
1590
1666
|
}
|
|
1591
|
-
|
|
1667
|
+
setProgressState({
|
|
1668
|
+
current: 0,
|
|
1669
|
+
total: imageKeys.length,
|
|
1670
|
+
percent: 0,
|
|
1671
|
+
status: "processing",
|
|
1672
|
+
message: "Syncing to CDN..."
|
|
1673
|
+
});
|
|
1674
|
+
setShowProgress(true);
|
|
1675
|
+
let synced = 0;
|
|
1676
|
+
let errors = 0;
|
|
1592
1677
|
try {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
} else {
|
|
1608
|
-
setAlertMessage({
|
|
1609
|
-
title: "Sync Complete",
|
|
1610
|
-
message: `Successfully synced ${syncedCount} images to CDN.`
|
|
1611
|
-
});
|
|
1612
|
-
}
|
|
1613
|
-
clearSelection();
|
|
1614
|
-
triggerRefresh();
|
|
1615
|
-
} else {
|
|
1616
|
-
if (data.error?.includes("R2 not configured") || data.error?.includes("CLOUDFLARE_R2")) {
|
|
1617
|
-
setShowR2SetupModal(true);
|
|
1618
|
-
} else {
|
|
1619
|
-
setAlertMessage({
|
|
1620
|
-
title: "Sync Failed",
|
|
1621
|
-
message: data.error || "Failed to sync to CDN."
|
|
1678
|
+
for (let i = 0; i < imageKeys.length; i++) {
|
|
1679
|
+
const imageKey = imageKeys[i];
|
|
1680
|
+
setProgressState({
|
|
1681
|
+
current: i + 1,
|
|
1682
|
+
total: imageKeys.length,
|
|
1683
|
+
percent: Math.round((i + 1) / imageKeys.length * 100),
|
|
1684
|
+
status: "processing",
|
|
1685
|
+
currentFile: imageKey.replace(/^\//, "")
|
|
1686
|
+
});
|
|
1687
|
+
try {
|
|
1688
|
+
const response = await fetch("/api/studio/sync", {
|
|
1689
|
+
method: "POST",
|
|
1690
|
+
headers: { "Content-Type": "application/json" },
|
|
1691
|
+
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
1622
1692
|
});
|
|
1693
|
+
const data = await response.json();
|
|
1694
|
+
if (!response.ok) {
|
|
1695
|
+
if (data.error?.includes("R2 not configured") || data.error?.includes("CLOUDFLARE_R2")) {
|
|
1696
|
+
setShowProgress(false);
|
|
1697
|
+
setShowR2SetupModal(true);
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
errors++;
|
|
1701
|
+
} else if (data.synced?.length > 0) {
|
|
1702
|
+
synced++;
|
|
1703
|
+
} else if (data.errors?.length > 0) {
|
|
1704
|
+
errors++;
|
|
1705
|
+
}
|
|
1706
|
+
} catch {
|
|
1707
|
+
errors++;
|
|
1623
1708
|
}
|
|
1624
1709
|
}
|
|
1710
|
+
setProgressState({
|
|
1711
|
+
current: imageKeys.length,
|
|
1712
|
+
total: imageKeys.length,
|
|
1713
|
+
percent: 100,
|
|
1714
|
+
status: "complete",
|
|
1715
|
+
processed: synced,
|
|
1716
|
+
errors
|
|
1717
|
+
});
|
|
1718
|
+
clearSelection();
|
|
1719
|
+
triggerRefresh();
|
|
1625
1720
|
} catch (error) {
|
|
1626
1721
|
console.error("Sync error:", error);
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1722
|
+
setProgressState({
|
|
1723
|
+
current: 0,
|
|
1724
|
+
total: 0,
|
|
1725
|
+
percent: 0,
|
|
1726
|
+
status: "error",
|
|
1727
|
+
message: "Failed to sync to CDN."
|
|
1630
1728
|
});
|
|
1631
|
-
} finally {
|
|
1632
|
-
setSyncing(false);
|
|
1633
1729
|
}
|
|
1634
1730
|
}, [selectedItems, clearSelection, triggerRefresh]);
|
|
1635
1731
|
const handleCreateFolder = useCallback(async (folderName) => {
|
|
@@ -1898,10 +1994,10 @@ function StudioToolbar() {
|
|
|
1898
1994
|
{
|
|
1899
1995
|
css: styles4.btn,
|
|
1900
1996
|
onClick: handleSyncCdn,
|
|
1901
|
-
disabled: !hasSelection
|
|
1997
|
+
disabled: !hasSelection,
|
|
1902
1998
|
children: [
|
|
1903
1999
|
/* @__PURE__ */ jsx4(CloudIcon, {}),
|
|
1904
|
-
|
|
2000
|
+
"Sync CDN"
|
|
1905
2001
|
]
|
|
1906
2002
|
}
|
|
1907
2003
|
),
|
|
@@ -4525,4 +4621,4 @@ export {
|
|
|
4525
4621
|
StudioUI,
|
|
4526
4622
|
StudioUI_default as default
|
|
4527
4623
|
};
|
|
4528
|
-
//# sourceMappingURL=StudioUI-
|
|
4624
|
+
//# sourceMappingURL=StudioUI-QTKNMFLF.mjs.map
|