@gallop.software/studio 1.4.1 → 1.4.3

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.
@@ -1741,15 +1741,13 @@ var styles5 = {
1741
1741
  `
1742
1742
  };
1743
1743
  function StudioToolbar() {
1744
- const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem, scanRequested, clearScanRequest, fileItems } = useStudio();
1744
+ const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem, scanRequested, clearScanRequest, fileItems, requestProcess, actionState } = useStudio();
1745
1745
  const fileInputRef = useRef2(null);
1746
1746
  const abortControllerRef = useRef2(null);
1747
1747
  const [showAddNewModal, setShowAddNewModal] = useState4(false);
1748
1748
  const [uploading, setUploading] = useState4(false);
1749
1749
  const [scanning, setScanning] = useState4(false);
1750
- const [processing, setProcessing] = useState4(false);
1751
1750
  const [showDeleteConfirm, setShowDeleteConfirm] = useState4(false);
1752
- const [showProcessConfirm, setShowProcessConfirm] = useState4(false);
1753
1751
  const [showSyncConfirm, setShowSyncConfirm] = useState4(false);
1754
1752
  const [syncImageCount, setSyncImageCount] = useState4(0);
1755
1753
  const [syncHasRemote, setSyncHasRemote] = useState4(false);
@@ -1762,9 +1760,6 @@ function StudioToolbar() {
1762
1760
  percent: 0,
1763
1761
  status: "processing"
1764
1762
  });
1765
- const [processCount, setProcessCount] = useState4(0);
1766
- const [processMode, setProcessMode] = useState4("all");
1767
- const [imagesToProcess, setImagesToProcess] = useState4([]);
1768
1763
  const [alertMessage, setAlertMessage] = useState4(null);
1769
1764
  const [showNewFolderModal, setShowNewFolderModal] = useState4(false);
1770
1765
  const [showRenameFolderModal, setShowRenameFolderModal] = useState4(false);
@@ -1999,234 +1994,29 @@ function StudioToolbar() {
1999
1994
  });
2000
1995
  return;
2001
1996
  }
2002
- setProcessCount(selectedImagePaths.length);
2003
- setImagesToProcess(selectedImagePaths);
2004
- setProcessMode("selected");
2005
- setShowProcessConfirm(true);
1997
+ requestProcess(selectedImagePaths);
2006
1998
  } else {
2007
1999
  try {
2008
2000
  const response = await fetch("/api/studio/count-images");
2009
2001
  const data = await response.json();
2010
- if (data.count === 0) {
2002
+ if (!data.images || data.images.length === 0) {
2011
2003
  setAlertMessage({
2012
2004
  title: "No Images Found",
2013
2005
  message: "No images found in the public folder to process."
2014
2006
  });
2015
2007
  return;
2016
2008
  }
2017
- setProcessCount(data.count);
2018
- setProcessMode("all");
2019
- setShowProcessConfirm(true);
2009
+ const allImagePaths = data.images.map((img) => `public/${img}`);
2010
+ requestProcess(allImagePaths);
2020
2011
  } catch (error) {
2021
- console.error("Failed to count images:", error);
2012
+ console.error("Failed to get images:", error);
2022
2013
  setAlertMessage({
2023
2014
  title: "Error",
2024
- message: "Failed to count images."
2015
+ message: "Failed to get images."
2025
2016
  });
2026
2017
  }
2027
2018
  }
2028
- }, [selectedItems]);
2029
- const handleProcessConfirm = useCallback2(async () => {
2030
- setShowProcessConfirm(false);
2031
- setProcessing(true);
2032
- abortControllerRef.current = new AbortController();
2033
- const signal = abortControllerRef.current.signal;
2034
- try {
2035
- if (processMode === "all") {
2036
- setProgressTitle("Processing Images");
2037
- setShowProgress(true);
2038
- setProgressState({
2039
- current: 0,
2040
- total: processCount,
2041
- percent: 0,
2042
- status: "processing"
2043
- });
2044
- const response = await fetch("/api/studio/process-all", {
2045
- method: "POST",
2046
- signal
2047
- });
2048
- if (!response.body) {
2049
- throw new Error("No response body");
2050
- }
2051
- const reader = response.body.getReader();
2052
- const decoder = new TextDecoder();
2053
- try {
2054
- while (true) {
2055
- const { done, value } = await reader.read();
2056
- if (done) break;
2057
- if (signal.aborted) {
2058
- reader.cancel();
2059
- break;
2060
- }
2061
- const text = decoder.decode(value);
2062
- const lines = text.split("\n\n").filter((line) => line.startsWith("data: "));
2063
- for (const line of lines) {
2064
- try {
2065
- const data = JSON.parse(line.replace("data: ", ""));
2066
- if (data.type === "start") {
2067
- setProgressState((prev) => ({
2068
- ...prev,
2069
- total: data.total
2070
- }));
2071
- } else if (data.type === "progress") {
2072
- setProgressState({
2073
- current: data.current,
2074
- total: data.total,
2075
- percent: data.percent,
2076
- currentFile: data.currentFile,
2077
- status: "processing"
2078
- });
2079
- } else if (data.type === "cleanup") {
2080
- setProgressState((prev) => ({
2081
- ...prev,
2082
- status: "cleanup",
2083
- currentFile: void 0
2084
- }));
2085
- } else if (data.type === "complete") {
2086
- setProgressState({
2087
- current: data.processed,
2088
- total: data.processed,
2089
- percent: 100,
2090
- status: "complete",
2091
- processed: data.processed,
2092
- alreadyProcessed: data.alreadyProcessed,
2093
- orphansRemoved: data.orphansRemoved,
2094
- errors: data.errors
2095
- });
2096
- triggerRefresh();
2097
- } else if (data.type === "error") {
2098
- setProgressState((prev) => ({
2099
- ...prev,
2100
- status: "error",
2101
- message: data.message
2102
- }));
2103
- }
2104
- } catch {
2105
- }
2106
- }
2107
- }
2108
- } catch (err) {
2109
- if (signal.aborted) {
2110
- setProgressState((prev) => ({
2111
- ...prev,
2112
- status: "stopped",
2113
- processed: prev.current
2114
- }));
2115
- triggerRefresh();
2116
- } else {
2117
- throw err;
2118
- }
2119
- }
2120
- } else {
2121
- setShowProgress(true);
2122
- setProgressState({
2123
- current: 0,
2124
- total: processCount,
2125
- percent: 0,
2126
- status: "processing"
2127
- });
2128
- const selectedImageKeys = imagesToProcess.map((p) => {
2129
- const key = p.replace(/^public\//, "");
2130
- return key.startsWith("/") ? key : `/${key}`;
2131
- });
2132
- const response = await fetch("/api/studio/reprocess-stream", {
2133
- method: "POST",
2134
- headers: { "Content-Type": "application/json" },
2135
- body: JSON.stringify({ imageKeys: selectedImageKeys }),
2136
- signal
2137
- });
2138
- if (!response.ok) {
2139
- const error = await response.json();
2140
- setProgressState({
2141
- current: 0,
2142
- total: 0,
2143
- percent: 0,
2144
- status: "error",
2145
- message: error.error || "Unknown error"
2146
- });
2147
- } else {
2148
- const reader = response.body?.getReader();
2149
- const decoder = new TextDecoder();
2150
- if (reader) {
2151
- let buffer = "";
2152
- while (true) {
2153
- const { done, value } = await reader.read();
2154
- if (done) break;
2155
- buffer += decoder.decode(value, { stream: true });
2156
- const lines = buffer.split("\n");
2157
- buffer = lines.pop() || "";
2158
- for (const line of lines) {
2159
- if (line.startsWith("data: ")) {
2160
- try {
2161
- const data = JSON.parse(line.slice(6));
2162
- if (data.type === "start") {
2163
- setProgressState((prev) => ({
2164
- ...prev,
2165
- total: data.total
2166
- }));
2167
- } else if (data.type === "progress") {
2168
- setProgressState({
2169
- current: data.current,
2170
- total: data.total,
2171
- percent: data.percent,
2172
- status: "processing",
2173
- message: data.message
2174
- });
2175
- } else if (data.type === "cleanup") {
2176
- setProgressState((prev) => ({
2177
- ...prev,
2178
- status: "cleanup",
2179
- message: data.message
2180
- }));
2181
- } else if (data.type === "complete") {
2182
- setProgressState({
2183
- current: data.processed,
2184
- total: data.processed,
2185
- percent: 100,
2186
- status: data.errors > 0 ? "error" : "complete",
2187
- processed: data.processed,
2188
- message: data.message
2189
- });
2190
- clearSelection();
2191
- triggerRefresh();
2192
- } else if (data.type === "error") {
2193
- setProgressState((prev) => ({
2194
- ...prev,
2195
- status: "error",
2196
- message: data.message
2197
- }));
2198
- }
2199
- } catch {
2200
- }
2201
- }
2202
- }
2203
- }
2204
- }
2205
- }
2206
- }
2207
- } catch (error) {
2208
- if (signal.aborted) {
2209
- setProgressState((prev) => ({
2210
- ...prev,
2211
- status: "stopped",
2212
- processed: prev.current
2213
- }));
2214
- triggerRefresh();
2215
- } else {
2216
- console.error("Processing error:", error);
2217
- setProgressState({
2218
- current: 0,
2219
- total: 0,
2220
- percent: 0,
2221
- status: "error",
2222
- message: "Processing failed. Check console for details."
2223
- });
2224
- }
2225
- } finally {
2226
- setProcessing(false);
2227
- abortControllerRef.current = null;
2228
- }
2229
- }, [processMode, processCount, imagesToProcess, clearSelection, triggerRefresh]);
2019
+ }, [selectedItems, requestProcess]);
2230
2020
  const handleStopProcessing = useCallback2(() => {
2231
2021
  if (abortControllerRef.current) {
2232
2022
  abortControllerRef.current.abort();
@@ -2605,16 +2395,6 @@ function StudioToolbar() {
2605
2395
  onCancel: () => setShowSyncConfirm(false)
2606
2396
  }
2607
2397
  ),
2608
- showProcessConfirm && /* @__PURE__ */ jsx5(
2609
- ConfirmModal,
2610
- {
2611
- title: "Process Images",
2612
- message: processMode === "all" ? `Found ${processCount} image${processCount !== 1 ? "s" : ""} in the public folder. This will regenerate all thumbnails and remove any orphaned files from the images folder.` : `Process ${processCount} selected image${processCount !== 1 ? "s" : ""}? This will regenerate thumbnails for these files.`,
2613
- confirmLabel: processing ? "Processing..." : "Process",
2614
- onConfirm: handleProcessConfirm,
2615
- onCancel: () => setShowProcessConfirm(false)
2616
- }
2617
- ),
2618
2398
  showProgress && /* @__PURE__ */ jsx5(
2619
2399
  ProgressModal,
2620
2400
  {
@@ -2738,11 +2518,11 @@ function StudioToolbar() {
2738
2518
  {
2739
2519
  css: styles5.btn,
2740
2520
  onClick: handleProcessImages,
2741
- disabled: processing || isInImagesFolder,
2521
+ disabled: actionState.showProgress || isInImagesFolder,
2742
2522
  title: isInImagesFolder ? "Cannot process images folder" : void 0,
2743
2523
  children: [
2744
2524
  /* @__PURE__ */ jsx5(ImageStackIcon, {}),
2745
- processing ? "Processing..." : "Process Images"
2525
+ "Process Images"
2746
2526
  ]
2747
2527
  }
2748
2528
  ),
@@ -5557,8 +5337,8 @@ function useStudioActions({
5557
5337
  });
5558
5338
  const isRemove = mode === "remove";
5559
5339
  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...";
5340
+ const progressTitle = isRemove ? "Removing Thumbnails" : "Generating Thumbnails";
5341
+ const progressMessage = isRemove ? "Removing thumbnails..." : "Generating thumbnails...";
5562
5342
  setActionState((prev) => ({
5563
5343
  ...prev,
5564
5344
  showProcessConfirm: false,
@@ -6324,4 +6104,4 @@ export {
6324
6104
  StudioUI,
6325
6105
  StudioUI_default as default
6326
6106
  };
6327
- //# sourceMappingURL=StudioUI-HLMTACHJ.mjs.map
6107
+ //# sourceMappingURL=StudioUI-DN4EP6CF.mjs.map