diff --git a/src/admin/components/ProjectFileManager.tsx b/src/admin/components/ProjectFileManager.tsx
index 31125c6..3050a8a 100644
--- a/src/admin/components/ProjectFileManager.tsx
+++ b/src/admin/components/ProjectFileManager.tsx
@@ -1,8 +1,21 @@
import { useState, useRef } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import IconButton from "@mui/material/IconButton";
+import CircularProgress from "@mui/material/CircularProgress";
import { projectFilesOptions } from "../lib/queries/projects";
import { useAlert } from "../context/AlertContext";
-import ConfirmModal from "./ConfirmModal";
+import {
+ Card,
+ Button,
+ TextField,
+ ConfirmDialog,
+ EmptyState,
+ LoadingState,
+ DataTable,
+ type DataColumn,
+} from "../ui";
import apiFetch from "../utils/api";
const API_BASE = "/api/admin";
@@ -143,7 +156,16 @@ function getFileIcon(type: string, extension?: string) {
function SymlinkBadge({ target }: { target?: string }) {
return (
-
+
-
+
);
}
@@ -168,26 +190,53 @@ function FileNameCell({
}) {
if (item.type === "folder") {
return (
-
-
+
{item.is_symlink && }
{item.item_count !== undefined && (
- {item.item_count}
+
+ {item.item_count}
+
)}
-
+
);
}
return (
-
- {item.name}
+
+ {item.name}
{item.is_symlink && }
-
+
);
}
@@ -469,76 +518,271 @@ export default function ProjectFileManager({
};
if (filesLoading && items.length === 0 && !errorMessage) {
- return (
-
- );
+ return ;
}
if (errorMessage) {
return (
-
-
-
Soubory
-
+
+
+ Soubory
+
+
- {errorMessage}
-
-
-
+ }
+ title={errorMessage}
+ />
+
);
}
- return (
-
-
-
Soubory
-
- {/* Toolbar */}
-
-
- {breadcrumb.map((segment, i) => (
-
- {i > 0 && /}
-
-
- ))}
-
-
- {fullPath && (
-
- {fullPath}
-
- )}
-
- {canManage && (
-
-
- )}
-
-
- {/* New folder input */}
- {newFolderMode && (
-
-
setNewFolderName(e.target.value)}
- className="admin-form-input"
- placeholder="Název složky..."
- autoFocus
- onKeyDown={(e) => {
- if (e.key === "Enter") handleCreateFolder();
- if (e.key === "Escape") {
- setNewFolderMode(false);
- setNewFolderName("");
- }
- }}
- style={{ fontSize: "12px", padding: "6px 10px" }}
- />
-
- {creatingFolder ? (
-
- ) : (
- "Vytvořit"
- )}
-
-
{
+ Složka
+
+
fileInputRef.current?.click()}
+ disabled={uploading}
+ startIcon={
+ uploading ? (
+
+ ) : (
+
+ )
+ }
+ >
+ {uploading ? "Nahrávání..." : "Nahrát"}
+
+
+
+ )}
+
+
+ {/* New folder input */}
+ {newFolderMode && (
+
+ setNewFolderName(e.target.value)}
+ placeholder="Název složky..."
+ autoFocus
+ sx={{ maxWidth: 320 }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") handleCreateFolder();
+ if (e.key === "Escape") {
setNewFolderMode(false);
setNewFolderName("");
- }}
+ }
+ }}
+ />
+
+ {creatingFolder ? (
+
+ ) : (
+ "Vytvořit"
+ )}
+
+ {
+ setNewFolderMode(false);
+ setNewFolderName("");
+ }}
+ >
+ Zrušit
+
+
+ )}
+
+ {/* Drop zone + table */}
+
+ {dragOver && (
+
+
+
+
+
+
+
Přetáhněte soubory sem
+
)}
- {/* Drop zone + table */}
-
- {dragOver && (
-
+ {items.length === 0 && !filesLoading ? (
+
-
-
-
-
- Přetáhněte soubory sem
-
- )}
-
- {items.length === 0 && !filesLoading ? (
-
-
-
- {hasNasFolder
- ? "Složka je prázdná"
- : "Složka projektu zatím neexistuje"}
-
- {canManage && !hasNasFolder && (
-
- Nahrání souboru ji automaticky vytvoří
-
- )}
-
- ) : (
-
-
-
-
- |
- Název |
- Velikost |
- Změněno |
- {canManage && (
-
- Akce
- |
- )}
-
-
-
- {items.map((item) => (
-
- |
- {getFileIcon(item.type, item.extension)}
- |
-
- {renamingItem === item.name ? (
- setRenameValue(e.target.value)}
- className="admin-form-input"
- style={{
- fontSize: "11px",
- padding: "3px 8px",
- maxWidth: "300px",
- }}
- autoFocus
- onKeyDown={(e) => {
- if (e.key === "Enter") {
- e.preventDefault();
- handleRename(item);
- }
- if (e.key === "Escape") {
- e.preventDefault();
- isCancelling.current = true;
- setRenamingItem(null);
- setRenameValue(item.name);
- setTimeout(() => {
- isCancelling.current = false;
- }, 0);
- }
- }}
- onBlur={() => {
- if (isCancelling.current) {
- return;
- }
- handleRename(item);
- }}
- />
- ) : (
-
- )}
- |
-
- {item.type === "file" ? item.size_formatted : "\u2014"}
- |
- {item.modified || "\u2014"} |
- {canManage && (
-
-
- {item.type === "file" && (
- handleDownload(item)}
- >
-
-
- )}
- startRename(item)}
- >
-
-
- setDeleteTarget(item)}
- >
-
-
-
- |
- )}
-
- ))}
-
-
-
- )}
-
-
+ }
+ title={
+ hasNasFolder
+ ? "Složka je prázdná"
+ : "Složka projektu zatím neexistuje"
+ }
+ description={
+ canManage && !hasNasFolder
+ ? "Nahrání souboru ji automaticky vytvoří"
+ : undefined
+ }
+ />
+ ) : (
+
item.name}
+ />
+ )}
+
- setDeleteTarget(null)}
onConfirm={handleDelete}
@@ -836,9 +978,9 @@ export default function ProjectFileManager({
message={`Opravdu chcete smazat "${deleteTarget?.name}"?${deleteTarget?.type === "folder" ? " Složka bude smazána včetně veškerého obsahu." : ""}`}
confirmText="Smazat"
cancelText="Zrušit"
- type="danger"
+ confirmVariant="danger"
loading={deleting}
/>
-
+
);
}