From 3a079ff14e9731cd50a168d5c586e86fca05b428 Mon Sep 17 00:00:00 2001 From: SoSweetHam Date: Fri, 9 Jan 2026 19:43:34 +0530 Subject: [PATCH] fix: file manager limits --- platforms/esigner/.svelte-kit/ambient.d.ts | 236 +- .../esigner/.svelte-kit/non-ambient.d.ts | 2 +- .../src/controllers/FileController.ts | 431 ++- .../file-manager/.svelte-kit/ambient.d.ts | 236 +- .../file-manager/.svelte-kit/non-ambient.d.ts | 2 +- .../src/routes/(protected)/files/+page.svelte | 3279 ++++++++++------- 6 files changed, 2597 insertions(+), 1589 deletions(-) diff --git a/platforms/esigner/.svelte-kit/ambient.d.ts b/platforms/esigner/.svelte-kit/ambient.d.ts index 08999d2e..b20e95b8 100644 --- a/platforms/esigner/.svelte-kit/ambient.d.ts +++ b/platforms/esigner/.svelte-kit/ambient.d.ts @@ -30,7 +30,6 @@ declare module '$env/static/private' { export const NEO4J_USER: string; export const NEO4J_PASSWORD: string; export const REGISTRY_ENTROPY_KEY_JWK: string; - export const ENCRYPTION_PASSWORD: string; export const W3ID: string; export const REGISTRY_DATABASE_URL: string; export const REGISTRY_SHARED_SECRET: string; @@ -40,70 +39,125 @@ declare module '$env/static/private' { export const IP_ADDR: string; export const PICTIQUE_DATABASE_URL: string; export const PICTIQUE_MAPPING_DB_PATH: string; - export const BLABSY_MAPPING_DB_PATH: string; - export const DREAMSYNC_MAPPING_DB_PATH: string; - export const GROUP_CHARTER_MAPPING_DB_PATH: string; - export const CERBERUS_MAPPING_DB_PATH: string; - export const GOOGLE_APPLICATION_CREDENTIALS: string; - export const GROUP_CHARTER_DATABASE_URL: string; - export const CERBERUS_DATABASE_URL: string; - export const EVOTING_DATABASE_URL: string; - export const EVOTING_MAPPING_DB_PATH: string; export const OPENAI_API_KEY: string; export const NOTIFICATION_SHARED_SECRET: string; - export const DREAMSYNC_DATABASE_URL: string; - export const VITE_DREAMSYNC_BASE_URL: string; - export const ECURRENCY_DATABASE_URL: string; - export const ECURRENCY_MAPPING_DB_PATH: string; - export const VITE_ECURRENCY_BASE_URL: string; - export const JWT_SECRET: string; - export const EREPUTATION_DATABASE_URL: string; - export const EREPUTATION_MAPPING_DB_PATH: string; - export const VITE_EREPUTATION_BASE_URL: string; - export const ESIGNER_DATABASE_URL: string; - export const ESIGNER_MAPPING_DB_PATH: string; - export const FILE_MANAGER_DATABASE_URL: string; - export const FILE_MANAGER_MAPPING_DB_PATH: string; - export const LOAD_TEST_USER_COUNT: string; + export const EMOVER_DATABASE_URL: string; + export const LOKI_URL: string; + export const LOKI_USERNAME: string; + export const LOKI_PASSWORD: string; + export const PROVISIONER_URLS: string; export const SHELL: string; export const npm_command: string; + export const SESSION_MANAGER: string; export const COLORTERM: string; + export const XDG_CONFIG_DIRS: string; + export const XDG_SESSION_PATH: string; + export const XDG_MENU_PREFIX: string; + export const TERM_PROGRAM_VERSION: string; export const npm_config_optional: string; + export const FNM_ARCH: string; export const npm_config_npm_globalconfig: string; + export const ICEAUTHORITY: string; export const NODE: string; + export const LC_ADDRESS: string; + export const JAVA_HOME: string; + export const LC_NAME: string; + export const SSH_AUTH_SOCK: string; export const npm_config_verify_deps_before_run: string; export const npm_config__jsr_registry: string; + export const MEMORY_PRESSURE_WRITE: string; + export const FNM_NODE_DIST_MIRROR: string; export const npm_config_strict_peer_dependencies: string; + export const LIBVA_DRIVER_NAME: string; + export const DESKTOP_SESSION: string; + export const LC_MONETARY: string; + export const SSH_AGENT_PID: string; + export const GTK_RC_FILES: string; + export const NO_AT_BRIDGE: string; export const npm_config_globalconfig: string; + export const XDG_SEAT: string; export const PWD: string; + export const XDG_SESSION_DESKTOP: string; + export const LOGNAME: string; + export const XDG_SESSION_TYPE: string; + export const SYSTEMD_EXEC_PID: string; + export const XAUTHORITY: string; + export const VSCODE_GIT_ASKPASS_NODE: string; + export const MOTD_SHOWN: string; + export const VSCODE_INJECTION: string; + export const GTK2_RC_FILES: string; export const HOME: string; + export const LC_PAPER: string; export const LANG: string; + export const FNM_COREPACK_ENABLED: string; + export const _JAVA_AWT_WM_NONREPARENTING: string; + export const XDG_CURRENT_DESKTOP: string; export const npm_package_version: string; - export const TURBO_IS_TUI: string; + export const MEMORY_PRESSURE_WATCH: string; + export const WAYLAND_DISPLAY: string; + export const VIRTUAL_ENV_DISABLE_PROMPT: string; + export const MANROFFOPT: string; + export const GIT_ASKPASS: string; + export const XDG_SEAT_PATH: string; + export const VSCODE_GIT_IPC_AUTH_TOKEN: string; + export const INVOCATION_ID: string; export const pnpm_config_verify_deps_before_run: string; + export const MANAGERPID: string; export const INIT_CWD: string; + export const CHROME_DESKTOP: string; + export const KDE_SESSION_UID: string; export const npm_lifecycle_script: string; - export const TURBO_HASH: string; + export const VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + export const XKB_DEFAULT_LAYOUT: string; + export const XDG_SESSION_CLASS: string; + export const ANDROID_HOME: string; + export const LC_IDENTIFICATION: string; export const TERM: string; export const npm_package_name: string; export const USER: string; export const npm_config_frozen_lockfile: string; + export const NDK_HOME: string; + export const VSCODE_GIT_IPC_HANDLE: string; + export const QT_WAYLAND_RECONNECT: string; + export const KDE_SESSION_VERSION: string; + export const PAM_KWALLET5_LOGIN: string; + export const MANPAGER: string; export const DISPLAY: string; export const npm_lifecycle_event: string; export const SHLVL: string; + export const LC_TELEPHONE: string; + export const LC_MEASUREMENT: string; + export const FNM_VERSION_FILE_STRATEGY: string; + export const XDG_VTNR: string; + export const XDG_SESSION_ID: string; + export const MANAGERPIDFDID: string; export const npm_config_user_agent: string; export const PNPM_SCRIPT_SRC_DIR: string; export const npm_execpath: string; export const XDG_RUNTIME_DIR: string; + export const FNM_RESOLVE_ENGINES: string; export const NODE_PATH: string; + export const DEBUGINFOD_URLS: string; + export const LC_TIME: string; export const npm_package_json: string; + export const VSCODE_GIT_ASKPASS_MAIN: string; + export const JOURNAL_STREAM: string; + export const KDE_FULL_SESSION: string; + export const GDK_BACKEND: string; export const PATH: string; export const npm_config_node_gyp: string; + export const ORIGINAL_XDG_CURRENT_DESKTOP: string; export const DBUS_SESSION_BUS_ADDRESS: string; + export const KDE_APPLICATIONS_AS_SCOPE: string; + export const MAIL: string; export const npm_config_registry: string; + export const FNM_DIR: string; + export const FNM_MULTISHELL_PATH: string; export const npm_node_execpath: string; + export const FNM_LOGLEVEL: string; + export const LC_NUMERIC: string; export const TERM_PROGRAM: string; - export const NODE_ENV: string; + export const CURSOR_TRACE_ID: string; } /** @@ -122,16 +176,10 @@ declare module '$env/static/public' { export const PUBLIC_PROVISIONER_URL: string; export const PUBLIC_PICTIQUE_URL: string; export const PUBLIC_PICTIQUE_BASE_URL: string; - export const PUBLIC_BLABSY_URL: string; - export const PUBLIC_BLABSY_BASE_URL: string; - export const PUBLIC_GROUP_CHARTER_BASE_URL: string; - export const PUBLIC_CERBERUS_BASE_URL: string; - export const PUBLIC_EVOTING_BASE_URL: string; - export const PUBLIC_EVOTING_URL: string; export const PUBLIC_APP_STORE_EID_WALLET: string; export const PUBLIC_PLAY_STORE_EID_WALLET: string; - export const PUBLIC_ESIGNER_BASE_URL: string; - export const PUBLIC_FILE_MANAGER_BASE_URL: string; + export const PUBLIC_EID_WALLET_TOKEN: string; + export const PUBLIC_EMOVER_BASE_URL: string; } /** @@ -152,7 +200,6 @@ declare module '$env/dynamic/private' { NEO4J_USER: string; NEO4J_PASSWORD: string; REGISTRY_ENTROPY_KEY_JWK: string; - ENCRYPTION_PASSWORD: string; W3ID: string; REGISTRY_DATABASE_URL: string; REGISTRY_SHARED_SECRET: string; @@ -162,70 +209,125 @@ declare module '$env/dynamic/private' { IP_ADDR: string; PICTIQUE_DATABASE_URL: string; PICTIQUE_MAPPING_DB_PATH: string; - BLABSY_MAPPING_DB_PATH: string; - DREAMSYNC_MAPPING_DB_PATH: string; - GROUP_CHARTER_MAPPING_DB_PATH: string; - CERBERUS_MAPPING_DB_PATH: string; - GOOGLE_APPLICATION_CREDENTIALS: string; - GROUP_CHARTER_DATABASE_URL: string; - CERBERUS_DATABASE_URL: string; - EVOTING_DATABASE_URL: string; - EVOTING_MAPPING_DB_PATH: string; OPENAI_API_KEY: string; NOTIFICATION_SHARED_SECRET: string; - DREAMSYNC_DATABASE_URL: string; - VITE_DREAMSYNC_BASE_URL: string; - ECURRENCY_DATABASE_URL: string; - ECURRENCY_MAPPING_DB_PATH: string; - VITE_ECURRENCY_BASE_URL: string; - JWT_SECRET: string; - EREPUTATION_DATABASE_URL: string; - EREPUTATION_MAPPING_DB_PATH: string; - VITE_EREPUTATION_BASE_URL: string; - ESIGNER_DATABASE_URL: string; - ESIGNER_MAPPING_DB_PATH: string; - FILE_MANAGER_DATABASE_URL: string; - FILE_MANAGER_MAPPING_DB_PATH: string; - LOAD_TEST_USER_COUNT: string; + EMOVER_DATABASE_URL: string; + LOKI_URL: string; + LOKI_USERNAME: string; + LOKI_PASSWORD: string; + PROVISIONER_URLS: string; SHELL: string; npm_command: string; + SESSION_MANAGER: string; COLORTERM: string; + XDG_CONFIG_DIRS: string; + XDG_SESSION_PATH: string; + XDG_MENU_PREFIX: string; + TERM_PROGRAM_VERSION: string; npm_config_optional: string; + FNM_ARCH: string; npm_config_npm_globalconfig: string; + ICEAUTHORITY: string; NODE: string; + LC_ADDRESS: string; + JAVA_HOME: string; + LC_NAME: string; + SSH_AUTH_SOCK: string; npm_config_verify_deps_before_run: string; npm_config__jsr_registry: string; + MEMORY_PRESSURE_WRITE: string; + FNM_NODE_DIST_MIRROR: string; npm_config_strict_peer_dependencies: string; + LIBVA_DRIVER_NAME: string; + DESKTOP_SESSION: string; + LC_MONETARY: string; + SSH_AGENT_PID: string; + GTK_RC_FILES: string; + NO_AT_BRIDGE: string; npm_config_globalconfig: string; + XDG_SEAT: string; PWD: string; + XDG_SESSION_DESKTOP: string; + LOGNAME: string; + XDG_SESSION_TYPE: string; + SYSTEMD_EXEC_PID: string; + XAUTHORITY: string; + VSCODE_GIT_ASKPASS_NODE: string; + MOTD_SHOWN: string; + VSCODE_INJECTION: string; + GTK2_RC_FILES: string; HOME: string; + LC_PAPER: string; LANG: string; + FNM_COREPACK_ENABLED: string; + _JAVA_AWT_WM_NONREPARENTING: string; + XDG_CURRENT_DESKTOP: string; npm_package_version: string; - TURBO_IS_TUI: string; + MEMORY_PRESSURE_WATCH: string; + WAYLAND_DISPLAY: string; + VIRTUAL_ENV_DISABLE_PROMPT: string; + MANROFFOPT: string; + GIT_ASKPASS: string; + XDG_SEAT_PATH: string; + VSCODE_GIT_IPC_AUTH_TOKEN: string; + INVOCATION_ID: string; pnpm_config_verify_deps_before_run: string; + MANAGERPID: string; INIT_CWD: string; + CHROME_DESKTOP: string; + KDE_SESSION_UID: string; npm_lifecycle_script: string; - TURBO_HASH: string; + VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + XKB_DEFAULT_LAYOUT: string; + XDG_SESSION_CLASS: string; + ANDROID_HOME: string; + LC_IDENTIFICATION: string; TERM: string; npm_package_name: string; USER: string; npm_config_frozen_lockfile: string; + NDK_HOME: string; + VSCODE_GIT_IPC_HANDLE: string; + QT_WAYLAND_RECONNECT: string; + KDE_SESSION_VERSION: string; + PAM_KWALLET5_LOGIN: string; + MANPAGER: string; DISPLAY: string; npm_lifecycle_event: string; SHLVL: string; + LC_TELEPHONE: string; + LC_MEASUREMENT: string; + FNM_VERSION_FILE_STRATEGY: string; + XDG_VTNR: string; + XDG_SESSION_ID: string; + MANAGERPIDFDID: string; npm_config_user_agent: string; PNPM_SCRIPT_SRC_DIR: string; npm_execpath: string; XDG_RUNTIME_DIR: string; + FNM_RESOLVE_ENGINES: string; NODE_PATH: string; + DEBUGINFOD_URLS: string; + LC_TIME: string; npm_package_json: string; + VSCODE_GIT_ASKPASS_MAIN: string; + JOURNAL_STREAM: string; + KDE_FULL_SESSION: string; + GDK_BACKEND: string; PATH: string; npm_config_node_gyp: string; + ORIGINAL_XDG_CURRENT_DESKTOP: string; DBUS_SESSION_BUS_ADDRESS: string; + KDE_APPLICATIONS_AS_SCOPE: string; + MAIL: string; npm_config_registry: string; + FNM_DIR: string; + FNM_MULTISHELL_PATH: string; npm_node_execpath: string; + FNM_LOGLEVEL: string; + LC_NUMERIC: string; TERM_PROGRAM: string; - NODE_ENV: string; + CURSOR_TRACE_ID: string; [key: `PUBLIC_${string}`]: undefined; [key: `${string}`]: string | undefined; } @@ -249,16 +351,10 @@ declare module '$env/dynamic/public' { PUBLIC_PROVISIONER_URL: string; PUBLIC_PICTIQUE_URL: string; PUBLIC_PICTIQUE_BASE_URL: string; - PUBLIC_BLABSY_URL: string; - PUBLIC_BLABSY_BASE_URL: string; - PUBLIC_GROUP_CHARTER_BASE_URL: string; - PUBLIC_CERBERUS_BASE_URL: string; - PUBLIC_EVOTING_BASE_URL: string; - PUBLIC_EVOTING_URL: string; PUBLIC_APP_STORE_EID_WALLET: string; PUBLIC_PLAY_STORE_EID_WALLET: string; - PUBLIC_ESIGNER_BASE_URL: string; - PUBLIC_FILE_MANAGER_BASE_URL: string; + PUBLIC_EID_WALLET_TOKEN: string; + PUBLIC_EMOVER_BASE_URL: string; [key: `PUBLIC_${string}`]: string | undefined; } } diff --git a/platforms/esigner/.svelte-kit/non-ambient.d.ts b/platforms/esigner/.svelte-kit/non-ambient.d.ts index 8dca0d20..baee1fca 100644 --- a/platforms/esigner/.svelte-kit/non-ambient.d.ts +++ b/platforms/esigner/.svelte-kit/non-ambient.d.ts @@ -43,6 +43,6 @@ declare module "$app/types" { }; Pathname(): "/" | "/auth" | "/auth/" | "/deeplink-login" | "/deeplink-login/" | "/files" | "/files/" | "/files/new" | "/files/new/" | `/files/${string}` & {} | `/files/${string}/` & {}; ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`; - Asset(): string & {}; + Asset(): "/android-chrome-192x192.png" | "/android-chrome-512x512.png" | "/apple-touch-icon.png" | "/favicon-16x16.png" | "/favicon-32x32.png" | "/favicon.ico" | "/site.webmanifest" | string & {}; } } \ No newline at end of file diff --git a/platforms/file-manager-api/src/controllers/FileController.ts b/platforms/file-manager-api/src/controllers/FileController.ts index 06be92a4..6b0f3afa 100644 --- a/platforms/file-manager-api/src/controllers/FileController.ts +++ b/platforms/file-manager-api/src/controllers/FileController.ts @@ -1,9 +1,14 @@ -import { Request, Response } from "express"; -import { FileService } from "../services/FileService"; +import type { Request, Response } from "express"; import multer from "multer"; +import { FileService } from "../services/FileService"; const upload = multer({ - limits: { fileSize: 100 * 1024 * 1024 }, // 100MB limit + limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit + storage: multer.memoryStorage(), +}); + +const uploadMultiple = multer({ + limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB limit storage: multer.memoryStorage(), }); @@ -15,7 +20,7 @@ export class FileController { } uploadFile = [ - upload.single('file'), + upload.single("file"), async (req: Request, res: Response) => { try { if (!req.file) { @@ -23,35 +28,44 @@ export class FileController { } if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } - // Check file size limit (5MB) - const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB in bytes + // Check file size limit (1GB) + const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes if (req.file.size > MAX_FILE_SIZE) { - return res.status(413).json({ - error: "File size exceeds 5MB limit", + return res.status(413).json({ + error: "File size exceeds 1GB limit", maxSize: MAX_FILE_SIZE, - fileSize: req.file.size + fileSize: req.file.size, }); } // Check user's storage quota (1GB total) - const { used, limit } = await this.fileService.getUserStorageUsage(req.user.id); + const { used, limit } = + await this.fileService.getUserStorageUsage(req.user.id); if (used + req.file.size > limit) { - return res.status(413).json({ + return res.status(413).json({ error: "Storage quota exceeded", used, limit, fileSize: req.file.size, - available: limit - used + available: limit - used, }); } const { displayName, description, folderId } = req.body; // Normalize folderId - convert string "null" to actual null - const normalizedFolderId = folderId === 'null' || folderId === '' || folderId === null || folderId === undefined ? null : folderId; + const normalizedFolderId = + folderId === "null" || + folderId === "" || + folderId === null || + folderId === undefined + ? null + : folderId; const file = await this.fileService.createFile( req.file.originalname, @@ -61,7 +75,7 @@ export class FileController { req.user.id, normalizedFolderId, displayName, - description + description, ); res.status(201).json({ @@ -82,38 +96,181 @@ export class FileController { } res.status(500).json({ error: "Failed to upload file" }); } - } + }, + ]; + + uploadFiles = [ + uploadMultiple.array("files", 50), + async (req: Request, res: Response) => { + try { + const files = req.files as Express.Multer.File[]; + if (!files || files.length === 0) { + return res.status(400).json({ error: "No files provided" }); + } + + if (!req.user) { + return res + .status(401) + .json({ error: "Authentication required" }); + } + + const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GB in bytes + const { used, limit } = + await this.fileService.getUserStorageUsage(req.user.id); + + const { folderId } = req.body; + const normalizedFolderId = + folderId === "null" || + folderId === "" || + folderId === null || + folderId === undefined + ? null + : folderId; + + interface UploadResult { + id: string; + name: string; + displayName: string | null; + description: string | null; + mimeType: string; + size: number; + md5Hash: string; + folderId: string | null; + createdAt: Date; + } + + interface UploadError { + fileName: string; + error: string; + fileSize?: number; + available?: number; + } + + const results: UploadResult[] = []; + const errors: UploadError[] = []; + let currentUsed = used; + + if (!req.user) { + return res + .status(401) + .json({ error: "Authentication required" }); + } + + for (const file of files) { + try { + // Check file size limit + if (file.size > MAX_FILE_SIZE) { + errors.push({ + fileName: file.originalname, + error: "File size exceeds 1GB limit", + fileSize: file.size, + }); + continue; + } + + // Check storage quota + if (currentUsed + file.size > limit) { + errors.push({ + fileName: file.originalname, + error: "Storage quota exceeded", + available: limit - currentUsed, + }); + continue; + } + + const createdFile = await this.fileService.createFile( + file.originalname, + file.mimetype, + file.size, + file.buffer, + req.user.id, + normalizedFolderId, + undefined, + undefined, + ); + + currentUsed += file.size; + results.push({ + id: createdFile.id, + name: createdFile.name, + displayName: createdFile.displayName, + description: createdFile.description, + mimeType: createdFile.mimeType, + size: createdFile.size, + md5Hash: createdFile.md5Hash, + folderId: createdFile.folderId, + createdAt: createdFile.createdAt, + }); + } catch (error) { + console.error( + `Error uploading file ${file.originalname}:`, + error, + ); + errors.push({ + fileName: file.originalname, + error: + error instanceof Error + ? error.message + : "Failed to upload file", + }); + } + } + + res.status(201).json({ + files: results, + errors: errors.length > 0 ? errors : undefined, + }); + } catch (error) { + console.error("Error uploading files:", error); + if (error instanceof Error) { + return res.status(400).json({ error: error.message }); + } + res.status(500).json({ error: "Failed to upload files" }); + } + }, ]; getFiles = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { folderId } = req.query; - const folderIdParam = folderId === 'null' || folderId === '' ? null : folderId as string | undefined; + const folderIdParam = + folderId === "null" || folderId === "" + ? null + : (folderId as string | undefined); - const files = await this.fileService.getUserFiles(req.user.id, folderIdParam); - res.json(files.map(file => ({ - id: file.id, - name: file.name, - displayName: file.displayName, - description: file.description, - mimeType: file.mimeType, - size: file.size, - md5Hash: file.md5Hash, - ownerId: file.ownerId, - owner: file.owner ? { - id: file.owner.id, - name: file.owner.name, - ename: file.owner.ename, - } : null, - folderId: file.folderId, - createdAt: file.createdAt, - updatedAt: file.updatedAt, - canPreview: this.fileService.canPreview(file.mimeType), - }))); + const files = await this.fileService.getUserFiles( + req.user.id, + folderIdParam, + ); + res.json( + files.map((file) => ({ + id: file.id, + name: file.name, + displayName: file.displayName, + description: file.description, + mimeType: file.mimeType, + size: file.size, + md5Hash: file.md5Hash, + ownerId: file.ownerId, + owner: file.owner + ? { + id: file.owner.id, + name: file.owner.name, + ename: file.owner.ename, + } + : null, + folderId: file.folderId, + createdAt: file.createdAt, + updatedAt: file.updatedAt, + canPreview: this.fileService.canPreview(file.mimeType), + })), + ); } catch (error) { console.error("Error getting files:", error); res.status(500).json({ error: "Failed to get files" }); @@ -123,7 +280,9 @@ export class FileController { getFile = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { id } = req.params; @@ -153,15 +312,17 @@ export class FileController { createdAt: file.createdAt, updatedAt: file.updatedAt, canPreview: this.fileService.canPreview(file.mimeType), - signatures: signatures.map(sig => ({ + signatures: signatures.map((sig) => ({ id: sig.id, userId: sig.userId, - user: sig.user ? { - id: sig.user.id, - name: sig.user.name, - ename: sig.user.ename, - avatarUrl: sig.user.avatarUrl, - } : null, + user: sig.user + ? { + id: sig.user.id, + name: sig.user.name, + ename: sig.user.ename, + avatarUrl: sig.user.avatarUrl, + } + : null, md5Hash: sig.md5Hash, signature: sig.signature, publicKey: sig.publicKey, @@ -185,7 +346,9 @@ export class FileController { updateFile = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { id } = req.params; @@ -196,11 +359,17 @@ export class FileController { req.user.id, displayName, description, - folderId !== undefined ? (folderId === 'null' || folderId === '' ? null : folderId) : undefined + folderId !== undefined + ? folderId === "null" || folderId === "" + ? null + : folderId + : undefined, ); if (!file) { - return res.status(404).json({ error: "File not found or not authorized" }); + return res + .status(404) + .json({ error: "File not found or not authorized" }); } res.json({ @@ -228,7 +397,9 @@ export class FileController { downloadFile = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { id } = req.params; @@ -238,9 +409,12 @@ export class FileController { return res.status(404).json({ error: "File not found" }); } - res.setHeader('Content-Type', file.mimeType); - res.setHeader('Content-Disposition', `attachment; filename="${file.name}"`); - res.setHeader('Content-Length', file.size.toString()); + res.setHeader("Content-Type", file.mimeType); + res.setHeader( + "Content-Disposition", + `attachment; filename="${file.name}"`, + ); + res.setHeader("Content-Length", file.size.toString()); res.send(file.data); } catch (error) { console.error("Error downloading file:", error); @@ -251,7 +425,9 @@ export class FileController { previewFile = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { id } = req.params; @@ -262,12 +438,17 @@ export class FileController { } if (!this.fileService.canPreview(file.mimeType)) { - return res.status(400).json({ error: "File type cannot be previewed" }); + return res + .status(400) + .json({ error: "File type cannot be previewed" }); } - res.setHeader('Content-Type', file.mimeType); - res.setHeader('Content-Disposition', `inline; filename="${file.name}"`); - res.setHeader('Content-Length', file.size.toString()); + res.setHeader("Content-Type", file.mimeType); + res.setHeader( + "Content-Disposition", + `inline; filename="${file.name}"`, + ); + res.setHeader("Content-Length", file.size.toString()); res.send(file.data); } catch (error) { console.error("Error previewing file:", error); @@ -275,76 +456,97 @@ export class FileController { } }; - deleteFile = async (req: Request, res: Response) => { - try { - if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); - } + deleteFile = async (req: Request, res: Response) => { + try { + if (!req.user) { + return res + .status(401) + .json({ error: "Authentication required" }); + } + + const { id } = req.params; + const deleted = await this.fileService.deleteFile(id, req.user.id); - const { id } = req.params; - const deleted = await this.fileService.deleteFile(id, req.user.id); + if (!deleted) { + return res + .status(404) + .json({ error: "File not found or not authorized" }); + } - if (!deleted) { - return res.status(404).json({ error: "File not found or not authorized" }); - } + res.json({ message: "File deleted successfully" }); + } catch (error) { + console.error("Error deleting file:", error); + res.status(500).json({ error: "Failed to delete file" }); + } + }; - res.json({ message: "File deleted successfully" }); - } catch (error) { - console.error("Error deleting file:", error); - res.status(500).json({ error: "Failed to delete file" }); - } - }; + getFileSignatures = async (req: Request, res: Response) => { + try { + if (!req.user) { + return res + .status(401) + .json({ error: "Authentication required" }); + } - getFileSignatures = async (req: Request, res: Response) => { - try { - if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); - } + const { id } = req.params; + const file = await this.fileService.getFileById(id, req.user.id); - const { id } = req.params; - const file = await this.fileService.getFileById(id, req.user.id); + if (!file) { + return res.status(404).json({ error: "File not found" }); + } - if (!file) { - return res.status(404).json({ error: "File not found" }); - } + const signatures = await this.fileService.getFileSignatures(id); - const signatures = await this.fileService.getFileSignatures(id); - - res.json(signatures.map(sig => ({ - id: sig.id, - userId: sig.userId, - user: sig.user ? { - id: sig.user.id, - name: sig.user.name, - ename: sig.user.ename, - avatarUrl: sig.user.avatarUrl, - } : null, - md5Hash: sig.md5Hash, - message: sig.message, - signature: sig.signature, - publicKey: sig.publicKey, - createdAt: sig.createdAt, - }))); - } catch (error) { - console.error("Error getting file signatures:", error); - res.status(500).json({ error: "Failed to get signatures" }); - } - }; + res.json( + signatures.map((sig) => ({ + id: sig.id, + userId: sig.userId, + user: sig.user + ? { + id: sig.user.id, + name: sig.user.name, + ename: sig.user.ename, + avatarUrl: sig.user.avatarUrl, + } + : null, + md5Hash: sig.md5Hash, + message: sig.message, + signature: sig.signature, + publicKey: sig.publicKey, + createdAt: sig.createdAt, + })), + ); + } catch (error) { + console.error("Error getting file signatures:", error); + res.status(500).json({ error: "Failed to get signatures" }); + } + }; moveFile = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } const { id } = req.params; const { folderId } = req.body; - const folderIdParam = folderId === 'null' || folderId === '' ? null : folderId as string | null; + const folderIdParam = + folderId === "null" || folderId === "" + ? null + : (folderId as string | null); - const file = await this.fileService.moveFile(id, folderIdParam, req.user.id); + const file = await this.fileService.moveFile( + id, + folderIdParam, + req.user.id, + ); if (!file) { - return res.status(404).json({ error: "File not found or not authorized" }); + return res + .status(404) + .json({ error: "File not found or not authorized" }); } res.json({ @@ -364,10 +566,14 @@ export class FileController { getStorageUsage = async (req: Request, res: Response) => { try { if (!req.user) { - return res.status(401).json({ error: "Authentication required" }); + return res + .status(401) + .json({ error: "Authentication required" }); } - const usage = await this.fileService.getUserStorageUsage(req.user.id); + const usage = await this.fileService.getUserStorageUsage( + req.user.id, + ); res.json(usage); } catch (error) { console.error("Error getting storage usage:", error); @@ -375,4 +581,3 @@ export class FileController { } }; } - diff --git a/platforms/file-manager/.svelte-kit/ambient.d.ts b/platforms/file-manager/.svelte-kit/ambient.d.ts index 08999d2e..b20e95b8 100644 --- a/platforms/file-manager/.svelte-kit/ambient.d.ts +++ b/platforms/file-manager/.svelte-kit/ambient.d.ts @@ -30,7 +30,6 @@ declare module '$env/static/private' { export const NEO4J_USER: string; export const NEO4J_PASSWORD: string; export const REGISTRY_ENTROPY_KEY_JWK: string; - export const ENCRYPTION_PASSWORD: string; export const W3ID: string; export const REGISTRY_DATABASE_URL: string; export const REGISTRY_SHARED_SECRET: string; @@ -40,70 +39,125 @@ declare module '$env/static/private' { export const IP_ADDR: string; export const PICTIQUE_DATABASE_URL: string; export const PICTIQUE_MAPPING_DB_PATH: string; - export const BLABSY_MAPPING_DB_PATH: string; - export const DREAMSYNC_MAPPING_DB_PATH: string; - export const GROUP_CHARTER_MAPPING_DB_PATH: string; - export const CERBERUS_MAPPING_DB_PATH: string; - export const GOOGLE_APPLICATION_CREDENTIALS: string; - export const GROUP_CHARTER_DATABASE_URL: string; - export const CERBERUS_DATABASE_URL: string; - export const EVOTING_DATABASE_URL: string; - export const EVOTING_MAPPING_DB_PATH: string; export const OPENAI_API_KEY: string; export const NOTIFICATION_SHARED_SECRET: string; - export const DREAMSYNC_DATABASE_URL: string; - export const VITE_DREAMSYNC_BASE_URL: string; - export const ECURRENCY_DATABASE_URL: string; - export const ECURRENCY_MAPPING_DB_PATH: string; - export const VITE_ECURRENCY_BASE_URL: string; - export const JWT_SECRET: string; - export const EREPUTATION_DATABASE_URL: string; - export const EREPUTATION_MAPPING_DB_PATH: string; - export const VITE_EREPUTATION_BASE_URL: string; - export const ESIGNER_DATABASE_URL: string; - export const ESIGNER_MAPPING_DB_PATH: string; - export const FILE_MANAGER_DATABASE_URL: string; - export const FILE_MANAGER_MAPPING_DB_PATH: string; - export const LOAD_TEST_USER_COUNT: string; + export const EMOVER_DATABASE_URL: string; + export const LOKI_URL: string; + export const LOKI_USERNAME: string; + export const LOKI_PASSWORD: string; + export const PROVISIONER_URLS: string; export const SHELL: string; export const npm_command: string; + export const SESSION_MANAGER: string; export const COLORTERM: string; + export const XDG_CONFIG_DIRS: string; + export const XDG_SESSION_PATH: string; + export const XDG_MENU_PREFIX: string; + export const TERM_PROGRAM_VERSION: string; export const npm_config_optional: string; + export const FNM_ARCH: string; export const npm_config_npm_globalconfig: string; + export const ICEAUTHORITY: string; export const NODE: string; + export const LC_ADDRESS: string; + export const JAVA_HOME: string; + export const LC_NAME: string; + export const SSH_AUTH_SOCK: string; export const npm_config_verify_deps_before_run: string; export const npm_config__jsr_registry: string; + export const MEMORY_PRESSURE_WRITE: string; + export const FNM_NODE_DIST_MIRROR: string; export const npm_config_strict_peer_dependencies: string; + export const LIBVA_DRIVER_NAME: string; + export const DESKTOP_SESSION: string; + export const LC_MONETARY: string; + export const SSH_AGENT_PID: string; + export const GTK_RC_FILES: string; + export const NO_AT_BRIDGE: string; export const npm_config_globalconfig: string; + export const XDG_SEAT: string; export const PWD: string; + export const XDG_SESSION_DESKTOP: string; + export const LOGNAME: string; + export const XDG_SESSION_TYPE: string; + export const SYSTEMD_EXEC_PID: string; + export const XAUTHORITY: string; + export const VSCODE_GIT_ASKPASS_NODE: string; + export const MOTD_SHOWN: string; + export const VSCODE_INJECTION: string; + export const GTK2_RC_FILES: string; export const HOME: string; + export const LC_PAPER: string; export const LANG: string; + export const FNM_COREPACK_ENABLED: string; + export const _JAVA_AWT_WM_NONREPARENTING: string; + export const XDG_CURRENT_DESKTOP: string; export const npm_package_version: string; - export const TURBO_IS_TUI: string; + export const MEMORY_PRESSURE_WATCH: string; + export const WAYLAND_DISPLAY: string; + export const VIRTUAL_ENV_DISABLE_PROMPT: string; + export const MANROFFOPT: string; + export const GIT_ASKPASS: string; + export const XDG_SEAT_PATH: string; + export const VSCODE_GIT_IPC_AUTH_TOKEN: string; + export const INVOCATION_ID: string; export const pnpm_config_verify_deps_before_run: string; + export const MANAGERPID: string; export const INIT_CWD: string; + export const CHROME_DESKTOP: string; + export const KDE_SESSION_UID: string; export const npm_lifecycle_script: string; - export const TURBO_HASH: string; + export const VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + export const XKB_DEFAULT_LAYOUT: string; + export const XDG_SESSION_CLASS: string; + export const ANDROID_HOME: string; + export const LC_IDENTIFICATION: string; export const TERM: string; export const npm_package_name: string; export const USER: string; export const npm_config_frozen_lockfile: string; + export const NDK_HOME: string; + export const VSCODE_GIT_IPC_HANDLE: string; + export const QT_WAYLAND_RECONNECT: string; + export const KDE_SESSION_VERSION: string; + export const PAM_KWALLET5_LOGIN: string; + export const MANPAGER: string; export const DISPLAY: string; export const npm_lifecycle_event: string; export const SHLVL: string; + export const LC_TELEPHONE: string; + export const LC_MEASUREMENT: string; + export const FNM_VERSION_FILE_STRATEGY: string; + export const XDG_VTNR: string; + export const XDG_SESSION_ID: string; + export const MANAGERPIDFDID: string; export const npm_config_user_agent: string; export const PNPM_SCRIPT_SRC_DIR: string; export const npm_execpath: string; export const XDG_RUNTIME_DIR: string; + export const FNM_RESOLVE_ENGINES: string; export const NODE_PATH: string; + export const DEBUGINFOD_URLS: string; + export const LC_TIME: string; export const npm_package_json: string; + export const VSCODE_GIT_ASKPASS_MAIN: string; + export const JOURNAL_STREAM: string; + export const KDE_FULL_SESSION: string; + export const GDK_BACKEND: string; export const PATH: string; export const npm_config_node_gyp: string; + export const ORIGINAL_XDG_CURRENT_DESKTOP: string; export const DBUS_SESSION_BUS_ADDRESS: string; + export const KDE_APPLICATIONS_AS_SCOPE: string; + export const MAIL: string; export const npm_config_registry: string; + export const FNM_DIR: string; + export const FNM_MULTISHELL_PATH: string; export const npm_node_execpath: string; + export const FNM_LOGLEVEL: string; + export const LC_NUMERIC: string; export const TERM_PROGRAM: string; - export const NODE_ENV: string; + export const CURSOR_TRACE_ID: string; } /** @@ -122,16 +176,10 @@ declare module '$env/static/public' { export const PUBLIC_PROVISIONER_URL: string; export const PUBLIC_PICTIQUE_URL: string; export const PUBLIC_PICTIQUE_BASE_URL: string; - export const PUBLIC_BLABSY_URL: string; - export const PUBLIC_BLABSY_BASE_URL: string; - export const PUBLIC_GROUP_CHARTER_BASE_URL: string; - export const PUBLIC_CERBERUS_BASE_URL: string; - export const PUBLIC_EVOTING_BASE_URL: string; - export const PUBLIC_EVOTING_URL: string; export const PUBLIC_APP_STORE_EID_WALLET: string; export const PUBLIC_PLAY_STORE_EID_WALLET: string; - export const PUBLIC_ESIGNER_BASE_URL: string; - export const PUBLIC_FILE_MANAGER_BASE_URL: string; + export const PUBLIC_EID_WALLET_TOKEN: string; + export const PUBLIC_EMOVER_BASE_URL: string; } /** @@ -152,7 +200,6 @@ declare module '$env/dynamic/private' { NEO4J_USER: string; NEO4J_PASSWORD: string; REGISTRY_ENTROPY_KEY_JWK: string; - ENCRYPTION_PASSWORD: string; W3ID: string; REGISTRY_DATABASE_URL: string; REGISTRY_SHARED_SECRET: string; @@ -162,70 +209,125 @@ declare module '$env/dynamic/private' { IP_ADDR: string; PICTIQUE_DATABASE_URL: string; PICTIQUE_MAPPING_DB_PATH: string; - BLABSY_MAPPING_DB_PATH: string; - DREAMSYNC_MAPPING_DB_PATH: string; - GROUP_CHARTER_MAPPING_DB_PATH: string; - CERBERUS_MAPPING_DB_PATH: string; - GOOGLE_APPLICATION_CREDENTIALS: string; - GROUP_CHARTER_DATABASE_URL: string; - CERBERUS_DATABASE_URL: string; - EVOTING_DATABASE_URL: string; - EVOTING_MAPPING_DB_PATH: string; OPENAI_API_KEY: string; NOTIFICATION_SHARED_SECRET: string; - DREAMSYNC_DATABASE_URL: string; - VITE_DREAMSYNC_BASE_URL: string; - ECURRENCY_DATABASE_URL: string; - ECURRENCY_MAPPING_DB_PATH: string; - VITE_ECURRENCY_BASE_URL: string; - JWT_SECRET: string; - EREPUTATION_DATABASE_URL: string; - EREPUTATION_MAPPING_DB_PATH: string; - VITE_EREPUTATION_BASE_URL: string; - ESIGNER_DATABASE_URL: string; - ESIGNER_MAPPING_DB_PATH: string; - FILE_MANAGER_DATABASE_URL: string; - FILE_MANAGER_MAPPING_DB_PATH: string; - LOAD_TEST_USER_COUNT: string; + EMOVER_DATABASE_URL: string; + LOKI_URL: string; + LOKI_USERNAME: string; + LOKI_PASSWORD: string; + PROVISIONER_URLS: string; SHELL: string; npm_command: string; + SESSION_MANAGER: string; COLORTERM: string; + XDG_CONFIG_DIRS: string; + XDG_SESSION_PATH: string; + XDG_MENU_PREFIX: string; + TERM_PROGRAM_VERSION: string; npm_config_optional: string; + FNM_ARCH: string; npm_config_npm_globalconfig: string; + ICEAUTHORITY: string; NODE: string; + LC_ADDRESS: string; + JAVA_HOME: string; + LC_NAME: string; + SSH_AUTH_SOCK: string; npm_config_verify_deps_before_run: string; npm_config__jsr_registry: string; + MEMORY_PRESSURE_WRITE: string; + FNM_NODE_DIST_MIRROR: string; npm_config_strict_peer_dependencies: string; + LIBVA_DRIVER_NAME: string; + DESKTOP_SESSION: string; + LC_MONETARY: string; + SSH_AGENT_PID: string; + GTK_RC_FILES: string; + NO_AT_BRIDGE: string; npm_config_globalconfig: string; + XDG_SEAT: string; PWD: string; + XDG_SESSION_DESKTOP: string; + LOGNAME: string; + XDG_SESSION_TYPE: string; + SYSTEMD_EXEC_PID: string; + XAUTHORITY: string; + VSCODE_GIT_ASKPASS_NODE: string; + MOTD_SHOWN: string; + VSCODE_INJECTION: string; + GTK2_RC_FILES: string; HOME: string; + LC_PAPER: string; LANG: string; + FNM_COREPACK_ENABLED: string; + _JAVA_AWT_WM_NONREPARENTING: string; + XDG_CURRENT_DESKTOP: string; npm_package_version: string; - TURBO_IS_TUI: string; + MEMORY_PRESSURE_WATCH: string; + WAYLAND_DISPLAY: string; + VIRTUAL_ENV_DISABLE_PROMPT: string; + MANROFFOPT: string; + GIT_ASKPASS: string; + XDG_SEAT_PATH: string; + VSCODE_GIT_IPC_AUTH_TOKEN: string; + INVOCATION_ID: string; pnpm_config_verify_deps_before_run: string; + MANAGERPID: string; INIT_CWD: string; + CHROME_DESKTOP: string; + KDE_SESSION_UID: string; npm_lifecycle_script: string; - TURBO_HASH: string; + VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + XKB_DEFAULT_LAYOUT: string; + XDG_SESSION_CLASS: string; + ANDROID_HOME: string; + LC_IDENTIFICATION: string; TERM: string; npm_package_name: string; USER: string; npm_config_frozen_lockfile: string; + NDK_HOME: string; + VSCODE_GIT_IPC_HANDLE: string; + QT_WAYLAND_RECONNECT: string; + KDE_SESSION_VERSION: string; + PAM_KWALLET5_LOGIN: string; + MANPAGER: string; DISPLAY: string; npm_lifecycle_event: string; SHLVL: string; + LC_TELEPHONE: string; + LC_MEASUREMENT: string; + FNM_VERSION_FILE_STRATEGY: string; + XDG_VTNR: string; + XDG_SESSION_ID: string; + MANAGERPIDFDID: string; npm_config_user_agent: string; PNPM_SCRIPT_SRC_DIR: string; npm_execpath: string; XDG_RUNTIME_DIR: string; + FNM_RESOLVE_ENGINES: string; NODE_PATH: string; + DEBUGINFOD_URLS: string; + LC_TIME: string; npm_package_json: string; + VSCODE_GIT_ASKPASS_MAIN: string; + JOURNAL_STREAM: string; + KDE_FULL_SESSION: string; + GDK_BACKEND: string; PATH: string; npm_config_node_gyp: string; + ORIGINAL_XDG_CURRENT_DESKTOP: string; DBUS_SESSION_BUS_ADDRESS: string; + KDE_APPLICATIONS_AS_SCOPE: string; + MAIL: string; npm_config_registry: string; + FNM_DIR: string; + FNM_MULTISHELL_PATH: string; npm_node_execpath: string; + FNM_LOGLEVEL: string; + LC_NUMERIC: string; TERM_PROGRAM: string; - NODE_ENV: string; + CURSOR_TRACE_ID: string; [key: `PUBLIC_${string}`]: undefined; [key: `${string}`]: string | undefined; } @@ -249,16 +351,10 @@ declare module '$env/dynamic/public' { PUBLIC_PROVISIONER_URL: string; PUBLIC_PICTIQUE_URL: string; PUBLIC_PICTIQUE_BASE_URL: string; - PUBLIC_BLABSY_URL: string; - PUBLIC_BLABSY_BASE_URL: string; - PUBLIC_GROUP_CHARTER_BASE_URL: string; - PUBLIC_CERBERUS_BASE_URL: string; - PUBLIC_EVOTING_BASE_URL: string; - PUBLIC_EVOTING_URL: string; PUBLIC_APP_STORE_EID_WALLET: string; PUBLIC_PLAY_STORE_EID_WALLET: string; - PUBLIC_ESIGNER_BASE_URL: string; - PUBLIC_FILE_MANAGER_BASE_URL: string; + PUBLIC_EID_WALLET_TOKEN: string; + PUBLIC_EMOVER_BASE_URL: string; [key: `PUBLIC_${string}`]: string | undefined; } } diff --git a/platforms/file-manager/.svelte-kit/non-ambient.d.ts b/platforms/file-manager/.svelte-kit/non-ambient.d.ts index 5e95f54d..18196732 100644 --- a/platforms/file-manager/.svelte-kit/non-ambient.d.ts +++ b/platforms/file-manager/.svelte-kit/non-ambient.d.ts @@ -43,6 +43,6 @@ declare module "$app/types" { }; Pathname(): "/" | "/auth" | "/auth/" | "/deeplink-login" | "/deeplink-login/" | "/files" | "/files/" | `/files/${string}` & {} | `/files/${string}/` & {} | "/storage" | "/storage/"; ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`; - Asset(): string & {}; + Asset(): "/android-chrome-192x192.png" | "/android-chrome-512x512.png" | "/apple-touch-icon.png" | "/favicon-16x16.png" | "/favicon-32x32.png" | "/favicon.ico" | "/site.webmanifest" | string & {}; } } \ No newline at end of file diff --git a/platforms/file-manager/src/routes/(protected)/files/+page.svelte b/platforms/file-manager/src/routes/(protected)/files/+page.svelte index c1c6da33..eef74c97 100644 --- a/platforms/file-manager/src/routes/(protected)/files/+page.svelte +++ b/platforms/file-manager/src/routes/(protected)/files/+page.svelte @@ -1,1367 +1,1978 @@
- -
- -
- {#if currentView === 'my-files'} - - - {/if} -
-
- - - {#if breadcrumbs.length > 1 || (breadcrumbs.length === 1 && breadcrumbs[0].id !== null)} -
- -
- {/if} - -
- {#if isLoading} -
-
-

Loading...

-
- {:else if allItems.length === 0} -
- {#if currentView === 'my-files'} -

No files or folders yet

-

Drag and drop files here or click Upload

- {:else} -

No files shared with you

-

Files that others share with you will appear here

- {/if} -
- {:else} -
- - - - - - - - - - - {#each allItems as item} - { - e.stopPropagation(); - if (item.type === 'folder') { - navigateToFolder(item.id); - } else { - handlePreviewFile(item, e); - } - }} - > - - - - - - {/each} - -
-
- - {item.type === 'folder' ? '📁' : getFileIcon(item.type === 'file' ? item.mimeType : '')} - -
-
-
- {truncateFileName(item.displayName || item.name)} -
- {#if currentView === 'shared' && item.owner} - - {/if} -
- {#if item.type === 'file' && item.description} - - {/if} -
-
-
- -
-
- {/if} -
+ +
+ +
+ {#if currentView === "my-files"} + + + {/if} +
+
+ + + {#if breadcrumbs.length > 1 || (breadcrumbs.length === 1 && breadcrumbs[0].id !== null)} +
+ +
+ {/if} + +
+ {#if isLoading} +
+
+

Loading...

+
+ {:else if allItems.length === 0} +
+ {#if currentView === "my-files"} +

No files or folders yet

+

+ Drag and drop files here or click Upload +

+ {:else} +

No files shared with you

+

+ Files that others share with you will appear here +

+ {/if} +
+ {:else} +
+ + + + + + + + + + + {#each allItems as item} + { + e.stopPropagation(); + if (item.type === "folder") { + navigateToFolder(item.id); + } else { + handlePreviewFile(item, e); + } + }} + > + + + + + + {/each} + +
+
+ + {item.type === "folder" + ? "📁" + : getFileIcon( + item.type === "file" + ? item.mimeType + : "", + )} + +
+
+
+ {truncateFileName( + item.displayName || + item.name, + )} +
+ {#if currentView === "shared" && item.owner} + + {/if} +
+ {#if item.type === "file" && item.description} + + {/if} +
+
+
+ +
+
+ {/if} +
{#if showUploadModal} -
-
-

Upload File

- - -
- {#if selectedFile} -
- - - -

{selectedFile.name}

-

{(selectedFile.size / 1024 / 1024).toFixed(2)} MB

-
- - {:else} - - - -

Drag and drop your file here

-

or

- - {/if} -
- - {#if isUploading} -
-
- Uploading... - {uploadProgress}% -
-
-
-
-
- {/if} - -
- - -
-
-
+
+
+

Upload Files

+ + +
+ {#if selectedFiles.length > 0} + + {:else} + + + +

+ Drag and drop your files here +

+

or

+ + {/if} +
+ + + {#if selectedFiles.length > 0} +
+
+ {#each selectedFiles as file, index} + {@const fileName = file.name} + {@const status = + fileUploadStatus[fileName] || "pending"} + {@const progress = uploadProgress[fileName] || 0} +
+
+
+

+ {file.name} +

+ {#if status === "success"} + + + + {:else if status === "error"} + + + + {/if} +
+

+ {(file.size / 1024 / 1024).toFixed(2)} MB +

+ {#if status === "uploading"} +
+
+
+
+

+ {progress}% +

+
+ {:else if status === "error"} +

+ Upload failed +

+ {/if} +
+ {#if !isUploading && status !== "uploading"} + + {/if} +
+ {/each} +
+
+ {/if} + +
+ + +
+
+
{/if} {#if showFolderModal} -
-
-

Create Folder

- e.key === 'Enter' && handleCreateFolder()} - /> -
- - -
-
-
+
+
+

Create Folder

+ e.key === "Enter" && handleCreateFolder()} + /> +
+ + +
+
+
{/if} {#if showMoveModal && itemToMove} -
-
-

Move {itemToMove._type === 'file' ? 'File' : 'Folder'}

-

Moving: {itemToMove.displayName || itemToMove.name}

- - -
- -
- - -
- {#if moveModalFolders.length === 0} -
-

No folders in this location

-
- {:else} -
- {#each moveModalFolders.filter(f => itemToMove?._type !== 'folder' || f.id !== itemToMove?.id) as folder} - - {/each} -
- {/if} -
- - -
-

- Current location: {moveModalBreadcrumbs[moveModalBreadcrumbs.length - 1].name} -

-
- - -
- - -
-
-
+
+
+

+ Move {itemToMove._type === "file" ? "File" : "Folder"} +

+

+ Moving: {itemToMove.displayName || itemToMove.name} +

+ + +
+ +
+ + +
+ {#if moveModalFolders.length === 0} +
+

No folders in this location

+
+ {:else} +
+ {#each moveModalFolders.filter((f) => itemToMove?._type !== "folder" || f.id !== itemToMove?.id) as folder} + + {/each} +
+ {/if} +
+ + +
+

+ Current location: + {moveModalBreadcrumbs[moveModalBreadcrumbs.length - 1].name} +

+
+ + +
+ + +
+
+
{/if} {#if showDeleteModal && itemToDelete} -
-
-

Delete {itemToDelete.type === 'file' ? 'File' : 'Folder'}

-

- Are you sure you want to delete {itemToDelete.name}? -

- {#if itemToDelete.type === 'folder'} -

- ⚠️ This will delete the folder and all its contents permanently. -

- {:else} -

- ⚠️ This action cannot be undone. -

- {/if} -
- - -
-
-
+
+
+

+ Delete {itemToDelete.type === "file" ? "File" : "Folder"} +

+

+ Are you sure you want to delete {itemToDelete.name}? +

+ {#if itemToDelete.type === "folder"} +

+ ⚠️ This will delete the folder and all its contents + permanently. +

+ {:else} +

+ ⚠️ This action cannot be undone. +

+ {/if} +
+ + +
+
+
{/if} {#if showShareModal && itemToShare} -
{ showShareModal = false; itemToShare = null; shareSelectedUsers = []; shareSearchQuery = ''; shareSearchResults = []; }}> -
e.stopPropagation()}> -

Share {itemToShare.type === 'file' ? 'File' : 'Folder'}

-

Sharing: {itemToShare.name}

- - {#if shareSearchResults.length > 0} -
- {#each shareSearchResults as item} -
{ - if (shareSelectedUsers.find(u => u.id === item.id)) { - shareSelectedUsers = shareSelectedUsers.filter(u => u.id !== item.id); - } else { - shareSelectedUsers = [...shareSelectedUsers, item]; - } - }} - > -
- {#if item.type === 'group'} - - - -
-
{item.name}
-
{item.memberCount} {item.memberCount === 1 ? 'member' : 'members'}
-
- {:else} - - - -
-
{item.name || item.ename}
- {#if item.name && item.ename} -
@{item.ename.replace(/^@+/, '')}
- {/if} -
- {/if} -
-
- {/each} -
- {/if} -
- - -
-
-
+
{ + showShareModal = false; + itemToShare = null; + shareSelectedUsers = []; + shareSearchQuery = ""; + shareSearchResults = []; + }} + > +
e.stopPropagation()} + > +

+ Share {itemToShare.type === "file" ? "File" : "Folder"} +

+

+ Sharing: {itemToShare.name} +

+ + {#if shareSearchResults.length > 0} +
+ {#each shareSearchResults as item} +
{ + if ( + shareSelectedUsers.find( + (u) => u.id === item.id, + ) + ) { + shareSelectedUsers = + shareSelectedUsers.filter( + (u) => u.id !== item.id, + ); + } else { + shareSelectedUsers = [ + ...shareSelectedUsers, + item, + ]; + } + }} + > +
+ {#if item.type === "group"} + + + +
+
+ {item.name} +
+
+ {item.memberCount} + {item.memberCount === 1 + ? "member" + : "members"} +
+
+ {:else} + + + +
+
+ {item.name || item.ename} +
+ {#if item.name && item.ename} +
+ @{item.ename.replace(/^@+/, "")} +
+ {/if} +
+ {/if} +
+
+ {/each} +
+ {/if} +
+ + +
+
+
{/if} {#if showRenameModal && itemToRename} -
-
-

Rename {itemToRename.type === 'file' ? 'File' : 'Folder'}

- { - if (e.key === 'Enter' && newName.trim()) { - handleRename(); - } - }} - /> -
- - -
-
-
+
+
+

+ Rename {itemToRename.type === "file" ? "File" : "Folder"} +

+ { + if (e.key === "Enter" && newName.trim()) { + handleRename(); + } + }} + /> +
+ + +
+
+
{/if} {#if previewFile && previewUrl} -
-
e.stopPropagation()}> -
-

{previewFile.displayName || previewFile.name}

- -
- {#if previewFile.mimeType.startsWith('image/')} - {previewFile.name} - {:else if previewFile.mimeType === 'application/pdf'} - - {/if} -
- - Download - - -
-
-
+
+
e.stopPropagation()} + > +
+

+ {previewFile.displayName || previewFile.name} +

+ +
+ {#if previewFile.mimeType.startsWith("image/")} + {previewFile.name} + {:else if previewFile.mimeType === "application/pdf"} + + {/if} +
+ + Download + + +
+
+
{/if} - -