@gallop.software/studio 2.3.55 → 2.3.57

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.
@@ -11,7 +11,7 @@
11
11
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
12
  }
13
13
  </style>
14
- <script type="module" crossorigin src="/assets/index-C-xFymfG.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-DiOqdQT0.js"></script>
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -1203,13 +1203,13 @@ async function handleSync(request) {
1203
1203
  } catch {
1204
1204
  }
1205
1205
  }
1206
+ await saveMeta(meta);
1206
1207
  pushed.push(imageKey);
1207
1208
  } catch (error) {
1208
1209
  console.error(`Failed to push ${imageKey}:`, error);
1209
1210
  errors.push(`Failed to push: ${imageKey}`);
1210
1211
  }
1211
1212
  }
1212
- await saveMeta(meta);
1213
1213
  for (const folder of sourceFolders) {
1214
1214
  await deleteEmptyFolders(folder);
1215
1215
  }
@@ -1306,6 +1306,7 @@ async function handleUnprocessStream(request) {
1306
1306
  b: entry.b,
1307
1307
  ...entry.c !== void 0 ? { c: entry.c } : {}
1308
1308
  };
1309
+ await saveMeta(meta);
1309
1310
  removed.push(imageKey);
1310
1311
  sendEvent({
1311
1312
  type: "progress",
@@ -1468,6 +1469,7 @@ async function handleReprocessStream(request) {
1468
1469
  }
1469
1470
  meta[imageKey] = updatedEntry;
1470
1471
  }
1472
+ await saveMeta(meta);
1471
1473
  processed.push(imageKey);
1472
1474
  sendEvent({
1473
1475
  type: "progress",
@@ -1546,9 +1548,10 @@ async function handleDownloadStream(request) {
1546
1548
  await saveMeta(meta);
1547
1549
  if (operationId) clearCancelledOperation(operationId);
1548
1550
  sendEvent({
1549
- type: "stopped",
1551
+ type: "complete",
1550
1552
  downloaded: downloaded.length,
1551
- message: `Stopped. ${downloaded.length} image${downloaded.length !== 1 ? "s" : ""} downloaded.`
1553
+ message: `Stopped. ${downloaded.length} image${downloaded.length !== 1 ? "s" : ""} downloaded.`,
1554
+ cancelled: true
1552
1555
  });
1553
1556
  controller.close();
1554
1557
  return;
@@ -1572,9 +1575,10 @@ async function handleDownloadStream(request) {
1572
1575
  await saveMeta(meta);
1573
1576
  if (operationId) clearCancelledOperation(operationId);
1574
1577
  sendEvent({
1575
- type: "stopped",
1578
+ type: "complete",
1576
1579
  downloaded: downloaded.length,
1577
- message: `Stopped. ${downloaded.length} image${downloaded.length !== 1 ? "s" : ""} downloaded.`
1580
+ message: `Stopped. ${downloaded.length} image${downloaded.length !== 1 ? "s" : ""} downloaded.`,
1581
+ cancelled: true
1578
1582
  });
1579
1583
  controller.close();
1580
1584
  return;
@@ -1592,6 +1596,7 @@ async function handleDownloadStream(request) {
1592
1596
  entry.lg = processedEntry.lg;
1593
1597
  entry.f = processedEntry.f;
1594
1598
  }
1599
+ await saveMeta(meta);
1595
1600
  downloaded.push(imageKey);
1596
1601
  sendEvent({
1597
1602
  type: "progress",
@@ -1663,12 +1668,13 @@ async function handlePushUpdatesStream(request) {
1663
1668
  controller.close();
1664
1669
  return;
1665
1670
  }
1666
- const { paths } = await request.json();
1671
+ const { paths, operationId } = await request.json();
1667
1672
  if (!paths || !Array.isArray(paths) || paths.length === 0) {
1668
1673
  sendEvent({ type: "error", message: "No paths provided" });
1669
1674
  controller.close();
1670
1675
  return;
1671
1676
  }
1677
+ const isCancelled = () => operationId ? isOperationCancelled(operationId) : false;
1672
1678
  const s3 = new S3Client2({
1673
1679
  region: "auto",
1674
1680
  endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
@@ -1683,6 +1689,13 @@ async function handlePushUpdatesStream(request) {
1683
1689
  const total = paths.length;
1684
1690
  sendEvent({ type: "start", total });
1685
1691
  for (let i = 0; i < paths.length; i++) {
1692
+ if (isCancelled()) {
1693
+ await saveMeta(meta);
1694
+ if (operationId) clearCancelledOperation(operationId);
1695
+ sendEvent({ type: "complete", pushed: pushed.length, message: `Stopped. ${pushed.length} file${pushed.length !== 1 ? "s" : ""} pushed.`, cancelled: true });
1696
+ controller.close();
1697
+ return;
1698
+ }
1686
1699
  const itemPath = paths[i];
1687
1700
  const key = itemPath.startsWith("public/") ? "/" + itemPath.slice(7) : itemPath;
1688
1701
  const entry = meta[key];
@@ -1738,6 +1751,7 @@ async function handlePushUpdatesStream(request) {
1738
1751
  }
1739
1752
  await fs6.unlink(localPath);
1740
1753
  delete entry.u;
1754
+ await saveMeta(meta);
1741
1755
  pushed.push(key);
1742
1756
  sendEvent({
1743
1757
  type: "progress",
@@ -2128,7 +2142,7 @@ async function handleRename(request) {
2128
2142
  return jsonResponse({ error: "An item with this name already exists" }, { status: 400 });
2129
2143
  } catch {
2130
2144
  }
2131
- if (isInOurR2 && !hasLocalFile && isImage) {
2145
+ if (isInOurR2 && !hasLocalFile) {
2132
2146
  await moveInCdn(oldKey, newKey, hasThumbnails);
2133
2147
  delete meta[oldKey];
2134
2148
  meta[newKey] = entry;
@@ -2287,11 +2301,17 @@ async function handleRenameStream(request) {
2287
2301
  }
2288
2302
  sendEvent({ type: "progress", current: 1, total, renamed: 1, message: "Renamed folder" });
2289
2303
  let renamed = 1;
2304
+ const handleRenameCancel = async () => {
2305
+ await saveMeta(meta);
2306
+ await deleteEmptyFolders(absoluteOldPath);
2307
+ const oldThumbFolder2 = path7.join(getPublicPath("/images"), oldRelativePath);
2308
+ await deleteEmptyFolders(oldThumbFolder2);
2309
+ sendEvent({ type: "complete", renamed, newPath, cancelled: true });
2310
+ controller.close();
2311
+ };
2290
2312
  for (const item of itemsToUpdate) {
2291
2313
  if (isCancelled()) {
2292
- await saveMeta(meta);
2293
- sendEvent({ type: "complete", renamed, newPath, cancelled: true });
2294
- controller.close();
2314
+ await handleRenameCancel();
2295
2315
  return;
2296
2316
  }
2297
2317
  const { oldKey: oldKey2, newKey: newKey2, entry: entry2 } = item;
@@ -2316,6 +2336,7 @@ async function handleRenameStream(request) {
2316
2336
  }
2317
2337
  delete meta[oldKey2];
2318
2338
  meta[newKey2] = entry2;
2339
+ await saveMeta(meta);
2319
2340
  renamed++;
2320
2341
  sendEvent({
2321
2342
  type: "progress",
@@ -2325,7 +2346,6 @@ async function handleRenameStream(request) {
2325
2346
  message: `Renamed ${path7.basename(newKey2)}`
2326
2347
  });
2327
2348
  }
2328
- await saveMeta(meta);
2329
2349
  await deleteEmptyFolders(absoluteOldPath);
2330
2350
  const oldThumbFolder = path7.join(getPublicPath("/images"), oldRelativePath);
2331
2351
  await deleteEmptyFolders(oldThumbFolder);
@@ -2341,7 +2361,7 @@ async function handleRenameStream(request) {
2341
2361
  const isInOurR2 = isInCloud && fileCdnUrl === publicUrl;
2342
2362
  const hasThumbnails = entry ? isProcessed(entry) : false;
2343
2363
  sendEvent({ type: "start", total: 1, message: "Renaming file..." });
2344
- if (isInOurR2 && !hasLocalItem && isImagePath) {
2364
+ if (isInOurR2 && !hasLocalItem) {
2345
2365
  await moveInCdn(oldKey, newKey, hasThumbnails);
2346
2366
  delete meta[oldKey];
2347
2367
  if (entry) meta[newKey] = entry;
@@ -2498,18 +2518,26 @@ async function handleMoveStream(request) {
2498
2518
  }
2499
2519
  sendEvent({ type: "start", total: totalFiles });
2500
2520
  let processedFiles = 0;
2521
+ let filesMoved = 0;
2522
+ const handleCancel = async () => {
2523
+ await saveMeta(meta);
2524
+ for (const folder of sourceFolders) {
2525
+ await deleteEmptyFolders(folder);
2526
+ }
2527
+ await deleteEmptyFolders(absoluteDestination);
2528
+ sendEvent({ type: "complete", moved: filesMoved, errors: errors.length, errorMessages: errors, cancelled: true });
2529
+ controller.close();
2530
+ };
2501
2531
  for (const expandedItem of expandedItems) {
2502
2532
  if (isCancelled()) {
2503
- sendEvent({ type: "complete", moved: moved.length, errors: errors.length, errorMessages: errors, cancelled: true });
2504
- controller.close();
2533
+ await handleCancel();
2505
2534
  return;
2506
2535
  }
2507
2536
  const { itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder, virtualFolderItems } = expandedItem;
2508
2537
  if (isVirtualFolder && virtualFolderItems) {
2509
2538
  for (const vItem of virtualFolderItems) {
2510
2539
  if (isCancelled()) {
2511
- sendEvent({ type: "complete", moved: moved.length, errors: errors.length, errorMessages: errors, cancelled: true });
2512
- controller.close();
2540
+ await handleCancel();
2513
2541
  return;
2514
2542
  }
2515
2543
  const itemEntry = vItem.entry;
@@ -2522,21 +2550,26 @@ async function handleMoveStream(request) {
2522
2550
  try {
2523
2551
  await moveInCdn(vItem.oldKey, vItem.newKey, itemHasThumbnails);
2524
2552
  vItemMoved = true;
2553
+ filesMoved++;
2525
2554
  } catch (err) {
2526
2555
  console.error(`Failed to move cloud item ${vItem.oldKey}:`, err);
2527
2556
  delete meta[vItem.oldKey];
2557
+ await saveMeta(meta);
2528
2558
  }
2529
2559
  }
2530
2560
  if (vItemMoved) {
2531
2561
  delete meta[vItem.oldKey];
2532
2562
  meta[vItem.newKey] = itemEntry;
2563
+ await saveMeta(meta);
2564
+ const oldAbsPath = getPublicPath(vItem.oldKey);
2565
+ sourceFolders.add(path7.dirname(oldAbsPath));
2533
2566
  }
2534
2567
  processedFiles++;
2535
2568
  sendEvent({
2536
2569
  type: "progress",
2537
2570
  current: processedFiles,
2538
2571
  total: totalFiles,
2539
- moved: moved.length,
2572
+ moved: filesMoved,
2540
2573
  percent: Math.round(processedFiles / totalFiles * 100),
2541
2574
  currentFile: path7.basename(vItem.newKey)
2542
2575
  });
@@ -2545,6 +2578,8 @@ async function handleMoveStream(request) {
2545
2578
  await deleteEmptyFolders(newFolderPath);
2546
2579
  const newThumbFolder = path7.join(getPublicPath("images"), newKey.slice(1));
2547
2580
  await deleteEmptyFolders(newThumbFolder);
2581
+ const oldFolderPath = getPublicPath(oldKey);
2582
+ sourceFolders.add(oldFolderPath);
2548
2583
  moved.push(itemPath);
2549
2584
  continue;
2550
2585
  }
@@ -2571,7 +2606,7 @@ async function handleMoveStream(request) {
2571
2606
  try {
2572
2607
  const sourceFolder = path7.dirname(getWorkspacePath(safePath));
2573
2608
  sourceFolders.add(sourceFolder);
2574
- if (isRemote && isImage) {
2609
+ if (isRemote) {
2575
2610
  const remoteUrl = `${fileCdnUrl}${oldKey}`;
2576
2611
  const buffer = await downloadFromRemoteUrl(remoteUrl);
2577
2612
  await fs7.mkdir(path7.dirname(newAbsolutePath), { recursive: true });
@@ -2582,29 +2617,33 @@ async function handleMoveStream(request) {
2582
2617
  };
2583
2618
  delete meta[oldKey];
2584
2619
  meta[newKey] = newEntry;
2620
+ await saveMeta(meta);
2585
2621
  moved.push(itemPath);
2622
+ filesMoved++;
2586
2623
  processedFiles++;
2587
2624
  sendEvent({
2588
2625
  type: "progress",
2589
2626
  current: processedFiles,
2590
2627
  total: totalFiles,
2591
- moved: moved.length,
2628
+ moved: filesMoved,
2592
2629
  percent: Math.round(processedFiles / totalFiles * 100),
2593
2630
  currentFile: itemName
2594
2631
  });
2595
- } else if (isPushedToR2 && isImage) {
2632
+ } else if (isPushedToR2) {
2596
2633
  await moveInCdn(oldKey, newKey, hasProcessedThumbnails);
2597
2634
  delete meta[oldKey];
2598
2635
  if (entry) {
2599
2636
  meta[newKey] = entry;
2600
2637
  }
2638
+ await saveMeta(meta);
2601
2639
  moved.push(itemPath);
2640
+ filesMoved++;
2602
2641
  processedFiles++;
2603
2642
  sendEvent({
2604
2643
  type: "progress",
2605
2644
  current: processedFiles,
2606
2645
  total: totalFiles,
2607
- moved: moved.length,
2646
+ moved: filesMoved,
2608
2647
  percent: Math.round(processedFiles / totalFiles * 100),
2609
2648
  currentFile: itemName
2610
2649
  });
@@ -2617,7 +2656,7 @@ async function handleMoveStream(request) {
2617
2656
  type: "progress",
2618
2657
  current: processedFiles,
2619
2658
  total: totalFiles,
2620
- moved: moved.length,
2659
+ moved: filesMoved,
2621
2660
  percent: Math.round(processedFiles / totalFiles * 100),
2622
2661
  currentFile: itemName
2623
2662
  });
@@ -2632,7 +2671,7 @@ async function handleMoveStream(request) {
2632
2671
  type: "progress",
2633
2672
  current: processedFiles,
2634
2673
  total: totalFiles,
2635
- moved: moved.length,
2674
+ moved: filesMoved,
2636
2675
  percent: Math.round(processedFiles / totalFiles * 100),
2637
2676
  currentFile: itemName
2638
2677
  });
@@ -2646,7 +2685,7 @@ async function handleMoveStream(request) {
2646
2685
  type: "progress",
2647
2686
  current: processedFiles,
2648
2687
  total: totalFiles,
2649
- moved: moved.length,
2688
+ moved: filesMoved,
2650
2689
  percent: Math.round(processedFiles / totalFiles * 100),
2651
2690
  currentFile: itemName
2652
2691
  });
@@ -2684,17 +2723,19 @@ async function handleMoveStream(request) {
2684
2723
  }
2685
2724
  delete meta[oldKey];
2686
2725
  meta[newKey] = entry;
2726
+ await saveMeta(meta);
2687
2727
  }
2728
+ moved.push(itemPath);
2729
+ filesMoved++;
2688
2730
  processedFiles++;
2689
2731
  sendEvent({
2690
2732
  type: "progress",
2691
2733
  current: processedFiles,
2692
2734
  total: totalFiles,
2693
- moved: moved.length,
2735
+ moved: filesMoved,
2694
2736
  percent: Math.round(processedFiles / totalFiles * 100),
2695
2737
  currentFile: itemName
2696
2738
  });
2697
- moved.push(itemPath);
2698
2739
  } else if (stats.isDirectory()) {
2699
2740
  const oldPrefix = oldKey + "/";
2700
2741
  const newPrefix = newKey + "/";
@@ -2729,9 +2770,7 @@ async function handleMoveStream(request) {
2729
2770
  }
2730
2771
  for (const localFile of localFiles) {
2731
2772
  if (isCancelled()) {
2732
- await saveMeta(meta);
2733
- sendEvent({ type: "complete", moved: moved.length, errors: errors.length, errorMessages: errors, cancelled: true });
2734
- controller.close();
2773
+ await handleCancel();
2735
2774
  return;
2736
2775
  }
2737
2776
  const fileOldPath = path7.join(absolutePath, localFile.relativePath);
@@ -2742,6 +2781,7 @@ async function handleMoveStream(request) {
2742
2781
  sourceFolders.add(path7.dirname(fileOldPath));
2743
2782
  await fs7.mkdir(path7.dirname(fileNewPath), { recursive: true });
2744
2783
  await fs7.rename(fileOldPath, fileNewPath);
2784
+ filesMoved++;
2745
2785
  if (localFile.isImage && fileEntry) {
2746
2786
  const oldThumbPaths = getAllThumbnailPaths(fileOldKey);
2747
2787
  const newThumbPaths = getAllThumbnailPaths(fileNewKey);
@@ -2765,22 +2805,21 @@ async function handleMoveStream(request) {
2765
2805
  }
2766
2806
  delete meta[fileOldKey];
2767
2807
  meta[fileNewKey] = fileEntry;
2808
+ await saveMeta(meta);
2768
2809
  }
2769
2810
  processedFiles++;
2770
2811
  sendEvent({
2771
2812
  type: "progress",
2772
2813
  current: processedFiles,
2773
2814
  total: totalFiles,
2774
- moved: moved.length,
2815
+ moved: filesMoved,
2775
2816
  percent: Math.round(processedFiles / totalFiles * 100),
2776
2817
  currentFile: path7.basename(localFile.relativePath)
2777
2818
  });
2778
2819
  }
2779
2820
  for (const cloudFile of cloudOnlyFiles) {
2780
2821
  if (isCancelled()) {
2781
- await saveMeta(meta);
2782
- sendEvent({ type: "complete", moved: moved.length, errors: errors.length, errorMessages: errors, cancelled: true });
2783
- controller.close();
2822
+ await handleCancel();
2784
2823
  return;
2785
2824
  }
2786
2825
  const cloudEntry = cloudFile.entry;
@@ -2793,21 +2832,24 @@ async function handleMoveStream(request) {
2793
2832
  try {
2794
2833
  await moveInCdn(cloudFile.oldKey, cloudFile.newKey, cloudHasThumbs);
2795
2834
  cloudFileMoved = true;
2835
+ filesMoved++;
2796
2836
  } catch (err) {
2797
2837
  console.error(`Failed to move cloud file ${cloudFile.oldKey}:`, err);
2798
2838
  delete meta[cloudFile.oldKey];
2839
+ await saveMeta(meta);
2799
2840
  }
2800
2841
  }
2801
2842
  if (cloudFileMoved) {
2802
2843
  delete meta[cloudFile.oldKey];
2803
2844
  meta[cloudFile.newKey] = cloudEntry;
2845
+ await saveMeta(meta);
2804
2846
  }
2805
2847
  processedFiles++;
2806
2848
  sendEvent({
2807
2849
  type: "progress",
2808
2850
  current: processedFiles,
2809
2851
  total: totalFiles,
2810
- moved: moved.length,
2852
+ moved: filesMoved,
2811
2853
  percent: Math.round(processedFiles / totalFiles * 100),
2812
2854
  currentFile: path7.basename(cloudFile.newKey)
2813
2855
  });
@@ -2827,7 +2869,7 @@ async function handleMoveStream(request) {
2827
2869
  type: "progress",
2828
2870
  current: processedFiles,
2829
2871
  total: totalFiles,
2830
- moved: moved.length,
2872
+ moved: filesMoved,
2831
2873
  percent: Math.round(processedFiles / totalFiles * 100),
2832
2874
  currentFile: itemName
2833
2875
  });
@@ -2840,7 +2882,7 @@ async function handleMoveStream(request) {
2840
2882
  await deleteEmptyFolders(absoluteDestination);
2841
2883
  sendEvent({
2842
2884
  type: "complete",
2843
- moved: moved.length,
2885
+ moved: filesMoved,
2844
2886
  errors: errors.length,
2845
2887
  errorMessages: errors
2846
2888
  });
@@ -2992,6 +3034,9 @@ async function handleScanStream() {
2992
3034
  }
2993
3035
  existingKeys.add(imageKey);
2994
3036
  added.push(imageKey);
3037
+ if (added.length % 10 === 0) {
3038
+ await saveMeta(meta);
3039
+ }
2995
3040
  } catch (error) {
2996
3041
  console.error(`Failed to process ${relativePath}:`, error);
2997
3042
  errors.push(relativePath);