@rebasepro/studio 0.23.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-pYMZflL3.js → ApiExplorer-CCtczj3F.js} +15 -28
- 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-7hjgSYId.js → CronJobsView-TDErHTuK.js} +126 -60
- 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/{RLSEditor-Djh43lBE.js → RLSEditor-BlLLV6xs.js} +237 -77
- package/dist/RLSEditor-BlLLV6xs.js.map +1 -0
- package/dist/{SQLEditor-TBw_K6CW.js → SQLEditor-1An7w0j6.js} +369 -294
- 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-CMG1DOVX.js → StorageView-CbsHuCBf.js} +355 -225
- 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/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 +90 -49
- package/package.json +9 -9
- package/dist/ApiExplorer-pYMZflL3.js.map +0 -1
- package/dist/ApiKeysView-qLSs47tw.js +0 -1239
- package/dist/ApiKeysView-qLSs47tw.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-7hjgSYId.js.map +0 -1
- package/dist/JSEditor-qiuwmcvk.js.map +0 -1
- package/dist/LogsExplorer-Xq8K4oo6.js.map +0 -1
- package/dist/RLSEditor-Djh43lBE.js.map +0 -1
- package/dist/SQLEditor-TBw_K6CW.js.map +0 -1
- package/dist/SchemaVisualizer-DtDzIUNy.js.map +0 -1
- package/dist/StorageView-CMG1DOVX.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,9 +588,30 @@ 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]);
|
|
501
612
|
const clearSelection = useCallback(() => {
|
|
502
613
|
setSelectedFile(null);
|
|
503
|
-
|
|
614
|
+
setSelectedLink(null);
|
|
504
615
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
505
616
|
lastClickedRef.current = null;
|
|
506
617
|
}, []);
|
|
@@ -548,24 +659,17 @@ var StorageView = () => {
|
|
|
548
659
|
} else {
|
|
549
660
|
setSelectedPaths(/* @__PURE__ */ new Set([path]));
|
|
550
661
|
lastClickedRef.current = path;
|
|
551
|
-
if (!item.isFolder)
|
|
552
|
-
|
|
553
|
-
if (item.downloadUrl) setSelectedDownloadUrl(item.downloadUrl);
|
|
554
|
-
else storageSourceRef.current.getSignedUrl(item.fullPath).then((config) => setSelectedDownloadUrl(config.url)).catch(() => setSelectedDownloadUrl(null));
|
|
555
|
-
} else {
|
|
662
|
+
if (!item.isFolder) openPreview(item);
|
|
663
|
+
else {
|
|
556
664
|
setSelectedFile(null);
|
|
557
|
-
|
|
665
|
+
setSelectedLink(null);
|
|
558
666
|
}
|
|
559
667
|
}
|
|
560
|
-
}, [allItems]);
|
|
668
|
+
}, [allItems, openPreview]);
|
|
561
669
|
const handleItemDoubleClick = useCallback((item) => {
|
|
562
670
|
if (item.isFolder) handleNavigate(item.fullPath);
|
|
563
|
-
else
|
|
564
|
-
|
|
565
|
-
if (item.downloadUrl) setSelectedDownloadUrl(item.downloadUrl);
|
|
566
|
-
else storageSourceRef.current.getSignedUrl(item.fullPath).then((config) => setSelectedDownloadUrl(config.url)).catch(() => setSelectedDownloadUrl(null));
|
|
567
|
-
}
|
|
568
|
-
}, [handleNavigate]);
|
|
671
|
+
else openPreview(item);
|
|
672
|
+
}, [handleNavigate, openPreview]);
|
|
569
673
|
const handleUpload = useCallback(async (uploadFiles) => {
|
|
570
674
|
for (const file of uploadFiles) {
|
|
571
675
|
const key = currentPath ? `${currentPath}/${file.name}` : file.name;
|
|
@@ -576,13 +680,14 @@ var StorageView = () => {
|
|
|
576
680
|
}
|
|
577
681
|
snackbarController.open({
|
|
578
682
|
type: "success",
|
|
579
|
-
message:
|
|
683
|
+
message: t("studio_storage_files_uploaded", { count: uploadFiles.length })
|
|
580
684
|
});
|
|
581
685
|
await fetchContents(currentPath);
|
|
582
686
|
}, [
|
|
583
687
|
currentPath,
|
|
584
688
|
snackbarController,
|
|
585
|
-
fetchContents
|
|
689
|
+
fetchContents,
|
|
690
|
+
t
|
|
586
691
|
]);
|
|
587
692
|
const handleCreateFolder = useCallback(async () => {
|
|
588
693
|
if (!newFolderName.trim() || !apiConfig?.apiUrl) return;
|
|
@@ -590,14 +695,14 @@ var StorageView = () => {
|
|
|
590
695
|
if (name.includes("/") || name.includes("\\")) {
|
|
591
696
|
snackbarController.open({
|
|
592
697
|
type: "error",
|
|
593
|
-
message: "
|
|
698
|
+
message: t("studio_storage_folder_name_has_slash")
|
|
594
699
|
});
|
|
595
700
|
return;
|
|
596
701
|
}
|
|
597
702
|
if (folders.find((f) => f.name === name)) {
|
|
598
703
|
snackbarController.open({
|
|
599
704
|
type: "error",
|
|
600
|
-
message:
|
|
705
|
+
message: t("studio_storage_folder_exists", { name })
|
|
601
706
|
});
|
|
602
707
|
return;
|
|
603
708
|
}
|
|
@@ -617,12 +722,12 @@ var StorageView = () => {
|
|
|
617
722
|
})
|
|
618
723
|
});
|
|
619
724
|
if (!response.ok) {
|
|
620
|
-
const err = await response.json().catch(() => ({ error: "
|
|
621
|
-
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"));
|
|
622
727
|
}
|
|
623
728
|
snackbarController.open({
|
|
624
729
|
type: "success",
|
|
625
|
-
message:
|
|
730
|
+
message: t("studio_storage_folder_created", { name })
|
|
626
731
|
});
|
|
627
732
|
setNewFolderDialogOpen(false);
|
|
628
733
|
setNewFolderName("");
|
|
@@ -643,7 +748,8 @@ var StorageView = () => {
|
|
|
643
748
|
snackbarController,
|
|
644
749
|
fetchContents,
|
|
645
750
|
folders,
|
|
646
|
-
selectedSourceKey
|
|
751
|
+
selectedSourceKey,
|
|
752
|
+
t
|
|
647
753
|
]);
|
|
648
754
|
const { getRootProps: getDropRootProps, getInputProps: getDropInputProps, isDragActive } = useDropzone({
|
|
649
755
|
onDrop: useCallback(async (droppedFiles) => {
|
|
@@ -658,7 +764,7 @@ var StorageView = () => {
|
|
|
658
764
|
}
|
|
659
765
|
snackbarController.open({
|
|
660
766
|
type: "success",
|
|
661
|
-
message:
|
|
767
|
+
message: t("studio_storage_files_uploaded", { count: droppedFiles.length })
|
|
662
768
|
});
|
|
663
769
|
await fetchContents(currentPath);
|
|
664
770
|
} catch (e) {
|
|
@@ -670,30 +776,51 @@ var StorageView = () => {
|
|
|
670
776
|
}, [
|
|
671
777
|
currentPath,
|
|
672
778
|
snackbarController,
|
|
673
|
-
fetchContents
|
|
779
|
+
fetchContents,
|
|
780
|
+
t
|
|
674
781
|
]),
|
|
675
782
|
noClick: true,
|
|
676
783
|
noKeyboard: true,
|
|
677
784
|
noDragEventsBubbling: true
|
|
678
785
|
});
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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));
|
|
686
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]);
|
|
687
814
|
const handleDeleteFile = useCallback(async (file) => {
|
|
688
815
|
try {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
snackbarController.open({
|
|
816
|
+
const remaining = await deleteItems([file], currentPath);
|
|
817
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
818
|
+
else snackbarController.open({
|
|
692
819
|
type: "success",
|
|
693
|
-
message:
|
|
820
|
+
message: t("studio_storage_file_deleted", { name: file.name })
|
|
694
821
|
});
|
|
695
822
|
setSelectedFile(null);
|
|
696
|
-
|
|
823
|
+
setSelectedLink(null);
|
|
697
824
|
setSelectedPaths((prev) => {
|
|
698
825
|
const next = new Set(prev);
|
|
699
826
|
next.delete(file.fullPath);
|
|
@@ -710,21 +837,23 @@ var StorageView = () => {
|
|
|
710
837
|
currentPath,
|
|
711
838
|
snackbarController,
|
|
712
839
|
fetchContents,
|
|
713
|
-
|
|
840
|
+
deleteItems,
|
|
841
|
+
reportStillThere,
|
|
842
|
+
t
|
|
714
843
|
]);
|
|
715
844
|
const handleBulkDelete = useCallback(async () => {
|
|
716
845
|
setDeleting(true);
|
|
717
846
|
try {
|
|
718
847
|
const items = allItems.filter((i) => selectedPaths.has(i.fullPath));
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
snackbarController.open({
|
|
848
|
+
const remaining = await deleteItems(items, currentPath);
|
|
849
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
850
|
+
else snackbarController.open({
|
|
722
851
|
type: "success",
|
|
723
|
-
message:
|
|
852
|
+
message: t("studio_storage_items_deleted", { count: items.length })
|
|
724
853
|
});
|
|
725
854
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
726
855
|
setSelectedFile(null);
|
|
727
|
-
|
|
856
|
+
setSelectedLink(null);
|
|
728
857
|
await fetchContents(currentPath);
|
|
729
858
|
} catch (e) {
|
|
730
859
|
snackbarController.open({
|
|
@@ -742,21 +871,23 @@ var StorageView = () => {
|
|
|
742
871
|
currentPath,
|
|
743
872
|
snackbarController,
|
|
744
873
|
fetchContents,
|
|
745
|
-
|
|
874
|
+
deleteItems,
|
|
875
|
+
reportStillThere,
|
|
876
|
+
t
|
|
746
877
|
]);
|
|
747
878
|
const handleConfirmDeleteItem = useCallback(async () => {
|
|
748
879
|
if (!deleteDialogTarget || deleteDialogTarget === "selection") return;
|
|
749
880
|
setDeleting(true);
|
|
750
881
|
try {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
snackbarController.open({
|
|
882
|
+
const remaining = await deleteItems([deleteDialogTarget], currentPath);
|
|
883
|
+
if (remaining.length > 0) reportStillThere(remaining);
|
|
884
|
+
else snackbarController.open({
|
|
754
885
|
type: "success",
|
|
755
|
-
message: deleteDialogTarget.isFolder ?
|
|
886
|
+
message: deleteDialogTarget.isFolder ? t("studio_storage_folder_deleted", { name: deleteDialogTarget.name }) : t("studio_storage_file_deleted", { name: deleteDialogTarget.name })
|
|
756
887
|
});
|
|
757
888
|
if (!deleteDialogTarget.isFolder && selectedFile?.fullPath === deleteDialogTarget.fullPath) {
|
|
758
889
|
setSelectedFile(null);
|
|
759
|
-
|
|
890
|
+
setSelectedLink(null);
|
|
760
891
|
}
|
|
761
892
|
setSelectedPaths((prev) => {
|
|
762
893
|
const next = new Set(prev);
|
|
@@ -780,7 +911,9 @@ var StorageView = () => {
|
|
|
780
911
|
currentPath,
|
|
781
912
|
snackbarController,
|
|
782
913
|
fetchContents,
|
|
783
|
-
|
|
914
|
+
deleteItems,
|
|
915
|
+
reportStillThere,
|
|
916
|
+
t
|
|
784
917
|
]);
|
|
785
918
|
const handleSelectAll = useCallback(() => {
|
|
786
919
|
if (selectedPaths.size === allItems.length) setSelectedPaths(/* @__PURE__ */ new Set());
|
|
@@ -789,6 +922,7 @@ var StorageView = () => {
|
|
|
789
922
|
useEffect(() => {
|
|
790
923
|
const handler = (e) => {
|
|
791
924
|
if (deleteDialogOpen || uploadDialogOpen || newFolderDialogOpen) return;
|
|
925
|
+
if (isKeyHandled(e)) return;
|
|
792
926
|
if ((e.metaKey || e.ctrlKey) && e.key === "a") {
|
|
793
927
|
e.preventDefault();
|
|
794
928
|
handleSelectAll();
|
|
@@ -796,7 +930,7 @@ var StorageView = () => {
|
|
|
796
930
|
if (e.key === "Escape") {
|
|
797
931
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
798
932
|
setSelectedFile(null);
|
|
799
|
-
|
|
933
|
+
setSelectedLink(null);
|
|
800
934
|
}
|
|
801
935
|
if ((e.key === "Delete" || e.key === "Backspace") && selectedPaths.size > 0 && !e.metaKey && !e.ctrlKey) {
|
|
802
936
|
if (e.target?.tagName === "INPUT" || e.target?.tagName === "TEXTAREA") return;
|
|
@@ -817,7 +951,7 @@ var StorageView = () => {
|
|
|
817
951
|
const handleRefresh = useCallback(() => {
|
|
818
952
|
fetchContents(currentPath);
|
|
819
953
|
}, [currentPath, fetchContents]);
|
|
820
|
-
const segments = breadcrumbSegments(currentPath);
|
|
954
|
+
const segments = breadcrumbSegments(currentPath, t("studio_storage_root"));
|
|
821
955
|
const renderContents = () => {
|
|
822
956
|
if (loading) return /* @__PURE__ */ jsx("div", {
|
|
823
957
|
className: "flex-grow flex items-center justify-center",
|
|
@@ -826,7 +960,7 @@ var StorageView = () => {
|
|
|
826
960
|
children: [/* @__PURE__ */ jsx(CircularProgress, { size: "medium" }), /* @__PURE__ */ jsx(Typography, {
|
|
827
961
|
variant: "body2",
|
|
828
962
|
className: "mt-4 text-text-secondary dark:text-text-secondary-dark font-mono tracking-tight animate-pulse",
|
|
829
|
-
children: "
|
|
963
|
+
children: t("studio_storage_loading")
|
|
830
964
|
})]
|
|
831
965
|
})
|
|
832
966
|
});
|
|
@@ -838,16 +972,12 @@ var StorageView = () => {
|
|
|
838
972
|
/* @__PURE__ */ jsx(Typography, {
|
|
839
973
|
variant: "subtitle2",
|
|
840
974
|
className: "block",
|
|
841
|
-
children: "
|
|
975
|
+
children: t("studio_storage_denied_title")
|
|
842
976
|
}),
|
|
843
|
-
/* @__PURE__ */
|
|
977
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
844
978
|
variant: "body2",
|
|
845
979
|
className: "text-text-secondary dark:text-text-secondary-dark block mt-2",
|
|
846
|
-
children:
|
|
847
|
-
"Nothing is wrong with the project. Its ",
|
|
848
|
-
/* @__PURE__ */ jsx("code", { children: "storageAuthorize" }),
|
|
849
|
-
" 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."
|
|
850
|
-
]
|
|
980
|
+
children: t("studio_storage_denied_hint")
|
|
851
981
|
}),
|
|
852
982
|
/* @__PURE__ */ jsx(Typography, {
|
|
853
983
|
variant: "caption",
|
|
@@ -860,7 +990,7 @@ var StorageView = () => {
|
|
|
860
990
|
if (failure) return /* @__PURE__ */ jsx("div", {
|
|
861
991
|
className: "flex-grow flex items-center justify-center p-6 overflow-auto",
|
|
862
992
|
children: /* @__PURE__ */ jsx(ErrorView, {
|
|
863
|
-
title: "
|
|
993
|
+
title: t("studio_storage_read_failed"),
|
|
864
994
|
error: failure.detail,
|
|
865
995
|
onRetry: failure.retryable ? handleRefresh : void 0
|
|
866
996
|
})
|
|
@@ -884,7 +1014,7 @@ var StorageView = () => {
|
|
|
884
1014
|
}),
|
|
885
1015
|
/* @__PURE__ */ jsx(Typography, {
|
|
886
1016
|
variant: "body2",
|
|
887
|
-
children: "
|
|
1017
|
+
children: t("studio_storage_empty")
|
|
888
1018
|
}),
|
|
889
1019
|
/* @__PURE__ */ jsxs("div", {
|
|
890
1020
|
className: "flex items-center gap-2 mt-3",
|
|
@@ -894,10 +1024,10 @@ var StorageView = () => {
|
|
|
894
1024
|
setNewFolderName("");
|
|
895
1025
|
setNewFolderDialogOpen(true);
|
|
896
1026
|
},
|
|
897
|
-
children: [/* @__PURE__ */ jsx(FolderPlusIcon, { size: iconSize.smallest }), "
|
|
1027
|
+
children: [/* @__PURE__ */ jsx(FolderPlusIcon, { size: iconSize.smallest }), t("studio_storage_new_folder")]
|
|
898
1028
|
}), /* @__PURE__ */ jsxs(Button, {
|
|
899
1029
|
onClick: () => setUploadDialogOpen(true),
|
|
900
|
-
children: [/* @__PURE__ */ jsx(PlusIcon, { size: iconSize.smallest }), "
|
|
1030
|
+
children: [/* @__PURE__ */ jsx(PlusIcon, { size: iconSize.smallest }), t("studio_storage_upload_files")]
|
|
901
1031
|
})]
|
|
902
1032
|
})
|
|
903
1033
|
]
|
|
@@ -921,15 +1051,15 @@ var StorageView = () => {
|
|
|
921
1051
|
}),
|
|
922
1052
|
/* @__PURE__ */ jsx("th", {
|
|
923
1053
|
className: "px-2 py-2 font-semibold",
|
|
924
|
-
children: "
|
|
1054
|
+
children: t("studio_storage_name")
|
|
925
1055
|
}),
|
|
926
1056
|
/* @__PURE__ */ jsx("th", {
|
|
927
1057
|
className: "px-4 py-2 font-semibold w-24",
|
|
928
|
-
children: "
|
|
1058
|
+
children: t("studio_storage_type")
|
|
929
1059
|
}),
|
|
930
1060
|
/* @__PURE__ */ jsx("th", {
|
|
931
1061
|
className: "px-4 py-2 font-semibold w-24 text-right",
|
|
932
|
-
children: "
|
|
1062
|
+
children: t("studio_storage_size")
|
|
933
1063
|
}),
|
|
934
1064
|
/* @__PURE__ */ jsx("th", { className: "px-2 py-2 w-10" })
|
|
935
1065
|
]
|
|
@@ -976,7 +1106,7 @@ var StorageView = () => {
|
|
|
976
1106
|
children: /* @__PURE__ */ jsx(Typography, {
|
|
977
1107
|
variant: "caption",
|
|
978
1108
|
className: "text-text-secondary dark:text-text-secondary-dark",
|
|
979
|
-
children: "
|
|
1109
|
+
children: t("studio_storage_folder")
|
|
980
1110
|
})
|
|
981
1111
|
}),
|
|
982
1112
|
/* @__PURE__ */ jsx("td", {
|
|
@@ -1070,7 +1200,7 @@ var StorageView = () => {
|
|
|
1070
1200
|
children: [/* @__PURE__ */ jsx(Typography, {
|
|
1071
1201
|
variant: "caption",
|
|
1072
1202
|
className: "text-[10px] uppercase tracking-wider font-semibold text-text-disabled dark:text-text-disabled-dark mb-2 block",
|
|
1073
|
-
children: "
|
|
1203
|
+
children: t("studio_storage_folders")
|
|
1074
1204
|
}), /* @__PURE__ */ jsx("div", {
|
|
1075
1205
|
className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]",
|
|
1076
1206
|
children: folders.map((folder) => {
|
|
@@ -1090,14 +1220,10 @@ var StorageView = () => {
|
|
|
1090
1220
|
}, folder.fullPath);
|
|
1091
1221
|
})
|
|
1092
1222
|
})]
|
|
1093
|
-
}), files.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */
|
|
1223
|
+
}), files.length > 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
|
|
1094
1224
|
variant: "caption",
|
|
1095
1225
|
className: "text-[10px] uppercase tracking-wider font-semibold text-text-disabled dark:text-text-disabled-dark mb-2 block",
|
|
1096
|
-
children:
|
|
1097
|
-
"Files (",
|
|
1098
|
-
files.length,
|
|
1099
|
-
")"
|
|
1100
|
-
]
|
|
1226
|
+
children: t("studio_storage_files_heading", { count: files.length })
|
|
1101
1227
|
}), /* @__PURE__ */ jsx("div", {
|
|
1102
1228
|
className: "grid gap-3 grid-cols-[repeat(auto-fill,minmax(140px,1fr))]",
|
|
1103
1229
|
children: files.map((file) => {
|
|
@@ -1159,8 +1285,9 @@ var StorageView = () => {
|
|
|
1159
1285
|
className: "flex items-center gap-1.5 flex-grow overflow-hidden px-3 py-2",
|
|
1160
1286
|
children: [
|
|
1161
1287
|
currentPath && /* @__PURE__ */ jsx(Tooltip, {
|
|
1162
|
-
title: "
|
|
1288
|
+
title: t("studio_storage_go_up"),
|
|
1163
1289
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1290
|
+
"aria-label": t("studio_storage_go_up"),
|
|
1164
1291
|
size: "small",
|
|
1165
1292
|
onClick: handleNavigateUp,
|
|
1166
1293
|
children: /* @__PURE__ */ jsx(ArrowLeftIcon, { size: iconSize.smallest })
|
|
@@ -1184,10 +1311,10 @@ var StorageView = () => {
|
|
|
1184
1311
|
selectedPaths.size > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
1185
1312
|
className: "flex items-center gap-1.5 shrink-0",
|
|
1186
1313
|
children: [
|
|
1187
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsx(Typography, {
|
|
1188
1315
|
variant: "body2",
|
|
1189
1316
|
className: "text-[13px] font-medium whitespace-nowrap",
|
|
1190
|
-
children:
|
|
1317
|
+
children: t("studio_storage_selected_count", { count: selectedPaths.size })
|
|
1191
1318
|
}),
|
|
1192
1319
|
/* @__PURE__ */ jsxs(Button, {
|
|
1193
1320
|
size: "small",
|
|
@@ -1199,7 +1326,7 @@ var StorageView = () => {
|
|
|
1199
1326
|
children: [/* @__PURE__ */ jsx(Trash2Icon, {
|
|
1200
1327
|
size: 14,
|
|
1201
1328
|
className: "mr-1"
|
|
1202
|
-
}), "
|
|
1329
|
+
}), t("studio_storage_delete")]
|
|
1203
1330
|
}),
|
|
1204
1331
|
/* @__PURE__ */ jsxs(Button, {
|
|
1205
1332
|
size: "small",
|
|
@@ -1207,23 +1334,18 @@ var StorageView = () => {
|
|
|
1207
1334
|
onClick: () => {
|
|
1208
1335
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1209
1336
|
setSelectedFile(null);
|
|
1210
|
-
|
|
1337
|
+
setSelectedLink(null);
|
|
1211
1338
|
},
|
|
1212
1339
|
children: [/* @__PURE__ */ jsx(XIcon, {
|
|
1213
1340
|
size: 14,
|
|
1214
1341
|
className: "mr-1"
|
|
1215
|
-
}), "
|
|
1342
|
+
}), t("studio_storage_deselect")]
|
|
1216
1343
|
})
|
|
1217
1344
|
]
|
|
1218
1345
|
}) : !loading ? /* @__PURE__ */ jsxs(Chip, {
|
|
1219
1346
|
size: "small",
|
|
1220
1347
|
className: "shrink-0 text-[10px]",
|
|
1221
|
-
children: [
|
|
1222
|
-
files.length,
|
|
1223
|
-
" file",
|
|
1224
|
-
files.length !== 1 ? "s" : "",
|
|
1225
|
-
folders.length > 0 ? `, ${folders.length} folder${folders.length !== 1 ? "s" : ""}` : ""
|
|
1226
|
-
]
|
|
1348
|
+
children: [t("studio_storage_file_count", { count: files.length }), folders.length > 0 ? `, ${t("studio_storage_folder_count", { count: folders.length })}` : ""]
|
|
1227
1349
|
}) : null
|
|
1228
1350
|
]
|
|
1229
1351
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -1237,16 +1359,17 @@ var StorageView = () => {
|
|
|
1237
1359
|
if (value && value !== selectedSourceKey) handleSourceChange(value);
|
|
1238
1360
|
},
|
|
1239
1361
|
renderValue: (key) => {
|
|
1240
|
-
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);
|
|
1241
1363
|
},
|
|
1242
1364
|
children: sourceKeys.map((key) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1243
1365
|
value: key,
|
|
1244
|
-
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)
|
|
1245
1367
|
}, key))
|
|
1246
1368
|
}),
|
|
1247
1369
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1248
|
-
title: "
|
|
1370
|
+
title: t("studio_storage_grid_view"),
|
|
1249
1371
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1372
|
+
"aria-label": t("studio_storage_grid_view"),
|
|
1250
1373
|
size: "small",
|
|
1251
1374
|
onClick: () => setViewMode("grid"),
|
|
1252
1375
|
className: cls(viewMode === "grid" && "bg-surface-raised"),
|
|
@@ -1254,8 +1377,9 @@ var StorageView = () => {
|
|
|
1254
1377
|
})
|
|
1255
1378
|
}),
|
|
1256
1379
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1257
|
-
title: "
|
|
1380
|
+
title: t("studio_storage_list_view"),
|
|
1258
1381
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1382
|
+
"aria-label": t("studio_storage_list_view"),
|
|
1259
1383
|
size: "small",
|
|
1260
1384
|
onClick: () => setViewMode("list"),
|
|
1261
1385
|
className: cls(viewMode === "list" && "bg-surface-raised"),
|
|
@@ -1264,8 +1388,9 @@ var StorageView = () => {
|
|
|
1264
1388
|
}),
|
|
1265
1389
|
/* @__PURE__ */ jsx("div", { className: cls("h-4 w-px mx-0.5", defaultBorderMixin, "bg-surface-raised") }),
|
|
1266
1390
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1267
|
-
title: "
|
|
1391
|
+
title: t("studio_storage_refresh"),
|
|
1268
1392
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1393
|
+
"aria-label": t("studio_storage_refresh"),
|
|
1269
1394
|
size: "small",
|
|
1270
1395
|
onClick: handleRefresh,
|
|
1271
1396
|
disabled: loading,
|
|
@@ -1273,8 +1398,9 @@ var StorageView = () => {
|
|
|
1273
1398
|
})
|
|
1274
1399
|
}),
|
|
1275
1400
|
/* @__PURE__ */ jsx(Tooltip, {
|
|
1276
|
-
title: "
|
|
1401
|
+
title: t("studio_storage_new_folder"),
|
|
1277
1402
|
children: /* @__PURE__ */ jsx(IconButton, {
|
|
1403
|
+
"aria-label": t("studio_storage_new_folder"),
|
|
1278
1404
|
size: "small",
|
|
1279
1405
|
onClick: () => {
|
|
1280
1406
|
setNewFolderName("");
|
|
@@ -1290,7 +1416,7 @@ var StorageView = () => {
|
|
|
1290
1416
|
children: [/* @__PURE__ */ jsx(UploadCloudIcon, {
|
|
1291
1417
|
size: iconSize.smallest,
|
|
1292
1418
|
className: "mr-1"
|
|
1293
|
-
}), "
|
|
1419
|
+
}), t("studio_storage_upload")]
|
|
1294
1420
|
})
|
|
1295
1421
|
]
|
|
1296
1422
|
})]
|
|
@@ -1302,7 +1428,7 @@ var StorageView = () => {
|
|
|
1302
1428
|
if (!e.target.closest("[data-storage-item]") && selectedPaths.size > 0) {
|
|
1303
1429
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1304
1430
|
setSelectedFile(null);
|
|
1305
|
-
|
|
1431
|
+
setSelectedLink(null);
|
|
1306
1432
|
}
|
|
1307
1433
|
},
|
|
1308
1434
|
children: [
|
|
@@ -1317,12 +1443,16 @@ var StorageView = () => {
|
|
|
1317
1443
|
/* @__PURE__ */ jsx(Typography, {
|
|
1318
1444
|
variant: "subtitle2",
|
|
1319
1445
|
className: "text-primary font-semibold",
|
|
1320
|
-
children: "
|
|
1446
|
+
children: t("studio_storage_drop_to_upload")
|
|
1321
1447
|
}),
|
|
1322
1448
|
/* @__PURE__ */ jsxs(Typography, {
|
|
1323
1449
|
variant: "caption",
|
|
1324
1450
|
color: "secondary",
|
|
1325
|
-
children: [
|
|
1451
|
+
children: [
|
|
1452
|
+
t("studio_storage_upload_to"),
|
|
1453
|
+
" /",
|
|
1454
|
+
currentPath || t("studio_storage_root_folder")
|
|
1455
|
+
]
|
|
1326
1456
|
})
|
|
1327
1457
|
]
|
|
1328
1458
|
})
|
|
@@ -1335,25 +1465,24 @@ var StorageView = () => {
|
|
|
1335
1465
|
className: "flex items-center gap-4 text-[11px]",
|
|
1336
1466
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1337
1467
|
className: "text-text-disabled dark:text-text-disabled-dark font-semibold uppercase tracking-tighter",
|
|
1338
|
-
children: "
|
|
1468
|
+
children: t("studio_storage_path")
|
|
1339
1469
|
}), /* @__PURE__ */ jsxs("span", {
|
|
1340
1470
|
className: "font-mono text-text-secondary dark:text-text-secondary-dark",
|
|
1341
1471
|
children: ["/", currentPath || ""]
|
|
1342
1472
|
})]
|
|
1343
|
-
}), selectedPaths.size > 0 ? /* @__PURE__ */
|
|
1473
|
+
}), selectedPaths.size > 0 ? /* @__PURE__ */ jsx("div", {
|
|
1344
1474
|
className: "text-[11px] text-text-secondary dark:text-text-secondary-dark",
|
|
1345
|
-
children:
|
|
1346
|
-
selectedPaths.size,
|
|
1347
|
-
" item",
|
|
1348
|
-
selectedPaths.size !== 1 ? "s" : "",
|
|
1349
|
-
" selected"
|
|
1350
|
-
]
|
|
1475
|
+
children: t("studio_storage_items_selected", { count: selectedPaths.size })
|
|
1351
1476
|
}) : selectedFile ? /* @__PURE__ */ jsxs("div", {
|
|
1352
1477
|
className: "text-[11px] text-text-secondary dark:text-text-secondary-dark",
|
|
1353
|
-
children: [
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1478
|
+
children: [
|
|
1479
|
+
t("studio_storage_selected_label"),
|
|
1480
|
+
" ",
|
|
1481
|
+
/* @__PURE__ */ jsx("span", {
|
|
1482
|
+
className: "font-mono",
|
|
1483
|
+
children: selectedFile.name
|
|
1484
|
+
})
|
|
1485
|
+
]
|
|
1357
1486
|
}) : null]
|
|
1358
1487
|
})
|
|
1359
1488
|
]
|
|
@@ -1361,10 +1490,11 @@ var StorageView = () => {
|
|
|
1361
1490
|
className: "w-80 lg:w-96 shrink-0",
|
|
1362
1491
|
children: /* @__PURE__ */ jsx(FilePreviewPanel, {
|
|
1363
1492
|
file: selectedFile,
|
|
1364
|
-
|
|
1493
|
+
link: selectedLink,
|
|
1494
|
+
mintLink: refreshPreviewLink,
|
|
1365
1495
|
onClose: () => {
|
|
1366
1496
|
setSelectedFile(null);
|
|
1367
|
-
|
|
1497
|
+
setSelectedLink(null);
|
|
1368
1498
|
},
|
|
1369
1499
|
onDelete: () => handleDeleteFile(selectedFile)
|
|
1370
1500
|
})
|
|
@@ -1387,20 +1517,16 @@ var StorageView = () => {
|
|
|
1387
1517
|
children: [
|
|
1388
1518
|
/* @__PURE__ */ jsx(DialogTitle, {
|
|
1389
1519
|
hidden: true,
|
|
1390
|
-
children: "
|
|
1520
|
+
children: t("studio_storage_delete_confirmation_title")
|
|
1391
1521
|
}),
|
|
1392
1522
|
/* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(Typography, {
|
|
1393
1523
|
variant: "subtitle1",
|
|
1394
1524
|
className: "font-semibold mb-2",
|
|
1395
|
-
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")
|
|
1396
1526
|
}), /* @__PURE__ */ jsx(Typography, {
|
|
1397
1527
|
variant: "body2",
|
|
1398
1528
|
color: "secondary",
|
|
1399
|
-
children: deleteDialogTarget === "selection" ? "
|
|
1400
|
-
"Are you sure you want to delete \"",
|
|
1401
|
-
deleteDialogTarget.name,
|
|
1402
|
-
"\"? This action cannot be undone."
|
|
1403
|
-
] }) : "This will permanently delete the folder and all of its contents. This action cannot be undone."
|
|
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")
|
|
1404
1530
|
})] }),
|
|
1405
1531
|
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
1406
1532
|
variant: "text",
|
|
@@ -1409,7 +1535,7 @@ var StorageView = () => {
|
|
|
1409
1535
|
setDeleteDialogTarget(null);
|
|
1410
1536
|
},
|
|
1411
1537
|
disabled: deleting,
|
|
1412
|
-
children: "
|
|
1538
|
+
children: t("studio_storage_cancel")
|
|
1413
1539
|
}), /* @__PURE__ */ jsxs(LoadingButton, {
|
|
1414
1540
|
color: "error",
|
|
1415
1541
|
loading: deleting,
|
|
@@ -1417,7 +1543,7 @@ var StorageView = () => {
|
|
|
1417
1543
|
children: [/* @__PURE__ */ jsx(Trash2Icon, {
|
|
1418
1544
|
size: 14,
|
|
1419
1545
|
className: "mr-1"
|
|
1420
|
-
}), "
|
|
1546
|
+
}), t("studio_storage_delete")]
|
|
1421
1547
|
})] })
|
|
1422
1548
|
]
|
|
1423
1549
|
}),
|
|
@@ -1432,12 +1558,12 @@ var StorageView = () => {
|
|
|
1432
1558
|
children: [
|
|
1433
1559
|
/* @__PURE__ */ jsx(DialogTitle, {
|
|
1434
1560
|
hidden: true,
|
|
1435
|
-
children: "
|
|
1561
|
+
children: t("studio_storage_new_folder_title")
|
|
1436
1562
|
}),
|
|
1437
1563
|
/* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(TextField, {
|
|
1438
1564
|
autoFocus: true,
|
|
1439
1565
|
size: "small",
|
|
1440
|
-
label: "
|
|
1566
|
+
label: t("studio_storage_folder_name"),
|
|
1441
1567
|
value: newFolderName,
|
|
1442
1568
|
onChange: (e) => setNewFolderName(e.target.value),
|
|
1443
1569
|
onKeyDown: (e) => {
|
|
@@ -1447,19 +1573,23 @@ var StorageView = () => {
|
|
|
1447
1573
|
}
|
|
1448
1574
|
},
|
|
1449
1575
|
disabled: creatingFolder,
|
|
1450
|
-
placeholder: "
|
|
1576
|
+
placeholder: t("studio_storage_folder_name_placeholder")
|
|
1451
1577
|
}), currentPath && /* @__PURE__ */ jsxs(Typography, {
|
|
1452
1578
|
variant: "caption",
|
|
1453
1579
|
color: "secondary",
|
|
1454
1580
|
className: "mt-2",
|
|
1455
|
-
children: [
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
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
|
+
]
|
|
1463
1593
|
})] }),
|
|
1464
1594
|
/* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
|
|
1465
1595
|
variant: "text",
|
|
@@ -1468,7 +1598,7 @@ var StorageView = () => {
|
|
|
1468
1598
|
setNewFolderName("");
|
|
1469
1599
|
},
|
|
1470
1600
|
disabled: creatingFolder,
|
|
1471
|
-
children: "
|
|
1601
|
+
children: t("studio_storage_cancel")
|
|
1472
1602
|
}), /* @__PURE__ */ jsxs(LoadingButton, {
|
|
1473
1603
|
color: "primary",
|
|
1474
1604
|
loading: creatingFolder,
|
|
@@ -1477,7 +1607,7 @@ var StorageView = () => {
|
|
|
1477
1607
|
children: [/* @__PURE__ */ jsx(FolderPlusIcon, {
|
|
1478
1608
|
size: 14,
|
|
1479
1609
|
className: "mr-1"
|
|
1480
|
-
}), "
|
|
1610
|
+
}), t("studio_storage_create")]
|
|
1481
1611
|
})] })
|
|
1482
1612
|
]
|
|
1483
1613
|
})
|
|
@@ -1487,4 +1617,4 @@ var StorageView = () => {
|
|
|
1487
1617
|
//#endregion
|
|
1488
1618
|
export { StorageView };
|
|
1489
1619
|
|
|
1490
|
-
//# sourceMappingURL=StorageView-
|
|
1620
|
+
//# sourceMappingURL=StorageView-CbsHuCBf.js.map
|