@rebasepro/studio 0.22.0 → 0.24.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/{ApiExplorer-D-jLWAaY.js → ApiExplorer-CCtczj3F.js} +16 -32
- package/dist/ApiExplorer-CCtczj3F.js.map +1 -0
- package/dist/ApiKeysView-B66TdzhH.js +1738 -0
- package/dist/ApiKeysView-B66TdzhH.js.map +1 -0
- package/dist/BackupsView-DmSMzAbT.js +368 -0
- package/dist/BackupsView-DmSMzAbT.js.map +1 -0
- package/dist/{BranchesView-D6Sz1a5f.js → BranchesView-DP1a87E-.js} +12 -8
- package/dist/BranchesView-DP1a87E-.js.map +1 -0
- package/dist/{CronJobsView-JwRjQCde.js → CronJobsView-TDErHTuK.js} +143 -68
- package/dist/CronJobsView-TDErHTuK.js.map +1 -0
- package/dist/{JSEditor-qiuwmcvk.js → JSEditor-B59pwg4c.js} +120 -74
- package/dist/JSEditor-B59pwg4c.js.map +1 -0
- package/dist/{LogsExplorer-Xq8K4oo6.js → LogsExplorer-BKM4yfP8.js} +48 -22
- package/dist/LogsExplorer-BKM4yfP8.js.map +1 -0
- package/dist/{MonacoEditor-D0_QljcX.js → MonacoEditor-CUxy5_k5.js} +11 -9
- package/dist/MonacoEditor-CUxy5_k5.js.map +1 -0
- package/dist/{RLSEditor-B-qrgdHy.js → RLSEditor-BlLLV6xs.js} +350 -98
- package/dist/RLSEditor-BlLLV6xs.js.map +1 -0
- package/dist/{SQLEditor-sdtoZv5F.js → SQLEditor-1An7w0j6.js} +496 -224
- package/dist/SQLEditor-1An7w0j6.js.map +1 -0
- package/dist/{SchemaVisualizer-DtDzIUNy.js → SchemaVisualizer-DCLVfA5t.js} +20 -24
- package/dist/SchemaVisualizer-DCLVfA5t.js.map +1 -0
- package/dist/{StorageView-C52dSZNf.js → StorageView-CbsHuCBf.js} +382 -228
- package/dist/StorageView-CbsHuCBf.js.map +1 -0
- package/dist/components/ApiExplorer/TryItPanel.d.ts +6 -1
- package/dist/components/ApiKeys/CreateApiKeyDialog.d.ts +21 -2
- package/dist/components/ApiKeys/scope-words.d.ts +37 -0
- package/dist/components/ApiKeys/scopes.d.ts +113 -0
- package/dist/components/AuthSimulationSelector.d.ts +5 -1
- package/dist/components/LogsExplorer/useLogTail.d.ts +9 -0
- package/dist/components/RLSEditor/policyListing.d.ts +44 -0
- package/dist/components/RLSEditor/policyRules.d.ts +49 -0
- package/dist/components/SQLEditor/MonacoEditor.d.ts +13 -1
- package/dist/components/SchemaVisualizer/schema-visualizer.utils.d.ts +0 -1
- package/dist/components/SchemaVisualizer/useSchemaGraph.d.ts +6 -0
- package/dist/components/load-failure.d.ts +1 -1
- package/dist/components/useRunAsUsers.d.ts +25 -0
- package/dist/index.es.js +11 -11
- package/dist/{load-failure-C6OMJSGC.js → load-failure-Bd8lFIO7.js} +2 -2
- package/dist/load-failure-Bd8lFIO7.js.map +1 -0
- package/dist/useRunAsUsers-CLaAtXt6.js +122 -0
- package/dist/useRunAsUsers-CLaAtXt6.js.map +1 -0
- package/dist/utils/sql_utils.d.ts +126 -36
- package/package.json +9 -9
- package/dist/ApiExplorer-D-jLWAaY.js.map +0 -1
- package/dist/ApiKeysView-OfJLH2x7.js +0 -1239
- package/dist/ApiKeysView-OfJLH2x7.js.map +0 -1
- package/dist/AuthSimulationSelector-BewmhMBw.js +0 -56
- package/dist/AuthSimulationSelector-BewmhMBw.js.map +0 -1
- package/dist/BackupsView-DYTAD6aW.js +0 -253
- package/dist/BackupsView-DYTAD6aW.js.map +0 -1
- package/dist/BranchesView-D6Sz1a5f.js.map +0 -1
- package/dist/CronJobsView-JwRjQCde.js.map +0 -1
- package/dist/JSEditor-qiuwmcvk.js.map +0 -1
- package/dist/LogsExplorer-Xq8K4oo6.js.map +0 -1
- package/dist/MonacoEditor-D0_QljcX.js.map +0 -1
- package/dist/RLSEditor-B-qrgdHy.js.map +0 -1
- package/dist/SQLEditor-sdtoZv5F.js.map +0 -1
- package/dist/SchemaVisualizer-DtDzIUNy.js.map +0 -1
- package/dist/StorageView-C52dSZNf.js.map +0 -1
- package/dist/components/ApiKeys/permissions.d.ts +0 -66
- package/dist/load-failure-C6OMJSGC.js.map +0 -1
|
@@ -1,12 +1,25 @@
|
|
|
1
|
-
import { t as classifyLoadFailure } from "./load-failure-
|
|
2
|
-
import { ErrorView, useApiBase, useApiConfig, useSnackbarController, useStorageSource, useStorageSources } from "@rebasepro/app";
|
|
1
|
+
import { t as classifyLoadFailure } from "./load-failure-Bd8lFIO7.js";
|
|
2
|
+
import { ErrorView, useApiBase, useApiConfig, useSnackbarController, useStorageSource, useStorageSources, useTranslation } from "@rebasepro/app";
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { ArrowLeftIcon, Button, CheckIcon, Checkbox, Chip, CircularProgress, CopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, FileTextIcon, FileUpload, FolderIcon, FolderPlusIcon, IconButton, ImageIcon, LayoutGridIcon, ListIcon, LoadingButton, Music2Icon, PlusIcon, RefreshCwIcon, Select, SelectItem, TextField, Tooltip, Trash2Icon, Typography, UploadCloudIcon, VideoIcon, XIcon, cls, defaultBorderMixin, iconSize } from "@rebasepro/ui";
|
|
4
|
+
import { ArrowLeftIcon, Button, CheckIcon, Checkbox, Chip, CircularProgress, CopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, FileTextIcon, FileUpload, FolderIcon, FolderPlusIcon, IconButton, ImageIcon, LayoutGridIcon, ListIcon, LoadingButton, Music2Icon, PlusIcon, RefreshCwIcon, Select, SelectItem, TextField, Tooltip, Trash2Icon, Typography, UploadCloudIcon, VideoIcon, XIcon, cls, defaultBorderMixin, iconSize, isKeyHandled } from "@rebasepro/ui";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { useSearchParams } from "react-router";
|
|
7
|
-
import { DEFAULT_STORAGE_SOURCE_KEY } from "@rebasepro/types";
|
|
7
|
+
import { DEFAULT_STORAGE_SOURCE_KEY, isPublicStorageKey } from "@rebasepro/types";
|
|
8
8
|
import { useDropzone } from "react-dropzone";
|
|
9
9
|
//#region src/components/StorageView/StorageView.tsx
|
|
10
|
+
function fileLinkOf(config, fullPath) {
|
|
11
|
+
if (!config.url) return null;
|
|
12
|
+
const metadata = config.metadata;
|
|
13
|
+
return {
|
|
14
|
+
url: config.url,
|
|
15
|
+
expiresInSeconds: metadata?.token && typeof metadata.tokenExpiresIn === "number" ? metadata.tokenExpiresIn : void 0,
|
|
16
|
+
isPublic: metadata ? metadata.public === true : isPublicStorageKey(fullPath)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** A URL the browser can open from anywhere: relative ones are this page's origin's. */
|
|
20
|
+
function absoluteUrl(url) {
|
|
21
|
+
return url.startsWith("http") ? url : `${window.location.origin}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
22
|
+
}
|
|
10
23
|
/**
|
|
11
24
|
* The query parameter holding the folder being browsed.
|
|
12
25
|
*
|
|
@@ -32,14 +45,14 @@ function getExtension(name) {
|
|
|
32
45
|
const parts = name.split(".");
|
|
33
46
|
return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : "";
|
|
34
47
|
}
|
|
35
|
-
function breadcrumbSegments(path) {
|
|
48
|
+
function breadcrumbSegments(path, rootLabel) {
|
|
36
49
|
if (!path || path === "/") return [{
|
|
37
|
-
label:
|
|
50
|
+
label: rootLabel,
|
|
38
51
|
path: ""
|
|
39
52
|
}];
|
|
40
53
|
const parts = path.split("/").filter(Boolean);
|
|
41
54
|
const segments = [{
|
|
42
|
-
label:
|
|
55
|
+
label: rootLabel,
|
|
43
56
|
path: ""
|
|
44
57
|
}];
|
|
45
58
|
let accumulated = "";
|
|
@@ -52,7 +65,43 @@ function breadcrumbSegments(path) {
|
|
|
52
65
|
}
|
|
53
66
|
return segments;
|
|
54
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Everything directly under `prefix`, across every page.
|
|
70
|
+
*
|
|
71
|
+
* A listing answers a page at a time — a thousand entries on the built-in
|
|
72
|
+
* controllers — and hands back a token for the next. Reading only the first
|
|
73
|
+
* showed a large folder cut short, and deleted the first page of it.
|
|
74
|
+
*/
|
|
75
|
+
async function listAllPages(source, prefix) {
|
|
76
|
+
const items = [];
|
|
77
|
+
const prefixes = [];
|
|
78
|
+
let pageToken;
|
|
79
|
+
do {
|
|
80
|
+
const page = pageToken ? await source.listObjects(prefix, { pageToken }) : await source.listObjects(prefix);
|
|
81
|
+
items.push(...page.items ?? []);
|
|
82
|
+
prefixes.push(...page.prefixes ?? []);
|
|
83
|
+
pageToken = page.nextPageToken;
|
|
84
|
+
} while (pageToken);
|
|
85
|
+
return {
|
|
86
|
+
items,
|
|
87
|
+
prefixes
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Delete a folder: every file in it, every folder below it, and the folder
|
|
92
|
+
* itself — the directory on local disk, or the zero-byte `name/` marker that
|
|
93
|
+
* "New folder" writes on S3 and GCS, which no listing shows as an entry.
|
|
94
|
+
*/
|
|
95
|
+
async function deleteFolderRecursive(source, prefix) {
|
|
96
|
+
const { items, prefixes } = await listAllPages(source, prefix);
|
|
97
|
+
for (const item of items) await source.deleteObject(item.fullPath);
|
|
98
|
+
for (const sub of prefixes) await deleteFolderRecursive(source, sub.fullPath);
|
|
99
|
+
try {
|
|
100
|
+
await source.deleteObject(prefix.endsWith("/") ? prefix : `${prefix}/`);
|
|
101
|
+
} catch {}
|
|
102
|
+
}
|
|
55
103
|
function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
104
|
+
const { t } = useTranslation();
|
|
56
105
|
const [uploading, setUploading] = useState(false);
|
|
57
106
|
const [selectedFiles, setSelectedFiles] = useState([]);
|
|
58
107
|
const [error, setError] = useState(null);
|
|
@@ -71,14 +120,15 @@ function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
|
71
120
|
setSelectedFiles([]);
|
|
72
121
|
onClose();
|
|
73
122
|
} catch (err) {
|
|
74
|
-
setError(err instanceof Error ? err.message : "
|
|
123
|
+
setError(err instanceof Error ? err.message : t("studio_storage_upload_failed"));
|
|
75
124
|
} finally {
|
|
76
125
|
setUploading(false);
|
|
77
126
|
}
|
|
78
127
|
}, [
|
|
79
128
|
selectedFiles,
|
|
80
129
|
onUpload,
|
|
81
|
-
onClose
|
|
130
|
+
onClose,
|
|
131
|
+
t
|
|
82
132
|
]);
|
|
83
133
|
const handleClose = useCallback(() => {
|
|
84
134
|
if (!uploading) {
|
|
@@ -92,13 +142,17 @@ function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
|
92
142
|
onOpenChange: (o) => !o && handleClose(),
|
|
93
143
|
maxWidth: "md",
|
|
94
144
|
children: [
|
|
95
|
-
/* @__PURE__ */ jsxs(DialogTitle, { children: ["
|
|
145
|
+
/* @__PURE__ */ jsxs(DialogTitle, { children: [t("studio_storage_upload_dialog_title"), /* @__PURE__ */ jsxs(Typography, {
|
|
96
146
|
variant: "caption",
|
|
97
147
|
className: "text-text-secondary dark:text-text-secondary-dark mt-0.5 block",
|
|
98
|
-
children: [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
148
|
+
children: [
|
|
149
|
+
t("studio_storage_upload_to"),
|
|
150
|
+
" ",
|
|
151
|
+
/* @__PURE__ */ jsxs("span", {
|
|
152
|
+
className: "font-mono text-primary",
|
|
153
|
+
children: ["/", currentPath || t("studio_storage_root_folder")]
|
|
154
|
+
})
|
|
155
|
+
]
|
|
102
156
|
})] }),
|
|
103
157
|
/* @__PURE__ */ jsxs(DialogContent, {
|
|
104
158
|
className: "space-y-4",
|
|
@@ -112,12 +166,12 @@ function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
|
112
166
|
/* @__PURE__ */ jsx(UploadCloudIcon, { className: "text-surface-accent-400 mb-2 w-8 h-8" }),
|
|
113
167
|
/* @__PURE__ */ jsx(Typography, {
|
|
114
168
|
variant: "label",
|
|
115
|
-
children: "
|
|
169
|
+
children: t("studio_storage_drop_or_browse")
|
|
116
170
|
}),
|
|
117
171
|
/* @__PURE__ */ jsx(Typography, {
|
|
118
172
|
variant: "caption",
|
|
119
173
|
color: "secondary",
|
|
120
|
-
children: "
|
|
174
|
+
children: t("studio_storage_any_file_type")
|
|
121
175
|
})
|
|
122
176
|
]
|
|
123
177
|
})
|
|
@@ -129,14 +183,10 @@ function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
|
129
183
|
}),
|
|
130
184
|
selectedFiles.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
131
185
|
className: "space-y-2",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
186
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
133
187
|
variant: "caption",
|
|
134
188
|
color: "secondary",
|
|
135
|
-
children:
|
|
136
|
-
"Selected files (",
|
|
137
|
-
selectedFiles.length,
|
|
138
|
-
")"
|
|
139
|
-
]
|
|
189
|
+
children: t("studio_storage_selected_files", { count: selectedFiles.length })
|
|
140
190
|
}), /* @__PURE__ */ jsx("div", {
|
|
141
191
|
className: "max-h-40 overflow-auto space-y-1",
|
|
142
192
|
children: selectedFiles.map((file, index) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -170,24 +220,45 @@ function UploadDialog({ open, currentPath, onClose, onUpload }) {
|
|
|
170
220
|
variant: "text",
|
|
171
221
|
onClick: handleClose,
|
|
172
222
|
disabled: uploading,
|
|
173
|
-
children: "
|
|
223
|
+
children: t("studio_storage_cancel")
|
|
174
224
|
}), /* @__PURE__ */ jsx(Button, {
|
|
175
225
|
variant: "filled",
|
|
176
226
|
onClick: handleUpload,
|
|
177
227
|
disabled: selectedFiles.length === 0 || uploading,
|
|
178
228
|
startIcon: uploading ? /* @__PURE__ */ jsx(CircularProgress, { size: "smallest" }) : /* @__PURE__ */ jsx(UploadCloudIcon, { size: 14 }),
|
|
179
|
-
children: uploading ? "
|
|
229
|
+
children: uploading ? t("studio_storage_uploading") : selectedFiles.length > 0 ? t("studio_storage_upload_count", { count: selectedFiles.length }) : t("studio_storage_upload")
|
|
180
230
|
})] })
|
|
181
231
|
]
|
|
182
232
|
});
|
|
183
233
|
}
|
|
184
|
-
function FilePreviewPanel({ file, onClose, onDelete,
|
|
234
|
+
function FilePreviewPanel({ file, onClose, onDelete, link, mintLink }) {
|
|
235
|
+
const { t } = useTranslation();
|
|
236
|
+
const snackbarController = useSnackbarController();
|
|
185
237
|
file.contentType?.startsWith("image/");
|
|
186
238
|
file.contentType?.startsWith("video/");
|
|
187
239
|
file.contentType?.startsWith("audio/");
|
|
188
240
|
const FileIconComponent = getFileIcon(file.contentType);
|
|
189
241
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
190
242
|
const [urlCopied, setUrlCopied] = useState(false);
|
|
243
|
+
const reportLinkError = (e) => {
|
|
244
|
+
snackbarController.open({
|
|
245
|
+
type: "error",
|
|
246
|
+
message: e instanceof Error ? e.message : String(e)
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
const handleDownload = () => {
|
|
250
|
+
mintLink().then((fresh) => {
|
|
251
|
+
if (fresh) window.open(fresh.url, "_blank");
|
|
252
|
+
}).catch(reportLinkError);
|
|
253
|
+
};
|
|
254
|
+
const handleCopy = () => {
|
|
255
|
+
mintLink().then(async (fresh) => {
|
|
256
|
+
if (!fresh) return;
|
|
257
|
+
await navigator.clipboard.writeText(absoluteUrl(fresh.url));
|
|
258
|
+
setUrlCopied(true);
|
|
259
|
+
setTimeout(() => setUrlCopied(false), 2e3);
|
|
260
|
+
}).catch(reportLinkError);
|
|
261
|
+
};
|
|
191
262
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
192
263
|
className: cls("flex flex-col h-full border-l", defaultBorderMixin, "bg-surface-card"),
|
|
193
264
|
children: [
|
|
@@ -200,17 +271,19 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
200
271
|
}), /* @__PURE__ */ jsxs("div", {
|
|
201
272
|
className: "flex items-center gap-0.5",
|
|
202
273
|
children: [
|
|
203
|
-
|
|
204
|
-
title: "
|
|
274
|
+
link && /* @__PURE__ */ jsx(Tooltip, {
|
|
275
|
+
title: t("studio_storage_download"),
|
|
205
276
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
277
|
+
"aria-label": t("studio_storage_download"),
|
|
206
278
|
size: "small",
|
|
207
|
-
onClick:
|
|
279
|
+
onClick: handleDownload,
|
|
208
280
|
children: /* @__PURE__ */ jsx(DownloadIcon, { size: iconSize.smallest })
|
|
209
281
|
})
|
|
210
282
|
}),
|
|
211
283
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
212
|
-
title: "
|
|
284
|
+
title: t("studio_storage_delete"),
|
|
213
285
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
286
|
+
"aria-label": t("studio_storage_delete"),
|
|
214
287
|
size: "small",
|
|
215
288
|
onClick: () => setDeleteDialogOpen(true),
|
|
216
289
|
className: "text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20",
|
|
@@ -251,21 +324,21 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
251
324
|
"ogg",
|
|
252
325
|
"m4a"
|
|
253
326
|
].includes(ext);
|
|
254
|
-
const
|
|
255
|
-
if (isImage &&
|
|
256
|
-
src:
|
|
327
|
+
const previewUrl = link?.url;
|
|
328
|
+
if (isImage && previewUrl) return /* @__PURE__ */ jsx("img", {
|
|
329
|
+
src: previewUrl,
|
|
257
330
|
alt: file.name,
|
|
258
331
|
className: "max-w-full max-h-[400px] object-contain rounded-md shadow-sm"
|
|
259
332
|
});
|
|
260
|
-
else if (isVideo &&
|
|
261
|
-
src:
|
|
333
|
+
else if (isVideo && previewUrl) return /* @__PURE__ */ jsx("video", {
|
|
334
|
+
src: previewUrl,
|
|
262
335
|
className: "max-w-full max-h-[400px] rounded-md",
|
|
263
336
|
controls: true
|
|
264
337
|
});
|
|
265
|
-
else if (isAudio &&
|
|
338
|
+
else if (isAudio && previewUrl) return /* @__PURE__ */ jsxs("div", {
|
|
266
339
|
className: "flex flex-col items-center gap-4",
|
|
267
340
|
children: [/* @__PURE__ */ jsx(Music2Icon, { className: "text-surface-accent-400 w-10 h-10" }), /* @__PURE__ */ jsx("audio", {
|
|
268
|
-
src:
|
|
341
|
+
src: previewUrl,
|
|
269
342
|
controls: true,
|
|
270
343
|
className: "w-full max-w-xs"
|
|
271
344
|
})]
|
|
@@ -275,7 +348,7 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
275
348
|
children: [/* @__PURE__ */ jsx(FileIconComponent, { className: "w-10 h-10" }), /* @__PURE__ */ jsx(Typography, {
|
|
276
349
|
variant: "caption",
|
|
277
350
|
className: "text-text-disabled dark:text-text-disabled-dark",
|
|
278
|
-
children: "
|
|
351
|
+
children: t("studio_storage_no_preview")
|
|
279
352
|
})]
|
|
280
353
|
});
|
|
281
354
|
})()
|
|
@@ -287,7 +360,7 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
287
360
|
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Typography, {
|
|
288
361
|
variant: "caption",
|
|
289
362
|
className: "text-text-disabled dark:text-text-disabled-dark text-[10px] uppercase tracking-wider font-semibold mb-1 block",
|
|
290
|
-
children: "
|
|
363
|
+
children: t("studio_storage_file_info")
|
|
291
364
|
}) }),
|
|
292
365
|
/* @__PURE__ */ jsxs("div", {
|
|
293
366
|
className: "grid grid-cols-2 gap-3",
|
|
@@ -295,7 +368,7 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
295
368
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
296
369
|
variant: "caption",
|
|
297
370
|
className: "text-surface-accent-500 text-[11px]",
|
|
298
|
-
children: "
|
|
371
|
+
children: t("studio_storage_name")
|
|
299
372
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
300
373
|
variant: "body2",
|
|
301
374
|
className: "text-[13px] break-all",
|
|
@@ -304,16 +377,16 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
304
377
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
305
378
|
variant: "caption",
|
|
306
379
|
className: "text-surface-accent-500 text-[11px]",
|
|
307
|
-
children: "
|
|
380
|
+
children: t("studio_storage_type")
|
|
308
381
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
309
382
|
variant: "body2",
|
|
310
383
|
className: "text-[13px]",
|
|
311
|
-
children: file.contentType || "
|
|
384
|
+
children: file.contentType || t("studio_storage_type_unknown")
|
|
312
385
|
})] }),
|
|
313
386
|
file.size !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
314
387
|
variant: "caption",
|
|
315
388
|
className: "text-surface-accent-500 text-[11px]",
|
|
316
|
-
children: "
|
|
389
|
+
children: t("studio_storage_size")
|
|
317
390
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
318
391
|
variant: "body2",
|
|
319
392
|
className: "text-[13px]",
|
|
@@ -322,7 +395,7 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
322
395
|
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
323
396
|
variant: "caption",
|
|
324
397
|
className: "text-surface-accent-500 text-[11px]",
|
|
325
|
-
children: "
|
|
398
|
+
children: t("studio_storage_extension")
|
|
326
399
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
327
400
|
variant: "body2",
|
|
328
401
|
className: "text-[13px] font-mono",
|
|
@@ -333,7 +406,7 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
333
406
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
334
407
|
variant: "caption",
|
|
335
408
|
className: "text-surface-accent-500 text-[11px]",
|
|
336
|
-
children: "
|
|
409
|
+
children: t("studio_storage_path")
|
|
337
410
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
338
411
|
variant: "body2",
|
|
339
412
|
className: "text-[13px] font-mono break-all",
|
|
@@ -342,41 +415,47 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
342
415
|
})
|
|
343
416
|
]
|
|
344
417
|
}),
|
|
345
|
-
|
|
418
|
+
link && /* @__PURE__ */ jsxs("div", {
|
|
346
419
|
className: "pt-2",
|
|
347
|
-
children: [
|
|
348
|
-
|
|
349
|
-
className: "text-surface-accent-500 text-[11px] block mb-1",
|
|
350
|
-
children: "URL"
|
|
351
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
352
|
-
className: cls("flex items-center gap-2 p-2 rounded cursor-pointer transition-colors", "bg-surface-raised hover:bg-surface-raised-hover"),
|
|
353
|
-
onClick: () => {
|
|
354
|
-
const fullUrl = downloadUrl.startsWith("http") ? downloadUrl : `${window.location.origin}${downloadUrl.startsWith("/") ? "" : "/"}${downloadUrl}`;
|
|
355
|
-
navigator.clipboard.writeText(fullUrl).then(() => {
|
|
356
|
-
setUrlCopied(true);
|
|
357
|
-
setTimeout(() => setUrlCopied(false), 2e3);
|
|
358
|
-
});
|
|
359
|
-
},
|
|
360
|
-
children: [/* @__PURE__ */ jsx(Typography, {
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
361
422
|
variant: "caption",
|
|
362
|
-
className: "
|
|
363
|
-
children: (
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
children: /* @__PURE__ */ jsx(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
className: "
|
|
423
|
+
className: "text-surface-accent-500 text-[11px] block mb-1",
|
|
424
|
+
children: t("studio_storage_url")
|
|
425
|
+
}),
|
|
426
|
+
/* @__PURE__ */ jsxs("div", {
|
|
427
|
+
className: cls("flex items-center gap-2 p-2 rounded cursor-pointer transition-colors", "bg-surface-raised hover:bg-surface-raised-hover"),
|
|
428
|
+
onClick: handleCopy,
|
|
429
|
+
children: [/* @__PURE__ */ jsx(Typography, {
|
|
430
|
+
variant: "caption",
|
|
431
|
+
className: "font-mono text-[11px] truncate flex-1 min-w-0 text-primary",
|
|
432
|
+
children: absoluteUrl(link.url)
|
|
433
|
+
}), /* @__PURE__ */ jsx(Tooltip, {
|
|
434
|
+
title: urlCopied ? t("studio_storage_url_copied") : t("studio_storage_copy_url"),
|
|
435
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
436
|
+
className: "shrink-0",
|
|
437
|
+
children: urlCopied ? /* @__PURE__ */ jsx(CheckIcon, {
|
|
438
|
+
size: 14,
|
|
439
|
+
className: "text-green-500"
|
|
440
|
+
}) : /* @__PURE__ */ jsx(CopyIcon, {
|
|
441
|
+
size: 14,
|
|
442
|
+
className: "text-surface-accent-400"
|
|
443
|
+
})
|
|
376
444
|
})
|
|
377
|
-
})
|
|
378
|
-
})
|
|
379
|
-
|
|
445
|
+
})]
|
|
446
|
+
}),
|
|
447
|
+
link.isPublic ? /* @__PURE__ */ jsx(Typography, {
|
|
448
|
+
variant: "caption",
|
|
449
|
+
color: "secondary",
|
|
450
|
+
className: "block mt-1 text-[11px]",
|
|
451
|
+
children: t("studio_storage_url_public")
|
|
452
|
+
}) : link.expiresInSeconds !== void 0 ? /* @__PURE__ */ jsx(Typography, {
|
|
453
|
+
variant: "caption",
|
|
454
|
+
color: "secondary",
|
|
455
|
+
className: "block mt-1 text-[11px]",
|
|
456
|
+
children: t("studio_storage_url_temporary", { minutes: Math.max(1, Math.round(link.expiresInSeconds / 60)) })
|
|
457
|
+
}) : null
|
|
458
|
+
]
|
|
380
459
|
})
|
|
381
460
|
]
|
|
382
461
|
})
|
|
@@ -387,24 +466,20 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
387
466
|
children: [
|
|
388
467
|
/* @__PURE__ */ jsx(DialogTitle, {
|
|
389
468
|
hidden: true,
|
|
390
|
-
children: "
|
|
469
|
+
children: t("studio_storage_delete_file_title")
|
|
391
470
|
}),
|
|
392
471
|
/* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(Typography, {
|
|
393
472
|
variant: "subtitle1",
|
|
394
473
|
className: "mb-2",
|
|
395
|
-
children: "
|
|
396
|
-
}), /* @__PURE__ */
|
|
474
|
+
children: t("studio_storage_delete_file_question")
|
|
475
|
+
}), /* @__PURE__ */ jsx(Typography, {
|
|
397
476
|
className: "text-surface-accent-600 dark:text-surface-accent-400",
|
|
398
|
-
children:
|
|
399
|
-
"Are you sure you want to delete \"",
|
|
400
|
-
file.name,
|
|
401
|
-
"\"? This action cannot be undone."
|
|
402
|
-
]
|
|
477
|
+
children: t("studio_storage_delete_file_body", { name: file.name })
|
|
403
478
|
})] }),
|
|
404
479
|
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
405
480
|
variant: "text",
|
|
406
481
|
onClick: () => setDeleteDialogOpen(false),
|
|
407
|
-
children: "
|
|
482
|
+
children: t("studio_storage_cancel")
|
|
408
483
|
}), /* @__PURE__ */ jsx(Button, {
|
|
409
484
|
variant: "filled",
|
|
410
485
|
color: "error",
|
|
@@ -412,12 +487,13 @@ function FilePreviewPanel({ file, onClose, onDelete, downloadUrl }) {
|
|
|
412
487
|
setDeleteDialogOpen(false);
|
|
413
488
|
onDelete();
|
|
414
489
|
},
|
|
415
|
-
children: "
|
|
490
|
+
children: t("studio_storage_delete")
|
|
416
491
|
})] })
|
|
417
492
|
]
|
|
418
493
|
})] });
|
|
419
494
|
}
|
|
420
495
|
var StorageView = () => {
|
|
496
|
+
const { t } = useTranslation();
|
|
421
497
|
const defaultStorageSource = useStorageSource();
|
|
422
498
|
const storageSources = useStorageSources();
|
|
423
499
|
const snackbarController = useSnackbarController();
|
|
@@ -436,7 +512,9 @@ var StorageView = () => {
|
|
|
436
512
|
const [folders, setFolders] = useState([]);
|
|
437
513
|
const [files, setFiles] = useState([]);
|
|
438
514
|
const [selectedFile, setSelectedFile] = useState(null);
|
|
439
|
-
const [
|
|
515
|
+
const [selectedLink, setSelectedLink] = useState(null);
|
|
516
|
+
/** The latest link asked for the preview: an earlier one answering later is dropped. */
|
|
517
|
+
const linkRequestRef = useRef(0);
|
|
440
518
|
const [uploadDialogOpen, setUploadDialogOpen] = useState(false);
|
|
441
519
|
const [viewMode, setViewMode] = useState("grid");
|
|
442
520
|
const [selectedPaths, setSelectedPaths] = useState(/* @__PURE__ */ new Set());
|
|
@@ -453,19 +531,29 @@ var StorageView = () => {
|
|
|
453
531
|
useEffect(() => {
|
|
454
532
|
storageSourceRef.current = storageSource;
|
|
455
533
|
}, [storageSource]);
|
|
534
|
+
/**
|
|
535
|
+
* The latest listing asked for. Only its answer is shown: a listing awaits
|
|
536
|
+
* every file's metadata, so an earlier one — of the source or folder the
|
|
537
|
+
* view has since left — can answer after a later one, and showed that
|
|
538
|
+
* source's files under the one selected, where their actions ran.
|
|
539
|
+
*/
|
|
540
|
+
const listingRequestRef = useRef(0);
|
|
456
541
|
const fetchContents = useCallback(async (path) => {
|
|
542
|
+
const request = ++listingRequestRef.current;
|
|
543
|
+
const isCurrent = () => request === listingRequestRef.current;
|
|
544
|
+
const source = storageSourceRef.current;
|
|
457
545
|
setLoading(true);
|
|
458
546
|
setFailure(null);
|
|
459
547
|
try {
|
|
460
|
-
const result = await
|
|
461
|
-
const folderItems =
|
|
548
|
+
const result = await listAllPages(source, path);
|
|
549
|
+
const folderItems = result.prefixes.map((ref) => ({
|
|
462
550
|
name: ref.name,
|
|
463
551
|
fullPath: ref.fullPath,
|
|
464
552
|
isFolder: true
|
|
465
553
|
}));
|
|
466
|
-
const fileItems = await Promise.all(
|
|
554
|
+
const fileItems = await Promise.all(result.items.map(async (ref) => {
|
|
467
555
|
try {
|
|
468
|
-
const downloadConfig = await
|
|
556
|
+
const downloadConfig = await source.getSignedUrl(ref.fullPath);
|
|
469
557
|
return {
|
|
470
558
|
name: ref.name,
|
|
471
559
|
fullPath: ref.fullPath,
|
|
@@ -482,13 +570,15 @@ var StorageView = () => {
|
|
|
482
570
|
};
|
|
483
571
|
}
|
|
484
572
|
}));
|
|
573
|
+
if (!isCurrent()) return;
|
|
485
574
|
setFolders(folderItems);
|
|
486
575
|
setFiles(fileItems);
|
|
487
576
|
} catch (e) {
|
|
577
|
+
if (!isCurrent()) return;
|
|
488
578
|
console.error("Storage list error:", e);
|
|
489
579
|
setFailure(classifyLoadFailure(e));
|
|
490
580
|
} finally {
|
|
491
|
-
setLoading(false);
|
|
581
|
+
if (isCurrent()) setLoading(false);
|
|
492
582
|
}
|
|
493
583
|
}, []);
|
|
494
584
|
useEffect(() => {
|
|
@@ -498,6 +588,33 @@ var StorageView = () => {
|
|
|
498
588
|
fetchContents,
|
|
499
589
|
selectedSourceKey
|
|
500
590
|
]);
|
|
591
|
+
/** A link to `file`, minted now through the source being browsed — see {@link FileLink}. */
|
|
592
|
+
const mintFileLink = useCallback(async (file) => fileLinkOf(await storageSourceRef.current.getSignedUrl(file.fullPath), file.fullPath), []);
|
|
593
|
+
/** Open `file` in the preview, with a link minted for it now. */
|
|
594
|
+
const openPreview = useCallback((file) => {
|
|
595
|
+
const request = ++linkRequestRef.current;
|
|
596
|
+
setSelectedFile(file);
|
|
597
|
+
setSelectedLink(null);
|
|
598
|
+
mintFileLink(file).then((link) => {
|
|
599
|
+
if (request === linkRequestRef.current) setSelectedLink(link);
|
|
600
|
+
}).catch(() => {
|
|
601
|
+
if (request === linkRequestRef.current) setSelectedLink(null);
|
|
602
|
+
});
|
|
603
|
+
}, [mintFileLink]);
|
|
604
|
+
/** A fresh link to the previewed file, for a download or a copy. It replaces the one shown. */
|
|
605
|
+
const refreshPreviewLink = useCallback(async () => {
|
|
606
|
+
if (!selectedFile) return null;
|
|
607
|
+
const request = ++linkRequestRef.current;
|
|
608
|
+
const link = await mintFileLink(selectedFile);
|
|
609
|
+
if (request === linkRequestRef.current) setSelectedLink(link);
|
|
610
|
+
return link;
|
|
611
|
+
}, [selectedFile, mintFileLink]);
|
|
612
|
+
const clearSelection = useCallback(() => {
|
|
613
|
+
setSelectedFile(null);
|
|
614
|
+
setSelectedLink(null);
|
|
615
|
+
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
616
|
+
lastClickedRef.current = null;
|
|
617
|
+
}, []);
|
|
501
618
|
const handleNavigate = useCallback((path) => {
|
|
502
619
|
setSearchParams((prev) => {
|
|
503
620
|
const next = new URLSearchParams(prev);
|
|
@@ -505,11 +622,12 @@ var StorageView = () => {
|
|
|
505
622
|
else next.delete(STORAGE_PATH_PARAM);
|
|
506
623
|
return next;
|
|
507
624
|
}, { replace: true });
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
625
|
+
clearSelection();
|
|
626
|
+
}, [setSearchParams, clearSelection]);
|
|
627
|
+
const handleSourceChange = useCallback((key) => {
|
|
628
|
+
setSelectedSourceKey(key);
|
|
629
|
+
clearSelection();
|
|
630
|
+
}, [clearSelection]);
|
|
513
631
|
const handleNavigateUp = useCallback(() => {
|
|
514
632
|
const parts = currentPath.split("/").filter(Boolean);
|
|
515
633
|
parts.pop();
|
|
@@ -541,24 +659,17 @@ var StorageView = () => {
|
|
|
541
659
|
} else {
|
|
542
660
|
setSelectedPaths(/* @__PURE__ */ new Set([path]));
|
|
543
661
|
lastClickedRef.current = path;
|
|
544
|
-
if (!item.isFolder)
|
|
545
|
-
|
|
546
|
-
if (item.downloadUrl) setSelectedDownloadUrl(item.downloadUrl);
|
|
547
|
-
else storageSourceRef.current.getSignedUrl(item.fullPath).then((config) => setSelectedDownloadUrl(config.url)).catch(() => setSelectedDownloadUrl(null));
|
|
548
|
-
} else {
|
|
662
|
+
if (!item.isFolder) openPreview(item);
|
|
663
|
+
else {
|
|
549
664
|
setSelectedFile(null);
|
|
550
|
-
|
|
665
|
+
setSelectedLink(null);
|
|
551
666
|
}
|
|
552
667
|
}
|
|
553
|
-
}, [allItems]);
|
|
668
|
+
}, [allItems, openPreview]);
|
|
554
669
|
const handleItemDoubleClick = useCallback((item) => {
|
|
555
670
|
if (item.isFolder) handleNavigate(item.fullPath);
|
|
556
|
-
else
|
|
557
|
-
|
|
558
|
-
if (item.downloadUrl) setSelectedDownloadUrl(item.downloadUrl);
|
|
559
|
-
else storageSourceRef.current.getSignedUrl(item.fullPath).then((config) => setSelectedDownloadUrl(config.url)).catch(() => setSelectedDownloadUrl(null));
|
|
560
|
-
}
|
|
561
|
-
}, [handleNavigate]);
|
|
671
|
+
else openPreview(item);
|
|
672
|
+
}, [handleNavigate, openPreview]);
|
|
562
673
|
const handleUpload = useCallback(async (uploadFiles) => {
|
|
563
674
|
for (const file of uploadFiles) {
|
|
564
675
|
const key = currentPath ? `${currentPath}/${file.name}` : file.name;
|
|
@@ -569,13 +680,14 @@ var StorageView = () => {
|
|
|
569
680
|
}
|
|
570
681
|
snackbarController.open({
|
|
571
682
|
type: "success",
|
|
572
|
-
message:
|
|
683
|
+
message: t("studio_storage_files_uploaded", { count: uploadFiles.length })
|
|
573
684
|
});
|
|
574
685
|
await fetchContents(currentPath);
|
|
575
686
|
}, [
|
|
576
687
|
currentPath,
|
|
577
688
|
snackbarController,
|
|
578
|
-
fetchContents
|
|
689
|
+
fetchContents,
|
|
690
|
+
t
|
|
579
691
|
]);
|
|
580
692
|
const handleCreateFolder = useCallback(async () => {
|
|
581
693
|
if (!newFolderName.trim() || !apiConfig?.apiUrl) return;
|
|
@@ -583,14 +695,14 @@ var StorageView = () => {
|
|
|
583
695
|
if (name.includes("/") || name.includes("\\")) {
|
|
584
696
|
snackbarController.open({
|
|
585
697
|
type: "error",
|
|
586
|
-
message: "
|
|
698
|
+
message: t("studio_storage_folder_name_has_slash")
|
|
587
699
|
});
|
|
588
700
|
return;
|
|
589
701
|
}
|
|
590
702
|
if (folders.find((f) => f.name === name)) {
|
|
591
703
|
snackbarController.open({
|
|
592
704
|
type: "error",
|
|
593
|
-
message:
|
|
705
|
+
message: t("studio_storage_folder_exists", { name })
|
|
594
706
|
});
|
|
595
707
|
return;
|
|
596
708
|
}
|
|
@@ -604,15 +716,18 @@ var StorageView = () => {
|
|
|
604
716
|
"Content-Type": "application/json",
|
|
605
717
|
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
606
718
|
},
|
|
607
|
-
body: JSON.stringify({
|
|
719
|
+
body: JSON.stringify({
|
|
720
|
+
path: folderPath,
|
|
721
|
+
...selectedSourceKey !== DEFAULT_STORAGE_SOURCE_KEY ? { storageId: selectedSourceKey } : {}
|
|
722
|
+
})
|
|
608
723
|
});
|
|
609
724
|
if (!response.ok) {
|
|
610
|
-
const err = await response.json().catch(() => ({ error: "
|
|
611
|
-
throw new Error(err.error || "
|
|
725
|
+
const err = await response.json().catch(() => ({ error: t("studio_storage_create_folder_failed") }));
|
|
726
|
+
throw new Error(err.error || t("studio_storage_create_folder_failed"));
|
|
612
727
|
}
|
|
613
728
|
snackbarController.open({
|
|
614
729
|
type: "success",
|
|
615
|
-
message:
|
|
730
|
+
message: t("studio_storage_folder_created", { name })
|
|
616
731
|
});
|
|
617
732
|
setNewFolderDialogOpen(false);
|
|
618
733
|
setNewFolderName("");
|
|
@@ -632,7 +747,9 @@ var StorageView = () => {
|
|
|
632
747
|
apiBase,
|
|
633
748
|
snackbarController,
|
|
634
749
|
fetchContents,
|
|
635
|
-
folders
|
|
750
|
+
folders,
|
|
751
|
+
selectedSourceKey,
|
|
752
|
+
t
|
|
636
753
|
]);
|
|
637
754
|
const { getRootProps: getDropRootProps, getInputProps: getDropInputProps, isDragActive } = useDropzone({
|
|
638
755
|
onDrop: useCallback(async (droppedFiles) => {
|
|
@@ -647,7 +764,7 @@ var StorageView = () => {
|
|
|
647
764
|
}
|
|
648
765
|
snackbarController.open({
|
|
649
766
|
type: "success",
|
|
650
|
-
message:
|
|
767
|
+
message: t("studio_storage_files_uploaded", { count: droppedFiles.length })
|
|
651
768
|
});
|
|
652
769
|
await fetchContents(currentPath);
|
|
653
770
|
} catch (e) {
|
|
@@ -659,30 +776,51 @@ var StorageView = () => {
|
|
|
659
776
|
}, [
|
|
660
777
|
currentPath,
|
|
661
778
|
snackbarController,
|
|
662
|
-
fetchContents
|
|
779
|
+
fetchContents,
|
|
780
|
+
t
|
|
663
781
|
]),
|
|
664
782
|
noClick: true,
|
|
665
783
|
noKeyboard: true,
|
|
666
784
|
noDragEventsBubbling: true
|
|
667
785
|
});
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
786
|
+
/**
|
|
787
|
+
* Delete files and folders from the source being browsed, then read back
|
|
788
|
+
* the folder they were listed in and return the ones still there.
|
|
789
|
+
*
|
|
790
|
+
* Nothing is reported deleted on the strength of the requests alone: a
|
|
791
|
+
* delete can answer success and leave the object behind — a directory that
|
|
792
|
+
* is not empty yet, a folder marker, a hook — and the folder listing is
|
|
793
|
+
* what the user sees next. One source for the whole operation, taken when
|
|
794
|
+
* it starts.
|
|
795
|
+
*/
|
|
796
|
+
const deleteItems = useCallback(async (items, folder) => {
|
|
797
|
+
const source = storageSourceRef.current;
|
|
798
|
+
for (const item of items) if (item.isFolder) await deleteFolderRecursive(source, item.fullPath);
|
|
799
|
+
else await source.deleteObject(item.fullPath);
|
|
800
|
+
const listed = await listAllPages(source, folder);
|
|
801
|
+
const stillListed = new Set([...listed.items, ...listed.prefixes].map((ref) => ref.fullPath));
|
|
802
|
+
return items.filter((item) => stillListed.has(item.fullPath));
|
|
675
803
|
}, []);
|
|
804
|
+
/** What a delete left behind, said as the error it is rather than a success. */
|
|
805
|
+
const reportStillThere = useCallback((remaining) => {
|
|
806
|
+
snackbarController.open({
|
|
807
|
+
type: "error",
|
|
808
|
+
message: t("studio_storage_delete_incomplete", {
|
|
809
|
+
count: remaining.length,
|
|
810
|
+
names: remaining.map((item) => item.name).join(", ")
|
|
811
|
+
})
|
|
812
|
+
});
|
|
813
|
+
}, [snackbarController, t]);
|
|
676
814
|
const handleDeleteFile = useCallback(async (file) => {
|
|
677
815
|
try {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
snackbarController.open({
|
|
816
|
+
const remaining = await deleteItems([file], currentPath);
|
|
817
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
818
|
+
else snackbarController.open({
|
|
681
819
|
type: "success",
|
|
682
|
-
message:
|
|
820
|
+
message: t("studio_storage_file_deleted", { name: file.name })
|
|
683
821
|
});
|
|
684
822
|
setSelectedFile(null);
|
|
685
|
-
|
|
823
|
+
setSelectedLink(null);
|
|
686
824
|
setSelectedPaths((prev) => {
|
|
687
825
|
const next = new Set(prev);
|
|
688
826
|
next.delete(file.fullPath);
|
|
@@ -699,21 +837,23 @@ var StorageView = () => {
|
|
|
699
837
|
currentPath,
|
|
700
838
|
snackbarController,
|
|
701
839
|
fetchContents,
|
|
702
|
-
|
|
840
|
+
deleteItems,
|
|
841
|
+
reportStillThere,
|
|
842
|
+
t
|
|
703
843
|
]);
|
|
704
844
|
const handleBulkDelete = useCallback(async () => {
|
|
705
845
|
setDeleting(true);
|
|
706
846
|
try {
|
|
707
847
|
const items = allItems.filter((i) => selectedPaths.has(i.fullPath));
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
snackbarController.open({
|
|
848
|
+
const remaining = await deleteItems(items, currentPath);
|
|
849
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
850
|
+
else snackbarController.open({
|
|
711
851
|
type: "success",
|
|
712
|
-
message:
|
|
852
|
+
message: t("studio_storage_items_deleted", { count: items.length })
|
|
713
853
|
});
|
|
714
854
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
715
855
|
setSelectedFile(null);
|
|
716
|
-
|
|
856
|
+
setSelectedLink(null);
|
|
717
857
|
await fetchContents(currentPath);
|
|
718
858
|
} catch (e) {
|
|
719
859
|
snackbarController.open({
|
|
@@ -731,17 +871,24 @@ var StorageView = () => {
|
|
|
731
871
|
currentPath,
|
|
732
872
|
snackbarController,
|
|
733
873
|
fetchContents,
|
|
734
|
-
|
|
874
|
+
deleteItems,
|
|
875
|
+
reportStillThere,
|
|
876
|
+
t
|
|
735
877
|
]);
|
|
736
|
-
const
|
|
878
|
+
const handleConfirmDeleteItem = useCallback(async () => {
|
|
737
879
|
if (!deleteDialogTarget || deleteDialogTarget === "selection") return;
|
|
738
880
|
setDeleting(true);
|
|
739
881
|
try {
|
|
740
|
-
await
|
|
741
|
-
|
|
882
|
+
const remaining = await deleteItems([deleteDialogTarget], currentPath);
|
|
883
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
884
|
+
else snackbarController.open({
|
|
742
885
|
type: "success",
|
|
743
|
-
message:
|
|
886
|
+
message: deleteDialogTarget.isFolder ? t("studio_storage_folder_deleted", { name: deleteDialogTarget.name }) : t("studio_storage_file_deleted", { name: deleteDialogTarget.name })
|
|
744
887
|
});
|
|
888
|
+
if (!deleteDialogTarget.isFolder && selectedFile?.fullPath === deleteDialogTarget.fullPath) {
|
|
889
|
+
setSelectedFile(null);
|
|
890
|
+
setSelectedLink(null);
|
|
891
|
+
}
|
|
745
892
|
setSelectedPaths((prev) => {
|
|
746
893
|
const next = new Set(prev);
|
|
747
894
|
next.delete(deleteDialogTarget.fullPath);
|
|
@@ -760,10 +907,13 @@ var StorageView = () => {
|
|
|
760
907
|
}
|
|
761
908
|
}, [
|
|
762
909
|
deleteDialogTarget,
|
|
910
|
+
selectedFile,
|
|
763
911
|
currentPath,
|
|
764
912
|
snackbarController,
|
|
765
913
|
fetchContents,
|
|
766
|
-
|
|
914
|
+
deleteItems,
|
|
915
|
+
reportStillThere,
|
|
916
|
+
t
|
|
767
917
|
]);
|
|
768
918
|
const handleSelectAll = useCallback(() => {
|
|
769
919
|
if (selectedPaths.size === allItems.length) setSelectedPaths(/* @__PURE__ */ new Set());
|
|
@@ -772,6 +922,7 @@ var StorageView = () => {
|
|
|
772
922
|
useEffect(() => {
|
|
773
923
|
const handler = (e) => {
|
|
774
924
|
if (deleteDialogOpen || uploadDialogOpen || newFolderDialogOpen) return;
|
|
925
|
+
if (isKeyHandled(e)) return;
|
|
775
926
|
if ((e.metaKey || e.ctrlKey) && e.key === "a") {
|
|
776
927
|
e.preventDefault();
|
|
777
928
|
handleSelectAll();
|
|
@@ -779,7 +930,7 @@ var StorageView = () => {
|
|
|
779
930
|
if (e.key === "Escape") {
|
|
780
931
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
781
932
|
setSelectedFile(null);
|
|
782
|
-
|
|
933
|
+
setSelectedLink(null);
|
|
783
934
|
}
|
|
784
935
|
if ((e.key === "Delete" || e.key === "Backspace") && selectedPaths.size > 0 && !e.metaKey && !e.ctrlKey) {
|
|
785
936
|
if (e.target?.tagName === "INPUT" || e.target?.tagName === "TEXTAREA") return;
|
|
@@ -800,7 +951,7 @@ var StorageView = () => {
|
|
|
800
951
|
const handleRefresh = useCallback(() => {
|
|
801
952
|
fetchContents(currentPath);
|
|
802
953
|
}, [currentPath, fetchContents]);
|
|
803
|
-
const segments = breadcrumbSegments(currentPath);
|
|
954
|
+
const segments = breadcrumbSegments(currentPath, t("studio_storage_root"));
|
|
804
955
|
const renderContents = () => {
|
|
805
956
|
if (loading) return /* @__PURE__ */ jsx("div", {
|
|
806
957
|
className: "flex-grow flex items-center justify-center",
|
|
@@ -809,7 +960,7 @@ var StorageView = () => {
|
|
|
809
960
|
children: [/* @__PURE__ */ jsx(CircularProgress, { size: "medium" }), /* @__PURE__ */ jsx(Typography, {
|
|
810
961
|
variant: "body2",
|
|
811
962
|
className: "mt-4 text-text-secondary dark:text-text-secondary-dark font-mono tracking-tight animate-pulse",
|
|
812
|
-
children: "
|
|
963
|
+
children: t("studio_storage_loading")
|
|
813
964
|
})]
|
|
814
965
|
})
|
|
815
966
|
});
|
|
@@ -821,16 +972,12 @@ var StorageView = () => {
|
|
|
821
972
|
/* @__PURE__ */ jsx(Typography, {
|
|
822
973
|
variant: "subtitle2",
|
|
823
974
|
className: "block",
|
|
824
|
-
children: "
|
|
975
|
+
children: t("studio_storage_denied_title")
|
|
825
976
|
}),
|
|
826
|
-
/* @__PURE__ */
|
|
977
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
827
978
|
variant: "body2",
|
|
828
979
|
className: "text-text-secondary dark:text-text-secondary-dark block mt-2",
|
|
829
|
-
children:
|
|
830
|
-
"Nothing is wrong with the project. Its ",
|
|
831
|
-
/* @__PURE__ */ jsx("code", { children: "storageAuthorize" }),
|
|
832
|
-
" hook decides who may read which keys, and it declined this path for the signed-in account — commonly because a listing must name a prefix the rule recognises rather than the bucket root."
|
|
833
|
-
]
|
|
980
|
+
children: t("studio_storage_denied_hint")
|
|
834
981
|
}),
|
|
835
982
|
/* @__PURE__ */ jsx(Typography, {
|
|
836
983
|
variant: "caption",
|
|
@@ -843,7 +990,7 @@ var StorageView = () => {
|
|
|
843
990
|
if (failure) return /* @__PURE__ */ jsx("div", {
|
|
844
991
|
className: "flex-grow flex items-center justify-center p-6 overflow-auto",
|
|
845
992
|
children: /* @__PURE__ */ jsx(ErrorView, {
|
|
846
|
-
title: "
|
|
993
|
+
title: t("studio_storage_read_failed"),
|
|
847
994
|
error: failure.detail,
|
|
848
995
|
onRetry: failure.retryable ? handleRefresh : void 0
|
|
849
996
|
})
|
|
@@ -867,7 +1014,7 @@ var StorageView = () => {
|
|
|
867
1014
|
}),
|
|
868
1015
|
/* @__PURE__ */ jsx(Typography, {
|
|
869
1016
|
variant: "body2",
|
|
870
|
-
children: "
|
|
1017
|
+
children: t("studio_storage_empty")
|
|
871
1018
|
}),
|
|
872
1019
|
/* @__PURE__ */ jsxs("div", {
|
|
873
1020
|
className: "flex items-center gap-2 mt-3",
|
|
@@ -877,10 +1024,10 @@ var StorageView = () => {
|
|
|
877
1024
|
setNewFolderName("");
|
|
878
1025
|
setNewFolderDialogOpen(true);
|
|
879
1026
|
},
|
|
880
|
-
children: [/* @__PURE__ */ jsx(FolderPlusIcon, { size: iconSize.smallest }), "
|
|
1027
|
+
children: [/* @__PURE__ */ jsx(FolderPlusIcon, { size: iconSize.smallest }), t("studio_storage_new_folder")]
|
|
881
1028
|
}), /* @__PURE__ */ jsxs(Button, {
|
|
882
1029
|
onClick: () => setUploadDialogOpen(true),
|
|
883
|
-
children: [/* @__PURE__ */ jsx(PlusIcon, { size: iconSize.smallest }), "
|
|
1030
|
+
children: [/* @__PURE__ */ jsx(PlusIcon, { size: iconSize.smallest }), t("studio_storage_upload_files")]
|
|
884
1031
|
})]
|
|
885
1032
|
})
|
|
886
1033
|
]
|
|
@@ -904,15 +1051,15 @@ var StorageView = () => {
|
|
|
904
1051
|
}),
|
|
905
1052
|
/* @__PURE__ */ jsx("th", {
|
|
906
1053
|
className: "px-2 py-2 font-semibold",
|
|
907
|
-
children: "
|
|
1054
|
+
children: t("studio_storage_name")
|
|
908
1055
|
}),
|
|
909
1056
|
/* @__PURE__ */ jsx("th", {
|
|
910
1057
|
className: "px-4 py-2 font-semibold w-24",
|
|
911
|
-
children: "
|
|
1058
|
+
children: t("studio_storage_type")
|
|
912
1059
|
}),
|
|
913
1060
|
/* @__PURE__ */ jsx("th", {
|
|
914
1061
|
className: "px-4 py-2 font-semibold w-24 text-right",
|
|
915
|
-
children: "
|
|
1062
|
+
children: t("studio_storage_size")
|
|
916
1063
|
}),
|
|
917
1064
|
/* @__PURE__ */ jsx("th", { className: "px-2 py-2 w-10" })
|
|
918
1065
|
]
|
|
@@ -959,7 +1106,7 @@ var StorageView = () => {
|
|
|
959
1106
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
960
1107
|
variant: "caption",
|
|
961
1108
|
className: "text-text-secondary dark:text-text-secondary-dark",
|
|
962
|
-
children: "
|
|
1109
|
+
children: t("studio_storage_folder")
|
|
963
1110
|
})
|
|
964
1111
|
}),
|
|
965
1112
|
/* @__PURE__ */ jsx("td", {
|
|
@@ -1034,7 +1181,10 @@ var StorageView = () => {
|
|
|
1034
1181
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1035
1182
|
size: "smallest",
|
|
1036
1183
|
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1037
|
-
onClick: () =>
|
|
1184
|
+
onClick: () => {
|
|
1185
|
+
setDeleteDialogTarget(file);
|
|
1186
|
+
setDeleteDialogOpen(true);
|
|
1187
|
+
},
|
|
1038
1188
|
children: /* @__PURE__ */ jsx(Trash2Icon, { size: 14 })
|
|
1039
1189
|
})
|
|
1040
1190
|
})
|
|
@@ -1050,7 +1200,7 @@ var StorageView = () => {
|
|
|
1050
1200
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
1051
1201
|
variant: "caption",
|
|
1052
1202
|
className: "text-[10px] uppercase tracking-wider font-semibold text-text-disabled dark:text-text-disabled-dark mb-2 block",
|
|
1053
|
-
children: "
|
|
1203
|
+
children: t("studio_storage_folders")
|
|
1054
1204
|
}), /* @__PURE__ */ jsx("div", {
|
|
1055
1205
|
className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]",
|
|
1056
1206
|
children: folders.map((folder) => {
|
|
@@ -1070,14 +1220,10 @@ var StorageView = () => {
|
|
|
1070
1220
|
}, folder.fullPath);
|
|
1071
1221
|
})
|
|
1072
1222
|
})]
|
|
1073
|
-
}), files.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */
|
|
1223
|
+
}), files.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
1074
1224
|
variant: "caption",
|
|
1075
1225
|
className: "text-[10px] uppercase tracking-wider font-semibold text-text-disabled dark:text-text-disabled-dark mb-2 block",
|
|
1076
|
-
children:
|
|
1077
|
-
"Files (",
|
|
1078
|
-
files.length,
|
|
1079
|
-
")"
|
|
1080
|
-
]
|
|
1226
|
+
children: t("studio_storage_files_heading", { count: files.length })
|
|
1081
1227
|
}), /* @__PURE__ */ jsx("div", {
|
|
1082
1228
|
className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]",
|
|
1083
1229
|
children: files.map((file) => {
|
|
@@ -1139,8 +1285,9 @@ var StorageView = () => {
|
|
|
1139
1285
|
className: "flex items-center gap-1.5 flex-grow overflow-hidden px-3 py-2",
|
|
1140
1286
|
children: [
|
|
1141
1287
|
currentPath && /* @__PURE__ */ jsx(Tooltip, {
|
|
1142
|
-
title: "
|
|
1288
|
+
title: t("studio_storage_go_up"),
|
|
1143
1289
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1290
|
+
"aria-label": t("studio_storage_go_up"),
|
|
1144
1291
|
size: "small",
|
|
1145
1292
|
onClick: handleNavigateUp,
|
|
1146
1293
|
children: /* @__PURE__ */ jsx(ArrowLeftIcon, { size: iconSize.smallest })
|
|
@@ -1164,10 +1311,10 @@ var StorageView = () => {
|
|
|
1164
1311
|
selectedPaths.size > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
1165
1312
|
className: "flex items-center gap-1.5 shrink-0",
|
|
1166
1313
|
children: [
|
|
1167
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
1168
1315
|
variant: "body2",
|
|
1169
1316
|
className: "text-[13px] font-medium whitespace-nowrap",
|
|
1170
|
-
children:
|
|
1317
|
+
children: t("studio_storage_selected_count", { count: selectedPaths.size })
|
|
1171
1318
|
}),
|
|
1172
1319
|
/* @__PURE__ */ jsxs(Button, {
|
|
1173
1320
|
size: "small",
|
|
@@ -1179,7 +1326,7 @@ var StorageView = () => {
|
|
|
1179
1326
|
children: [/* @__PURE__ */ jsx(Trash2Icon, {
|
|
1180
1327
|
size: 14,
|
|
1181
1328
|
className: "mr-1"
|
|
1182
|
-
}), "
|
|
1329
|
+
}), t("studio_storage_delete")]
|
|
1183
1330
|
}),
|
|
1184
1331
|
/* @__PURE__ */ jsxs(Button, {
|
|
1185
1332
|
size: "small",
|
|
@@ -1187,23 +1334,18 @@ var StorageView = () => {
|
|
|
1187
1334
|
onClick: () => {
|
|
1188
1335
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1189
1336
|
setSelectedFile(null);
|
|
1190
|
-
|
|
1337
|
+
setSelectedLink(null);
|
|
1191
1338
|
},
|
|
1192
1339
|
children: [/* @__PURE__ */ jsx(XIcon, {
|
|
1193
1340
|
size: 14,
|
|
1194
1341
|
className: "mr-1"
|
|
1195
|
-
}), "
|
|
1342
|
+
}), t("studio_storage_deselect")]
|
|
1196
1343
|
})
|
|
1197
1344
|
]
|
|
1198
1345
|
}) : !loading ? /* @__PURE__ */ jsxs(Chip, {
|
|
1199
1346
|
size: "small",
|
|
1200
1347
|
className: "shrink-0 text-[10px]",
|
|
1201
|
-
children: [
|
|
1202
|
-
files.length,
|
|
1203
|
-
" file",
|
|
1204
|
-
files.length !== 1 ? "s" : "",
|
|
1205
|
-
folders.length > 0 ? `, ${folders.length} folder${folders.length !== 1 ? "s" : ""}` : ""
|
|
1206
|
-
]
|
|
1348
|
+
children: [t("studio_storage_file_count", { count: files.length }), folders.length > 0 ? `, ${t("studio_storage_folder_count", { count: folders.length })}` : ""]
|
|
1207
1349
|
}) : null
|
|
1208
1350
|
]
|
|
1209
1351
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -1214,19 +1356,20 @@ var StorageView = () => {
|
|
|
1214
1356
|
position: "item-aligned",
|
|
1215
1357
|
value: selectedSourceKey,
|
|
1216
1358
|
onValueChange: (value) => {
|
|
1217
|
-
if (value)
|
|
1359
|
+
if (value && value !== selectedSourceKey) handleSourceChange(value);
|
|
1218
1360
|
},
|
|
1219
1361
|
renderValue: (key) => {
|
|
1220
|
-
return storageSources.registry[key]?.label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? "
|
|
1362
|
+
return storageSources.registry[key]?.label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? t("studio_storage_default_source") : key);
|
|
1221
1363
|
},
|
|
1222
1364
|
children: sourceKeys.map((key) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1223
1365
|
value: key,
|
|
1224
|
-
children: storageSources.registry[key]?.label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? "
|
|
1366
|
+
children: storageSources.registry[key]?.label ?? (key === DEFAULT_STORAGE_SOURCE_KEY ? t("studio_storage_default_source") : key)
|
|
1225
1367
|
}, key))
|
|
1226
1368
|
}),
|
|
1227
1369
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1228
|
-
title: "
|
|
1370
|
+
title: t("studio_storage_grid_view"),
|
|
1229
1371
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1372
|
+
"aria-label": t("studio_storage_grid_view"),
|
|
1230
1373
|
size: "small",
|
|
1231
1374
|
onClick: () => setViewMode("grid"),
|
|
1232
1375
|
className: cls(viewMode === "grid" && "bg-surface-raised"),
|
|
@@ -1234,8 +1377,9 @@ var StorageView = () => {
|
|
|
1234
1377
|
})
|
|
1235
1378
|
}),
|
|
1236
1379
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1237
|
-
title: "
|
|
1380
|
+
title: t("studio_storage_list_view"),
|
|
1238
1381
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1382
|
+
"aria-label": t("studio_storage_list_view"),
|
|
1239
1383
|
size: "small",
|
|
1240
1384
|
onClick: () => setViewMode("list"),
|
|
1241
1385
|
className: cls(viewMode === "list" && "bg-surface-raised"),
|
|
@@ -1244,8 +1388,9 @@ var StorageView = () => {
|
|
|
1244
1388
|
}),
|
|
1245
1389
|
/* @__PURE__ */ jsx("div", { className: cls("h-4 w-px mx-0.5", defaultBorderMixin, "bg-surface-raised") }),
|
|
1246
1390
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1247
|
-
title: "
|
|
1391
|
+
title: t("studio_storage_refresh"),
|
|
1248
1392
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1393
|
+
"aria-label": t("studio_storage_refresh"),
|
|
1249
1394
|
size: "small",
|
|
1250
1395
|
onClick: handleRefresh,
|
|
1251
1396
|
disabled: loading,
|
|
@@ -1253,8 +1398,9 @@ var StorageView = () => {
|
|
|
1253
1398
|
})
|
|
1254
1399
|
}),
|
|
1255
1400
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1256
|
-
title: "
|
|
1401
|
+
title: t("studio_storage_new_folder"),
|
|
1257
1402
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1403
|
+
"aria-label": t("studio_storage_new_folder"),
|
|
1258
1404
|
size: "small",
|
|
1259
1405
|
onClick: () => {
|
|
1260
1406
|
setNewFolderName("");
|
|
@@ -1270,7 +1416,7 @@ var StorageView = () => {
|
|
|
1270
1416
|
children: [/* @__PURE__ */ jsx(UploadCloudIcon, {
|
|
1271
1417
|
size: iconSize.smallest,
|
|
1272
1418
|
className: "mr-1"
|
|
1273
|
-
}), "
|
|
1419
|
+
}), t("studio_storage_upload")]
|
|
1274
1420
|
})
|
|
1275
1421
|
]
|
|
1276
1422
|
})]
|
|
@@ -1282,7 +1428,7 @@ var StorageView = () => {
|
|
|
1282
1428
|
if (!e.target.closest("[data-storage-item]") && selectedPaths.size > 0) {
|
|
1283
1429
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1284
1430
|
setSelectedFile(null);
|
|
1285
|
-
|
|
1431
|
+
setSelectedLink(null);
|
|
1286
1432
|
}
|
|
1287
1433
|
},
|
|
1288
1434
|
children: [
|
|
@@ -1297,12 +1443,16 @@ var StorageView = () => {
|
|
|
1297
1443
|
/* @__PURE__ */ jsx(Typography, {
|
|
1298
1444
|
variant: "subtitle2",
|
|
1299
1445
|
className: "text-primary font-semibold",
|
|
1300
|
-
children: "
|
|
1446
|
+
children: t("studio_storage_drop_to_upload")
|
|
1301
1447
|
}),
|
|
1302
1448
|
/* @__PURE__ */ jsxs(Typography, {
|
|
1303
1449
|
variant: "caption",
|
|
1304
1450
|
color: "secondary",
|
|
1305
|
-
children: [
|
|
1451
|
+
children: [
|
|
1452
|
+
t("studio_storage_upload_to"),
|
|
1453
|
+
" /",
|
|
1454
|
+
currentPath || t("studio_storage_root_folder")
|
|
1455
|
+
]
|
|
1306
1456
|
})
|
|
1307
1457
|
]
|
|
1308
1458
|
})
|
|
@@ -1315,25 +1465,24 @@ var StorageView = () => {
|
|
|
1315
1465
|
className: "flex items-center gap-4 text-[11px]",
|
|
1316
1466
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1317
1467
|
className: "text-text-disabled dark:text-text-disabled-dark font-semibold uppercase tracking-tighter",
|
|
1318
|
-
children: "
|
|
1468
|
+
children: t("studio_storage_path")
|
|
1319
1469
|
}), /* @__PURE__ */ jsxs("span", {
|
|
1320
1470
|
className: "font-mono text-text-secondary dark:text-text-secondary-dark",
|
|
1321
1471
|
children: ["/", currentPath || ""]
|
|
1322
1472
|
})]
|
|
1323
|
-
}), selectedPaths.size > 0 ? /* @__PURE__ */
|
|
1473
|
+
}), selectedPaths.size > 0 ? /* @__PURE__ */ jsx("div", {
|
|
1324
1474
|
className: "text-[11px] text-text-secondary dark:text-text-secondary-dark",
|
|
1325
|
-
children:
|
|
1326
|
-
selectedPaths.size,
|
|
1327
|
-
" item",
|
|
1328
|
-
selectedPaths.size !== 1 ? "s" : "",
|
|
1329
|
-
" selected"
|
|
1330
|
-
]
|
|
1475
|
+
children: t("studio_storage_items_selected", { count: selectedPaths.size })
|
|
1331
1476
|
}) : selectedFile ? /* @__PURE__ */ jsxs("div", {
|
|
1332
1477
|
className: "text-[11px] text-text-secondary dark:text-text-secondary-dark",
|
|
1333
|
-
children: [
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1478
|
+
children: [
|
|
1479
|
+
t("studio_storage_selected_label"),
|
|
1480
|
+
" ",
|
|
1481
|
+
/* @__PURE__ */ jsx("span", {
|
|
1482
|
+
className: "font-mono",
|
|
1483
|
+
children: selectedFile.name
|
|
1484
|
+
})
|
|
1485
|
+
]
|
|
1337
1486
|
}) : null]
|
|
1338
1487
|
})
|
|
1339
1488
|
]
|
|
@@ -1341,10 +1490,11 @@ var StorageView = () => {
|
|
|
1341
1490
|
className: "w-80 lg:w-96 shrink-0",
|
|
1342
1491
|
children: /* @__PURE__ */ jsx(FilePreviewPanel, {
|
|
1343
1492
|
file: selectedFile,
|
|
1344
|
-
|
|
1493
|
+
link: selectedLink,
|
|
1494
|
+
mintLink: refreshPreviewLink,
|
|
1345
1495
|
onClose: () => {
|
|
1346
1496
|
setSelectedFile(null);
|
|
1347
|
-
|
|
1497
|
+
setSelectedLink(null);
|
|
1348
1498
|
},
|
|
1349
1499
|
onDelete: () => handleDeleteFile(selectedFile)
|
|
1350
1500
|
})
|
|
@@ -1367,16 +1517,16 @@ var StorageView = () => {
|
|
|
1367
1517
|
children: [
|
|
1368
1518
|
/* @__PURE__ */ jsx(DialogTitle, {
|
|
1369
1519
|
hidden: true,
|
|
1370
|
-
children: "
|
|
1520
|
+
children: t("studio_storage_delete_confirmation_title")
|
|
1371
1521
|
}),
|
|
1372
1522
|
/* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(Typography, {
|
|
1373
1523
|
variant: "subtitle1",
|
|
1374
1524
|
className: "font-semibold mb-2",
|
|
1375
|
-
children: deleteDialogTarget === "selection" ?
|
|
1525
|
+
children: deleteDialogTarget === "selection" ? t("studio_storage_delete_items_question", { count: selectedPaths.size }) : deleteDialogTarget?.isFolder ? t("studio_storage_delete_folder_question", { name: deleteDialogTarget.name }) : deleteDialogTarget ? t("studio_storage_delete_file_question") : t("studio_storage_delete_question")
|
|
1376
1526
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
1377
1527
|
variant: "body2",
|
|
1378
1528
|
color: "secondary",
|
|
1379
|
-
children: deleteDialogTarget === "selection" ? "
|
|
1529
|
+
children: deleteDialogTarget === "selection" ? t("studio_storage_delete_selection_body") : deleteDialogTarget && !deleteDialogTarget.isFolder ? t("studio_storage_delete_file_body", { name: deleteDialogTarget.name }) : t("studio_storage_delete_folder_body")
|
|
1380
1530
|
})] }),
|
|
1381
1531
|
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
1382
1532
|
variant: "text",
|
|
@@ -1385,15 +1535,15 @@ var StorageView = () => {
|
|
|
1385
1535
|
setDeleteDialogTarget(null);
|
|
1386
1536
|
},
|
|
1387
1537
|
disabled: deleting,
|
|
1388
|
-
children: "
|
|
1538
|
+
children: t("studio_storage_cancel")
|
|
1389
1539
|
}), /* @__PURE__ */ jsxs(LoadingButton, {
|
|
1390
1540
|
color: "error",
|
|
1391
1541
|
loading: deleting,
|
|
1392
|
-
onClick: deleteDialogTarget === "selection" ? handleBulkDelete :
|
|
1542
|
+
onClick: deleteDialogTarget === "selection" ? handleBulkDelete : handleConfirmDeleteItem,
|
|
1393
1543
|
children: [/* @__PURE__ */ jsx(Trash2Icon, {
|
|
1394
1544
|
size: 14,
|
|
1395
1545
|
className: "mr-1"
|
|
1396
|
-
}), "
|
|
1546
|
+
}), t("studio_storage_delete")]
|
|
1397
1547
|
})] })
|
|
1398
1548
|
]
|
|
1399
1549
|
}),
|
|
@@ -1408,12 +1558,12 @@ var StorageView = () => {
|
|
|
1408
1558
|
children: [
|
|
1409
1559
|
/* @__PURE__ */ jsx(DialogTitle, {
|
|
1410
1560
|
hidden: true,
|
|
1411
|
-
children: "
|
|
1561
|
+
children: t("studio_storage_new_folder_title")
|
|
1412
1562
|
}),
|
|
1413
1563
|
/* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(TextField, {
|
|
1414
1564
|
autoFocus: true,
|
|
1415
1565
|
size: "small",
|
|
1416
|
-
label: "
|
|
1566
|
+
label: t("studio_storage_folder_name"),
|
|
1417
1567
|
value: newFolderName,
|
|
1418
1568
|
onChange: (e) => setNewFolderName(e.target.value),
|
|
1419
1569
|
onKeyDown: (e) => {
|
|
@@ -1423,19 +1573,23 @@ var StorageView = () => {
|
|
|
1423
1573
|
}
|
|
1424
1574
|
},
|
|
1425
1575
|
disabled: creatingFolder,
|
|
1426
|
-
placeholder: "
|
|
1576
|
+
placeholder: t("studio_storage_folder_name_placeholder")
|
|
1427
1577
|
}), currentPath && /* @__PURE__ */ jsxs(Typography, {
|
|
1428
1578
|
variant: "caption",
|
|
1429
1579
|
color: "secondary",
|
|
1430
1580
|
className: "mt-2",
|
|
1431
|
-
children: [
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1581
|
+
children: [
|
|
1582
|
+
t("studio_storage_created_in"),
|
|
1583
|
+
" ",
|
|
1584
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1585
|
+
className: "font-mono",
|
|
1586
|
+
children: [
|
|
1587
|
+
"/",
|
|
1588
|
+
currentPath,
|
|
1589
|
+
"/"
|
|
1590
|
+
]
|
|
1591
|
+
})
|
|
1592
|
+
]
|
|
1439
1593
|
})] }),
|
|
1440
1594
|
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
1441
1595
|
variant: "text",
|
|
@@ -1444,7 +1598,7 @@ var StorageView = () => {
|
|
|
1444
1598
|
setNewFolderName("");
|
|
1445
1599
|
},
|
|
1446
1600
|
disabled: creatingFolder,
|
|
1447
|
-
children: "
|
|
1601
|
+
children: t("studio_storage_cancel")
|
|
1448
1602
|
}), /* @__PURE__ */ jsxs(LoadingButton, {
|
|
1449
1603
|
color: "primary",
|
|
1450
1604
|
loading: creatingFolder,
|
|
@@ -1453,7 +1607,7 @@ var StorageView = () => {
|
|
|
1453
1607
|
children: [/* @__PURE__ */ jsx(FolderPlusIcon, {
|
|
1454
1608
|
size: 14,
|
|
1455
1609
|
className: "mr-1"
|
|
1456
|
-
}), "
|
|
1610
|
+
}), t("studio_storage_create")]
|
|
1457
1611
|
})] })
|
|
1458
1612
|
]
|
|
1459
1613
|
})
|
|
@@ -1463,4 +1617,4 @@ var StorageView = () => {
|
|
|
1463
1617
|
//#endregion
|
|
1464
1618
|
export { StorageView };
|
|
1465
1619
|
|
|
1466
|
-
//# sourceMappingURL=StorageView-
|
|
1620
|
+
//# sourceMappingURL=StorageView-CbsHuCBf.js.map
|