@gallop.software/studio 1.4.0 → 1.4.1

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.
@@ -20,11 +20,11 @@ var defaultActionState = {
20
20
  showMoveModal: false,
21
21
  showSyncConfirm: false,
22
22
  showProcessConfirm: false,
23
- showUnprocessConfirm: false,
24
23
  actionPaths: [],
25
24
  syncImageCount: 0,
26
25
  syncHasRemote: false,
27
- syncHasLocal: false
26
+ syncHasLocal: false,
27
+ processMode: "generate"
28
28
  };
29
29
  var defaultState = {
30
30
  isOpen: false,
@@ -91,7 +91,7 @@ var defaultState = {
91
91
  },
92
92
  requestProcess: () => {
93
93
  },
94
- requestUnprocess: () => {
94
+ setProcessMode: () => {
95
95
  },
96
96
  confirmDelete: async () => {
97
97
  },
@@ -101,8 +101,6 @@ var defaultState = {
101
101
  },
102
102
  confirmProcess: async () => {
103
103
  },
104
- confirmUnprocess: async () => {
105
- },
106
104
  cancelAction: () => {
107
105
  },
108
106
  closeProgress: () => {
@@ -4498,7 +4496,6 @@ function StudioDetailView() {
4498
4496
  requestMove,
4499
4497
  requestSync,
4500
4498
  requestProcess,
4501
- requestUnprocess,
4502
4499
  actionState
4503
4500
  } = useStudio();
4504
4501
  const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
@@ -4698,19 +4695,6 @@ function StudioDetailView() {
4698
4695
  ]
4699
4696
  }
4700
4697
  ),
4701
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4702
- "button",
4703
- {
4704
- css: styles8.actionBtn,
4705
- onClick: () => requestUnprocess([focusedItem.path]),
4706
- disabled: isActionInProgress || focusedItem.isProtected || !focusedItem.hasThumbnail,
4707
- title: !focusedItem.hasThumbnail ? "No thumbnails to remove" : void 0,
4708
- children: [
4709
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
4710
- "Remove Thumbnails"
4711
- ]
4712
- }
4713
- ),
4714
4698
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4715
4699
  "button",
4716
4700
  {
@@ -5310,11 +5294,11 @@ var defaultActionState2 = {
5310
5294
  showMoveModal: false,
5311
5295
  showSyncConfirm: false,
5312
5296
  showProcessConfirm: false,
5313
- showUnprocessConfirm: false,
5314
5297
  actionPaths: [],
5315
5298
  syncImageCount: 0,
5316
5299
  syncHasRemote: false,
5317
- syncHasLocal: false
5300
+ syncHasLocal: false,
5301
+ processMode: "generate"
5318
5302
  };
5319
5303
  function useStudioActions({
5320
5304
  triggerRefresh,
@@ -5371,14 +5355,15 @@ function useStudioActions({
5371
5355
  setActionState((prev) => ({
5372
5356
  ...prev,
5373
5357
  actionPaths: paths,
5374
- showProcessConfirm: true
5358
+ showProcessConfirm: true,
5359
+ processMode: "generate"
5360
+ // Reset to default when opening modal
5375
5361
  }));
5376
5362
  }, []);
5377
- const requestUnprocess = _react.useCallback.call(void 0, (paths) => {
5363
+ const setProcessMode = _react.useCallback.call(void 0, (mode) => {
5378
5364
  setActionState((prev) => ({
5379
5365
  ...prev,
5380
- actionPaths: paths,
5381
- showUnprocessConfirm: true
5366
+ processMode: mode
5382
5367
  }));
5383
5368
  }, []);
5384
5369
  const cancelAction = _react.useCallback.call(void 0, () => {
@@ -5387,8 +5372,7 @@ function useStudioActions({
5387
5372
  showDeleteConfirm: false,
5388
5373
  showMoveModal: false,
5389
5374
  showSyncConfirm: false,
5390
- showProcessConfirm: false,
5391
- showUnprocessConfirm: false
5375
+ showProcessConfirm: false
5392
5376
  }));
5393
5377
  }, []);
5394
5378
  const closeProgress = _react.useCallback.call(void 0, () => {
@@ -5566,27 +5550,32 @@ function useStudioActions({
5566
5550
  }, [actionState.actionPaths, clearSelection, triggerRefresh, showError, setProgressState]);
5567
5551
  const confirmProcess = _react.useCallback.call(void 0, async () => {
5568
5552
  const paths = actionState.actionPaths;
5553
+ const mode = actionState.processMode;
5569
5554
  const imageKeys = paths.map((p) => {
5570
5555
  const key = p.replace(/^public\//, "");
5571
5556
  return key.startsWith("/") ? key : `/${key}`;
5572
5557
  });
5558
+ const isRemove = mode === "remove";
5559
+ const endpoint = isRemove ? "/api/studio/unprocess-stream" : "/api/studio/reprocess-stream";
5560
+ const progressTitle = isRemove ? "Removing Thumbnails" : "Processing Images";
5561
+ const progressMessage = isRemove ? "Removing thumbnails..." : "Processing images...";
5573
5562
  setActionState((prev) => ({
5574
5563
  ...prev,
5575
5564
  showProcessConfirm: false,
5576
5565
  showProgress: true,
5577
- progressTitle: "Processing Images",
5566
+ progressTitle,
5578
5567
  progressState: {
5579
5568
  current: 0,
5580
5569
  total: imageKeys.length,
5581
5570
  percent: 0,
5582
5571
  status: "processing",
5583
- message: "Processing images..."
5572
+ message: progressMessage
5584
5573
  }
5585
5574
  }));
5586
5575
  abortControllerRef.current = new AbortController();
5587
5576
  const signal = abortControllerRef.current.signal;
5588
5577
  try {
5589
- const response = await fetch("/api/studio/reprocess-stream", {
5578
+ const response = await fetch(endpoint, {
5590
5579
  method: "POST",
5591
5580
  headers: { "Content-Type": "application/json" },
5592
5581
  body: JSON.stringify({ imageKeys }),
@@ -5599,7 +5588,7 @@ function useStudioActions({
5599
5588
  total: imageKeys.length,
5600
5589
  percent: 0,
5601
5590
  status: "error",
5602
- message: error.error || "Processing failed"
5591
+ message: error.error || (isRemove ? "Failed to remove thumbnails" : "Processing failed")
5603
5592
  });
5604
5593
  return;
5605
5594
  }
@@ -5663,7 +5652,7 @@ function useStudioActions({
5663
5652
  setProgressState((prev) => ({
5664
5653
  ...prev,
5665
5654
  status: "stopped",
5666
- message: "Processing stopped by user"
5655
+ message: isRemove ? "Removal stopped by user" : "Processing stopped by user"
5667
5656
  }));
5668
5657
  } else {
5669
5658
  console.error("Processing error:", error);
@@ -5672,115 +5661,13 @@ function useStudioActions({
5672
5661
  total: imageKeys.length,
5673
5662
  percent: 0,
5674
5663
  status: "error",
5675
- message: "Processing failed. Check console for details."
5664
+ message: isRemove ? "Failed to remove thumbnails. Check console for details." : "Processing failed. Check console for details."
5676
5665
  });
5677
5666
  }
5678
5667
  } finally {
5679
5668
  abortControllerRef.current = null;
5680
5669
  }
5681
- }, [actionState.actionPaths, triggerRefresh, setProgressState]);
5682
- const confirmUnprocess = _react.useCallback.call(void 0, async () => {
5683
- const paths = actionState.actionPaths;
5684
- const imageKeys = paths.map((p) => {
5685
- const key = p.replace(/^public\//, "");
5686
- return key.startsWith("/") ? key : `/${key}`;
5687
- });
5688
- setActionState((prev) => ({
5689
- ...prev,
5690
- showUnprocessConfirm: false,
5691
- showProgress: true,
5692
- progressTitle: "Removing Thumbnails",
5693
- progressState: {
5694
- current: 0,
5695
- total: imageKeys.length,
5696
- percent: 0,
5697
- status: "processing",
5698
- message: "Removing thumbnails..."
5699
- }
5700
- }));
5701
- try {
5702
- const response = await fetch("/api/studio/unprocess-stream", {
5703
- method: "POST",
5704
- headers: { "Content-Type": "application/json" },
5705
- body: JSON.stringify({ imageKeys })
5706
- });
5707
- if (!response.ok) {
5708
- const error = await response.json();
5709
- setProgressState({
5710
- current: 0,
5711
- total: imageKeys.length,
5712
- percent: 0,
5713
- status: "error",
5714
- message: error.error || "Failed to remove thumbnails"
5715
- });
5716
- return;
5717
- }
5718
- const reader = _optionalChain([response, 'access', _53 => _53.body, 'optionalAccess', _54 => _54.getReader, 'call', _55 => _55()]);
5719
- const decoder = new TextDecoder();
5720
- if (reader) {
5721
- let buffer = "";
5722
- while (true) {
5723
- const { done, value } = await reader.read();
5724
- if (done) break;
5725
- buffer += decoder.decode(value, { stream: true });
5726
- const lines = buffer.split("\n");
5727
- buffer = lines.pop() || "";
5728
- for (const line of lines) {
5729
- if (line.startsWith("data: ")) {
5730
- try {
5731
- const data = JSON.parse(line.slice(6));
5732
- if (data.type === "start") {
5733
- setProgressState((prev) => ({
5734
- ...prev,
5735
- total: data.total
5736
- }));
5737
- } else if (data.type === "progress") {
5738
- setProgressState({
5739
- current: data.current,
5740
- total: data.total,
5741
- percent: data.percent,
5742
- status: "processing",
5743
- message: data.message
5744
- });
5745
- } else if (data.type === "cleanup") {
5746
- setProgressState((prev) => ({
5747
- ...prev,
5748
- status: "cleanup",
5749
- message: data.message
5750
- }));
5751
- } else if (data.type === "complete") {
5752
- setProgressState({
5753
- current: data.processed,
5754
- total: data.processed,
5755
- percent: 100,
5756
- status: data.errors > 0 ? "error" : "complete",
5757
- message: data.message
5758
- });
5759
- triggerRefresh();
5760
- } else if (data.type === "error") {
5761
- setProgressState((prev) => ({
5762
- ...prev,
5763
- status: "error",
5764
- message: data.message
5765
- }));
5766
- }
5767
- } catch (e8) {
5768
- }
5769
- }
5770
- }
5771
- }
5772
- }
5773
- } catch (error) {
5774
- console.error("Unprocess error:", error);
5775
- setProgressState({
5776
- current: 0,
5777
- total: imageKeys.length,
5778
- percent: 0,
5779
- status: "error",
5780
- message: "Failed to remove thumbnails. Check console for details."
5781
- });
5782
- }
5783
- }, [actionState.actionPaths, triggerRefresh, setProgressState]);
5670
+ }, [actionState.actionPaths, actionState.processMode, triggerRefresh, setProgressState]);
5784
5671
  const deleteOrphans = _react.useCallback.call(void 0, async () => {
5785
5672
  const orphanedFiles = actionState.progressState.orphanedFiles;
5786
5673
  if (!orphanedFiles || orphanedFiles.length === 0) return;
@@ -5794,7 +5681,7 @@ function useStudioActions({
5794
5681
  setProgressState((prev) => ({
5795
5682
  ...prev,
5796
5683
  orphanedFiles: void 0,
5797
- message: _optionalChain([prev, 'access', _56 => _56.message, 'optionalAccess', _57 => _57.replace, 'call', _58 => _58(/Found \d+ orphaned thumbnail\(s\).*/, "Orphaned thumbnails deleted.")])
5684
+ message: _optionalChain([prev, 'access', _53 => _53.message, 'optionalAccess', _54 => _54.replace, 'call', _55 => _55(/Found \d+ orphaned thumbnail\(s\).*/, "Orphaned thumbnails deleted.")])
5798
5685
  }));
5799
5686
  triggerRefresh();
5800
5687
  } else {
@@ -5814,7 +5701,7 @@ function useStudioActions({
5814
5701
  requestMove,
5815
5702
  requestSync,
5816
5703
  requestProcess,
5817
- requestUnprocess,
5704
+ setProcessMode,
5818
5705
  cancelAction,
5819
5706
  closeProgress,
5820
5707
  stopProcessing,
@@ -5822,7 +5709,6 @@ function useStudioActions({
5822
5709
  confirmMove,
5823
5710
  confirmSync,
5824
5711
  confirmProcess,
5825
- confirmUnprocess,
5826
5712
  deleteOrphans
5827
5713
  };
5828
5714
  }
@@ -6153,12 +6039,11 @@ function StudioUI({ onClose, isVisible = true }) {
6153
6039
  requestMove: actions.requestMove,
6154
6040
  requestSync: actions.requestSync,
6155
6041
  requestProcess: actions.requestProcess,
6156
- requestUnprocess: actions.requestUnprocess,
6042
+ setProcessMode: actions.setProcessMode,
6157
6043
  confirmDelete: actions.confirmDelete,
6158
6044
  confirmMove: actions.confirmMove,
6159
6045
  confirmSync: actions.confirmSync,
6160
6046
  confirmProcess: actions.confirmProcess,
6161
- confirmUnprocess: actions.confirmUnprocess,
6162
6047
  cancelAction: actions.cancelAction,
6163
6048
  closeProgress: actions.closeProgress,
6164
6049
  stopProcessing: actions.stopProcessing,
@@ -6223,26 +6108,15 @@ function StudioUI({ onClose, isVisible = true }) {
6223
6108
  }
6224
6109
  ),
6225
6110
  actions.actionState.showProcessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6226
- ConfirmModal,
6111
+ ProcessConfirmModal,
6227
6112
  {
6228
- title: "Process Images",
6229
- message: `Generate thumbnails for ${actions.actionState.actionPaths.length} image${actions.actionState.actionPaths.length !== 1 ? "s" : ""}?`,
6230
- confirmLabel: "Process",
6113
+ imageCount: actions.actionState.actionPaths.length,
6114
+ mode: actions.actionState.processMode,
6115
+ onModeChange: actions.setProcessMode,
6231
6116
  onConfirm: actions.confirmProcess,
6232
6117
  onCancel: actions.cancelAction
6233
6118
  }
6234
6119
  ),
6235
- actions.actionState.showUnprocessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6236
- ConfirmModal,
6237
- {
6238
- title: "Remove Thumbnails",
6239
- message: `Remove generated thumbnails for ${actions.actionState.actionPaths.length} image${actions.actionState.actionPaths.length !== 1 ? "s" : ""}? Original images will be kept.`,
6240
- confirmLabel: "Remove",
6241
- variant: "danger",
6242
- onConfirm: actions.confirmUnprocess,
6243
- onCancel: actions.cancelAction
6244
- }
6245
- ),
6246
6120
  actions.actionState.showMoveModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6247
6121
  StudioFolderPicker,
6248
6122
  {
@@ -6264,6 +6138,150 @@ function StudioUI({ onClose, isVisible = true }) {
6264
6138
  )
6265
6139
  ] }) });
6266
6140
  }
6141
+ function ProcessConfirmModal({ imageCount, mode, onModeChange, onConfirm, onCancel }) {
6142
+ const processModalStyles = {
6143
+ overlay: _react3.css`
6144
+ position: fixed;
6145
+ inset: 0;
6146
+ background: rgba(0, 0, 0, 0.5);
6147
+ display: flex;
6148
+ align-items: center;
6149
+ justify-content: center;
6150
+ z-index: 10000;
6151
+ `,
6152
+ container: _react3.css`
6153
+ background: ${_chunkN6JYTJCBjs.colors.surface};
6154
+ border-radius: 12px;
6155
+ padding: 24px;
6156
+ max-width: 420px;
6157
+ width: 90%;
6158
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
6159
+ `,
6160
+ title: _react3.css`
6161
+ font-size: ${_chunkN6JYTJCBjs.fontSize.lg};
6162
+ font-weight: 600;
6163
+ color: ${_chunkN6JYTJCBjs.colors.text};
6164
+ margin: 0 0 16px;
6165
+ `,
6166
+ modeToggle: _react3.css`
6167
+ display: flex;
6168
+ gap: 8px;
6169
+ margin-bottom: 16px;
6170
+ `,
6171
+ modeBtn: _react3.css`
6172
+ flex: 1;
6173
+ padding: 10px 16px;
6174
+ border: 2px solid ${_chunkN6JYTJCBjs.colors.border};
6175
+ border-radius: 8px;
6176
+ background: ${_chunkN6JYTJCBjs.colors.background};
6177
+ color: ${_chunkN6JYTJCBjs.colors.textSecondary};
6178
+ font-size: ${_chunkN6JYTJCBjs.fontSize.base};
6179
+ font-weight: 500;
6180
+ cursor: pointer;
6181
+ transition: all 0.15s ease;
6182
+
6183
+ &:hover {
6184
+ border-color: ${_chunkN6JYTJCBjs.colors.borderHover};
6185
+ }
6186
+ `,
6187
+ modeBtnActive: _react3.css`
6188
+ border-color: ${_chunkN6JYTJCBjs.colors.primary};
6189
+ background: rgba(99, 91, 255, 0.1);
6190
+ color: ${_chunkN6JYTJCBjs.colors.primary};
6191
+ `,
6192
+ modeBtnDanger: _react3.css`
6193
+ border-color: ${_chunkN6JYTJCBjs.colors.danger};
6194
+ background: rgba(239, 68, 68, 0.1);
6195
+ color: ${_chunkN6JYTJCBjs.colors.danger};
6196
+ `,
6197
+ message: _react3.css`
6198
+ font-size: ${_chunkN6JYTJCBjs.fontSize.base};
6199
+ color: ${_chunkN6JYTJCBjs.colors.textSecondary};
6200
+ margin: 0 0 20px;
6201
+ line-height: 1.5;
6202
+ `,
6203
+ actions: _react3.css`
6204
+ display: flex;
6205
+ gap: 12px;
6206
+ justify-content: flex-end;
6207
+ `,
6208
+ cancelBtn: _react3.css`
6209
+ padding: 10px 20px;
6210
+ border: 1px solid ${_chunkN6JYTJCBjs.colors.border};
6211
+ border-radius: 8px;
6212
+ background: ${_chunkN6JYTJCBjs.colors.background};
6213
+ color: ${_chunkN6JYTJCBjs.colors.text};
6214
+ font-size: ${_chunkN6JYTJCBjs.fontSize.base};
6215
+ font-weight: 500;
6216
+ cursor: pointer;
6217
+ transition: all 0.15s ease;
6218
+
6219
+ &:hover {
6220
+ background: ${_chunkN6JYTJCBjs.colors.surfaceHover};
6221
+ border-color: ${_chunkN6JYTJCBjs.colors.borderHover};
6222
+ }
6223
+ `,
6224
+ confirmBtn: _react3.css`
6225
+ padding: 10px 20px;
6226
+ border: none;
6227
+ border-radius: 8px;
6228
+ background: ${_chunkN6JYTJCBjs.colors.primary};
6229
+ color: white;
6230
+ font-size: ${_chunkN6JYTJCBjs.fontSize.base};
6231
+ font-weight: 500;
6232
+ cursor: pointer;
6233
+ transition: all 0.15s ease;
6234
+
6235
+ &:hover {
6236
+ background: ${_chunkN6JYTJCBjs.colors.primaryHover};
6237
+ }
6238
+ `,
6239
+ confirmBtnDanger: _react3.css`
6240
+ background: ${_chunkN6JYTJCBjs.colors.danger};
6241
+
6242
+ &:hover {
6243
+ background: #dc2626;
6244
+ }
6245
+ `
6246
+ };
6247
+ const isRemove = mode === "remove";
6248
+ const title = "Process Images";
6249
+ const message = isRemove ? `Remove generated thumbnails for ${imageCount} image${imageCount !== 1 ? "s" : ""}? Original images will be kept.` : `Generate thumbnails for ${imageCount} image${imageCount !== 1 ? "s" : ""}?`;
6250
+ const confirmLabel = isRemove ? "Remove" : "Process";
6251
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: processModalStyles.overlay, onClick: onCancel, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: processModalStyles.container, onClick: (e) => e.stopPropagation(), children: [
6252
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: processModalStyles.title, children: title }),
6253
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: processModalStyles.modeToggle, children: [
6254
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6255
+ "button",
6256
+ {
6257
+ css: [processModalStyles.modeBtn, mode === "generate" && processModalStyles.modeBtnActive],
6258
+ onClick: () => onModeChange("generate"),
6259
+ children: "Generate Thumbnails"
6260
+ }
6261
+ ),
6262
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6263
+ "button",
6264
+ {
6265
+ css: [processModalStyles.modeBtn, mode === "remove" && processModalStyles.modeBtnDanger],
6266
+ onClick: () => onModeChange("remove"),
6267
+ children: "Remove Thumbnails"
6268
+ }
6269
+ )
6270
+ ] }),
6271
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: processModalStyles.message, children: message }),
6272
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: processModalStyles.actions, children: [
6273
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: processModalStyles.cancelBtn, onClick: onCancel, children: "Cancel" }),
6274
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
6275
+ "button",
6276
+ {
6277
+ css: [processModalStyles.confirmBtn, isRemove && processModalStyles.confirmBtnDanger],
6278
+ onClick: onConfirm,
6279
+ children: confirmLabel
6280
+ }
6281
+ )
6282
+ ] })
6283
+ ] }) });
6284
+ }
6267
6285
  function Breadcrumbs({ currentPath, onNavigate }) {
6268
6286
  const parts = currentPath.split("/").filter(Boolean);
6269
6287
  const breadcrumbs = parts.map((part, index) => ({
@@ -6306,4 +6324,4 @@ var StudioUI_default = StudioUI;
6306
6324
 
6307
6325
 
6308
6326
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
6309
- //# sourceMappingURL=StudioUI-YRXPBDUX.js.map
6327
+ //# sourceMappingURL=StudioUI-DBZLGGPL.js.map