@gallop.software/studio 1.4.0 → 1.4.2
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-YRXPBDUX.js → StudioUI-MAOXE72P.js} +196 -398
- package/dist/StudioUI-MAOXE72P.js.map +1 -0
- package/dist/{StudioUI-XLQBCXNU.mjs → StudioUI-TTBNASM5.mjs} +184 -386
- package/dist/StudioUI-TTBNASM5.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/StudioUI-XLQBCXNU.mjs.map +0 -1
- package/dist/StudioUI-YRXPBDUX.js.map +0 -1
|
@@ -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
|
-
|
|
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: () => {
|
|
@@ -1743,15 +1741,13 @@ var styles5 = {
|
|
|
1743
1741
|
`
|
|
1744
1742
|
};
|
|
1745
1743
|
function StudioToolbar() {
|
|
1746
|
-
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();
|
|
1747
1745
|
const fileInputRef = useRef2(null);
|
|
1748
1746
|
const abortControllerRef = useRef2(null);
|
|
1749
1747
|
const [showAddNewModal, setShowAddNewModal] = useState4(false);
|
|
1750
1748
|
const [uploading, setUploading] = useState4(false);
|
|
1751
1749
|
const [scanning, setScanning] = useState4(false);
|
|
1752
|
-
const [processing, setProcessing] = useState4(false);
|
|
1753
1750
|
const [showDeleteConfirm, setShowDeleteConfirm] = useState4(false);
|
|
1754
|
-
const [showProcessConfirm, setShowProcessConfirm] = useState4(false);
|
|
1755
1751
|
const [showSyncConfirm, setShowSyncConfirm] = useState4(false);
|
|
1756
1752
|
const [syncImageCount, setSyncImageCount] = useState4(0);
|
|
1757
1753
|
const [syncHasRemote, setSyncHasRemote] = useState4(false);
|
|
@@ -1764,9 +1760,6 @@ function StudioToolbar() {
|
|
|
1764
1760
|
percent: 0,
|
|
1765
1761
|
status: "processing"
|
|
1766
1762
|
});
|
|
1767
|
-
const [processCount, setProcessCount] = useState4(0);
|
|
1768
|
-
const [processMode, setProcessMode] = useState4("all");
|
|
1769
|
-
const [imagesToProcess, setImagesToProcess] = useState4([]);
|
|
1770
1763
|
const [alertMessage, setAlertMessage] = useState4(null);
|
|
1771
1764
|
const [showNewFolderModal, setShowNewFolderModal] = useState4(false);
|
|
1772
1765
|
const [showRenameFolderModal, setShowRenameFolderModal] = useState4(false);
|
|
@@ -2001,234 +1994,29 @@ function StudioToolbar() {
|
|
|
2001
1994
|
});
|
|
2002
1995
|
return;
|
|
2003
1996
|
}
|
|
2004
|
-
|
|
2005
|
-
setImagesToProcess(selectedImagePaths);
|
|
2006
|
-
setProcessMode("selected");
|
|
2007
|
-
setShowProcessConfirm(true);
|
|
1997
|
+
requestProcess(selectedImagePaths);
|
|
2008
1998
|
} else {
|
|
2009
1999
|
try {
|
|
2010
2000
|
const response = await fetch("/api/studio/count-images");
|
|
2011
2001
|
const data = await response.json();
|
|
2012
|
-
if (data.
|
|
2002
|
+
if (!data.images || data.images.length === 0) {
|
|
2013
2003
|
setAlertMessage({
|
|
2014
2004
|
title: "No Images Found",
|
|
2015
2005
|
message: "No images found in the public folder to process."
|
|
2016
2006
|
});
|
|
2017
2007
|
return;
|
|
2018
2008
|
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
setShowProcessConfirm(true);
|
|
2009
|
+
const allImagePaths = data.images.map((img) => `public/${img}`);
|
|
2010
|
+
requestProcess(allImagePaths);
|
|
2022
2011
|
} catch (error) {
|
|
2023
|
-
console.error("Failed to
|
|
2012
|
+
console.error("Failed to get images:", error);
|
|
2024
2013
|
setAlertMessage({
|
|
2025
2014
|
title: "Error",
|
|
2026
|
-
message: "Failed to
|
|
2027
|
-
});
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
}, [selectedItems]);
|
|
2031
|
-
const handleProcessConfirm = useCallback2(async () => {
|
|
2032
|
-
setShowProcessConfirm(false);
|
|
2033
|
-
setProcessing(true);
|
|
2034
|
-
abortControllerRef.current = new AbortController();
|
|
2035
|
-
const signal = abortControllerRef.current.signal;
|
|
2036
|
-
try {
|
|
2037
|
-
if (processMode === "all") {
|
|
2038
|
-
setProgressTitle("Processing Images");
|
|
2039
|
-
setShowProgress(true);
|
|
2040
|
-
setProgressState({
|
|
2041
|
-
current: 0,
|
|
2042
|
-
total: processCount,
|
|
2043
|
-
percent: 0,
|
|
2044
|
-
status: "processing"
|
|
2045
|
-
});
|
|
2046
|
-
const response = await fetch("/api/studio/process-all", {
|
|
2047
|
-
method: "POST",
|
|
2048
|
-
signal
|
|
2049
|
-
});
|
|
2050
|
-
if (!response.body) {
|
|
2051
|
-
throw new Error("No response body");
|
|
2052
|
-
}
|
|
2053
|
-
const reader = response.body.getReader();
|
|
2054
|
-
const decoder = new TextDecoder();
|
|
2055
|
-
try {
|
|
2056
|
-
while (true) {
|
|
2057
|
-
const { done, value } = await reader.read();
|
|
2058
|
-
if (done) break;
|
|
2059
|
-
if (signal.aborted) {
|
|
2060
|
-
reader.cancel();
|
|
2061
|
-
break;
|
|
2062
|
-
}
|
|
2063
|
-
const text = decoder.decode(value);
|
|
2064
|
-
const lines = text.split("\n\n").filter((line) => line.startsWith("data: "));
|
|
2065
|
-
for (const line of lines) {
|
|
2066
|
-
try {
|
|
2067
|
-
const data = JSON.parse(line.replace("data: ", ""));
|
|
2068
|
-
if (data.type === "start") {
|
|
2069
|
-
setProgressState((prev) => ({
|
|
2070
|
-
...prev,
|
|
2071
|
-
total: data.total
|
|
2072
|
-
}));
|
|
2073
|
-
} else if (data.type === "progress") {
|
|
2074
|
-
setProgressState({
|
|
2075
|
-
current: data.current,
|
|
2076
|
-
total: data.total,
|
|
2077
|
-
percent: data.percent,
|
|
2078
|
-
currentFile: data.currentFile,
|
|
2079
|
-
status: "processing"
|
|
2080
|
-
});
|
|
2081
|
-
} else if (data.type === "cleanup") {
|
|
2082
|
-
setProgressState((prev) => ({
|
|
2083
|
-
...prev,
|
|
2084
|
-
status: "cleanup",
|
|
2085
|
-
currentFile: void 0
|
|
2086
|
-
}));
|
|
2087
|
-
} else if (data.type === "complete") {
|
|
2088
|
-
setProgressState({
|
|
2089
|
-
current: data.processed,
|
|
2090
|
-
total: data.processed,
|
|
2091
|
-
percent: 100,
|
|
2092
|
-
status: "complete",
|
|
2093
|
-
processed: data.processed,
|
|
2094
|
-
alreadyProcessed: data.alreadyProcessed,
|
|
2095
|
-
orphansRemoved: data.orphansRemoved,
|
|
2096
|
-
errors: data.errors
|
|
2097
|
-
});
|
|
2098
|
-
triggerRefresh();
|
|
2099
|
-
} else if (data.type === "error") {
|
|
2100
|
-
setProgressState((prev) => ({
|
|
2101
|
-
...prev,
|
|
2102
|
-
status: "error",
|
|
2103
|
-
message: data.message
|
|
2104
|
-
}));
|
|
2105
|
-
}
|
|
2106
|
-
} catch {
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
} catch (err) {
|
|
2111
|
-
if (signal.aborted) {
|
|
2112
|
-
setProgressState((prev) => ({
|
|
2113
|
-
...prev,
|
|
2114
|
-
status: "stopped",
|
|
2115
|
-
processed: prev.current
|
|
2116
|
-
}));
|
|
2117
|
-
triggerRefresh();
|
|
2118
|
-
} else {
|
|
2119
|
-
throw err;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
} else {
|
|
2123
|
-
setShowProgress(true);
|
|
2124
|
-
setProgressState({
|
|
2125
|
-
current: 0,
|
|
2126
|
-
total: processCount,
|
|
2127
|
-
percent: 0,
|
|
2128
|
-
status: "processing"
|
|
2129
|
-
});
|
|
2130
|
-
const selectedImageKeys = imagesToProcess.map((p) => {
|
|
2131
|
-
const key = p.replace(/^public\//, "");
|
|
2132
|
-
return key.startsWith("/") ? key : `/${key}`;
|
|
2133
|
-
});
|
|
2134
|
-
const response = await fetch("/api/studio/reprocess-stream", {
|
|
2135
|
-
method: "POST",
|
|
2136
|
-
headers: { "Content-Type": "application/json" },
|
|
2137
|
-
body: JSON.stringify({ imageKeys: selectedImageKeys }),
|
|
2138
|
-
signal
|
|
2015
|
+
message: "Failed to get images."
|
|
2139
2016
|
});
|
|
2140
|
-
if (!response.ok) {
|
|
2141
|
-
const error = await response.json();
|
|
2142
|
-
setProgressState({
|
|
2143
|
-
current: 0,
|
|
2144
|
-
total: 0,
|
|
2145
|
-
percent: 0,
|
|
2146
|
-
status: "error",
|
|
2147
|
-
message: error.error || "Unknown error"
|
|
2148
|
-
});
|
|
2149
|
-
} else {
|
|
2150
|
-
const reader = response.body?.getReader();
|
|
2151
|
-
const decoder = new TextDecoder();
|
|
2152
|
-
if (reader) {
|
|
2153
|
-
let buffer = "";
|
|
2154
|
-
while (true) {
|
|
2155
|
-
const { done, value } = await reader.read();
|
|
2156
|
-
if (done) break;
|
|
2157
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2158
|
-
const lines = buffer.split("\n");
|
|
2159
|
-
buffer = lines.pop() || "";
|
|
2160
|
-
for (const line of lines) {
|
|
2161
|
-
if (line.startsWith("data: ")) {
|
|
2162
|
-
try {
|
|
2163
|
-
const data = JSON.parse(line.slice(6));
|
|
2164
|
-
if (data.type === "start") {
|
|
2165
|
-
setProgressState((prev) => ({
|
|
2166
|
-
...prev,
|
|
2167
|
-
total: data.total
|
|
2168
|
-
}));
|
|
2169
|
-
} else if (data.type === "progress") {
|
|
2170
|
-
setProgressState({
|
|
2171
|
-
current: data.current,
|
|
2172
|
-
total: data.total,
|
|
2173
|
-
percent: data.percent,
|
|
2174
|
-
status: "processing",
|
|
2175
|
-
message: data.message
|
|
2176
|
-
});
|
|
2177
|
-
} else if (data.type === "cleanup") {
|
|
2178
|
-
setProgressState((prev) => ({
|
|
2179
|
-
...prev,
|
|
2180
|
-
status: "cleanup",
|
|
2181
|
-
message: data.message
|
|
2182
|
-
}));
|
|
2183
|
-
} else if (data.type === "complete") {
|
|
2184
|
-
setProgressState({
|
|
2185
|
-
current: data.processed,
|
|
2186
|
-
total: data.processed,
|
|
2187
|
-
percent: 100,
|
|
2188
|
-
status: data.errors > 0 ? "error" : "complete",
|
|
2189
|
-
processed: data.processed,
|
|
2190
|
-
message: data.message
|
|
2191
|
-
});
|
|
2192
|
-
clearSelection();
|
|
2193
|
-
triggerRefresh();
|
|
2194
|
-
} else if (data.type === "error") {
|
|
2195
|
-
setProgressState((prev) => ({
|
|
2196
|
-
...prev,
|
|
2197
|
-
status: "error",
|
|
2198
|
-
message: data.message
|
|
2199
|
-
}));
|
|
2200
|
-
}
|
|
2201
|
-
} catch {
|
|
2202
|
-
}
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
2017
|
}
|
|
2209
|
-
} catch (error) {
|
|
2210
|
-
if (signal.aborted) {
|
|
2211
|
-
setProgressState((prev) => ({
|
|
2212
|
-
...prev,
|
|
2213
|
-
status: "stopped",
|
|
2214
|
-
processed: prev.current
|
|
2215
|
-
}));
|
|
2216
|
-
triggerRefresh();
|
|
2217
|
-
} else {
|
|
2218
|
-
console.error("Processing error:", error);
|
|
2219
|
-
setProgressState({
|
|
2220
|
-
current: 0,
|
|
2221
|
-
total: 0,
|
|
2222
|
-
percent: 0,
|
|
2223
|
-
status: "error",
|
|
2224
|
-
message: "Processing failed. Check console for details."
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
} finally {
|
|
2228
|
-
setProcessing(false);
|
|
2229
|
-
abortControllerRef.current = null;
|
|
2230
2018
|
}
|
|
2231
|
-
}, [
|
|
2019
|
+
}, [selectedItems, requestProcess]);
|
|
2232
2020
|
const handleStopProcessing = useCallback2(() => {
|
|
2233
2021
|
if (abortControllerRef.current) {
|
|
2234
2022
|
abortControllerRef.current.abort();
|
|
@@ -2607,16 +2395,6 @@ function StudioToolbar() {
|
|
|
2607
2395
|
onCancel: () => setShowSyncConfirm(false)
|
|
2608
2396
|
}
|
|
2609
2397
|
),
|
|
2610
|
-
showProcessConfirm && /* @__PURE__ */ jsx5(
|
|
2611
|
-
ConfirmModal,
|
|
2612
|
-
{
|
|
2613
|
-
title: "Process Images",
|
|
2614
|
-
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.`,
|
|
2615
|
-
confirmLabel: processing ? "Processing..." : "Process",
|
|
2616
|
-
onConfirm: handleProcessConfirm,
|
|
2617
|
-
onCancel: () => setShowProcessConfirm(false)
|
|
2618
|
-
}
|
|
2619
|
-
),
|
|
2620
2398
|
showProgress && /* @__PURE__ */ jsx5(
|
|
2621
2399
|
ProgressModal,
|
|
2622
2400
|
{
|
|
@@ -2740,11 +2518,11 @@ function StudioToolbar() {
|
|
|
2740
2518
|
{
|
|
2741
2519
|
css: styles5.btn,
|
|
2742
2520
|
onClick: handleProcessImages,
|
|
2743
|
-
disabled:
|
|
2521
|
+
disabled: actionState.showProgress || isInImagesFolder,
|
|
2744
2522
|
title: isInImagesFolder ? "Cannot process images folder" : void 0,
|
|
2745
2523
|
children: [
|
|
2746
2524
|
/* @__PURE__ */ jsx5(ImageStackIcon, {}),
|
|
2747
|
-
|
|
2525
|
+
"Process Images"
|
|
2748
2526
|
]
|
|
2749
2527
|
}
|
|
2750
2528
|
),
|
|
@@ -4498,7 +4276,6 @@ function StudioDetailView() {
|
|
|
4498
4276
|
requestMove,
|
|
4499
4277
|
requestSync,
|
|
4500
4278
|
requestProcess,
|
|
4501
|
-
requestUnprocess,
|
|
4502
4279
|
actionState
|
|
4503
4280
|
} = useStudio();
|
|
4504
4281
|
const [showRenameModal, setShowRenameModal] = useState8(false);
|
|
@@ -4698,19 +4475,6 @@ function StudioDetailView() {
|
|
|
4698
4475
|
]
|
|
4699
4476
|
}
|
|
4700
4477
|
),
|
|
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
|
-
),
|
|
4714
4478
|
/* @__PURE__ */ jsxs8(
|
|
4715
4479
|
"button",
|
|
4716
4480
|
{
|
|
@@ -5310,11 +5074,11 @@ var defaultActionState2 = {
|
|
|
5310
5074
|
showMoveModal: false,
|
|
5311
5075
|
showSyncConfirm: false,
|
|
5312
5076
|
showProcessConfirm: false,
|
|
5313
|
-
showUnprocessConfirm: false,
|
|
5314
5077
|
actionPaths: [],
|
|
5315
5078
|
syncImageCount: 0,
|
|
5316
5079
|
syncHasRemote: false,
|
|
5317
|
-
syncHasLocal: false
|
|
5080
|
+
syncHasLocal: false,
|
|
5081
|
+
processMode: "generate"
|
|
5318
5082
|
};
|
|
5319
5083
|
function useStudioActions({
|
|
5320
5084
|
triggerRefresh,
|
|
@@ -5371,14 +5135,15 @@ function useStudioActions({
|
|
|
5371
5135
|
setActionState((prev) => ({
|
|
5372
5136
|
...prev,
|
|
5373
5137
|
actionPaths: paths,
|
|
5374
|
-
showProcessConfirm: true
|
|
5138
|
+
showProcessConfirm: true,
|
|
5139
|
+
processMode: "generate"
|
|
5140
|
+
// Reset to default when opening modal
|
|
5375
5141
|
}));
|
|
5376
5142
|
}, []);
|
|
5377
|
-
const
|
|
5143
|
+
const setProcessMode = useCallback5((mode) => {
|
|
5378
5144
|
setActionState((prev) => ({
|
|
5379
5145
|
...prev,
|
|
5380
|
-
|
|
5381
|
-
showUnprocessConfirm: true
|
|
5146
|
+
processMode: mode
|
|
5382
5147
|
}));
|
|
5383
5148
|
}, []);
|
|
5384
5149
|
const cancelAction = useCallback5(() => {
|
|
@@ -5387,8 +5152,7 @@ function useStudioActions({
|
|
|
5387
5152
|
showDeleteConfirm: false,
|
|
5388
5153
|
showMoveModal: false,
|
|
5389
5154
|
showSyncConfirm: false,
|
|
5390
|
-
showProcessConfirm: false
|
|
5391
|
-
showUnprocessConfirm: false
|
|
5155
|
+
showProcessConfirm: false
|
|
5392
5156
|
}));
|
|
5393
5157
|
}, []);
|
|
5394
5158
|
const closeProgress = useCallback5(() => {
|
|
@@ -5566,27 +5330,32 @@ function useStudioActions({
|
|
|
5566
5330
|
}, [actionState.actionPaths, clearSelection, triggerRefresh, showError, setProgressState]);
|
|
5567
5331
|
const confirmProcess = useCallback5(async () => {
|
|
5568
5332
|
const paths = actionState.actionPaths;
|
|
5333
|
+
const mode = actionState.processMode;
|
|
5569
5334
|
const imageKeys = paths.map((p) => {
|
|
5570
5335
|
const key = p.replace(/^public\//, "");
|
|
5571
5336
|
return key.startsWith("/") ? key : `/${key}`;
|
|
5572
5337
|
});
|
|
5338
|
+
const isRemove = mode === "remove";
|
|
5339
|
+
const endpoint = isRemove ? "/api/studio/unprocess-stream" : "/api/studio/reprocess-stream";
|
|
5340
|
+
const progressTitle = isRemove ? "Removing Thumbnails" : "Processing Images";
|
|
5341
|
+
const progressMessage = isRemove ? "Removing thumbnails..." : "Processing images...";
|
|
5573
5342
|
setActionState((prev) => ({
|
|
5574
5343
|
...prev,
|
|
5575
5344
|
showProcessConfirm: false,
|
|
5576
5345
|
showProgress: true,
|
|
5577
|
-
progressTitle
|
|
5346
|
+
progressTitle,
|
|
5578
5347
|
progressState: {
|
|
5579
5348
|
current: 0,
|
|
5580
5349
|
total: imageKeys.length,
|
|
5581
5350
|
percent: 0,
|
|
5582
5351
|
status: "processing",
|
|
5583
|
-
message:
|
|
5352
|
+
message: progressMessage
|
|
5584
5353
|
}
|
|
5585
5354
|
}));
|
|
5586
5355
|
abortControllerRef.current = new AbortController();
|
|
5587
5356
|
const signal = abortControllerRef.current.signal;
|
|
5588
5357
|
try {
|
|
5589
|
-
const response = await fetch(
|
|
5358
|
+
const response = await fetch(endpoint, {
|
|
5590
5359
|
method: "POST",
|
|
5591
5360
|
headers: { "Content-Type": "application/json" },
|
|
5592
5361
|
body: JSON.stringify({ imageKeys }),
|
|
@@ -5599,7 +5368,7 @@ function useStudioActions({
|
|
|
5599
5368
|
total: imageKeys.length,
|
|
5600
5369
|
percent: 0,
|
|
5601
5370
|
status: "error",
|
|
5602
|
-
message: error.error || "Processing failed"
|
|
5371
|
+
message: error.error || (isRemove ? "Failed to remove thumbnails" : "Processing failed")
|
|
5603
5372
|
});
|
|
5604
5373
|
return;
|
|
5605
5374
|
}
|
|
@@ -5663,7 +5432,7 @@ function useStudioActions({
|
|
|
5663
5432
|
setProgressState((prev) => ({
|
|
5664
5433
|
...prev,
|
|
5665
5434
|
status: "stopped",
|
|
5666
|
-
message: "Processing stopped by user"
|
|
5435
|
+
message: isRemove ? "Removal stopped by user" : "Processing stopped by user"
|
|
5667
5436
|
}));
|
|
5668
5437
|
} else {
|
|
5669
5438
|
console.error("Processing error:", error);
|
|
@@ -5672,115 +5441,13 @@ function useStudioActions({
|
|
|
5672
5441
|
total: imageKeys.length,
|
|
5673
5442
|
percent: 0,
|
|
5674
5443
|
status: "error",
|
|
5675
|
-
message: "Processing failed. Check console for details."
|
|
5444
|
+
message: isRemove ? "Failed to remove thumbnails. Check console for details." : "Processing failed. Check console for details."
|
|
5676
5445
|
});
|
|
5677
5446
|
}
|
|
5678
5447
|
} finally {
|
|
5679
5448
|
abortControllerRef.current = null;
|
|
5680
5449
|
}
|
|
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]);
|
|
5450
|
+
}, [actionState.actionPaths, actionState.processMode, triggerRefresh, setProgressState]);
|
|
5784
5451
|
const deleteOrphans = useCallback5(async () => {
|
|
5785
5452
|
const orphanedFiles = actionState.progressState.orphanedFiles;
|
|
5786
5453
|
if (!orphanedFiles || orphanedFiles.length === 0) return;
|
|
@@ -5814,7 +5481,7 @@ function useStudioActions({
|
|
|
5814
5481
|
requestMove,
|
|
5815
5482
|
requestSync,
|
|
5816
5483
|
requestProcess,
|
|
5817
|
-
|
|
5484
|
+
setProcessMode,
|
|
5818
5485
|
cancelAction,
|
|
5819
5486
|
closeProgress,
|
|
5820
5487
|
stopProcessing,
|
|
@@ -5822,7 +5489,6 @@ function useStudioActions({
|
|
|
5822
5489
|
confirmMove,
|
|
5823
5490
|
confirmSync,
|
|
5824
5491
|
confirmProcess,
|
|
5825
|
-
confirmUnprocess,
|
|
5826
5492
|
deleteOrphans
|
|
5827
5493
|
};
|
|
5828
5494
|
}
|
|
@@ -6153,12 +5819,11 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
6153
5819
|
requestMove: actions.requestMove,
|
|
6154
5820
|
requestSync: actions.requestSync,
|
|
6155
5821
|
requestProcess: actions.requestProcess,
|
|
6156
|
-
|
|
5822
|
+
setProcessMode: actions.setProcessMode,
|
|
6157
5823
|
confirmDelete: actions.confirmDelete,
|
|
6158
5824
|
confirmMove: actions.confirmMove,
|
|
6159
5825
|
confirmSync: actions.confirmSync,
|
|
6160
5826
|
confirmProcess: actions.confirmProcess,
|
|
6161
|
-
confirmUnprocess: actions.confirmUnprocess,
|
|
6162
5827
|
cancelAction: actions.cancelAction,
|
|
6163
5828
|
closeProgress: actions.closeProgress,
|
|
6164
5829
|
stopProcessing: actions.stopProcessing,
|
|
@@ -6223,26 +5888,15 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
6223
5888
|
}
|
|
6224
5889
|
),
|
|
6225
5890
|
actions.actionState.showProcessConfirm && /* @__PURE__ */ jsx11(
|
|
6226
|
-
|
|
5891
|
+
ProcessConfirmModal,
|
|
6227
5892
|
{
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
5893
|
+
imageCount: actions.actionState.actionPaths.length,
|
|
5894
|
+
mode: actions.actionState.processMode,
|
|
5895
|
+
onModeChange: actions.setProcessMode,
|
|
6231
5896
|
onConfirm: actions.confirmProcess,
|
|
6232
5897
|
onCancel: actions.cancelAction
|
|
6233
5898
|
}
|
|
6234
5899
|
),
|
|
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
|
-
),
|
|
6246
5900
|
actions.actionState.showMoveModal && /* @__PURE__ */ jsx11(
|
|
6247
5901
|
StudioFolderPicker,
|
|
6248
5902
|
{
|
|
@@ -6264,6 +5918,150 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
6264
5918
|
)
|
|
6265
5919
|
] }) });
|
|
6266
5920
|
}
|
|
5921
|
+
function ProcessConfirmModal({ imageCount, mode, onModeChange, onConfirm, onCancel }) {
|
|
5922
|
+
const processModalStyles = {
|
|
5923
|
+
overlay: css11`
|
|
5924
|
+
position: fixed;
|
|
5925
|
+
inset: 0;
|
|
5926
|
+
background: rgba(0, 0, 0, 0.5);
|
|
5927
|
+
display: flex;
|
|
5928
|
+
align-items: center;
|
|
5929
|
+
justify-content: center;
|
|
5930
|
+
z-index: 10000;
|
|
5931
|
+
`,
|
|
5932
|
+
container: css11`
|
|
5933
|
+
background: ${colors.surface};
|
|
5934
|
+
border-radius: 12px;
|
|
5935
|
+
padding: 24px;
|
|
5936
|
+
max-width: 420px;
|
|
5937
|
+
width: 90%;
|
|
5938
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
5939
|
+
`,
|
|
5940
|
+
title: css11`
|
|
5941
|
+
font-size: ${fontSize.lg};
|
|
5942
|
+
font-weight: 600;
|
|
5943
|
+
color: ${colors.text};
|
|
5944
|
+
margin: 0 0 16px;
|
|
5945
|
+
`,
|
|
5946
|
+
modeToggle: css11`
|
|
5947
|
+
display: flex;
|
|
5948
|
+
gap: 8px;
|
|
5949
|
+
margin-bottom: 16px;
|
|
5950
|
+
`,
|
|
5951
|
+
modeBtn: css11`
|
|
5952
|
+
flex: 1;
|
|
5953
|
+
padding: 10px 16px;
|
|
5954
|
+
border: 2px solid ${colors.border};
|
|
5955
|
+
border-radius: 8px;
|
|
5956
|
+
background: ${colors.background};
|
|
5957
|
+
color: ${colors.textSecondary};
|
|
5958
|
+
font-size: ${fontSize.base};
|
|
5959
|
+
font-weight: 500;
|
|
5960
|
+
cursor: pointer;
|
|
5961
|
+
transition: all 0.15s ease;
|
|
5962
|
+
|
|
5963
|
+
&:hover {
|
|
5964
|
+
border-color: ${colors.borderHover};
|
|
5965
|
+
}
|
|
5966
|
+
`,
|
|
5967
|
+
modeBtnActive: css11`
|
|
5968
|
+
border-color: ${colors.primary};
|
|
5969
|
+
background: rgba(99, 91, 255, 0.1);
|
|
5970
|
+
color: ${colors.primary};
|
|
5971
|
+
`,
|
|
5972
|
+
modeBtnDanger: css11`
|
|
5973
|
+
border-color: ${colors.danger};
|
|
5974
|
+
background: rgba(239, 68, 68, 0.1);
|
|
5975
|
+
color: ${colors.danger};
|
|
5976
|
+
`,
|
|
5977
|
+
message: css11`
|
|
5978
|
+
font-size: ${fontSize.base};
|
|
5979
|
+
color: ${colors.textSecondary};
|
|
5980
|
+
margin: 0 0 20px;
|
|
5981
|
+
line-height: 1.5;
|
|
5982
|
+
`,
|
|
5983
|
+
actions: css11`
|
|
5984
|
+
display: flex;
|
|
5985
|
+
gap: 12px;
|
|
5986
|
+
justify-content: flex-end;
|
|
5987
|
+
`,
|
|
5988
|
+
cancelBtn: css11`
|
|
5989
|
+
padding: 10px 20px;
|
|
5990
|
+
border: 1px solid ${colors.border};
|
|
5991
|
+
border-radius: 8px;
|
|
5992
|
+
background: ${colors.background};
|
|
5993
|
+
color: ${colors.text};
|
|
5994
|
+
font-size: ${fontSize.base};
|
|
5995
|
+
font-weight: 500;
|
|
5996
|
+
cursor: pointer;
|
|
5997
|
+
transition: all 0.15s ease;
|
|
5998
|
+
|
|
5999
|
+
&:hover {
|
|
6000
|
+
background: ${colors.surfaceHover};
|
|
6001
|
+
border-color: ${colors.borderHover};
|
|
6002
|
+
}
|
|
6003
|
+
`,
|
|
6004
|
+
confirmBtn: css11`
|
|
6005
|
+
padding: 10px 20px;
|
|
6006
|
+
border: none;
|
|
6007
|
+
border-radius: 8px;
|
|
6008
|
+
background: ${colors.primary};
|
|
6009
|
+
color: white;
|
|
6010
|
+
font-size: ${fontSize.base};
|
|
6011
|
+
font-weight: 500;
|
|
6012
|
+
cursor: pointer;
|
|
6013
|
+
transition: all 0.15s ease;
|
|
6014
|
+
|
|
6015
|
+
&:hover {
|
|
6016
|
+
background: ${colors.primaryHover};
|
|
6017
|
+
}
|
|
6018
|
+
`,
|
|
6019
|
+
confirmBtnDanger: css11`
|
|
6020
|
+
background: ${colors.danger};
|
|
6021
|
+
|
|
6022
|
+
&:hover {
|
|
6023
|
+
background: #dc2626;
|
|
6024
|
+
}
|
|
6025
|
+
`
|
|
6026
|
+
};
|
|
6027
|
+
const isRemove = mode === "remove";
|
|
6028
|
+
const title = "Process Images";
|
|
6029
|
+
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" : ""}?`;
|
|
6030
|
+
const confirmLabel = isRemove ? "Remove" : "Process";
|
|
6031
|
+
return /* @__PURE__ */ jsx11("div", { css: processModalStyles.overlay, onClick: onCancel, children: /* @__PURE__ */ jsxs11("div", { css: processModalStyles.container, onClick: (e) => e.stopPropagation(), children: [
|
|
6032
|
+
/* @__PURE__ */ jsx11("h2", { css: processModalStyles.title, children: title }),
|
|
6033
|
+
/* @__PURE__ */ jsxs11("div", { css: processModalStyles.modeToggle, children: [
|
|
6034
|
+
/* @__PURE__ */ jsx11(
|
|
6035
|
+
"button",
|
|
6036
|
+
{
|
|
6037
|
+
css: [processModalStyles.modeBtn, mode === "generate" && processModalStyles.modeBtnActive],
|
|
6038
|
+
onClick: () => onModeChange("generate"),
|
|
6039
|
+
children: "Generate Thumbnails"
|
|
6040
|
+
}
|
|
6041
|
+
),
|
|
6042
|
+
/* @__PURE__ */ jsx11(
|
|
6043
|
+
"button",
|
|
6044
|
+
{
|
|
6045
|
+
css: [processModalStyles.modeBtn, mode === "remove" && processModalStyles.modeBtnDanger],
|
|
6046
|
+
onClick: () => onModeChange("remove"),
|
|
6047
|
+
children: "Remove Thumbnails"
|
|
6048
|
+
}
|
|
6049
|
+
)
|
|
6050
|
+
] }),
|
|
6051
|
+
/* @__PURE__ */ jsx11("p", { css: processModalStyles.message, children: message }),
|
|
6052
|
+
/* @__PURE__ */ jsxs11("div", { css: processModalStyles.actions, children: [
|
|
6053
|
+
/* @__PURE__ */ jsx11("button", { css: processModalStyles.cancelBtn, onClick: onCancel, children: "Cancel" }),
|
|
6054
|
+
/* @__PURE__ */ jsx11(
|
|
6055
|
+
"button",
|
|
6056
|
+
{
|
|
6057
|
+
css: [processModalStyles.confirmBtn, isRemove && processModalStyles.confirmBtnDanger],
|
|
6058
|
+
onClick: onConfirm,
|
|
6059
|
+
children: confirmLabel
|
|
6060
|
+
}
|
|
6061
|
+
)
|
|
6062
|
+
] })
|
|
6063
|
+
] }) });
|
|
6064
|
+
}
|
|
6267
6065
|
function Breadcrumbs({ currentPath, onNavigate }) {
|
|
6268
6066
|
const parts = currentPath.split("/").filter(Boolean);
|
|
6269
6067
|
const breadcrumbs = parts.map((part, index) => ({
|
|
@@ -6306,4 +6104,4 @@ export {
|
|
|
6306
6104
|
StudioUI,
|
|
6307
6105
|
StudioUI_default as default
|
|
6308
6106
|
};
|
|
6309
|
-
//# sourceMappingURL=StudioUI-
|
|
6107
|
+
//# sourceMappingURL=StudioUI-TTBNASM5.mjs.map
|