@gallop.software/studio 1.3.6 → 1.4.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.
@@ -20,6 +20,7 @@ var defaultActionState = {
20
20
  showMoveModal: false,
21
21
  showSyncConfirm: false,
22
22
  showProcessConfirm: false,
23
+ showUnprocessConfirm: false,
23
24
  actionPaths: [],
24
25
  syncImageCount: 0,
25
26
  syncHasRemote: false,
@@ -90,6 +91,8 @@ var defaultState = {
90
91
  },
91
92
  requestProcess: () => {
92
93
  },
94
+ requestUnprocess: () => {
95
+ },
93
96
  confirmDelete: async () => {
94
97
  },
95
98
  confirmMove: async () => {
@@ -98,6 +101,8 @@ var defaultState = {
98
101
  },
99
102
  confirmProcess: async () => {
100
103
  },
104
+ confirmUnprocess: async () => {
105
+ },
101
106
  cancelAction: () => {
102
107
  },
103
108
  closeProgress: () => {
@@ -4493,6 +4498,7 @@ function StudioDetailView() {
4493
4498
  requestMove,
4494
4499
  requestSync,
4495
4500
  requestProcess,
4501
+ requestUnprocess,
4496
4502
  actionState
4497
4503
  } = useStudio();
4498
4504
  const [showRenameModal, setShowRenameModal] = useState8(false);
@@ -4692,6 +4698,19 @@ function StudioDetailView() {
4692
4698
  ]
4693
4699
  }
4694
4700
  ),
4701
+ /* @__PURE__ */ jsxs8(
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__ */ jsx8("svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("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
+ ),
4695
4714
  /* @__PURE__ */ jsxs8(
4696
4715
  "button",
4697
4716
  {
@@ -5291,6 +5310,7 @@ var defaultActionState2 = {
5291
5310
  showMoveModal: false,
5292
5311
  showSyncConfirm: false,
5293
5312
  showProcessConfirm: false,
5313
+ showUnprocessConfirm: false,
5294
5314
  actionPaths: [],
5295
5315
  syncImageCount: 0,
5296
5316
  syncHasRemote: false,
@@ -5354,13 +5374,21 @@ function useStudioActions({
5354
5374
  showProcessConfirm: true
5355
5375
  }));
5356
5376
  }, []);
5377
+ const requestUnprocess = useCallback5((paths) => {
5378
+ setActionState((prev) => ({
5379
+ ...prev,
5380
+ actionPaths: paths,
5381
+ showUnprocessConfirm: true
5382
+ }));
5383
+ }, []);
5357
5384
  const cancelAction = useCallback5(() => {
5358
5385
  setActionState((prev) => ({
5359
5386
  ...prev,
5360
5387
  showDeleteConfirm: false,
5361
5388
  showMoveModal: false,
5362
5389
  showSyncConfirm: false,
5363
- showProcessConfirm: false
5390
+ showProcessConfirm: false,
5391
+ showUnprocessConfirm: false
5364
5392
  }));
5365
5393
  }, []);
5366
5394
  const closeProgress = useCallback5(() => {
@@ -5651,6 +5679,108 @@ function useStudioActions({
5651
5679
  abortControllerRef.current = null;
5652
5680
  }
5653
5681
  }, [actionState.actionPaths, triggerRefresh, setProgressState]);
5682
+ const confirmUnprocess = useCallback5(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 = response.body?.getReader();
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 {
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]);
5654
5784
  const deleteOrphans = useCallback5(async () => {
5655
5785
  const orphanedFiles = actionState.progressState.orphanedFiles;
5656
5786
  if (!orphanedFiles || orphanedFiles.length === 0) return;
@@ -5684,6 +5814,7 @@ function useStudioActions({
5684
5814
  requestMove,
5685
5815
  requestSync,
5686
5816
  requestProcess,
5817
+ requestUnprocess,
5687
5818
  cancelAction,
5688
5819
  closeProgress,
5689
5820
  stopProcessing,
@@ -5691,6 +5822,7 @@ function useStudioActions({
5691
5822
  confirmMove,
5692
5823
  confirmSync,
5693
5824
  confirmProcess,
5825
+ confirmUnprocess,
5694
5826
  deleteOrphans
5695
5827
  };
5696
5828
  }
@@ -6021,10 +6153,12 @@ function StudioUI({ onClose, isVisible = true }) {
6021
6153
  requestMove: actions.requestMove,
6022
6154
  requestSync: actions.requestSync,
6023
6155
  requestProcess: actions.requestProcess,
6156
+ requestUnprocess: actions.requestUnprocess,
6024
6157
  confirmDelete: actions.confirmDelete,
6025
6158
  confirmMove: actions.confirmMove,
6026
6159
  confirmSync: actions.confirmSync,
6027
6160
  confirmProcess: actions.confirmProcess,
6161
+ confirmUnprocess: actions.confirmUnprocess,
6028
6162
  cancelAction: actions.cancelAction,
6029
6163
  closeProgress: actions.closeProgress,
6030
6164
  stopProcessing: actions.stopProcessing,
@@ -6098,6 +6232,17 @@ function StudioUI({ onClose, isVisible = true }) {
6098
6232
  onCancel: actions.cancelAction
6099
6233
  }
6100
6234
  ),
6235
+ actions.actionState.showUnprocessConfirm && /* @__PURE__ */ jsx11(
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
+ ),
6101
6246
  actions.actionState.showMoveModal && /* @__PURE__ */ jsx11(
6102
6247
  StudioFolderPicker,
6103
6248
  {
@@ -6161,4 +6306,4 @@ export {
6161
6306
  StudioUI,
6162
6307
  StudioUI_default as default
6163
6308
  };
6164
- //# sourceMappingURL=StudioUI-DNDMPY7Q.mjs.map
6309
+ //# sourceMappingURL=StudioUI-XLQBCXNU.mjs.map