@gallop.software/studio 1.2.7 → 1.3.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.
- package/dist/{StudioUI-XQRJTVYU.js → StudioUI-52NHWBVJ.js} +555 -231
- package/dist/StudioUI-52NHWBVJ.js.map +1 -0
- package/dist/{StudioUI-TZB57JJT.mjs → StudioUI-K6TIH6LF.mjs} +584 -260
- package/dist/StudioUI-K6TIH6LF.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/StudioUI-TZB57JJT.mjs.map +0 -1
- package/dist/StudioUI-XQRJTVYU.js.map +0 -1
|
@@ -12,6 +12,19 @@ var _react3 = require('@emotion/react');
|
|
|
12
12
|
|
|
13
13
|
// src/components/StudioContext.tsx
|
|
14
14
|
|
|
15
|
+
var defaultActionState = {
|
|
16
|
+
showProgress: false,
|
|
17
|
+
progressTitle: "",
|
|
18
|
+
progressState: { current: 0, total: 0, percent: 0, status: "processing" },
|
|
19
|
+
showDeleteConfirm: false,
|
|
20
|
+
showMoveModal: false,
|
|
21
|
+
showSyncConfirm: false,
|
|
22
|
+
showProcessConfirm: false,
|
|
23
|
+
actionPaths: [],
|
|
24
|
+
syncImageCount: 0,
|
|
25
|
+
syncHasRemote: false,
|
|
26
|
+
syncHasLocal: false
|
|
27
|
+
};
|
|
15
28
|
var defaultState = {
|
|
16
29
|
isOpen: false,
|
|
17
30
|
openStudio: () => {
|
|
@@ -65,6 +78,34 @@ var defaultState = {
|
|
|
65
78
|
},
|
|
66
79
|
fileItems: [],
|
|
67
80
|
setFileItems: () => {
|
|
81
|
+
},
|
|
82
|
+
// Shared action state
|
|
83
|
+
actionState: defaultActionState,
|
|
84
|
+
// Shared action handlers
|
|
85
|
+
requestDelete: () => {
|
|
86
|
+
},
|
|
87
|
+
requestMove: () => {
|
|
88
|
+
},
|
|
89
|
+
requestSync: () => {
|
|
90
|
+
},
|
|
91
|
+
requestProcess: () => {
|
|
92
|
+
},
|
|
93
|
+
confirmDelete: async () => {
|
|
94
|
+
},
|
|
95
|
+
confirmMove: async () => {
|
|
96
|
+
},
|
|
97
|
+
confirmSync: async () => {
|
|
98
|
+
},
|
|
99
|
+
confirmProcess: async () => {
|
|
100
|
+
},
|
|
101
|
+
cancelAction: () => {
|
|
102
|
+
},
|
|
103
|
+
closeProgress: () => {
|
|
104
|
+
},
|
|
105
|
+
stopProcessing: () => {
|
|
106
|
+
},
|
|
107
|
+
abortController: null,
|
|
108
|
+
deleteOrphans: async () => {
|
|
68
109
|
}
|
|
69
110
|
};
|
|
70
111
|
var StudioContext = _react.createContext.call(void 0, defaultState);
|
|
@@ -4367,15 +4408,20 @@ var styles8 = {
|
|
|
4367
4408
|
color: ${_chunkN6JYTJCBjs.colors.text};
|
|
4368
4409
|
text-align: left;
|
|
4369
4410
|
|
|
4370
|
-
&:hover {
|
|
4411
|
+
&:hover:not(:disabled) {
|
|
4371
4412
|
background-color: ${_chunkN6JYTJCBjs.colors.surfaceHover};
|
|
4372
4413
|
border-color: ${_chunkN6JYTJCBjs.colors.borderHover};
|
|
4373
4414
|
}
|
|
4415
|
+
|
|
4416
|
+
&:disabled {
|
|
4417
|
+
opacity: 0.5;
|
|
4418
|
+
cursor: not-allowed;
|
|
4419
|
+
}
|
|
4374
4420
|
`,
|
|
4375
4421
|
actionBtnDanger: _react3.css`
|
|
4376
4422
|
color: ${_chunkN6JYTJCBjs.colors.danger};
|
|
4377
4423
|
|
|
4378
|
-
&:hover {
|
|
4424
|
+
&:hover:not(:disabled) {
|
|
4379
4425
|
background-color: ${_chunkN6JYTJCBjs.colors.dangerLight};
|
|
4380
4426
|
border-color: ${_chunkN6JYTJCBjs.colors.danger};
|
|
4381
4427
|
}
|
|
@@ -4387,17 +4433,23 @@ var styles8 = {
|
|
|
4387
4433
|
`
|
|
4388
4434
|
};
|
|
4389
4435
|
function StudioDetailView() {
|
|
4390
|
-
const {
|
|
4391
|
-
|
|
4436
|
+
const {
|
|
4437
|
+
focusedItem,
|
|
4438
|
+
setFocusedItem,
|
|
4439
|
+
triggerRefresh,
|
|
4440
|
+
fileItems,
|
|
4441
|
+
// Shared action handlers
|
|
4442
|
+
requestDelete,
|
|
4443
|
+
requestMove,
|
|
4444
|
+
requestSync,
|
|
4445
|
+
requestProcess,
|
|
4446
|
+
actionState
|
|
4447
|
+
} = useStudio();
|
|
4392
4448
|
const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
|
|
4393
|
-
const [showMoveModal, setShowMoveModal] = _react.useState.call(void 0, false);
|
|
4394
|
-
const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
|
|
4395
4449
|
const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
|
|
4396
|
-
const [processProgress, setProcessProgress] = _react.useState.call(void 0, null);
|
|
4397
4450
|
const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
|
|
4398
4451
|
const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
|
|
4399
|
-
const
|
|
4400
|
-
const [moving, setMoving] = _react.useState.call(void 0, false);
|
|
4452
|
+
const isActionInProgress = actionState.showProgress;
|
|
4401
4453
|
if (!focusedItem) return null;
|
|
4402
4454
|
const isImage = isImageFile(focusedItem.name);
|
|
4403
4455
|
const isVideo = isVideoFile(focusedItem.name);
|
|
@@ -4444,177 +4496,6 @@ function StudioDetailView() {
|
|
|
4444
4496
|
}
|
|
4445
4497
|
}
|
|
4446
4498
|
};
|
|
4447
|
-
const handleDelete = async () => {
|
|
4448
|
-
setShowDeleteConfirm(false);
|
|
4449
|
-
try {
|
|
4450
|
-
const response = await fetch("/api/studio/delete", {
|
|
4451
|
-
method: "POST",
|
|
4452
|
-
headers: { "Content-Type": "application/json" },
|
|
4453
|
-
body: JSON.stringify({ paths: [focusedItem.path] })
|
|
4454
|
-
});
|
|
4455
|
-
if (response.ok) {
|
|
4456
|
-
clearSelection();
|
|
4457
|
-
triggerRefresh();
|
|
4458
|
-
setFocusedItem(null);
|
|
4459
|
-
} else {
|
|
4460
|
-
const error = await response.json();
|
|
4461
|
-
setAlertMessage({
|
|
4462
|
-
title: "Delete Failed",
|
|
4463
|
-
message: error.error || "Unknown error"
|
|
4464
|
-
});
|
|
4465
|
-
}
|
|
4466
|
-
} catch (error) {
|
|
4467
|
-
console.error("Delete error:", error);
|
|
4468
|
-
setAlertMessage({
|
|
4469
|
-
title: "Delete Failed",
|
|
4470
|
-
message: "Delete failed. Check console for details."
|
|
4471
|
-
});
|
|
4472
|
-
}
|
|
4473
|
-
};
|
|
4474
|
-
const handleMove = async (destination) => {
|
|
4475
|
-
setShowMoveModal(false);
|
|
4476
|
-
setMoving(true);
|
|
4477
|
-
try {
|
|
4478
|
-
const response = await fetch("/api/studio/move", {
|
|
4479
|
-
method: "POST",
|
|
4480
|
-
headers: { "Content-Type": "application/json" },
|
|
4481
|
-
body: JSON.stringify({ paths: [focusedItem.path], destination })
|
|
4482
|
-
});
|
|
4483
|
-
if (!response.body) {
|
|
4484
|
-
throw new Error("No response body");
|
|
4485
|
-
}
|
|
4486
|
-
const reader = response.body.getReader();
|
|
4487
|
-
const decoder = new TextDecoder();
|
|
4488
|
-
let buffer = "";
|
|
4489
|
-
while (true) {
|
|
4490
|
-
const { done, value } = await reader.read();
|
|
4491
|
-
if (done) break;
|
|
4492
|
-
buffer += decoder.decode(value, { stream: true });
|
|
4493
|
-
const lines = buffer.split("\n\n");
|
|
4494
|
-
buffer = lines.pop() || "";
|
|
4495
|
-
for (const line of lines) {
|
|
4496
|
-
if (!line.startsWith("data: ")) continue;
|
|
4497
|
-
try {
|
|
4498
|
-
const data = JSON.parse(line.slice(6));
|
|
4499
|
-
if (data.type === "complete") {
|
|
4500
|
-
if (data.errors > 0 && _optionalChain([data, 'access', _50 => _50.errorMessages, 'optionalAccess', _51 => _51.length]) > 0) {
|
|
4501
|
-
setAlertMessage({
|
|
4502
|
-
title: "Move Failed",
|
|
4503
|
-
message: data.errorMessages.join("\n")
|
|
4504
|
-
});
|
|
4505
|
-
} else {
|
|
4506
|
-
clearSelection();
|
|
4507
|
-
triggerRefresh();
|
|
4508
|
-
setFocusedItem(null);
|
|
4509
|
-
}
|
|
4510
|
-
} else if (data.type === "error") {
|
|
4511
|
-
setAlertMessage({
|
|
4512
|
-
title: "Move Failed",
|
|
4513
|
-
message: data.message || "Unknown error"
|
|
4514
|
-
});
|
|
4515
|
-
}
|
|
4516
|
-
} catch (e5) {
|
|
4517
|
-
}
|
|
4518
|
-
}
|
|
4519
|
-
}
|
|
4520
|
-
} catch (error) {
|
|
4521
|
-
console.error("Move error:", error);
|
|
4522
|
-
setAlertMessage({
|
|
4523
|
-
title: "Move Failed",
|
|
4524
|
-
message: "Failed to move file. Check console for details."
|
|
4525
|
-
});
|
|
4526
|
-
} finally {
|
|
4527
|
-
setMoving(false);
|
|
4528
|
-
}
|
|
4529
|
-
};
|
|
4530
|
-
const handleSync = async () => {
|
|
4531
|
-
const imageKey = "/" + focusedItem.path.replace(/^public\//, "");
|
|
4532
|
-
setPushing(true);
|
|
4533
|
-
try {
|
|
4534
|
-
const response = await fetch("/api/studio/sync", {
|
|
4535
|
-
method: "POST",
|
|
4536
|
-
headers: { "Content-Type": "application/json" },
|
|
4537
|
-
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
4538
|
-
});
|
|
4539
|
-
const data = await response.json();
|
|
4540
|
-
if (response.ok) {
|
|
4541
|
-
setAlertMessage({
|
|
4542
|
-
title: "Push Complete",
|
|
4543
|
-
message: "Successfully pushed to CDN."
|
|
4544
|
-
});
|
|
4545
|
-
triggerRefresh();
|
|
4546
|
-
} else {
|
|
4547
|
-
if (_optionalChain([data, 'access', _52 => _52.error, 'optionalAccess', _53 => _53.includes, 'call', _54 => _54("R2 not configured")]) || _optionalChain([data, 'access', _55 => _55.error, 'optionalAccess', _56 => _56.includes, 'call', _57 => _57("CLOUDFLARE_R2")])) {
|
|
4548
|
-
setShowR2SetupModal(true);
|
|
4549
|
-
} else {
|
|
4550
|
-
setAlertMessage({
|
|
4551
|
-
title: "Push Failed",
|
|
4552
|
-
message: data.error || "Failed to push to CDN."
|
|
4553
|
-
});
|
|
4554
|
-
}
|
|
4555
|
-
}
|
|
4556
|
-
} catch (error) {
|
|
4557
|
-
console.error("Push error:", error);
|
|
4558
|
-
setAlertMessage({
|
|
4559
|
-
title: "Push Failed",
|
|
4560
|
-
message: "Failed to push to CDN. Check console for details."
|
|
4561
|
-
});
|
|
4562
|
-
} finally {
|
|
4563
|
-
setPushing(false);
|
|
4564
|
-
}
|
|
4565
|
-
};
|
|
4566
|
-
const handleProcessImage = async () => {
|
|
4567
|
-
setShowProcessConfirm(false);
|
|
4568
|
-
setProcessProgress({
|
|
4569
|
-
current: 0,
|
|
4570
|
-
total: 1,
|
|
4571
|
-
percent: 0,
|
|
4572
|
-
status: "processing",
|
|
4573
|
-
currentFile: focusedItem.name
|
|
4574
|
-
});
|
|
4575
|
-
try {
|
|
4576
|
-
const imageKey = focusedItem.path.replace(/^public\//, "");
|
|
4577
|
-
const formattedKey = imageKey.startsWith("/") ? imageKey : `/${imageKey}`;
|
|
4578
|
-
const response = await fetch("/api/studio/reprocess", {
|
|
4579
|
-
method: "POST",
|
|
4580
|
-
headers: { "Content-Type": "application/json" },
|
|
4581
|
-
body: JSON.stringify({
|
|
4582
|
-
imageKeys: [formattedKey]
|
|
4583
|
-
})
|
|
4584
|
-
});
|
|
4585
|
-
const data = await response.json();
|
|
4586
|
-
if (!response.ok) {
|
|
4587
|
-
throw new Error(data.error || "Processing failed");
|
|
4588
|
-
}
|
|
4589
|
-
if (_optionalChain([data, 'access', _58 => _58.processed, 'optionalAccess', _59 => _59.length]) > 0) {
|
|
4590
|
-
setProcessProgress({
|
|
4591
|
-
current: 1,
|
|
4592
|
-
total: 1,
|
|
4593
|
-
percent: 100,
|
|
4594
|
-
status: "complete",
|
|
4595
|
-
message: `Processed ${focusedItem.name}`
|
|
4596
|
-
});
|
|
4597
|
-
} else if (_optionalChain([data, 'access', _60 => _60.errors, 'optionalAccess', _61 => _61.length]) > 0) {
|
|
4598
|
-
setProcessProgress({
|
|
4599
|
-
current: 0,
|
|
4600
|
-
total: 1,
|
|
4601
|
-
percent: 0,
|
|
4602
|
-
status: "error",
|
|
4603
|
-
message: `Failed to process: ${data.errors.join(", ")}`
|
|
4604
|
-
});
|
|
4605
|
-
}
|
|
4606
|
-
triggerRefresh();
|
|
4607
|
-
} catch (error) {
|
|
4608
|
-
console.error("Process error:", error);
|
|
4609
|
-
setProcessProgress({
|
|
4610
|
-
current: 0,
|
|
4611
|
-
total: 1,
|
|
4612
|
-
percent: 0,
|
|
4613
|
-
status: "error",
|
|
4614
|
-
message: error instanceof Error ? error.message : "Failed to process image"
|
|
4615
|
-
});
|
|
4616
|
-
}
|
|
4617
|
-
};
|
|
4618
4499
|
const renderMedia = () => {
|
|
4619
4500
|
if (isImage) {
|
|
4620
4501
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles8.image, src: imageSrc, alt: focusedItem.name });
|
|
@@ -4628,17 +4509,6 @@ function StudioDetailView() {
|
|
|
4628
4509
|
] });
|
|
4629
4510
|
};
|
|
4630
4511
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
4631
|
-
showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
4632
|
-
ConfirmModal,
|
|
4633
|
-
{
|
|
4634
|
-
title: "Delete File",
|
|
4635
|
-
message: `Are you sure you want to delete "${focusedItem.name}"? This action cannot be undone.`,
|
|
4636
|
-
confirmLabel: "Delete",
|
|
4637
|
-
variant: "danger",
|
|
4638
|
-
onConfirm: handleDelete,
|
|
4639
|
-
onCancel: () => setShowDeleteConfirm(false)
|
|
4640
|
-
}
|
|
4641
|
-
),
|
|
4642
4512
|
alertMessage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
4643
4513
|
AlertModal,
|
|
4644
4514
|
{
|
|
@@ -4666,33 +4536,6 @@ function StudioDetailView() {
|
|
|
4666
4536
|
onCancel: () => setShowRenameModal(false)
|
|
4667
4537
|
}
|
|
4668
4538
|
),
|
|
4669
|
-
showMoveModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
4670
|
-
StudioFolderPicker,
|
|
4671
|
-
{
|
|
4672
|
-
selectedItems: /* @__PURE__ */ new Set([focusedItem.path]),
|
|
4673
|
-
currentPath: focusedItem.path.split("/").slice(0, -1).join("/"),
|
|
4674
|
-
onMove: handleMove,
|
|
4675
|
-
onCancel: () => setShowMoveModal(false)
|
|
4676
|
-
}
|
|
4677
|
-
),
|
|
4678
|
-
showProcessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
4679
|
-
ConfirmModal,
|
|
4680
|
-
{
|
|
4681
|
-
title: "Process Image",
|
|
4682
|
-
message: `Generate thumbnails for "${focusedItem.name}"?`,
|
|
4683
|
-
confirmLabel: "Process",
|
|
4684
|
-
onConfirm: handleProcessImage,
|
|
4685
|
-
onCancel: () => setShowProcessConfirm(false)
|
|
4686
|
-
}
|
|
4687
|
-
),
|
|
4688
|
-
processProgress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
4689
|
-
ProgressModal,
|
|
4690
|
-
{
|
|
4691
|
-
title: "Processing Image",
|
|
4692
|
-
progress: processProgress,
|
|
4693
|
-
onClose: () => setProcessProgress(null)
|
|
4694
|
-
}
|
|
4695
|
-
),
|
|
4696
4539
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.container, onClick: (e) => e.stopPropagation(), children: [
|
|
4697
4540
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.main, children: [
|
|
4698
4541
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.headerButtons, children: [
|
|
@@ -4766,11 +4609,11 @@ function StudioDetailView() {
|
|
|
4766
4609
|
"button",
|
|
4767
4610
|
{
|
|
4768
4611
|
css: styles8.actionBtn,
|
|
4769
|
-
onClick: () =>
|
|
4770
|
-
disabled:
|
|
4612
|
+
onClick: () => requestMove([focusedItem.path]),
|
|
4613
|
+
disabled: isActionInProgress || focusedItem.isProtected,
|
|
4771
4614
|
children: [
|
|
4772
4615
|
/* @__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: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) }),
|
|
4773
|
-
|
|
4616
|
+
"Move"
|
|
4774
4617
|
]
|
|
4775
4618
|
}
|
|
4776
4619
|
),
|
|
@@ -4778,12 +4621,12 @@ function StudioDetailView() {
|
|
|
4778
4621
|
"button",
|
|
4779
4622
|
{
|
|
4780
4623
|
css: styles8.actionBtn,
|
|
4781
|
-
onClick:
|
|
4782
|
-
disabled:
|
|
4624
|
+
onClick: () => requestSync([focusedItem.path], fileItems),
|
|
4625
|
+
disabled: isActionInProgress || focusedItem.isProtected || focusedItem.cdnPushed && !focusedItem.isRemote,
|
|
4783
4626
|
title: focusedItem.cdnPushed && !focusedItem.isRemote ? "Already in R2" : void 0,
|
|
4784
4627
|
children: [
|
|
4785
4628
|
/* @__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: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
|
|
4786
|
-
|
|
4629
|
+
"Push to CDN"
|
|
4787
4630
|
]
|
|
4788
4631
|
}
|
|
4789
4632
|
),
|
|
@@ -4791,8 +4634,8 @@ function StudioDetailView() {
|
|
|
4791
4634
|
"button",
|
|
4792
4635
|
{
|
|
4793
4636
|
css: styles8.actionBtn,
|
|
4794
|
-
onClick: () =>
|
|
4795
|
-
disabled: focusedItem.isProtected,
|
|
4637
|
+
onClick: () => requestProcess([focusedItem.path]),
|
|
4638
|
+
disabled: isActionInProgress || focusedItem.isProtected,
|
|
4796
4639
|
children: [
|
|
4797
4640
|
/* @__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: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
4798
4641
|
"Process Image"
|
|
@@ -4803,8 +4646,8 @@ function StudioDetailView() {
|
|
|
4803
4646
|
"button",
|
|
4804
4647
|
{
|
|
4805
4648
|
css: [styles8.actionBtn, styles8.actionBtnDanger],
|
|
4806
|
-
onClick: () =>
|
|
4807
|
-
disabled: focusedItem.isProtected,
|
|
4649
|
+
onClick: () => requestDelete([focusedItem.path]),
|
|
4650
|
+
disabled: isActionInProgress || focusedItem.isProtected,
|
|
4808
4651
|
children: [
|
|
4809
4652
|
/* @__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" }) }),
|
|
4810
4653
|
"Delete"
|
|
@@ -5388,6 +5231,413 @@ function ErrorModal() {
|
|
|
5388
5231
|
] }) });
|
|
5389
5232
|
}
|
|
5390
5233
|
|
|
5234
|
+
// src/components/useStudioActions.tsx
|
|
5235
|
+
|
|
5236
|
+
var defaultActionState2 = {
|
|
5237
|
+
showProgress: false,
|
|
5238
|
+
progressTitle: "",
|
|
5239
|
+
progressState: { current: 0, total: 0, percent: 0, status: "processing" },
|
|
5240
|
+
showDeleteConfirm: false,
|
|
5241
|
+
showMoveModal: false,
|
|
5242
|
+
showSyncConfirm: false,
|
|
5243
|
+
showProcessConfirm: false,
|
|
5244
|
+
actionPaths: [],
|
|
5245
|
+
syncImageCount: 0,
|
|
5246
|
+
syncHasRemote: false,
|
|
5247
|
+
syncHasLocal: false
|
|
5248
|
+
};
|
|
5249
|
+
function useStudioActions({
|
|
5250
|
+
triggerRefresh,
|
|
5251
|
+
clearSelection,
|
|
5252
|
+
setFocusedItem,
|
|
5253
|
+
showError
|
|
5254
|
+
}) {
|
|
5255
|
+
const [actionState, setActionState] = _react.useState.call(void 0, defaultActionState2);
|
|
5256
|
+
const abortControllerRef = _react.useRef.call(void 0, null);
|
|
5257
|
+
const setProgressState = _react.useCallback.call(void 0, (update) => {
|
|
5258
|
+
setActionState((prev) => ({
|
|
5259
|
+
...prev,
|
|
5260
|
+
progressState: typeof update === "function" ? update(prev.progressState) : { ...prev.progressState, ...update }
|
|
5261
|
+
}));
|
|
5262
|
+
}, []);
|
|
5263
|
+
const requestDelete = _react.useCallback.call(void 0, (paths) => {
|
|
5264
|
+
setActionState((prev) => ({
|
|
5265
|
+
...prev,
|
|
5266
|
+
actionPaths: paths,
|
|
5267
|
+
showDeleteConfirm: true
|
|
5268
|
+
}));
|
|
5269
|
+
}, []);
|
|
5270
|
+
const requestMove = _react.useCallback.call(void 0, (paths) => {
|
|
5271
|
+
setActionState((prev) => ({
|
|
5272
|
+
...prev,
|
|
5273
|
+
actionPaths: paths,
|
|
5274
|
+
showMoveModal: true
|
|
5275
|
+
}));
|
|
5276
|
+
}, []);
|
|
5277
|
+
const requestSync = _react.useCallback.call(void 0, (paths, fileItems) => {
|
|
5278
|
+
const imageKeys = paths.map((p) => "/" + p.replace(/^public\//, ""));
|
|
5279
|
+
let hasRemote = false;
|
|
5280
|
+
let hasLocal = false;
|
|
5281
|
+
for (const path of paths) {
|
|
5282
|
+
const item = fileItems.find((f) => f.path === path);
|
|
5283
|
+
if (item) {
|
|
5284
|
+
if (item.isRemote) {
|
|
5285
|
+
hasRemote = true;
|
|
5286
|
+
} else if (!item.cdnPushed) {
|
|
5287
|
+
hasLocal = true;
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5291
|
+
setActionState((prev) => ({
|
|
5292
|
+
...prev,
|
|
5293
|
+
actionPaths: paths,
|
|
5294
|
+
syncImageCount: imageKeys.length,
|
|
5295
|
+
syncHasRemote: hasRemote,
|
|
5296
|
+
syncHasLocal: hasLocal,
|
|
5297
|
+
showSyncConfirm: true
|
|
5298
|
+
}));
|
|
5299
|
+
}, []);
|
|
5300
|
+
const requestProcess = _react.useCallback.call(void 0, (paths) => {
|
|
5301
|
+
setActionState((prev) => ({
|
|
5302
|
+
...prev,
|
|
5303
|
+
actionPaths: paths,
|
|
5304
|
+
showProcessConfirm: true
|
|
5305
|
+
}));
|
|
5306
|
+
}, []);
|
|
5307
|
+
const cancelAction = _react.useCallback.call(void 0, () => {
|
|
5308
|
+
setActionState((prev) => ({
|
|
5309
|
+
...prev,
|
|
5310
|
+
showDeleteConfirm: false,
|
|
5311
|
+
showMoveModal: false,
|
|
5312
|
+
showSyncConfirm: false,
|
|
5313
|
+
showProcessConfirm: false
|
|
5314
|
+
}));
|
|
5315
|
+
}, []);
|
|
5316
|
+
const closeProgress = _react.useCallback.call(void 0, () => {
|
|
5317
|
+
setActionState(defaultActionState2);
|
|
5318
|
+
}, []);
|
|
5319
|
+
const stopProcessing = _react.useCallback.call(void 0, () => {
|
|
5320
|
+
if (abortControllerRef.current) {
|
|
5321
|
+
abortControllerRef.current.abort();
|
|
5322
|
+
}
|
|
5323
|
+
}, []);
|
|
5324
|
+
const confirmDelete = _react.useCallback.call(void 0, async () => {
|
|
5325
|
+
const paths = actionState.actionPaths;
|
|
5326
|
+
setActionState((prev) => ({ ...prev, showDeleteConfirm: false }));
|
|
5327
|
+
try {
|
|
5328
|
+
const response = await fetch("/api/studio/delete", {
|
|
5329
|
+
method: "POST",
|
|
5330
|
+
headers: { "Content-Type": "application/json" },
|
|
5331
|
+
body: JSON.stringify({ paths })
|
|
5332
|
+
});
|
|
5333
|
+
if (response.ok) {
|
|
5334
|
+
clearSelection();
|
|
5335
|
+
setFocusedItem(null);
|
|
5336
|
+
triggerRefresh();
|
|
5337
|
+
} else {
|
|
5338
|
+
const error = await response.json();
|
|
5339
|
+
showError("Delete Failed", error.error || "Unknown error");
|
|
5340
|
+
}
|
|
5341
|
+
} catch (error) {
|
|
5342
|
+
console.error("Delete error:", error);
|
|
5343
|
+
showError("Delete Failed", "Delete failed. Check console for details.");
|
|
5344
|
+
}
|
|
5345
|
+
}, [actionState.actionPaths, clearSelection, setFocusedItem, triggerRefresh, showError]);
|
|
5346
|
+
const confirmMove = _react.useCallback.call(void 0, async (destination) => {
|
|
5347
|
+
const paths = actionState.actionPaths;
|
|
5348
|
+
setActionState((prev) => ({
|
|
5349
|
+
...prev,
|
|
5350
|
+
showMoveModal: false,
|
|
5351
|
+
showProgress: true,
|
|
5352
|
+
progressTitle: "Moving Files",
|
|
5353
|
+
progressState: {
|
|
5354
|
+
current: 0,
|
|
5355
|
+
total: paths.length,
|
|
5356
|
+
percent: 0,
|
|
5357
|
+
status: "processing",
|
|
5358
|
+
message: "Moving files..."
|
|
5359
|
+
}
|
|
5360
|
+
}));
|
|
5361
|
+
try {
|
|
5362
|
+
const response = await fetch("/api/studio/move-stream", {
|
|
5363
|
+
method: "POST",
|
|
5364
|
+
headers: { "Content-Type": "application/json" },
|
|
5365
|
+
body: JSON.stringify({ paths, destination })
|
|
5366
|
+
});
|
|
5367
|
+
if (!response.ok) {
|
|
5368
|
+
const error = await response.json();
|
|
5369
|
+
setProgressState({
|
|
5370
|
+
status: "error",
|
|
5371
|
+
message: error.error || "Move failed"
|
|
5372
|
+
});
|
|
5373
|
+
return;
|
|
5374
|
+
}
|
|
5375
|
+
const reader = _optionalChain([response, 'access', _50 => _50.body, 'optionalAccess', _51 => _51.getReader, 'call', _52 => _52()]);
|
|
5376
|
+
const decoder = new TextDecoder();
|
|
5377
|
+
if (reader) {
|
|
5378
|
+
let buffer = "";
|
|
5379
|
+
while (true) {
|
|
5380
|
+
const { done, value } = await reader.read();
|
|
5381
|
+
if (done) break;
|
|
5382
|
+
buffer += decoder.decode(value, { stream: true });
|
|
5383
|
+
const lines = buffer.split("\n");
|
|
5384
|
+
buffer = lines.pop() || "";
|
|
5385
|
+
for (const line of lines) {
|
|
5386
|
+
if (line.startsWith("data: ")) {
|
|
5387
|
+
try {
|
|
5388
|
+
const data = JSON.parse(line.slice(6));
|
|
5389
|
+
if (data.type === "start") {
|
|
5390
|
+
setProgressState((prev) => ({ ...prev, total: data.total }));
|
|
5391
|
+
} else if (data.type === "progress") {
|
|
5392
|
+
setProgressState({
|
|
5393
|
+
current: data.current,
|
|
5394
|
+
total: data.total,
|
|
5395
|
+
percent: Math.round(data.current / data.total * 100),
|
|
5396
|
+
status: "processing",
|
|
5397
|
+
message: data.message
|
|
5398
|
+
});
|
|
5399
|
+
} else if (data.type === "complete") {
|
|
5400
|
+
setProgressState((prev) => ({
|
|
5401
|
+
...prev,
|
|
5402
|
+
status: "complete",
|
|
5403
|
+
message: `Moved ${data.moved} file${data.moved !== 1 ? "s" : ""}${data.errors > 0 ? `, ${data.errors} error${data.errors !== 1 ? "s" : ""}` : ""}`
|
|
5404
|
+
}));
|
|
5405
|
+
if (data.errors > 0 && _optionalChain([data, 'access', _53 => _53.errorMessages, 'optionalAccess', _54 => _54.length]) > 0) {
|
|
5406
|
+
showError("Move Failed", data.errorMessages.join("\n"));
|
|
5407
|
+
}
|
|
5408
|
+
clearSelection();
|
|
5409
|
+
setFocusedItem(null);
|
|
5410
|
+
triggerRefresh();
|
|
5411
|
+
} else if (data.type === "error") {
|
|
5412
|
+
setProgressState((prev) => ({
|
|
5413
|
+
...prev,
|
|
5414
|
+
status: "error",
|
|
5415
|
+
message: data.message || "Unknown error"
|
|
5416
|
+
}));
|
|
5417
|
+
}
|
|
5418
|
+
} catch (e5) {
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
}
|
|
5424
|
+
} catch (error) {
|
|
5425
|
+
console.error("Move error:", error);
|
|
5426
|
+
setProgressState((prev) => ({
|
|
5427
|
+
...prev,
|
|
5428
|
+
status: "error",
|
|
5429
|
+
message: "Failed to move files. Check console for details."
|
|
5430
|
+
}));
|
|
5431
|
+
}
|
|
5432
|
+
}, [actionState.actionPaths, clearSelection, setFocusedItem, triggerRefresh, showError, setProgressState]);
|
|
5433
|
+
const confirmSync = _react.useCallback.call(void 0, async () => {
|
|
5434
|
+
const paths = actionState.actionPaths;
|
|
5435
|
+
const imageKeys = paths.map((p) => "/" + p.replace(/^public\//, ""));
|
|
5436
|
+
setActionState((prev) => ({
|
|
5437
|
+
...prev,
|
|
5438
|
+
showSyncConfirm: false,
|
|
5439
|
+
showProgress: true,
|
|
5440
|
+
progressTitle: "Pushing to CDN",
|
|
5441
|
+
progressState: {
|
|
5442
|
+
current: 0,
|
|
5443
|
+
total: imageKeys.length,
|
|
5444
|
+
percent: 0,
|
|
5445
|
+
status: "processing",
|
|
5446
|
+
message: "Pushing to CDN..."
|
|
5447
|
+
}
|
|
5448
|
+
}));
|
|
5449
|
+
let pushed = 0;
|
|
5450
|
+
const errors = [];
|
|
5451
|
+
for (let i = 0; i < imageKeys.length; i++) {
|
|
5452
|
+
const imageKey = imageKeys[i];
|
|
5453
|
+
setProgressState({
|
|
5454
|
+
current: i + 1,
|
|
5455
|
+
total: imageKeys.length,
|
|
5456
|
+
percent: Math.round((i + 1) / imageKeys.length * 100),
|
|
5457
|
+
status: "processing",
|
|
5458
|
+
message: `Pushing ${imageKey}...`
|
|
5459
|
+
});
|
|
5460
|
+
try {
|
|
5461
|
+
const response = await fetch("/api/studio/sync", {
|
|
5462
|
+
method: "POST",
|
|
5463
|
+
headers: { "Content-Type": "application/json" },
|
|
5464
|
+
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
5465
|
+
});
|
|
5466
|
+
if (response.ok) {
|
|
5467
|
+
pushed++;
|
|
5468
|
+
} else {
|
|
5469
|
+
const data = await response.json();
|
|
5470
|
+
errors.push(`${imageKey}: ${data.error || "Unknown error"}`);
|
|
5471
|
+
}
|
|
5472
|
+
} catch (error) {
|
|
5473
|
+
errors.push(`${imageKey}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
5476
|
+
setProgressState({
|
|
5477
|
+
current: imageKeys.length,
|
|
5478
|
+
total: imageKeys.length,
|
|
5479
|
+
percent: 100,
|
|
5480
|
+
status: errors.length > 0 ? "error" : "complete",
|
|
5481
|
+
message: `Pushed ${pushed} file${pushed !== 1 ? "s" : ""}${errors.length > 0 ? `, ${errors.length} error${errors.length !== 1 ? "s" : ""}` : ""}`
|
|
5482
|
+
});
|
|
5483
|
+
if (errors.length > 0) {
|
|
5484
|
+
showError("Push Errors", errors.join("\n"));
|
|
5485
|
+
}
|
|
5486
|
+
clearSelection();
|
|
5487
|
+
triggerRefresh();
|
|
5488
|
+
}, [actionState.actionPaths, clearSelection, triggerRefresh, showError, setProgressState]);
|
|
5489
|
+
const confirmProcess = _react.useCallback.call(void 0, async () => {
|
|
5490
|
+
const paths = actionState.actionPaths;
|
|
5491
|
+
const imageKeys = paths.map((p) => "/" + p.replace(/^public\//, ""));
|
|
5492
|
+
setActionState((prev) => ({
|
|
5493
|
+
...prev,
|
|
5494
|
+
showProcessConfirm: false,
|
|
5495
|
+
showProgress: true,
|
|
5496
|
+
progressTitle: "Processing Images",
|
|
5497
|
+
progressState: {
|
|
5498
|
+
current: 0,
|
|
5499
|
+
total: imageKeys.length,
|
|
5500
|
+
percent: 0,
|
|
5501
|
+
status: "processing",
|
|
5502
|
+
message: "Processing images..."
|
|
5503
|
+
}
|
|
5504
|
+
}));
|
|
5505
|
+
abortControllerRef.current = new AbortController();
|
|
5506
|
+
const signal = abortControllerRef.current.signal;
|
|
5507
|
+
try {
|
|
5508
|
+
const response = await fetch("/api/studio/process-stream", {
|
|
5509
|
+
method: "POST",
|
|
5510
|
+
headers: { "Content-Type": "application/json" },
|
|
5511
|
+
body: JSON.stringify({ imageKeys }),
|
|
5512
|
+
signal
|
|
5513
|
+
});
|
|
5514
|
+
if (!response.ok) {
|
|
5515
|
+
const error = await response.json();
|
|
5516
|
+
setProgressState({
|
|
5517
|
+
status: "error",
|
|
5518
|
+
message: error.error || "Processing failed"
|
|
5519
|
+
});
|
|
5520
|
+
return;
|
|
5521
|
+
}
|
|
5522
|
+
const reader = _optionalChain([response, 'access', _55 => _55.body, 'optionalAccess', _56 => _56.getReader, 'call', _57 => _57()]);
|
|
5523
|
+
const decoder = new TextDecoder();
|
|
5524
|
+
if (reader) {
|
|
5525
|
+
let buffer = "";
|
|
5526
|
+
while (true) {
|
|
5527
|
+
const { done, value } = await reader.read();
|
|
5528
|
+
if (done) break;
|
|
5529
|
+
buffer += decoder.decode(value, { stream: true });
|
|
5530
|
+
const lines = buffer.split("\n");
|
|
5531
|
+
buffer = lines.pop() || "";
|
|
5532
|
+
for (const line of lines) {
|
|
5533
|
+
if (line.startsWith("data: ")) {
|
|
5534
|
+
try {
|
|
5535
|
+
const data = JSON.parse(line.slice(6));
|
|
5536
|
+
if (data.type === "start") {
|
|
5537
|
+
setProgressState((prev) => ({
|
|
5538
|
+
...prev,
|
|
5539
|
+
total: data.total
|
|
5540
|
+
}));
|
|
5541
|
+
} else if (data.type === "progress") {
|
|
5542
|
+
setProgressState({
|
|
5543
|
+
current: data.current,
|
|
5544
|
+
total: data.total,
|
|
5545
|
+
percent: Math.round(data.current / data.total * 100),
|
|
5546
|
+
status: "processing",
|
|
5547
|
+
message: data.message
|
|
5548
|
+
});
|
|
5549
|
+
} else if (data.type === "cleanup") {
|
|
5550
|
+
setProgressState((prev) => ({
|
|
5551
|
+
...prev,
|
|
5552
|
+
status: "cleanup",
|
|
5553
|
+
message: data.message
|
|
5554
|
+
}));
|
|
5555
|
+
} else if (data.type === "complete") {
|
|
5556
|
+
setProgressState({
|
|
5557
|
+
current: data.processed,
|
|
5558
|
+
total: data.processed,
|
|
5559
|
+
percent: 100,
|
|
5560
|
+
status: "complete",
|
|
5561
|
+
message: `Processed ${data.processed} image${data.processed !== 1 ? "s" : ""}${data.errors > 0 ? `, ${data.errors} error${data.errors !== 1 ? "s" : ""}` : ""}`
|
|
5562
|
+
});
|
|
5563
|
+
triggerRefresh();
|
|
5564
|
+
} else if (data.type === "error") {
|
|
5565
|
+
setProgressState((prev) => ({
|
|
5566
|
+
...prev,
|
|
5567
|
+
status: "error",
|
|
5568
|
+
message: data.message
|
|
5569
|
+
}));
|
|
5570
|
+
}
|
|
5571
|
+
} catch (e6) {
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
} catch (error) {
|
|
5578
|
+
if (signal.aborted) {
|
|
5579
|
+
setProgressState((prev) => ({
|
|
5580
|
+
...prev,
|
|
5581
|
+
status: "stopped",
|
|
5582
|
+
message: "Processing stopped by user"
|
|
5583
|
+
}));
|
|
5584
|
+
} else {
|
|
5585
|
+
console.error("Processing error:", error);
|
|
5586
|
+
setProgressState({
|
|
5587
|
+
current: 0,
|
|
5588
|
+
total: 0,
|
|
5589
|
+
status: "error",
|
|
5590
|
+
message: "Processing failed. Check console for details."
|
|
5591
|
+
});
|
|
5592
|
+
}
|
|
5593
|
+
} finally {
|
|
5594
|
+
abortControllerRef.current = null;
|
|
5595
|
+
}
|
|
5596
|
+
}, [actionState.actionPaths, triggerRefresh, setProgressState]);
|
|
5597
|
+
const deleteOrphans = _react.useCallback.call(void 0, async () => {
|
|
5598
|
+
const orphanedFiles = actionState.progressState.orphanedFiles;
|
|
5599
|
+
if (!orphanedFiles || orphanedFiles.length === 0) return;
|
|
5600
|
+
try {
|
|
5601
|
+
const response = await fetch("/api/studio/delete-orphans", {
|
|
5602
|
+
method: "POST",
|
|
5603
|
+
headers: { "Content-Type": "application/json" },
|
|
5604
|
+
body: JSON.stringify({ files: orphanedFiles })
|
|
5605
|
+
});
|
|
5606
|
+
if (response.ok) {
|
|
5607
|
+
setProgressState((prev) => ({
|
|
5608
|
+
...prev,
|
|
5609
|
+
orphanedFiles: void 0,
|
|
5610
|
+
message: _optionalChain([prev, 'access', _58 => _58.message, 'optionalAccess', _59 => _59.replace, 'call', _60 => _60(/Found \d+ orphaned thumbnail\(s\).*/, "Orphaned thumbnails deleted.")])
|
|
5611
|
+
}));
|
|
5612
|
+
triggerRefresh();
|
|
5613
|
+
} else {
|
|
5614
|
+
const error = await response.json();
|
|
5615
|
+
showError("Delete Failed", error.error || "Failed to delete orphaned files");
|
|
5616
|
+
}
|
|
5617
|
+
} catch (error) {
|
|
5618
|
+
console.error("Delete orphans error:", error);
|
|
5619
|
+
showError("Delete Failed", "Failed to delete orphaned files. Check console for details.");
|
|
5620
|
+
}
|
|
5621
|
+
}, [actionState.progressState.orphanedFiles, triggerRefresh, showError, setProgressState]);
|
|
5622
|
+
return {
|
|
5623
|
+
actionState,
|
|
5624
|
+
setActionState,
|
|
5625
|
+
abortController: abortControllerRef.current,
|
|
5626
|
+
requestDelete,
|
|
5627
|
+
requestMove,
|
|
5628
|
+
requestSync,
|
|
5629
|
+
requestProcess,
|
|
5630
|
+
cancelAction,
|
|
5631
|
+
closeProgress,
|
|
5632
|
+
stopProcessing,
|
|
5633
|
+
confirmDelete,
|
|
5634
|
+
confirmMove,
|
|
5635
|
+
confirmSync,
|
|
5636
|
+
confirmProcess,
|
|
5637
|
+
deleteOrphans
|
|
5638
|
+
};
|
|
5639
|
+
}
|
|
5640
|
+
|
|
5391
5641
|
// src/components/StudioUI.tsx
|
|
5392
5642
|
|
|
5393
5643
|
var btnHeight3 = "36px";
|
|
@@ -5638,6 +5888,15 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
5638
5888
|
const clearSelection = _react.useCallback.call(void 0, () => {
|
|
5639
5889
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
5640
5890
|
}, []);
|
|
5891
|
+
const setFocusedItemCallback = _react.useCallback.call(void 0, (item) => {
|
|
5892
|
+
setFocusedItem(item);
|
|
5893
|
+
}, []);
|
|
5894
|
+
const actions = useStudioActions({
|
|
5895
|
+
triggerRefresh,
|
|
5896
|
+
clearSelection,
|
|
5897
|
+
setFocusedItem: setFocusedItemCallback,
|
|
5898
|
+
showError
|
|
5899
|
+
});
|
|
5641
5900
|
const handleKeyDown = _react.useCallback.call(void 0,
|
|
5642
5901
|
(e) => {
|
|
5643
5902
|
if (e.key === "Escape") {
|
|
@@ -5698,7 +5957,22 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
5698
5957
|
showError,
|
|
5699
5958
|
clearError,
|
|
5700
5959
|
fileItems,
|
|
5701
|
-
setFileItems
|
|
5960
|
+
setFileItems,
|
|
5961
|
+
// Shared action state and handlers
|
|
5962
|
+
actionState: actions.actionState,
|
|
5963
|
+
requestDelete: actions.requestDelete,
|
|
5964
|
+
requestMove: actions.requestMove,
|
|
5965
|
+
requestSync: actions.requestSync,
|
|
5966
|
+
requestProcess: actions.requestProcess,
|
|
5967
|
+
confirmDelete: actions.confirmDelete,
|
|
5968
|
+
confirmMove: actions.confirmMove,
|
|
5969
|
+
confirmSync: actions.confirmSync,
|
|
5970
|
+
confirmProcess: actions.confirmProcess,
|
|
5971
|
+
cancelAction: actions.cancelAction,
|
|
5972
|
+
closeProgress: actions.closeProgress,
|
|
5973
|
+
stopProcessing: actions.stopProcessing,
|
|
5974
|
+
abortController: actions.abortController,
|
|
5975
|
+
deleteOrphans: actions.deleteOrphans
|
|
5702
5976
|
};
|
|
5703
5977
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.container, children: [
|
|
5704
5978
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.header, children: [
|
|
@@ -5735,7 +6009,57 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
5735
6009
|
}
|
|
5736
6010
|
),
|
|
5737
6011
|
focusedItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {}),
|
|
5738
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ErrorModal, {})
|
|
6012
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ErrorModal, {}),
|
|
6013
|
+
actions.actionState.showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6014
|
+
ConfirmModal,
|
|
6015
|
+
{
|
|
6016
|
+
title: "Delete Files",
|
|
6017
|
+
message: `Are you sure you want to delete ${actions.actionState.actionPaths.length} item${actions.actionState.actionPaths.length !== 1 ? "s" : ""}? This action cannot be undone.`,
|
|
6018
|
+
confirmLabel: "Delete",
|
|
6019
|
+
variant: "danger",
|
|
6020
|
+
onConfirm: actions.confirmDelete,
|
|
6021
|
+
onCancel: actions.cancelAction
|
|
6022
|
+
}
|
|
6023
|
+
),
|
|
6024
|
+
actions.actionState.showSyncConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6025
|
+
ConfirmModal,
|
|
6026
|
+
{
|
|
6027
|
+
title: "Push to CDN",
|
|
6028
|
+
message: `Push ${actions.actionState.syncImageCount} image${actions.actionState.syncImageCount !== 1 ? "s" : ""} to Cloudflare R2?${actions.actionState.syncHasRemote ? " Remote images will be downloaded first." : ""}${actions.actionState.syncHasLocal ? " After pushing, local files will be deleted." : ""}`,
|
|
6029
|
+
confirmLabel: "Push",
|
|
6030
|
+
onConfirm: actions.confirmSync,
|
|
6031
|
+
onCancel: actions.cancelAction
|
|
6032
|
+
}
|
|
6033
|
+
),
|
|
6034
|
+
actions.actionState.showProcessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6035
|
+
ConfirmModal,
|
|
6036
|
+
{
|
|
6037
|
+
title: "Process Images",
|
|
6038
|
+
message: `Generate thumbnails for ${actions.actionState.actionPaths.length} image${actions.actionState.actionPaths.length !== 1 ? "s" : ""}?`,
|
|
6039
|
+
confirmLabel: "Process",
|
|
6040
|
+
onConfirm: actions.confirmProcess,
|
|
6041
|
+
onCancel: actions.cancelAction
|
|
6042
|
+
}
|
|
6043
|
+
),
|
|
6044
|
+
actions.actionState.showMoveModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6045
|
+
StudioFolderPicker,
|
|
6046
|
+
{
|
|
6047
|
+
selectedItems: new Set(actions.actionState.actionPaths),
|
|
6048
|
+
currentPath,
|
|
6049
|
+
onMove: (destination) => actions.confirmMove(destination),
|
|
6050
|
+
onCancel: actions.cancelAction
|
|
6051
|
+
}
|
|
6052
|
+
),
|
|
6053
|
+
actions.actionState.showProgress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
6054
|
+
ProgressModal,
|
|
6055
|
+
{
|
|
6056
|
+
title: actions.actionState.progressTitle,
|
|
6057
|
+
progress: actions.actionState.progressState,
|
|
6058
|
+
onStop: actions.stopProcessing,
|
|
6059
|
+
onDeleteOrphans: actions.deleteOrphans,
|
|
6060
|
+
onClose: actions.closeProgress
|
|
6061
|
+
}
|
|
6062
|
+
)
|
|
5739
6063
|
] }) });
|
|
5740
6064
|
}
|
|
5741
6065
|
function Breadcrumbs({ currentPath, onNavigate }) {
|
|
@@ -5780,4 +6104,4 @@ var StudioUI_default = StudioUI;
|
|
|
5780
6104
|
|
|
5781
6105
|
|
|
5782
6106
|
exports.StudioUI = StudioUI; exports.default = StudioUI_default;
|
|
5783
|
-
//# sourceMappingURL=StudioUI-
|
|
6107
|
+
//# sourceMappingURL=StudioUI-52NHWBVJ.js.map
|