diff --git a/docker-compose.core.yml b/docker-compose.core.yml index 63b32cd0a..aba03bbb8 100644 --- a/docker-compose.core.yml +++ b/docker-compose.core.yml @@ -1,147 +1,151 @@ -version: '3.8' +version: "3.8" x-common-host-access: &common-host-access - extra_hosts: - - "host.docker.internal:host-gateway" - dns: - - 8.8.8.8 - - 8.8.4.4 - - 1.1.1.1 + extra_hosts: + - "host.docker.internal:host-gateway" + dns: + - 8.8.8.8 + - 8.8.4.4 + - 1.1.1.1 services: - # PostgreSQL database for registry and evault-core - postgres: - image: postgres:15-alpine - container_name: metastate-postgres - ports: - - "5433:5432" - environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - - POSTGRES_MULTIPLE_DATABASES=registry - volumes: - - postgres_data:/var/lib/postgresql/data - - ./db/init-multiple-databases.sh:/docker-entrypoint-initdb.d/init-multiple-databases.sh - networks: - - metastate-core-network - <<: *common-host-access - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s - timeout: 5s - retries: 5 - logging: - driver: "none" + # PostgreSQL database for registry and evault-core + postgres: + image: postgres:15-alpine + container_name: metastate-postgres + ports: + - "5433:5432" + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_MULTIPLE_DATABASES=registry + volumes: + - postgres_data:/var/lib/postgresql/data + - ./db/init-multiple-databases.sh:/docker-entrypoint-initdb.d/init-multiple-databases.sh + networks: + - metastate-core-network + <<: *common-host-access + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 + logging: + driver: "none" - # Neo4j for evault-core graph data - neo4j: - image: neo4j:5.15 - container_name: metastate-neo4j - ports: - - "7474:7474" # HTTP - - "7687:7687" # Bolt - environment: - - NEO4J_AUTH=${NEO4J_USER:-neo4j}/${NEO4J_PASSWORD:-neo4j} - - NEO4J_USER=${NEO4J_USER:-neo4j} - - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} - - NEO4J_dbms_connector_bolt_listen__address=0.0.0.0:7687 - - NEO4J_dbms_connector_http_listen__address=0.0.0.0:7474 - - NEO4J_dbms_connector_bolt_advertised__address=neo4j:7687 - volumes: - - neo4j_data:/var/lib/neo4j/data - networks: - - metastate-core-network - <<: *common-host-access - entrypoint: ["/bin/sh", "-c"] - command: - - | - # Remove any stale PID files before starting Neo4j - rm -f /var/lib/neo4j/run/neo4j.pid 2>/dev/null || true - rm -f /var/lib/neo4j/data/run/neo4j.pid 2>/dev/null || true - rm -f /var/lib/neo4j/data/neo4j.pid 2>/dev/null || true - find /var/lib/neo4j -name "*.pid" -type f -delete 2>/dev/null || true - find /var/lib/neo4j/data -name "*.pid" -type f -delete 2>/dev/null || true - exec /startup/docker-entrypoint.sh neo4j - healthcheck: - test: ["CMD-SHELL", "cypher-shell -u neo4j -p ${NEO4J_PASSWORD:-neo4j} 'RETURN 1' || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - start_period: 30s + # Neo4j for evault-core graph data + neo4j: + image: neo4j:5.15 + container_name: metastate-neo4j + ports: + - "7474:7474" # HTTP + - "7687:7687" # Bolt + environment: + - NEO4J_AUTH=${NEO4J_USER:-neo4j}/${NEO4J_PASSWORD:-neo4j} + - NEO4J_USER=${NEO4J_USER:-neo4j} + - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} + - NEO4J_dbms_connector_bolt_listen__address=0.0.0.0:7687 + - NEO4J_dbms_connector_http_listen__address=0.0.0.0:7474 + - NEO4J_dbms_connector_bolt_advertised__address=neo4j:7687 + volumes: + - neo4j_data:/var/lib/neo4j/data + networks: + - metastate-core-network + <<: *common-host-access + entrypoint: ["/bin/sh", "-c"] + command: + - | + # Remove any stale PID files before starting Neo4j + rm -f /var/lib/neo4j/run/neo4j.pid 2>/dev/null || true + rm -f /var/lib/neo4j/data/run/neo4j.pid 2>/dev/null || true + rm -f /var/lib/neo4j/data/neo4j.pid 2>/dev/null || true + find /var/lib/neo4j -name "*.pid" -type f -delete 2>/dev/null || true + find /var/lib/neo4j/data -name "*.pid" -type f -delete 2>/dev/null || true + exec /startup/docker-entrypoint.sh neo4j + healthcheck: + test: + [ + "CMD-SHELL", + "cypher-shell -u neo4j -p ${NEO4J_PASSWORD:-neo4j} 'RETURN 1' || exit 1", + ] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s - # Registry service - registry: - profiles: - - core - build: - context: . - dockerfile: ./docker/Dockerfile.registry - network: host - container_name: metastate-registry - ports: - - "4321:4321" - environment: - - NODE_ENV=${NODE_ENV:-production} - - DATABASE_URL=${REGISTRY_DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/registry} - - REGISTRY_SHARED_SECRET=${REGISTRY_SHARED_SECRET:-dev-secret-change-me} - - PUBLIC_REGISTRY_URL=${PUBLIC_REGISTRY_URL:-http://localhost:4321} - depends_on: - postgres: - condition: service_healthy - networks: - - metastate-core-network - <<: *common-host-access - restart: unless-stopped + # Registry service + registry: + profiles: + - core + build: + context: . + dockerfile: ./docker/Dockerfile.registry + network: host + container_name: metastate-registry + ports: + - "4321:4321" + environment: + - NODE_ENV=${NODE_ENV:-production} + - DATABASE_URL=${REGISTRY_DATABASE_URL} + - REGISTRY_SHARED_SECRET=${REGISTRY_SHARED_SECRET} + - PUBLIC_REGISTRY_URL=${PUBLIC_REGISTRY_URL} + depends_on: + postgres: + condition: service_healthy + networks: + - metastate-core-network + <<: *common-host-access + restart: unless-stopped - # eVault Core service - evault-core: - profiles: - - core - build: - context: . - dockerfile: ./docker/Dockerfile.evault-core - network: host - container_name: metastate-evault-core - ports: - - "3001:3001" # Express (provisioning API) - - "4000:4000" # Fastify (GraphQL/HTTP) - environment: - - NODE_ENV=${NODE_ENV:-production} - - EXPRESS_PORT=3001 - - FASTIFY_PORT=4000 - - PORT=4000 - - REGISTRY_DATABASE_URL=${REGISTRY_DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/registry} - - PUBLIC_REGISTRY_URL=${PUBLIC_REGISTRY_URL:-http://registry:4321} - - REGISTRY_SHARED_SECRET=${REGISTRY_SHARED_SECRET:-dev-secret-change-me} - - NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687} - - NEO4J_USER=${NEO4J_USER:-neo4j} - - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} - - EVAULT_PUBLIC_KEY=${EVAULT_PUBLIC_KEY:-} - - W3ID=${W3ID:-} - depends_on: - postgres: - condition: service_healthy - registry: - condition: service_started - neo4j: - condition: service_healthy - networks: - - metastate-core-network - <<: *common-host-access - restart: unless-stopped + # eVault Core service + evault-core: + profiles: + - core + build: + context: . + dockerfile: ./docker/Dockerfile.evault-core + network: host + container_name: metastate-evault-core + ports: + - "3001:3001" # Express (provisioning API) + - "4000:4000" # Fastify (GraphQL/HTTP) + environment: + - NODE_ENV=${NODE_ENV:-production} + - EXPRESS_PORT=3001 + - FASTIFY_PORT=4000 + - PORT=4000 + - REGISTRY_DATABASE_URL=${REGISTRY_DATABASE_URL} + - PUBLIC_REGISTRY_URL=${PUBLIC_REGISTRY_URL} + - REGISTRY_SHARED_SECRET=${REGISTRY_SHARED_SECRET} + - NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687} + - NEO4J_USER=${NEO4J_USER:-neo4j} + - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4j} + - EVAULT_PUBLIC_KEY=${EVAULT_PUBLIC_KEY:-} + - W3ID=${W3ID:-} + depends_on: + postgres: + condition: service_healthy + registry: + condition: service_started + neo4j: + condition: service_healthy + networks: + - metastate-core-network + <<: *common-host-access + restart: unless-stopped volumes: - postgres_data: - driver: local - neo4j_data: - driver: local + postgres_data: + driver: local + neo4j_data: + driver: local networks: - metastate-core-network: - driver: bridge - driver_opts: - com.docker.network.bridge.enable_icc: "true" - com.docker.network.bridge.enable_ip_masquerade: "true" - ipam: - config: - - subnet: 172.28.0.0/16 + metastate-core-network: + driver: bridge + driver_opts: + com.docker.network.bridge.enable_icc: "true" + com.docker.network.bridge.enable_ip_masquerade: "true" + ipam: + config: + - subnet: 172.28.0.0/16 diff --git a/infrastructure/control-panel/src/lib/ui/Table/Table.svelte b/infrastructure/control-panel/src/lib/ui/Table/Table.svelte index d353ae977..133bdb6ed 100644 --- a/infrastructure/control-panel/src/lib/ui/Table/Table.svelte +++ b/infrastructure/control-panel/src/lib/ui/Table/Table.svelte @@ -374,7 +374,7 @@ {/snippet} -{#snippet BodyCell(data: Record, field: string, i: number)} +{#snippet BodyCell(data: Record>, field: string, i: number)} ({ - resolver: zodResolver(registerSchema), + resolver: zodResolver(registerSchema as any), defaultValues: { email: "", password: "", diff --git a/platforms/eVoting/src/app/(auth)/login/page.tsx b/platforms/eVoting/src/app/(auth)/login/page.tsx index 2402579c8..eb7c76f40 100644 --- a/platforms/eVoting/src/app/(auth)/login/page.tsx +++ b/platforms/eVoting/src/app/(auth)/login/page.tsx @@ -14,6 +14,8 @@ export default function LoginPage() { const [errorMessage, setErrorMessage] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isMobile, setIsMobile] = useState(false); + const [redirectTo, setRedirectTo] = useState("/"); + useEffect(() => { setIsMobile(isMobileDevice()); @@ -24,6 +26,7 @@ export default function LoginPage() { if (typeof window === 'undefined') return; const params = new URLSearchParams(window.location.search); + const redirect = params.get("redirect"); const ename = params.get('ename'); const session = params.get('session'); const signature = params.get('signature'); @@ -38,6 +41,11 @@ export default function LoginPage() { return; } + if (redirect && redirect.startsWith("/") && !redirect.startsWith("//")) { + setRedirectTo(redirect); + sessionStorage.setItem("postLoginRedirect", redirect); + } + // If no query params, proceed with normal flow const fetchQRCode = async () => { try { @@ -84,7 +92,11 @@ export default function LoginPage() { if (data.token && data.user) { setAuthToken(data.token); setAuthId(data.user.id); - window.location.href = "/"; + const redirect = + sessionStorage.getItem("postLoginRedirect") || redirectTo || "/"; + +sessionStorage.removeItem("postLoginRedirect"); +window.location.href = redirect; } } else { const errorData = await response.json(); @@ -122,7 +134,11 @@ export default function LoginPage() { if (data.token && data.user) { setAuthToken(data.token); setAuthId(data.user.id); - window.location.href = "/"; + const redirect = + sessionStorage.getItem("postLoginRedirect") || redirectTo || "/"; + +sessionStorage.removeItem("postLoginRedirect"); +window.location.href = redirect; } } catch (error) { console.error("Error parsing SSE data:", error); @@ -134,7 +150,7 @@ export default function LoginPage() { }; return () => eventSource.close(); - }, [sessionId, login]); + }, [sessionId, login, redirectTo]); const getAppStoreLink = () => { if (typeof navigator === 'undefined') return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; @@ -170,7 +186,7 @@ export default function LoginPage() {
{isMobile ? ( <> - Click the button below using your + Click the button below using you eID App to login diff --git a/platforms/esigner/.svelte-kit/ambient.d.ts b/platforms/esigner/.svelte-kit/ambient.d.ts index 0bdd04597..53deecca6 100644 --- a/platforms/esigner/.svelte-kit/ambient.d.ts +++ b/platforms/esigner/.svelte-kit/ambient.d.ts @@ -45,7 +45,9 @@ declare module '$env/static/private' { export const GROUP_CHARTER_MAPPING_DB_PATH: string; export const CERBERUS_MAPPING_DB_PATH: string; export const GOOGLE_APPLICATION_CREDENTIALS: string; + export const PICTIQUE_JWT_SECRET: string; export const GROUP_CHARTER_DATABASE_URL: string; + export const CHARTER_JWT_SECRET: string; export const CERBERUS_DATABASE_URL: string; export const EVOTING_DATABASE_URL: string; export const EVOTING_MAPPING_DB_PATH: string; @@ -53,112 +55,54 @@ declare module '$env/static/private' { 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 SHELL: string; - export const LSCOLORS: string; export const npm_command: string; - export const GHOSTTY_BIN_DIR: string; export const COLORTERM: 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 NODE: string; - export const JAVA_HOME: string; export const npm_config_verify_deps_before_run: string; export const npm_config__jsr_registry: string; - export const CLOJURE_HOME: string; - export const MEMORY_PRESSURE_WRITE: string; - export const FNM_NODE_DIST_MIRROR: string; export const npm_config_strict_peer_dependencies: string; - export const DESKTOP_SESSION: string; - export const ELECTRON_OZONE_PLATFORM_HINT: string; - export const XCURSOR_SIZE: string; export const npm_config_globalconfig: string; - export const EDITOR: string; - export const XDG_SEAT: string; export const PWD: string; - export const XDG_SESSION_DESKTOP: string; - export const LOGNAME: string; - export const QT_QPA_PLATFORMTHEME: string; - export const XDG_SESSION_TYPE: string; - export const SYSTEMD_EXEC_PID: string; - export const TERMINAL: string; - export const QT_QPA_PLATFORMTHEME_QT6: string; - export const MOTD_SHOWN: string; - export const GDM_LANG: string; - export const GHOSTTY_SHELL_FEATURES: string; + export const XAUTHORITY: string; + export const VSCODE_GIT_ASKPASS_NODE: string; + export const VSCODE_INJECTION: string; export const HOME: string; - export const USERNAME: string; export const LANG: string; - export const FNM_COREPACK_ENABLED: string; - export const LS_COLORS: string; - export const XDG_CURRENT_DESKTOP: string; export const npm_package_version: string; - export const MESA_GLSL_CACHE_MAX_SIZE: string; - export const MEMORY_PRESSURE_WATCH: string; - export const STARSHIP_SHELL: string; - export const WAYLAND_DISPLAY: string; + export const TURBO_IS_TUI: string; export const pnpm_config_verify_deps_before_run: string; - export const NIRI_SOCKET: string; - export const MANAGERPID: string; export const INIT_CWD: string; - export const STARSHIP_SESSION_KEY: string; - export const QT_QPA_PLATFORM: string; export const npm_lifecycle_script: string; - export const GHOSTTY_RESOURCES_DIR: string; - export const XDG_SESSION_CLASS: string; - export const ANDROID_HOME: string; - export const TERMINFO: string; + export const VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + export const TURBO_HASH: string; export const TERM: string; export const npm_package_name: string; - export const ZSH: 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 DISPLAY: string; export const npm_lifecycle_event: string; export const SHLVL: string; - export const PAGER: string; - export const npm_config_manage_package_manager_versions: 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 mesa_glthread: string; export const NODE_PATH: string; - export const DEBUGINFOD_URLS: string; export const npm_package_json: string; - export const XCURSOR_THEME: string; + export const VSCODE_GIT_ASKPASS_MAIN: string; export const PATH: string; export const npm_config_node_gyp: string; - export const GDMSESSION: string; export const DBUS_SESSION_BUS_ADDRESS: string; - export const MAIL: string; export const npm_config_registry: string; - export const MESA_SHADER_CACHE_DIR: 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 OLDPWD: string; export const TERM_PROGRAM: string; + export const NODE_ENV: string; } /** @@ -185,6 +129,7 @@ declare module '$env/static/public' { 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_EID_WALLET_TOKEN: string; export const PUBLIC_ESIGNER_BASE_URL: string; export const PUBLIC_FILE_MANAGER_BASE_URL: string; } @@ -222,7 +167,9 @@ declare module '$env/dynamic/private' { GROUP_CHARTER_MAPPING_DB_PATH: string; CERBERUS_MAPPING_DB_PATH: string; GOOGLE_APPLICATION_CREDENTIALS: string; + PICTIQUE_JWT_SECRET: string; GROUP_CHARTER_DATABASE_URL: string; + CHARTER_JWT_SECRET: string; CERBERUS_DATABASE_URL: string; EVOTING_DATABASE_URL: string; EVOTING_MAPPING_DB_PATH: string; @@ -230,112 +177,54 @@ declare module '$env/dynamic/private' { 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; SHELL: string; - LSCOLORS: string; npm_command: string; - GHOSTTY_BIN_DIR: string; COLORTERM: string; - TERM_PROGRAM_VERSION: string; npm_config_optional: string; - FNM_ARCH: string; npm_config_npm_globalconfig: string; NODE: string; - JAVA_HOME: string; npm_config_verify_deps_before_run: string; npm_config__jsr_registry: string; - CLOJURE_HOME: string; - MEMORY_PRESSURE_WRITE: string; - FNM_NODE_DIST_MIRROR: string; npm_config_strict_peer_dependencies: string; - DESKTOP_SESSION: string; - ELECTRON_OZONE_PLATFORM_HINT: string; - XCURSOR_SIZE: string; npm_config_globalconfig: string; - EDITOR: string; - XDG_SEAT: string; PWD: string; - XDG_SESSION_DESKTOP: string; - LOGNAME: string; - QT_QPA_PLATFORMTHEME: string; - XDG_SESSION_TYPE: string; - SYSTEMD_EXEC_PID: string; - TERMINAL: string; - QT_QPA_PLATFORMTHEME_QT6: string; - MOTD_SHOWN: string; - GDM_LANG: string; - GHOSTTY_SHELL_FEATURES: string; + XAUTHORITY: string; + VSCODE_GIT_ASKPASS_NODE: string; + VSCODE_INJECTION: string; HOME: string; - USERNAME: string; LANG: string; - FNM_COREPACK_ENABLED: string; - LS_COLORS: string; - XDG_CURRENT_DESKTOP: string; npm_package_version: string; - MESA_GLSL_CACHE_MAX_SIZE: string; - MEMORY_PRESSURE_WATCH: string; - STARSHIP_SHELL: string; - WAYLAND_DISPLAY: string; + TURBO_IS_TUI: string; pnpm_config_verify_deps_before_run: string; - NIRI_SOCKET: string; - MANAGERPID: string; INIT_CWD: string; - STARSHIP_SESSION_KEY: string; - QT_QPA_PLATFORM: string; npm_lifecycle_script: string; - GHOSTTY_RESOURCES_DIR: string; - XDG_SESSION_CLASS: string; - ANDROID_HOME: string; - TERMINFO: string; + VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + TURBO_HASH: string; TERM: string; npm_package_name: string; - ZSH: string; USER: string; npm_config_frozen_lockfile: string; - NDK_HOME: string; + VSCODE_GIT_IPC_HANDLE: string; DISPLAY: string; npm_lifecycle_event: string; SHLVL: string; - PAGER: string; - npm_config_manage_package_manager_versions: 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; - mesa_glthread: string; NODE_PATH: string; - DEBUGINFOD_URLS: string; npm_package_json: string; - XCURSOR_THEME: string; + VSCODE_GIT_ASKPASS_MAIN: string; PATH: string; npm_config_node_gyp: string; - GDMSESSION: string; DBUS_SESSION_BUS_ADDRESS: string; - MAIL: string; npm_config_registry: string; - MESA_SHADER_CACHE_DIR: string; - FNM_DIR: string; - FNM_MULTISHELL_PATH: string; npm_node_execpath: string; - FNM_LOGLEVEL: string; - OLDPWD: string; TERM_PROGRAM: string; + NODE_ENV: string; [key: `PUBLIC_${string}`]: undefined; [key: `${string}`]: string | undefined; } @@ -367,6 +256,7 @@ declare module '$env/dynamic/public' { PUBLIC_EVOTING_URL: string; PUBLIC_APP_STORE_EID_WALLET: string; PUBLIC_PLAY_STORE_EID_WALLET: string; + PUBLIC_EID_WALLET_TOKEN: string; PUBLIC_ESIGNER_BASE_URL: string; PUBLIC_FILE_MANAGER_BASE_URL: string; [key: `PUBLIC_${string}`]: string | undefined; diff --git a/platforms/esigner/.svelte-kit/generated/client/nodes/1.js b/platforms/esigner/.svelte-kit/generated/client/nodes/1.js index 635016f9c..84e41cf4d 100644 --- a/platforms/esigner/.svelte-kit/generated/client/nodes/1.js +++ b/platforms/esigner/.svelte-kit/generated/client/nodes/1.js @@ -1 +1 @@ -export { default as component } from "../../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_f2289347040f8edd51fabc9e5c8ef0b5/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte"; \ No newline at end of file +export { default as component } from "../../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_3d1fb29ef4e8e19a50794ceca30c7fc9/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte"; \ No newline at end of file diff --git a/platforms/esigner/.svelte-kit/generated/server/internal.js b/platforms/esigner/.svelte-kit/generated/server/internal.js index 22b9bf2f8..e05382ee3 100644 --- a/platforms/esigner/.svelte-kit/generated/server/internal.js +++ b/platforms/esigner/.svelte-kit/generated/server/internal.js @@ -3,7 +3,7 @@ import root from '../root.js'; import { set_building, set_prerendering } from '__sveltekit/environment'; import { set_assets } from '$app/paths/internal/server'; import { set_manifest, set_read_implementation } from '__sveltekit/server'; -import { set_private_env, set_public_env } from '../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_f2289347040f8edd51fabc9e5c8ef0b5/node_modules/@sveltejs/kit/src/runtime/shared-server.js'; +import { set_private_env, set_public_env } from '../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_3d1fb29ef4e8e19a50794ceca30c7fc9/node_modules/@sveltejs/kit/src/runtime/shared-server.js'; export const options = { app_template_contains_nonce: false, @@ -21,10 +21,10 @@ export const options = { service_worker: false, service_worker_options: undefined, templates: { - app: ({ head, body, assets, nonce, env }) => "\n\n\t\n\t\t\n\t\t\n\t\t" + head + "\n\t\n\t\n\t\t
" + body + "
\n\t\n\n\n", + app: ({ head, body, assets, nonce, env }) => "\n\n \n \n \n \n \n \n \n " + head + "\n \n \n
" + body + "
\n \n\n", error: ({ status, message }) => "\n\n\t\n\t\t\n\t\t" + message + "\n\n\t\t\n\t\n\t\n\t\t
\n\t\t\t" + status + "\n\t\t\t
\n\t\t\t\t

" + message + "

\n\t\t\t
\n\t\t
\n\t\n\n" }, - version_hash: "he2m2" + version_hash: "153et77" }; export async function get_hooks() { diff --git a/platforms/esigner/package.json b/platforms/esigner/package.json index 990782087..c94d023df 100644 --- a/platforms/esigner/package.json +++ b/platforms/esigner/package.json @@ -1,46 +1,45 @@ { - "name": "esigner", - "private": true, - "version": "0.0.1", - "type": "module", - "scripts": { - "dev": "vite dev --host", - "build": "vite build", - "preview": "vite preview", - "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "format": "prettier --write .", - "lint": "prettier --check . && eslint ." - }, - "devDependencies": { - "@eslint/compat": "^1.2.5", - "@eslint/js": "^9.18.0", - "@sveltejs/adapter-static": "^3.0.8", - "@sveltejs/kit": "^2.16.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", - "@tailwindcss/vite": "^4.0.0", - "clsx": "^2.1.1", - "eslint": "^9.18.0", - "eslint-config-prettier": "^10.0.1", - "eslint-plugin-svelte": "^3.0.0", - "globals": "^16.0.0", - "prettier": "^3.4.2", - "prettier-plugin-svelte": "^3.3.3", - "prettier-plugin-tailwindcss": "^0.7.0", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^5.0.0", - "typescript-eslint": "^8.20.0", - "vite": "^6.2.6" - }, - "dependencies": { - "@sveltejs/adapter-node": "^5.2.12", - "axios": "^1.6.7", - "svelte-qrcode": "^1.0.1", - "svelte-qrcode-action": "^1.0.2", - "tailwind-merge": "^3.0.2" - } + "name": "esigner", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev --host", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint ." + }, + "devDependencies": { + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@sveltejs/adapter-static": "^3.0.8", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.0.0", + "clsx": "^2.1.1", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.0.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.7.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.20.0", + "vite": "^6.2.6" + }, + "dependencies": { + "@sveltejs/adapter-node": "^5.2.12", + "axios": "^1.6.7", + "svelte-qrcode": "^1.0.1", + "svelte-qrcode-action": "^1.0.2", + "tailwind-merge": "^3.0.2" + } } - diff --git a/platforms/esigner/src/app.css b/platforms/esigner/src/app.css index ea5d081ba..037324f86 100644 --- a/platforms/esigner/src/app.css +++ b/platforms/esigner/src/app.css @@ -1,7 +1,9 @@ -@import 'tailwindcss'; +@import "tailwindcss"; body { - font-family: system-ui, -apple-system, sans-serif; - background-color: white; + font-family: + system-ui, + -apple-system, + sans-serif; + background-color: white; } - diff --git a/platforms/esigner/src/app.d.ts b/platforms/esigner/src/app.d.ts index 92b602baa..addc02a5a 100644 --- a/platforms/esigner/src/app.d.ts +++ b/platforms/esigner/src/app.d.ts @@ -1,14 +1,12 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface Platform {} - } + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface Platform {} + } } export {}; - - diff --git a/platforms/esigner/src/app.html b/platforms/esigner/src/app.html index da25433f0..584010c08 100644 --- a/platforms/esigner/src/app.html +++ b/platforms/esigner/src/app.html @@ -1,16 +1,28 @@ - - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- + + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ - diff --git a/platforms/esigner/src/lib/stores/auth.ts b/platforms/esigner/src/lib/stores/auth.ts index 0945d8d27..7654207d8 100644 --- a/platforms/esigner/src/lib/stores/auth.ts +++ b/platforms/esigner/src/lib/stores/auth.ts @@ -1,77 +1,81 @@ -import { writable } from 'svelte/store'; -import { apiClient, setAuthToken, removeAuthToken, removeAuthId } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { + apiClient, + setAuthToken, + removeAuthToken, + removeAuthId, +} from "$lib/utils/axios"; export const isAuthenticated = writable(false); export const currentUser = writable(null); export const authInitialized = writable(false); export const initializeAuth = async () => { - authInitialized.set(false); - const token = localStorage.getItem('esigner_auth_token'); - if (token) { - // Set token in axios headers immediately - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; - // Verify token is still valid by fetching current user - try { - const response = await apiClient.get('/api/users'); - if (response.data) { - currentUser.set(response.data); - isAuthenticated.set(true); - authInitialized.set(true); - return true; - } - } catch (err) { - // Token invalid, clear it - console.error('Auth token invalid:', err); - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - } - } - isAuthenticated.set(false); - currentUser.set(null); - authInitialized.set(true); - return false; + authInitialized.set(false); + const token = localStorage.getItem("esigner_auth_token"); + if (token) { + // Set token in axios headers immediately + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; + // Verify token is still valid by fetching current user + try { + const response = await apiClient.get("/api/users"); + if (response.data) { + currentUser.set(response.data); + isAuthenticated.set(true); + authInitialized.set(true); + return true; + } + } catch (err) { + // Token invalid, clear it + console.error("Auth token invalid:", err); + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + } + } + isAuthenticated.set(false); + currentUser.set(null); + authInitialized.set(true); + return false; }; export const login = async (token: string, user?: any) => { - // Store token in localStorage first - setAuthToken(token); - // Set token in axios headers - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; - - // Set user if provided - if (user) { - currentUser.set(user); - isAuthenticated.set(true); - } - - // Verify by fetching user to ensure token is valid - try { - const response = await apiClient.get('/api/users'); - if (response.data) { - currentUser.set(response.data); - isAuthenticated.set(true); - return true; - } - } catch (err) { - console.error('Failed to verify login:', err); - // If verification fails, clear everything - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - isAuthenticated.set(false); - currentUser.set(null); - return false; - } - return true; + // Store token in localStorage first + setAuthToken(token); + // Set token in axios headers + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; + + // Set user if provided + if (user) { + currentUser.set(user); + isAuthenticated.set(true); + } + + // Verify by fetching user to ensure token is valid + try { + const response = await apiClient.get("/api/users"); + if (response.data) { + currentUser.set(response.data); + isAuthenticated.set(true); + return true; + } + } catch (err) { + console.error("Failed to verify login:", err); + // If verification fails, clear everything + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + isAuthenticated.set(false); + currentUser.set(null); + return false; + } + return true; }; export const logout = () => { - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - isAuthenticated.set(false); - currentUser.set(null); + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + isAuthenticated.set(false); + currentUser.set(null); }; - diff --git a/platforms/esigner/src/lib/stores/files.ts b/platforms/esigner/src/lib/stores/files.ts index 570eef2d7..6760284ea 100644 --- a/platforms/esigner/src/lib/stores/files.ts +++ b/platforms/esigner/src/lib/stores/files.ts @@ -139,4 +139,3 @@ export const deleteDocument = async (documentId: string) => { // Keep deleteFile alias for backward compatibility export const deleteFile = deleteDocument; - diff --git a/platforms/esigner/src/lib/stores/invitations.ts b/platforms/esigner/src/lib/stores/invitations.ts index 656f898c2..d77e8b2ea 100644 --- a/platforms/esigner/src/lib/stores/invitations.ts +++ b/platforms/esigner/src/lib/stores/invitations.ts @@ -1,31 +1,31 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; -import type { Writable } from 'svelte/store'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; +import type { Writable } from "svelte/store"; export interface Invitation { - id: string; - fileId: string; - userId: string; - status: 'pending' | 'signed' | 'declined'; - invitedAt: string; - signedAt?: string; - declinedAt?: string; - file?: { - id: string; - name: string; - displayName?: string | null; - description?: string | null; - mimeType: string; - size: number; - ownerId: string; - createdAt: string; - }; - user?: { - id: string; - name: string; - ename: string; - avatarUrl?: string; - }; + id: string; + fileId: string; + userId: string; + status: "pending" | "signed" | "declined"; + invitedAt: string; + signedAt?: string; + declinedAt?: string; + file?: { + id: string; + name: string; + displayName?: string | null; + description?: string | null; + mimeType: string; + size: number; + ownerId: string; + createdAt: string; + }; + user?: { + id: string; + name: string; + ename: string; + avatarUrl?: string; + }; } export const invitations: Writable = writable([]); @@ -33,45 +33,51 @@ export const isLoading = writable(false); export const error = writable(null); export const fetchInvitations = async () => { - try { - isLoading.set(true); - error.set(null); - const response = await apiClient.get('/api/invitations'); - invitations.set(response.data); - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to fetch invitations'); - throw err; - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + error.set(null); + const response = await apiClient.get("/api/invitations"); + invitations.set(response.data); + } catch (err) { + error.set( + err instanceof Error ? err.message : "Failed to fetch invitations", + ); + throw err; + } finally { + isLoading.set(false); + } }; export const inviteSignees = async (fileId: string, userIds: string[]) => { - try { - isLoading.set(true); - error.set(null); - const response = await apiClient.post(`/api/files/${fileId}/invite`, { userIds }); - return response.data; - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to invite signees'); - throw err; - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + error.set(null); + const response = await apiClient.post(`/api/files/${fileId}/invite`, { + userIds, + }); + return response.data; + } catch (err) { + error.set( + err instanceof Error ? err.message : "Failed to invite signees", + ); + throw err; + } finally { + isLoading.set(false); + } }; export const declineInvitation = async (invitationId: string) => { - try { - isLoading.set(true); - error.set(null); - await apiClient.post(`/api/invitations/${invitationId}/decline`); - await fetchInvitations(); - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to decline invitation'); - throw err; - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + error.set(null); + await apiClient.post(`/api/invitations/${invitationId}/decline`); + await fetchInvitations(); + } catch (err) { + error.set( + err instanceof Error ? err.message : "Failed to decline invitation", + ); + throw err; + } finally { + isLoading.set(false); + } }; - - diff --git a/platforms/esigner/src/lib/stores/signatures.ts b/platforms/esigner/src/lib/stores/signatures.ts index 7525c4111..5d0ec9776 100644 --- a/platforms/esigner/src/lib/stores/signatures.ts +++ b/platforms/esigner/src/lib/stores/signatures.ts @@ -1,28 +1,28 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; -import type { Writable } from 'svelte/store'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; +import type { Writable } from "svelte/store"; export interface Signature { - id: string; - userId: string; - fileSigneeId?: string | null; - md5Hash: string; - message: string; - signature: string; - publicKey: string; - createdAt: string; - user?: { - id: string; - name: string; - ename: string; - avatarUrl?: string; - }; + id: string; + userId: string; + fileSigneeId?: string | null; + md5Hash: string; + message: string; + signature: string; + publicKey: string; + createdAt: string; + user?: { + id: string; + name: string; + ename: string; + avatarUrl?: string; + }; } export interface SigningSession { - sessionId: string; - qrData: string; - expiresAt: string; + sessionId: string; + qrData: string; + expiresAt: string; } export const signatures: Writable = writable([]); @@ -30,31 +30,39 @@ export const isLoading = writable(false); export const error = writable(null); export const fetchFileSignatures = async (fileId: string) => { - try { - isLoading.set(true); - error.set(null); - const response = await apiClient.get(`/api/files/${fileId}/signatures`); - signatures.set(response.data); - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to fetch signatures'); - throw err; - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + error.set(null); + const response = await apiClient.get(`/api/files/${fileId}/signatures`); + signatures.set(response.data); + } catch (err) { + error.set( + err instanceof Error ? err.message : "Failed to fetch signatures", + ); + throw err; + } finally { + isLoading.set(false); + } }; -export const createSigningSession = async (fileId: string): Promise => { - try { - isLoading.set(true); - error.set(null); - const response = await apiClient.post('/api/signatures/session', { fileId }); - return response.data; - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to create signing session'); - throw err; - } finally { - isLoading.set(false); - } +export const createSigningSession = async ( + fileId: string, +): Promise => { + try { + isLoading.set(true); + error.set(null); + const response = await apiClient.post("/api/signatures/session", { + fileId, + }); + return response.data; + } catch (err) { + error.set( + err instanceof Error + ? err.message + : "Failed to create signing session", + ); + throw err; + } finally { + isLoading.set(false); + } }; - - diff --git a/platforms/esigner/src/lib/stores/toast.ts b/platforms/esigner/src/lib/stores/toast.ts index 34c33d965..c0bdf2ef1 100644 --- a/platforms/esigner/src/lib/stores/toast.ts +++ b/platforms/esigner/src/lib/stores/toast.ts @@ -1,40 +1,46 @@ -import { writable } from 'svelte/store'; +import { writable } from "svelte/store"; export interface Toast { - id: string; - message: string; - type: 'success' | 'error' | 'info' | 'warning'; - duration?: number; + id: string; + message: string; + type: "success" | "error" | "info" | "warning"; + duration?: number; } export const toasts = writable([]); let toastIdCounter = 0; -export function showToast(message: string, type: Toast['type'] = 'info', duration: number = 3000) { - const id = `toast-${toastIdCounter++}`; - const toast: Toast = { id, message, type, duration }; - - toasts.update((current) => [...current, toast]); - - if (duration > 0) { - setTimeout(() => { - removeToast(id); - }, duration); - } - - return id; +export function showToast( + message: string, + type: Toast["type"] = "info", + duration: number = 3000, +) { + const id = `toast-${toastIdCounter++}`; + const toast: Toast = { id, message, type, duration }; + + toasts.update((current) => [...current, toast]); + + if (duration > 0) { + setTimeout(() => { + removeToast(id); + }, duration); + } + + return id; } export function removeToast(id: string) { - toasts.update((current) => current.filter((t) => t.id !== id)); + toasts.update((current) => current.filter((t) => t.id !== id)); } export const toast = { - success: (message: string, duration?: number) => showToast(message, 'success', duration), - error: (message: string, duration?: number) => showToast(message, 'error', duration), - info: (message: string, duration?: number) => showToast(message, 'info', duration), - warning: (message: string, duration?: number) => showToast(message, 'warning', duration), + success: (message: string, duration?: number) => + showToast(message, "success", duration), + error: (message: string, duration?: number) => + showToast(message, "error", duration), + info: (message: string, duration?: number) => + showToast(message, "info", duration), + warning: (message: string, duration?: number) => + showToast(message, "warning", duration), }; - - diff --git a/platforms/esigner/src/lib/utils/axios.ts b/platforms/esigner/src/lib/utils/axios.ts index 4ee855bd3..d400e290b 100644 --- a/platforms/esigner/src/lib/utils/axios.ts +++ b/platforms/esigner/src/lib/utils/axios.ts @@ -1,26 +1,25 @@ -import axios from 'axios'; -import { PUBLIC_ESIGNER_BASE_URL } from '$env/static/public'; +import axios from "axios"; +import { PUBLIC_ESIGNER_BASE_URL } from "$env/static/public"; -const API_BASE_URL = PUBLIC_ESIGNER_BASE_URL || 'http://localhost:3004'; +const API_BASE_URL = PUBLIC_ESIGNER_BASE_URL || "http://localhost:3004"; export const apiClient = axios.create({ - baseURL: API_BASE_URL, - headers: { - 'Content-Type': 'application/json', - }, + baseURL: API_BASE_URL, + headers: { + "Content-Type": "application/json", + }, }); export const setAuthToken = (token: string) => { - localStorage.setItem('esigner_auth_token', token); - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; + localStorage.setItem("esigner_auth_token", token); + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; }; export const removeAuthToken = () => { - localStorage.removeItem('esigner_auth_token'); - delete apiClient.defaults.headers.common['Authorization']; + localStorage.removeItem("esigner_auth_token"); + delete apiClient.defaults.headers.common["Authorization"]; }; export const removeAuthId = () => { - localStorage.removeItem('esigner_auth_id'); + localStorage.removeItem("esigner_auth_id"); }; - diff --git a/platforms/esigner/src/lib/utils/mime-type.ts b/platforms/esigner/src/lib/utils/mime-type.ts index 5417b63ac..f603ecb16 100644 --- a/platforms/esigner/src/lib/utils/mime-type.ts +++ b/platforms/esigner/src/lib/utils/mime-type.ts @@ -3,16 +3,20 @@ * instead of long strings like application/vnd.openxmlformats-officedocument.spreadsheetml.sheet */ export function getMimeTypeDisplayLabel(mimeType: string): string { - if (!mimeType || typeof mimeType !== "string") return mimeType ?? ""; - const m = mimeType.toLowerCase(); - // Office / common document types - if (m.includes("spreadsheetml.sheet") || m.includes("ms-excel")) return "XLSX"; - if (m.includes("wordprocessingml.document") || m.includes("msword")) return "DOCX"; - if (m.includes("presentationml") || m.includes("ms-powerpoint")) return "PPTX"; - if (m === "application/pdf") return "PDF"; - // Generic fallback: last meaningful part - const parts = m.split(/[/+]/); - const last = parts[parts.length - 1]; - if (last && last !== "application" && last.length <= 20) return last.toUpperCase(); - return mimeType; + if (!mimeType || typeof mimeType !== "string") return mimeType ?? ""; + const m = mimeType.toLowerCase(); + // Office / common document types + if (m.includes("spreadsheetml.sheet") || m.includes("ms-excel")) + return "XLSX"; + if (m.includes("wordprocessingml.document") || m.includes("msword")) + return "DOCX"; + if (m.includes("presentationml") || m.includes("ms-powerpoint")) + return "PPTX"; + if (m === "application/pdf") return "PDF"; + // Generic fallback: last meaningful part + const parts = m.split(/[/+]/); + const last = parts[parts.length - 1]; + if (last && last !== "application" && last.length <= 20) + return last.toUpperCase(); + return mimeType; } diff --git a/platforms/esigner/src/lib/utils/mobile-detection.ts b/platforms/esigner/src/lib/utils/mobile-detection.ts index e99efff39..723462a2f 100644 --- a/platforms/esigner/src/lib/utils/mobile-detection.ts +++ b/platforms/esigner/src/lib/utils/mobile-detection.ts @@ -1,10 +1,13 @@ export function isMobileDevice(): boolean { - if (typeof window === 'undefined') return false; - - return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || - (window.innerWidth <= 768); + if (typeof window === "undefined") return false; + + return ( + /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( + navigator.userAgent, + ) || window.innerWidth <= 768 + ); } export function getDeepLinkUrl(qrData: string): string { - return qrData; + return qrData; } diff --git a/platforms/esigner/src/routes/(protected)/files/[id]/+page.svelte b/platforms/esigner/src/routes/(protected)/files/[id]/+page.svelte index d8379ec38..a7f73e515 100644 --- a/platforms/esigner/src/routes/(protected)/files/[id]/+page.svelte +++ b/platforms/esigner/src/routes/(protected)/files/[id]/+page.svelte @@ -1,666 +1,858 @@
- -
- - - - - Back to Signature Containers - -

{file?.displayName || file?.name || 'Signature Container'}

- {#if file?.description} -

{file.description}

- {/if} -
- -
- {#if isLoading} -
-
-
-

Loading...

-
-
- {:else if file} - - - - -
-
- -
- {#if previewUrl && (file.mimeType?.startsWith('image/') || file.mimeType === 'application/pdf')} - - {/if} -
- - -
-

Signature Container

-
-
-

Name

-

{file.displayName || file.name}

-
- {#if file.description} -
-

Description

-

{file.description}

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

File Information

-
-
- File Name: - {file.name} -
-
- Size: - {formatFileSize(file.size)} -
-
- Type: - {getMimeTypeDisplayLabel(file.mimeType || '')} -
-
- Created: - {new Date(file.createdAt).toLocaleDateString()} -
-
-
- - -
-

Actions

-
- - {#if !hasUserSigned} - - {:else} - - {/if} -
-
- - -
-

- Signees ({invitations.length}) -

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

No signees invited yet

- {:else} -
- {#each getCombinedSignees() as signee} -
-
- - {signee.user?.name?.[0] || signee.user?.ename?.[0] || '?'} - -
-
-

- {signee.user?.name || signee.user?.ename || 'Unknown User'} -

-

- {#if signee.hasSigned && signee.signature} - Signed on {new Date(signee.signature.createdAt).toLocaleDateString()} - {:else} - Invited {new Date(signee.invitedAt).toLocaleDateString()} - {/if} -

-
- {#if signee.hasSigned} - ✓ Signed - {:else if signee.status === 'declined'} - - Declined - - {:else} - - Pending - - {/if} -
- {/each} -
- {/if} -
-
-
- {/if} -
-
- - - {#if showDownloadModal} -
showDownloadModal = false} - > -
e.stopPropagation()} - > -

Download Options

-

Choose what you would like to download:

- -
- - - -
- - -
-
- {/if} - - - {#if showSignModal && signingSession} -
{ - showSignModal = false; - sseConnection?.close(); - }} - > -
e.stopPropagation()} - > -

Sign Signature Container

-

- {isMobileDevice() ? 'Click the button below to open your eID Wallet and sign' : 'Scan this QR code with your eID Wallet to sign the signature container'} -

- -
- {#if isMobileDevice()} -
- - Sign with eID Wallet - -
- Click the button to open your eID wallet app -
-
- {:else} -
- {/if} -
- -
- {#if isMobileDevice()} -

1. Click the button above

-

2. Your eID wallet app will open

-

3. Review and sign the message

-

4. The signature will be recorded automatically

- {:else} -

1. Open your eID Wallet app

-

2. Scan this QR code

-

3. Review and sign the message

-

4. The signature will be recorded automatically

- {/if} -
- -

- Waiting for signature... -

- - -
-
- {/if} - + +
+ + + + + Back to Signature Containers + +

+ {file?.displayName || file?.name || "Signature Container"} +

+ {#if file?.description} +

{file.description}

+ {/if} +
+ +
+ {#if isLoading} +
+
+
+

Loading...

+
+
+ {:else if file} + + + + +
+
+ +
+ {#if previewUrl && (file.mimeType?.startsWith("image/") || file.mimeType === "application/pdf")} + + {/if} +
+ + +
+

+ Signature Container +

+
+
+

Name

+

+ {file.displayName || file.name} +

+
+ {#if file.description} +
+

+ Description +

+

+ {file.description} +

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

+ File Information +

+
+
+ File Name: + {file.name} +
+
+ Size: + {formatFileSize(file.size)} +
+
+ Type: + {getMimeTypeDisplayLabel( + file.mimeType || "", + )} +
+
+ Created: + {new Date( + file.createdAt, + ).toLocaleDateString()} +
+
+
+ + +
+

+ Actions +

+
+ + {#if !hasUserSigned} + + {:else} + + {/if} +
+
+ + +
+

+ Signees ({invitations.length}) +

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

+ No signees invited yet +

+ {:else} +
+ {#each getCombinedSignees() as signee} +
+
+ + {signee.user?.name?.[0] || + signee.user?.ename?.[0] || + "?"} + +
+
+

+ {signee.user?.name || + signee.user?.ename || + "Unknown User"} +

+

+ {#if signee.hasSigned && signee.signature} + Signed on {new Date( + signee.signature + .createdAt, + ).toLocaleDateString()} + {:else} + Invited {new Date( + signee.invitedAt, + ).toLocaleDateString()} + {/if} +

+
+ {#if signee.hasSigned} + ✓ Signed + {:else if signee.status === "declined"} + + Declined + + {:else} + + Pending + + {/if} +
+ {/each} +
+ {/if} +
+
+
+ {/if} +
+ + + +{#if showDownloadModal} +
(showDownloadModal = false)} + > +
e.stopPropagation()} + > +

+ Download Options +

+

+ Choose what you would like to download: +

+ +
+ + + +
+ + +
+
+{/if} + + +{#if showSignModal && signingSession} +
{ + showSignModal = false; + sseConnection?.close(); + }} + > +
e.stopPropagation()} + > +

+ Sign Signature Container +

+

+ {isMobileDevice() + ? "Click the button below to open your eID Wallet and sign" + : "Scan this QR code with your eID Wallet to sign the signature container"} +

+ +
+ {#if isMobileDevice()} +
+ + Sign with eID Wallet + +
+ Click the button to open your eID wallet app +
+
+ {:else} +
+ {/if} +
+ +
+ {#if isMobileDevice()} +

1. Click the button above

+

2. Your eID wallet app will open

+

3. Review and sign the message

+

4. The signature will be recorded automatically

+ {:else} +

1. Open your eID Wallet app

+

2. Scan this QR code

+

3. Review and sign the message

+

4. The signature will be recorded automatically

+ {/if} +
+ +

+ Waiting for signature... +

+ + +
+
+{/if} diff --git a/platforms/esigner/static/site.webmanifest b/platforms/esigner/static/site.webmanifest index 45dc8a206..b20abb7cb 100644 --- a/platforms/esigner/static/site.webmanifest +++ b/platforms/esigner/static/site.webmanifest @@ -1 +1,19 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/platforms/esigner/svelte.config.js b/platforms/esigner/svelte.config.js index 8c3b30445..4ca2087b8 100644 --- a/platforms/esigner/svelte.config.js +++ b/platforms/esigner/svelte.config.js @@ -1,16 +1,14 @@ -import adapter from '@sveltejs/adapter-node'; -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import adapter from "@sveltejs/adapter-node"; +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; const config = { - preprocess: vitePreprocess(), - kit: { - adapter: adapter(), - env: { - dir: '../../' - } - } + preprocess: vitePreprocess(), + kit: { + adapter: adapter(), + env: { + dir: "../../", + }, + }, }; export default config; - - diff --git a/platforms/esigner/tsconfig.json b/platforms/esigner/tsconfig.json index 2525103ca..104691d2d 100644 --- a/platforms/esigner/tsconfig.json +++ b/platforms/esigner/tsconfig.json @@ -1,16 +1,14 @@ { - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" - } + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } } - - diff --git a/platforms/esigner/vite.config.ts b/platforms/esigner/vite.config.ts index 41536d4d5..22020e1ce 100644 --- a/platforms/esigner/vite.config.ts +++ b/platforms/esigner/vite.config.ts @@ -1,16 +1,14 @@ -import tailwindcss from '@tailwindcss/vite'; -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import tailwindcss from "@tailwindcss/vite"; +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; export default defineConfig({ - plugins: [tailwindcss(), sveltekit()], - server: { - allowedHosts: [ - 'esigner.w3ds-prototype.merul.org', - 'esigner.staging.metastate.foundation', - 'esigner.w3ds.metastate.foundation' - ] - } + plugins: [tailwindcss(), sveltekit()], + server: { + allowedHosts: [ + "esigner.w3ds-prototype.merul.org", + "esigner.staging.metastate.foundation", + "esigner.w3ds.metastate.foundation", + ], + }, }); - - diff --git a/platforms/file-manager/.svelte-kit/ambient.d.ts b/platforms/file-manager/.svelte-kit/ambient.d.ts index 0bdd04597..53deecca6 100644 --- a/platforms/file-manager/.svelte-kit/ambient.d.ts +++ b/platforms/file-manager/.svelte-kit/ambient.d.ts @@ -45,7 +45,9 @@ declare module '$env/static/private' { export const GROUP_CHARTER_MAPPING_DB_PATH: string; export const CERBERUS_MAPPING_DB_PATH: string; export const GOOGLE_APPLICATION_CREDENTIALS: string; + export const PICTIQUE_JWT_SECRET: string; export const GROUP_CHARTER_DATABASE_URL: string; + export const CHARTER_JWT_SECRET: string; export const CERBERUS_DATABASE_URL: string; export const EVOTING_DATABASE_URL: string; export const EVOTING_MAPPING_DB_PATH: string; @@ -53,112 +55,54 @@ declare module '$env/static/private' { 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 SHELL: string; - export const LSCOLORS: string; export const npm_command: string; - export const GHOSTTY_BIN_DIR: string; export const COLORTERM: 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 NODE: string; - export const JAVA_HOME: string; export const npm_config_verify_deps_before_run: string; export const npm_config__jsr_registry: string; - export const CLOJURE_HOME: string; - export const MEMORY_PRESSURE_WRITE: string; - export const FNM_NODE_DIST_MIRROR: string; export const npm_config_strict_peer_dependencies: string; - export const DESKTOP_SESSION: string; - export const ELECTRON_OZONE_PLATFORM_HINT: string; - export const XCURSOR_SIZE: string; export const npm_config_globalconfig: string; - export const EDITOR: string; - export const XDG_SEAT: string; export const PWD: string; - export const XDG_SESSION_DESKTOP: string; - export const LOGNAME: string; - export const QT_QPA_PLATFORMTHEME: string; - export const XDG_SESSION_TYPE: string; - export const SYSTEMD_EXEC_PID: string; - export const TERMINAL: string; - export const QT_QPA_PLATFORMTHEME_QT6: string; - export const MOTD_SHOWN: string; - export const GDM_LANG: string; - export const GHOSTTY_SHELL_FEATURES: string; + export const XAUTHORITY: string; + export const VSCODE_GIT_ASKPASS_NODE: string; + export const VSCODE_INJECTION: string; export const HOME: string; - export const USERNAME: string; export const LANG: string; - export const FNM_COREPACK_ENABLED: string; - export const LS_COLORS: string; - export const XDG_CURRENT_DESKTOP: string; export const npm_package_version: string; - export const MESA_GLSL_CACHE_MAX_SIZE: string; - export const MEMORY_PRESSURE_WATCH: string; - export const STARSHIP_SHELL: string; - export const WAYLAND_DISPLAY: string; + export const TURBO_IS_TUI: string; export const pnpm_config_verify_deps_before_run: string; - export const NIRI_SOCKET: string; - export const MANAGERPID: string; export const INIT_CWD: string; - export const STARSHIP_SESSION_KEY: string; - export const QT_QPA_PLATFORM: string; export const npm_lifecycle_script: string; - export const GHOSTTY_RESOURCES_DIR: string; - export const XDG_SESSION_CLASS: string; - export const ANDROID_HOME: string; - export const TERMINFO: string; + export const VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + export const TURBO_HASH: string; export const TERM: string; export const npm_package_name: string; - export const ZSH: 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 DISPLAY: string; export const npm_lifecycle_event: string; export const SHLVL: string; - export const PAGER: string; - export const npm_config_manage_package_manager_versions: 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 mesa_glthread: string; export const NODE_PATH: string; - export const DEBUGINFOD_URLS: string; export const npm_package_json: string; - export const XCURSOR_THEME: string; + export const VSCODE_GIT_ASKPASS_MAIN: string; export const PATH: string; export const npm_config_node_gyp: string; - export const GDMSESSION: string; export const DBUS_SESSION_BUS_ADDRESS: string; - export const MAIL: string; export const npm_config_registry: string; - export const MESA_SHADER_CACHE_DIR: 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 OLDPWD: string; export const TERM_PROGRAM: string; + export const NODE_ENV: string; } /** @@ -185,6 +129,7 @@ declare module '$env/static/public' { 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_EID_WALLET_TOKEN: string; export const PUBLIC_ESIGNER_BASE_URL: string; export const PUBLIC_FILE_MANAGER_BASE_URL: string; } @@ -222,7 +167,9 @@ declare module '$env/dynamic/private' { GROUP_CHARTER_MAPPING_DB_PATH: string; CERBERUS_MAPPING_DB_PATH: string; GOOGLE_APPLICATION_CREDENTIALS: string; + PICTIQUE_JWT_SECRET: string; GROUP_CHARTER_DATABASE_URL: string; + CHARTER_JWT_SECRET: string; CERBERUS_DATABASE_URL: string; EVOTING_DATABASE_URL: string; EVOTING_MAPPING_DB_PATH: string; @@ -230,112 +177,54 @@ declare module '$env/dynamic/private' { 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; SHELL: string; - LSCOLORS: string; npm_command: string; - GHOSTTY_BIN_DIR: string; COLORTERM: string; - TERM_PROGRAM_VERSION: string; npm_config_optional: string; - FNM_ARCH: string; npm_config_npm_globalconfig: string; NODE: string; - JAVA_HOME: string; npm_config_verify_deps_before_run: string; npm_config__jsr_registry: string; - CLOJURE_HOME: string; - MEMORY_PRESSURE_WRITE: string; - FNM_NODE_DIST_MIRROR: string; npm_config_strict_peer_dependencies: string; - DESKTOP_SESSION: string; - ELECTRON_OZONE_PLATFORM_HINT: string; - XCURSOR_SIZE: string; npm_config_globalconfig: string; - EDITOR: string; - XDG_SEAT: string; PWD: string; - XDG_SESSION_DESKTOP: string; - LOGNAME: string; - QT_QPA_PLATFORMTHEME: string; - XDG_SESSION_TYPE: string; - SYSTEMD_EXEC_PID: string; - TERMINAL: string; - QT_QPA_PLATFORMTHEME_QT6: string; - MOTD_SHOWN: string; - GDM_LANG: string; - GHOSTTY_SHELL_FEATURES: string; + XAUTHORITY: string; + VSCODE_GIT_ASKPASS_NODE: string; + VSCODE_INJECTION: string; HOME: string; - USERNAME: string; LANG: string; - FNM_COREPACK_ENABLED: string; - LS_COLORS: string; - XDG_CURRENT_DESKTOP: string; npm_package_version: string; - MESA_GLSL_CACHE_MAX_SIZE: string; - MEMORY_PRESSURE_WATCH: string; - STARSHIP_SHELL: string; - WAYLAND_DISPLAY: string; + TURBO_IS_TUI: string; pnpm_config_verify_deps_before_run: string; - NIRI_SOCKET: string; - MANAGERPID: string; INIT_CWD: string; - STARSHIP_SESSION_KEY: string; - QT_QPA_PLATFORM: string; npm_lifecycle_script: string; - GHOSTTY_RESOURCES_DIR: string; - XDG_SESSION_CLASS: string; - ANDROID_HOME: string; - TERMINFO: string; + VSCODE_GIT_ASKPASS_EXTRA_ARGS: string; + TURBO_HASH: string; TERM: string; npm_package_name: string; - ZSH: string; USER: string; npm_config_frozen_lockfile: string; - NDK_HOME: string; + VSCODE_GIT_IPC_HANDLE: string; DISPLAY: string; npm_lifecycle_event: string; SHLVL: string; - PAGER: string; - npm_config_manage_package_manager_versions: 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; - mesa_glthread: string; NODE_PATH: string; - DEBUGINFOD_URLS: string; npm_package_json: string; - XCURSOR_THEME: string; + VSCODE_GIT_ASKPASS_MAIN: string; PATH: string; npm_config_node_gyp: string; - GDMSESSION: string; DBUS_SESSION_BUS_ADDRESS: string; - MAIL: string; npm_config_registry: string; - MESA_SHADER_CACHE_DIR: string; - FNM_DIR: string; - FNM_MULTISHELL_PATH: string; npm_node_execpath: string; - FNM_LOGLEVEL: string; - OLDPWD: string; TERM_PROGRAM: string; + NODE_ENV: string; [key: `PUBLIC_${string}`]: undefined; [key: `${string}`]: string | undefined; } @@ -367,6 +256,7 @@ declare module '$env/dynamic/public' { PUBLIC_EVOTING_URL: string; PUBLIC_APP_STORE_EID_WALLET: string; PUBLIC_PLAY_STORE_EID_WALLET: string; + PUBLIC_EID_WALLET_TOKEN: string; PUBLIC_ESIGNER_BASE_URL: string; PUBLIC_FILE_MANAGER_BASE_URL: string; [key: `PUBLIC_${string}`]: string | undefined; diff --git a/platforms/file-manager/.svelte-kit/generated/client/nodes/1.js b/platforms/file-manager/.svelte-kit/generated/client/nodes/1.js index 635016f9c..84e41cf4d 100644 --- a/platforms/file-manager/.svelte-kit/generated/client/nodes/1.js +++ b/platforms/file-manager/.svelte-kit/generated/client/nodes/1.js @@ -1 +1 @@ -export { default as component } from "../../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_f2289347040f8edd51fabc9e5c8ef0b5/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte"; \ No newline at end of file +export { default as component } from "../../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_3d1fb29ef4e8e19a50794ceca30c7fc9/node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte"; \ No newline at end of file diff --git a/platforms/file-manager/.svelte-kit/generated/server/internal.js b/platforms/file-manager/.svelte-kit/generated/server/internal.js index fe43d0868..364f3733e 100644 --- a/platforms/file-manager/.svelte-kit/generated/server/internal.js +++ b/platforms/file-manager/.svelte-kit/generated/server/internal.js @@ -3,7 +3,7 @@ import root from '../root.js'; import { set_building, set_prerendering } from '__sveltekit/environment'; import { set_assets } from '$app/paths/internal/server'; import { set_manifest, set_read_implementation } from '__sveltekit/server'; -import { set_private_env, set_public_env } from '../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_f2289347040f8edd51fabc9e5c8ef0b5/node_modules/@sveltejs/kit/src/runtime/shared-server.js'; +import { set_private_env, set_public_env } from '../../../../../node_modules/.pnpm/@sveltejs+kit@2.49.2_@opentelemetry+api@1.9.0_@sveltejs+vite-plugin-svelte@5.1.1_svelte_3d1fb29ef4e8e19a50794ceca30c7fc9/node_modules/@sveltejs/kit/src/runtime/shared-server.js'; export const options = { app_template_contains_nonce: false, @@ -21,10 +21,10 @@ export const options = { service_worker: false, service_worker_options: undefined, templates: { - app: ({ head, body, assets, nonce, env }) => "\n\n\t\n\t\t\n\t\t\n\t\t" + head + "\n\t\n\t\n\t\t
" + body + "
\n\t\n\n\n", + app: ({ head, body, assets, nonce, env }) => "\n\n \n \n \n \n \n \n \n " + head + "\n \n \n
" + body + "
\n \n\n", error: ({ status, message }) => "\n\n\t\n\t\t\n\t\t" + message + "\n\n\t\t\n\t\n\t\n\t\t
\n\t\t\t" + status + "\n\t\t\t
\n\t\t\t\t

" + message + "

\n\t\t\t
\n\t\t
\n\t\n\n" }, - version_hash: "1oo11i4" + version_hash: "1480iad" }; export async function get_hooks() { diff --git a/platforms/file-manager/package.json b/platforms/file-manager/package.json index f88e0ce7c..bb7ae94c4 100644 --- a/platforms/file-manager/package.json +++ b/platforms/file-manager/package.json @@ -1,46 +1,45 @@ { - "name": "file-manager", - "private": true, - "version": "0.0.1", - "type": "module", - "scripts": { - "dev": "vite dev --host", - "build": "vite build", - "preview": "vite preview", - "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "format": "prettier --write .", - "lint": "prettier --check . && eslint ." - }, - "devDependencies": { - "@eslint/compat": "^1.2.5", - "@eslint/js": "^9.18.0", - "@sveltejs/adapter-static": "^3.0.8", - "@sveltejs/kit": "^2.16.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", - "@tailwindcss/vite": "^4.0.0", - "clsx": "^2.1.1", - "eslint": "^9.18.0", - "eslint-config-prettier": "^10.0.1", - "eslint-plugin-svelte": "^3.0.0", - "globals": "^16.0.0", - "prettier": "^3.4.2", - "prettier-plugin-svelte": "^3.3.3", - "prettier-plugin-tailwindcss": "^0.7.0", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", - "tailwindcss": "^4.0.0", - "typescript": "^5.0.0", - "typescript-eslint": "^8.20.0", - "vite": "^6.2.6" - }, - "dependencies": { - "@sveltejs/adapter-node": "^5.2.12", - "axios": "^1.6.7", - "svelte-qrcode": "^1.0.1", - "svelte-qrcode-action": "^1.0.2", - "tailwind-merge": "^3.0.2" - } + "name": "file-manager", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev --host", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint ." + }, + "devDependencies": { + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@sveltejs/adapter-static": "^3.0.8", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.0.0", + "clsx": "^2.1.1", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.0.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.7.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.20.0", + "vite": "^6.2.6" + }, + "dependencies": { + "@sveltejs/adapter-node": "^5.2.12", + "axios": "^1.6.7", + "svelte-qrcode": "^1.0.1", + "svelte-qrcode-action": "^1.0.2", + "tailwind-merge": "^3.0.2" + } } - diff --git a/platforms/file-manager/src/app.css b/platforms/file-manager/src/app.css index ea5d081ba..037324f86 100644 --- a/platforms/file-manager/src/app.css +++ b/platforms/file-manager/src/app.css @@ -1,7 +1,9 @@ -@import 'tailwindcss'; +@import "tailwindcss"; body { - font-family: system-ui, -apple-system, sans-serif; - background-color: white; + font-family: + system-ui, + -apple-system, + sans-serif; + background-color: white; } - diff --git a/platforms/file-manager/src/app.d.ts b/platforms/file-manager/src/app.d.ts index 03dda6813..addc02a5a 100644 --- a/platforms/file-manager/src/app.d.ts +++ b/platforms/file-manager/src/app.d.ts @@ -1,13 +1,12 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface Platform {} - } + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface Platform {} + } } export {}; - diff --git a/platforms/file-manager/src/app.html b/platforms/file-manager/src/app.html index da25433f0..584010c08 100644 --- a/platforms/file-manager/src/app.html +++ b/platforms/file-manager/src/app.html @@ -1,16 +1,28 @@ - - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- + + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ - diff --git a/platforms/file-manager/src/lib/stores/access.ts b/platforms/file-manager/src/lib/stores/access.ts index 48e57e72c..8fe860e6b 100644 --- a/platforms/file-manager/src/lib/stores/access.ts +++ b/platforms/file-manager/src/lib/stores/access.ts @@ -1,105 +1,120 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; export const fileAccess = writable([]); export const folderAccess = writable([]); export const isLoading = writable(false); export interface FileAccess { - id: string; - fileId: string; - userId: string; - user: { - id: string; - name: string; - ename: string; - avatarUrl: string; - } | null; - grantedBy: string; - granter: { - id: string; - name: string; - ename: string; - } | null; - permission: 'view'; - createdAt: string; + id: string; + fileId: string; + userId: string; + user: { + id: string; + name: string; + ename: string; + avatarUrl: string; + } | null; + grantedBy: string; + granter: { + id: string; + name: string; + ename: string; + } | null; + permission: "view"; + createdAt: string; } export interface FolderAccess { - id: string; - folderId: string; - userId: string; - user: { - id: string; - name: string; - ename: string; - avatarUrl: string; - } | null; - grantedBy: string; - granter: { - id: string; - name: string; - ename: string; - } | null; - permission: 'view'; - createdAt: string; + id: string; + folderId: string; + userId: string; + user: { + id: string; + name: string; + ename: string; + avatarUrl: string; + } | null; + grantedBy: string; + granter: { + id: string; + name: string; + ename: string; + } | null; + permission: "view"; + createdAt: string; } export const fetchFileAccess = async (fileId: string) => { - try { - isLoading.set(true); - const response = await apiClient.get(`/api/files/${fileId}/access`); - fileAccess.set(response.data || []); - } catch (error) { - console.error('Failed to fetch file access:', error); - fileAccess.set([]); - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + const response = await apiClient.get(`/api/files/${fileId}/access`); + fileAccess.set(response.data || []); + } catch (error) { + console.error("Failed to fetch file access:", error); + fileAccess.set([]); + } finally { + isLoading.set(false); + } }; export const fetchFolderAccess = async (folderId: string) => { - try { - isLoading.set(true); - const response = await apiClient.get(`/api/folders/${folderId}/access`); - folderAccess.set(response.data || []); - } catch (error) { - console.error('Failed to fetch folder access:', error); - folderAccess.set([]); - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + const response = await apiClient.get(`/api/folders/${folderId}/access`); + folderAccess.set(response.data || []); + } catch (error) { + console.error("Failed to fetch folder access:", error); + folderAccess.set([]); + } finally { + isLoading.set(false); + } }; -export const grantFileAccess = async (fileId: string, userId: string): Promise => { - const response = await apiClient.post(`/api/files/${fileId}/access`, { - userId, - permission: 'view', - }); +export const grantFileAccess = async ( + fileId: string, + userId: string, +): Promise => { + const response = await apiClient.post(`/api/files/${fileId}/access`, { + userId, + permission: "view", + }); - const newAccess = response.data; - fileAccess.update(access => [...access, newAccess]); - return newAccess; + const newAccess = response.data; + fileAccess.update((access) => [...access, newAccess]); + return newAccess; }; -export const revokeFileAccess = async (fileId: string, userId: string): Promise => { - await apiClient.delete(`/api/files/${fileId}/access/${userId}`); - fileAccess.update(access => access.filter(a => !(a.fileId === fileId && a.userId === userId))); +export const revokeFileAccess = async ( + fileId: string, + userId: string, +): Promise => { + await apiClient.delete(`/api/files/${fileId}/access/${userId}`); + fileAccess.update((access) => + access.filter((a) => !(a.fileId === fileId && a.userId === userId)), + ); }; -export const grantFolderAccess = async (folderId: string, userId: string): Promise => { - const response = await apiClient.post(`/api/folders/${folderId}/access`, { - userId, - permission: 'view', - }); +export const grantFolderAccess = async ( + folderId: string, + userId: string, +): Promise => { + const response = await apiClient.post(`/api/folders/${folderId}/access`, { + userId, + permission: "view", + }); - const newAccess = response.data; - folderAccess.update(access => [...access, newAccess]); - return newAccess; + const newAccess = response.data; + folderAccess.update((access) => [...access, newAccess]); + return newAccess; }; -export const revokeFolderAccess = async (folderId: string, userId: string): Promise => { - await apiClient.delete(`/api/folders/${folderId}/access/${userId}`); - folderAccess.update(access => access.filter(a => !(a.folderId === folderId && a.userId === userId))); +export const revokeFolderAccess = async ( + folderId: string, + userId: string, +): Promise => { + await apiClient.delete(`/api/folders/${folderId}/access/${userId}`); + folderAccess.update((access) => + access.filter((a) => !(a.folderId === folderId && a.userId === userId)), + ); }; - diff --git a/platforms/file-manager/src/lib/stores/auth.ts b/platforms/file-manager/src/lib/stores/auth.ts index fb37e1a26..8f6a37421 100644 --- a/platforms/file-manager/src/lib/stores/auth.ts +++ b/platforms/file-manager/src/lib/stores/auth.ts @@ -1,77 +1,81 @@ -import { writable } from 'svelte/store'; -import { apiClient, setAuthToken, removeAuthToken, removeAuthId } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { + apiClient, + setAuthToken, + removeAuthToken, + removeAuthId, +} from "$lib/utils/axios"; export const isAuthenticated = writable(false); export const currentUser = writable(null); export const authInitialized = writable(false); export const initializeAuth = async () => { - authInitialized.set(false); - const token = localStorage.getItem('file_manager_auth_token'); - if (token) { - // Set token in axios headers immediately - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; - // Verify token is still valid by fetching current user - try { - const response = await apiClient.get('/api/users'); - if (response.data) { - currentUser.set(response.data); - isAuthenticated.set(true); - authInitialized.set(true); - return true; - } - } catch (err) { - // Token invalid, clear it - console.error('Auth token invalid:', err); - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - } - } - isAuthenticated.set(false); - currentUser.set(null); - authInitialized.set(true); - return false; + authInitialized.set(false); + const token = localStorage.getItem("file_manager_auth_token"); + if (token) { + // Set token in axios headers immediately + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; + // Verify token is still valid by fetching current user + try { + const response = await apiClient.get("/api/users"); + if (response.data) { + currentUser.set(response.data); + isAuthenticated.set(true); + authInitialized.set(true); + return true; + } + } catch (err) { + // Token invalid, clear it + console.error("Auth token invalid:", err); + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + } + } + isAuthenticated.set(false); + currentUser.set(null); + authInitialized.set(true); + return false; }; export const login = async (token: string, user?: any) => { - // Store token in localStorage first - setAuthToken(token); - // Set token in axios headers - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; - - // Set user if provided - if (user) { - currentUser.set(user); - isAuthenticated.set(true); - } - - // Verify by fetching user to ensure token is valid - try { - const response = await apiClient.get('/api/users'); - if (response.data) { - currentUser.set(response.data); - isAuthenticated.set(true); - return true; - } - } catch (err) { - console.error('Failed to verify login:', err); - // If verification fails, clear everything - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - isAuthenticated.set(false); - currentUser.set(null); - return false; - } - return true; + // Store token in localStorage first + setAuthToken(token); + // Set token in axios headers + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; + + // Set user if provided + if (user) { + currentUser.set(user); + isAuthenticated.set(true); + } + + // Verify by fetching user to ensure token is valid + try { + const response = await apiClient.get("/api/users"); + if (response.data) { + currentUser.set(response.data); + isAuthenticated.set(true); + return true; + } + } catch (err) { + console.error("Failed to verify login:", err); + // If verification fails, clear everything + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + isAuthenticated.set(false); + currentUser.set(null); + return false; + } + return true; }; export const logout = () => { - removeAuthToken(); - removeAuthId(); - delete apiClient.defaults.headers.common['Authorization']; - isAuthenticated.set(false); - currentUser.set(null); + removeAuthToken(); + removeAuthId(); + delete apiClient.defaults.headers.common["Authorization"]; + isAuthenticated.set(false); + currentUser.set(null); }; - diff --git a/platforms/file-manager/src/lib/stores/files.ts b/platforms/file-manager/src/lib/stores/files.ts index 7703c669e..1a1672394 100644 --- a/platforms/file-manager/src/lib/stores/files.ts +++ b/platforms/file-manager/src/lib/stores/files.ts @@ -1,99 +1,109 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; export const files = writable([]); export const isLoading = writable(false); export interface File { - id: string; - name: string; - displayName: string | null; - description: string | null; - mimeType: string; - size: number; - md5Hash: string; - ownerId: string; - folderId: string | null; - createdAt: string; - updatedAt: string; - canPreview: boolean; + id: string; + name: string; + displayName: string | null; + description: string | null; + mimeType: string; + size: number; + md5Hash: string; + ownerId: string; + folderId: string | null; + createdAt: string; + updatedAt: string; + canPreview: boolean; } export const fetchFiles = async (folderId?: string | null) => { - try { - isLoading.set(true); - // Always pass folderId - use 'null' string for root, or the actual folderId - const params: any = {}; - if (folderId === null || folderId === undefined) { - params.folderId = 'null'; - } else { - params.folderId = folderId; - } - const response = await apiClient.get('/api/files', { params }); - files.set(response.data || []); - } catch (error) { - console.error('Failed to fetch files:', error); - files.set([]); - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + // Always pass folderId - use 'null' string for root, or the actual folderId + const params: any = {}; + if (folderId === null || folderId === undefined) { + params.folderId = "null"; + } else { + params.folderId = folderId; + } + const response = await apiClient.get("/api/files", { params }); + files.set(response.data || []); + } catch (error) { + console.error("Failed to fetch files:", error); + files.set([]); + } finally { + isLoading.set(false); + } }; export const uploadFile = async ( - file: globalThis.File, - folderId?: string | null, - displayName?: string, - description?: string + file: globalThis.File, + folderId?: string | null, + displayName?: string, + description?: string, ): Promise => { - const formData = new FormData(); - formData.append('file', file); - if (folderId !== undefined) { - formData.append('folderId', folderId || 'null'); - } - if (displayName) { - formData.append('displayName', displayName); - } - if (description) { - formData.append('description', description); - } + const formData = new FormData(); + formData.append("file", file); + if (folderId !== undefined) { + formData.append("folderId", folderId || "null"); + } + if (displayName) { + formData.append("displayName", displayName); + } + if (description) { + formData.append("description", description); + } - const response = await apiClient.post('/api/files', formData, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }); + const response = await apiClient.post("/api/files", formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + }); - const newFile = response.data; - files.update(files => [newFile, ...files]); - return newFile; + const newFile = response.data; + files.update((files) => [newFile, ...files]); + return newFile; }; export const deleteFile = async (fileId: string): Promise => { - await apiClient.delete(`/api/files/${fileId}`); - files.update(files => files.filter(f => f.id !== fileId)); + await apiClient.delete(`/api/files/${fileId}`); + files.update((files) => files.filter((f) => f.id !== fileId)); }; export const updateFile = async ( - fileId: string, - displayName?: string, - description?: string, - folderId?: string | null + fileId: string, + displayName?: string, + description?: string, + folderId?: string | null, ): Promise => { - const response = await apiClient.patch(`/api/files/${fileId}`, { - displayName, - description, - folderId: folderId !== undefined ? (folderId || 'null') : undefined, - }); + const response = await apiClient.patch(`/api/files/${fileId}`, { + displayName, + description, + folderId: folderId !== undefined ? folderId || "null" : undefined, + }); - const updatedFile = response.data; - files.update(files => files.map(f => f.id === fileId ? updatedFile : f)); - return updatedFile; + const updatedFile = response.data; + files.update((files) => + files.map((f) => (f.id === fileId ? updatedFile : f)), + ); + return updatedFile; }; -export const moveFile = async (fileId: string, folderId: string | null): Promise => { - const response = await apiClient.post(`/api/files/${fileId}/move`, { folderId: folderId || 'null' }); - const updatedFile = response.data; - // Update the file in the store with the new folderId - files.update(files => files.map(f => f.id === fileId ? { ...f, folderId: updatedFile.folderId } : f)); +export const moveFile = async ( + fileId: string, + folderId: string | null, +): Promise => { + const response = await apiClient.post(`/api/files/${fileId}/move`, { + folderId: folderId || "null", + }); + const updatedFile = response.data; + // Update the file in the store with the new folderId + files.update((files) => + files.map((f) => + f.id === fileId ? { ...f, folderId: updatedFile.folderId } : f, + ), + ); }; - diff --git a/platforms/file-manager/src/lib/stores/folders.ts b/platforms/file-manager/src/lib/stores/folders.ts index 8c43cd79e..fc4a6afdb 100644 --- a/platforms/file-manager/src/lib/stores/folders.ts +++ b/platforms/file-manager/src/lib/stores/folders.ts @@ -1,92 +1,107 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; export const folders = writable([]); export const folderTree = writable([]); export const isLoading = writable(false); export interface Folder { - id: string; - name: string; - ownerId: string; - parentFolderId: string | null; - createdAt: string; - updatedAt: string; + id: string; + name: string; + ownerId: string; + parentFolderId: string | null; + createdAt: string; + updatedAt: string; } export const fetchFolders = async (parentFolderId?: string | null) => { - try { - isLoading.set(true); - // Always pass parentFolderId - use 'null' string for root, or the actual parentFolderId - const params: any = {}; - if (parentFolderId === null || parentFolderId === undefined) { - params.parentFolderId = 'null'; - } else { - params.parentFolderId = parentFolderId; - } - const response = await apiClient.get('/api/folders', { params }); - folders.set(response.data || []); - } catch (error) { - console.error('Failed to fetch folders:', error); - folders.set([]); - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + // Always pass parentFolderId - use 'null' string for root, or the actual parentFolderId + const params: any = {}; + if (parentFolderId === null || parentFolderId === undefined) { + params.parentFolderId = "null"; + } else { + params.parentFolderId = parentFolderId; + } + const response = await apiClient.get("/api/folders", { params }); + folders.set(response.data || []); + } catch (error) { + console.error("Failed to fetch folders:", error); + folders.set([]); + } finally { + isLoading.set(false); + } }; export const fetchFolderTree = async () => { - try { - const response = await apiClient.get('/api/folders/tree'); - folderTree.set(response.data || []); - } catch (error) { - console.error('Failed to fetch folder tree:', error); - folderTree.set([]); - } + try { + const response = await apiClient.get("/api/folders/tree"); + folderTree.set(response.data || []); + } catch (error) { + console.error("Failed to fetch folder tree:", error); + folderTree.set([]); + } }; export const createFolder = async ( - name: string, - parentFolderId?: string | null + name: string, + parentFolderId?: string | null, ): Promise => { - const response = await apiClient.post('/api/folders', { - name, - parentFolderId: parentFolderId || null, - }); + const response = await apiClient.post("/api/folders", { + name, + parentFolderId: parentFolderId || null, + }); - const newFolder = response.data; - folders.update(folders => [newFolder, ...folders]); - return newFolder; + const newFolder = response.data; + folders.update((folders) => [newFolder, ...folders]); + return newFolder; }; export const deleteFolder = async (folderId: string): Promise => { - await apiClient.delete(`/api/folders/${folderId}`); - folders.update(folders => folders.filter(f => f.id !== folderId)); + await apiClient.delete(`/api/folders/${folderId}`); + folders.update((folders) => folders.filter((f) => f.id !== folderId)); }; export const updateFolder = async ( - folderId: string, - name?: string, - parentFolderId?: string | null + folderId: string, + name?: string, + parentFolderId?: string | null, ): Promise => { - const response = await apiClient.patch(`/api/folders/${folderId}`, { - name, - parentFolderId: parentFolderId !== undefined ? (parentFolderId || 'null') : undefined, - }); + const response = await apiClient.patch(`/api/folders/${folderId}`, { + name, + parentFolderId: + parentFolderId !== undefined ? parentFolderId || "null" : undefined, + }); - const updatedFolder = response.data; - folders.update(folders => folders.map(f => f.id === folderId ? updatedFolder : f)); - return updatedFolder; + const updatedFolder = response.data; + folders.update((folders) => + folders.map((f) => (f.id === folderId ? updatedFolder : f)), + ); + return updatedFolder; }; -export const moveFolder = async (folderId: string, parentFolderId: string | null): Promise => { - const response = await apiClient.post(`/api/folders/${folderId}/move`, { parentFolderId: parentFolderId || 'null' }); - const updatedFolder = response.data; - // Update the folder in the store with the new parentFolderId - folders.update(folders => folders.map(f => f.id === folderId ? { ...f, parentFolderId: updatedFolder.parentFolderId } : f)); +export const moveFolder = async ( + folderId: string, + parentFolderId: string | null, +): Promise => { + const response = await apiClient.post(`/api/folders/${folderId}/move`, { + parentFolderId: parentFolderId || "null", + }); + const updatedFolder = response.data; + // Update the folder in the store with the new parentFolderId + folders.update((folders) => + folders.map((f) => + f.id === folderId + ? { ...f, parentFolderId: updatedFolder.parentFolderId } + : f, + ), + ); }; -export const getFolderContents = async (folderId: string): Promise<{ files: any[]; folders: any[] }> => { - const response = await apiClient.get(`/api/folders/${folderId}/contents`); - return response.data; +export const getFolderContents = async ( + folderId: string, +): Promise<{ files: any[]; folders: any[] }> => { + const response = await apiClient.get(`/api/folders/${folderId}/contents`); + return response.data; }; - diff --git a/platforms/file-manager/src/lib/stores/signatures.ts b/platforms/file-manager/src/lib/stores/signatures.ts index fd4f9c5d7..be4cf64c2 100644 --- a/platforms/file-manager/src/lib/stores/signatures.ts +++ b/platforms/file-manager/src/lib/stores/signatures.ts @@ -1,21 +1,21 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; -import type { Writable } from 'svelte/store'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; +import type { Writable } from "svelte/store"; export interface Signature { - id: string; - userId: string; - md5Hash: string; - message: string; - signature: string; - publicKey: string; - createdAt: string; - user?: { - id: string; - name: string; - ename: string; - avatarUrl?: string; - } | null; + id: string; + userId: string; + md5Hash: string; + message: string; + signature: string; + publicKey: string; + createdAt: string; + user?: { + id: string; + name: string; + ename: string; + avatarUrl?: string; + } | null; } export const signatures: Writable = writable([]); @@ -23,16 +23,17 @@ export const isLoading = writable(false); export const error = writable(null); export const fetchFileSignatures = async (fileId: string) => { - try { - isLoading.set(true); - error.set(null); - const response = await apiClient.get(`/api/files/${fileId}/signatures`); - signatures.set(response.data); - } catch (err) { - error.set(err instanceof Error ? err.message : 'Failed to fetch signatures'); - throw err; - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + error.set(null); + const response = await apiClient.get(`/api/files/${fileId}/signatures`); + signatures.set(response.data); + } catch (err) { + error.set( + err instanceof Error ? err.message : "Failed to fetch signatures", + ); + throw err; + } finally { + isLoading.set(false); + } }; - diff --git a/platforms/file-manager/src/lib/stores/tags.ts b/platforms/file-manager/src/lib/stores/tags.ts index 0271cd77e..2040882c7 100644 --- a/platforms/file-manager/src/lib/stores/tags.ts +++ b/platforms/file-manager/src/lib/stores/tags.ts @@ -1,70 +1,87 @@ -import { writable } from 'svelte/store'; -import { apiClient } from '$lib/utils/axios'; +import { writable } from "svelte/store"; +import { apiClient } from "$lib/utils/axios"; export const tags = writable([]); export const isLoading = writable(false); export interface Tag { - id: string; - name: string; - color: string | null; - ownerId: string; - createdAt: string; + id: string; + name: string; + color: string | null; + ownerId: string; + createdAt: string; } export const fetchTags = async () => { - try { - isLoading.set(true); - const response = await apiClient.get('/api/tags'); - tags.set(response.data || []); - } catch (error) { - console.error('Failed to fetch tags:', error); - tags.set([]); - } finally { - isLoading.set(false); - } + try { + isLoading.set(true); + const response = await apiClient.get("/api/tags"); + tags.set(response.data || []); + } catch (error) { + console.error("Failed to fetch tags:", error); + tags.set([]); + } finally { + isLoading.set(false); + } }; -export const createTag = async (name: string, color?: string | null): Promise => { - const response = await apiClient.post('/api/tags', { name, color: color || null }); - const newTag = response.data; - tags.update(tags => [newTag, ...tags]); - return newTag; +export const createTag = async ( + name: string, + color?: string | null, +): Promise => { + const response = await apiClient.post("/api/tags", { + name, + color: color || null, + }); + const newTag = response.data; + tags.update((tags) => [newTag, ...tags]); + return newTag; }; export const updateTag = async ( - tagId: string, - name?: string, - color?: string | null + tagId: string, + name?: string, + color?: string | null, ): Promise => { - const response = await apiClient.patch(`/api/tags/${tagId}`, { - name, - color: color !== undefined ? (color || null) : undefined, - }); + const response = await apiClient.patch(`/api/tags/${tagId}`, { + name, + color: color !== undefined ? color || null : undefined, + }); - const updatedTag = response.data; - tags.update(tags => tags.map(t => t.id === tagId ? updatedTag : t)); - return updatedTag; + const updatedTag = response.data; + tags.update((tags) => tags.map((t) => (t.id === tagId ? updatedTag : t))); + return updatedTag; }; export const deleteTag = async (tagId: string): Promise => { - await apiClient.delete(`/api/tags/${tagId}`); - tags.update(tags => tags.filter(t => t.id !== tagId)); + await apiClient.delete(`/api/tags/${tagId}`); + tags.update((tags) => tags.filter((t) => t.id !== tagId)); }; -export const addTagToFile = async (fileId: string, tagId: string): Promise => { - await apiClient.post(`/api/files/${fileId}/tags`, { tagId }); +export const addTagToFile = async ( + fileId: string, + tagId: string, +): Promise => { + await apiClient.post(`/api/files/${fileId}/tags`, { tagId }); }; -export const removeTagFromFile = async (fileId: string, tagId: string): Promise => { - await apiClient.delete(`/api/files/${fileId}/tags/${tagId}`); +export const removeTagFromFile = async ( + fileId: string, + tagId: string, +): Promise => { + await apiClient.delete(`/api/files/${fileId}/tags/${tagId}`); }; -export const addTagToFolder = async (folderId: string, tagId: string): Promise => { - await apiClient.post(`/api/folders/${folderId}/tags`, { tagId }); +export const addTagToFolder = async ( + folderId: string, + tagId: string, +): Promise => { + await apiClient.post(`/api/folders/${folderId}/tags`, { tagId }); }; -export const removeTagFromFolder = async (folderId: string, tagId: string): Promise => { - await apiClient.delete(`/api/folders/${folderId}/tags/${tagId}`); +export const removeTagFromFolder = async ( + folderId: string, + tagId: string, +): Promise => { + await apiClient.delete(`/api/folders/${folderId}/tags/${tagId}`); }; - diff --git a/platforms/file-manager/src/lib/stores/toast.ts b/platforms/file-manager/src/lib/stores/toast.ts index ff612a496..c0bdf2ef1 100644 --- a/platforms/file-manager/src/lib/stores/toast.ts +++ b/platforms/file-manager/src/lib/stores/toast.ts @@ -1,39 +1,46 @@ -import { writable } from 'svelte/store'; +import { writable } from "svelte/store"; export interface Toast { - id: string; - message: string; - type: 'success' | 'error' | 'info' | 'warning'; - duration?: number; + id: string; + message: string; + type: "success" | "error" | "info" | "warning"; + duration?: number; } export const toasts = writable([]); let toastIdCounter = 0; -export function showToast(message: string, type: Toast['type'] = 'info', duration: number = 3000) { - const id = `toast-${toastIdCounter++}`; - const toast: Toast = { id, message, type, duration }; - - toasts.update((current) => [...current, toast]); - - if (duration > 0) { - setTimeout(() => { - removeToast(id); - }, duration); - } - - return id; +export function showToast( + message: string, + type: Toast["type"] = "info", + duration: number = 3000, +) { + const id = `toast-${toastIdCounter++}`; + const toast: Toast = { id, message, type, duration }; + + toasts.update((current) => [...current, toast]); + + if (duration > 0) { + setTimeout(() => { + removeToast(id); + }, duration); + } + + return id; } export function removeToast(id: string) { - toasts.update((current) => current.filter((t) => t.id !== id)); + toasts.update((current) => current.filter((t) => t.id !== id)); } export const toast = { - success: (message: string, duration?: number) => showToast(message, 'success', duration), - error: (message: string, duration?: number) => showToast(message, 'error', duration), - info: (message: string, duration?: number) => showToast(message, 'info', duration), - warning: (message: string, duration?: number) => showToast(message, 'warning', duration), + success: (message: string, duration?: number) => + showToast(message, "success", duration), + error: (message: string, duration?: number) => + showToast(message, "error", duration), + info: (message: string, duration?: number) => + showToast(message, "info", duration), + warning: (message: string, duration?: number) => + showToast(message, "warning", duration), }; - diff --git a/platforms/file-manager/src/lib/utils/axios.ts b/platforms/file-manager/src/lib/utils/axios.ts index e1d2d9863..ac427bfe9 100644 --- a/platforms/file-manager/src/lib/utils/axios.ts +++ b/platforms/file-manager/src/lib/utils/axios.ts @@ -1,26 +1,25 @@ -import axios from 'axios'; -import { PUBLIC_FILE_MANAGER_BASE_URL } from '$env/static/public'; +import axios from "axios"; +import { PUBLIC_FILE_MANAGER_BASE_URL } from "$env/static/public"; -const API_BASE_URL = PUBLIC_FILE_MANAGER_BASE_URL || 'http://localhost:3005'; +const API_BASE_URL = PUBLIC_FILE_MANAGER_BASE_URL || "http://localhost:3005"; export const apiClient = axios.create({ - baseURL: API_BASE_URL, - headers: { - 'Content-Type': 'application/json', - }, + baseURL: API_BASE_URL, + headers: { + "Content-Type": "application/json", + }, }); export const setAuthToken = (token: string) => { - localStorage.setItem('file_manager_auth_token', token); - apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; + localStorage.setItem("file_manager_auth_token", token); + apiClient.defaults.headers.common["Authorization"] = `Bearer ${token}`; }; export const removeAuthToken = () => { - localStorage.removeItem('file_manager_auth_token'); - delete apiClient.defaults.headers.common['Authorization']; + localStorage.removeItem("file_manager_auth_token"); + delete apiClient.defaults.headers.common["Authorization"]; }; export const removeAuthId = () => { - localStorage.removeItem('file_manager_auth_id'); + localStorage.removeItem("file_manager_auth_id"); }; - diff --git a/platforms/file-manager/src/lib/utils/mime-type.ts b/platforms/file-manager/src/lib/utils/mime-type.ts index da64f9d95..4b69863a2 100644 --- a/platforms/file-manager/src/lib/utils/mime-type.ts +++ b/platforms/file-manager/src/lib/utils/mime-type.ts @@ -3,16 +3,20 @@ * instead of long strings like application/vnd.openxmlformats-officedocument.spreadsheetml.sheet */ export function getMimeTypeDisplayLabel(mimeType: string): string { - if (!mimeType || typeof mimeType !== "string") return mimeType ?? ""; - const m = mimeType.toLowerCase(); - // Office / common document types - if (m.includes("spreadsheetml.sheet") || m.includes("ms-excel")) return "XLSX"; - if (m.includes("wordprocessingml.document") || m.includes("msword")) return "DOCX"; - if (m.includes("presentationml") || m.includes("ms-powerpoint")) return "PPTX"; - if (m === "application/pdf") return "PDF"; - // Generic fallback: last meaningful part (e.g. "sheet", "pdf") - const parts = m.split(/[/+]/); - const last = parts[parts.length - 1]; - if (last && last !== "application" && last.length <= 20) return last.toUpperCase(); - return mimeType; + if (!mimeType || typeof mimeType !== "string") return mimeType ?? ""; + const m = mimeType.toLowerCase(); + // Office / common document types + if (m.includes("spreadsheetml.sheet") || m.includes("ms-excel")) + return "XLSX"; + if (m.includes("wordprocessingml.document") || m.includes("msword")) + return "DOCX"; + if (m.includes("presentationml") || m.includes("ms-powerpoint")) + return "PPTX"; + if (m === "application/pdf") return "PDF"; + // Generic fallback: last meaningful part (e.g. "sheet", "pdf") + const parts = m.split(/[/+]/); + const last = parts[parts.length - 1]; + if (last && last !== "application" && last.length <= 20) + return last.toUpperCase(); + return mimeType; } diff --git a/platforms/file-manager/static/site.webmanifest b/platforms/file-manager/static/site.webmanifest index 45dc8a206..b20abb7cb 100644 --- a/platforms/file-manager/static/site.webmanifest +++ b/platforms/file-manager/static/site.webmanifest @@ -1 +1,19 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/platforms/file-manager/svelte.config.js b/platforms/file-manager/svelte.config.js index 36202a10a..4ca2087b8 100644 --- a/platforms/file-manager/svelte.config.js +++ b/platforms/file-manager/svelte.config.js @@ -1,15 +1,14 @@ -import adapter from '@sveltejs/adapter-node'; -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import adapter from "@sveltejs/adapter-node"; +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; const config = { - preprocess: vitePreprocess(), - kit: { - adapter: adapter(), - env: { - dir: '../../' - } - } + preprocess: vitePreprocess(), + kit: { + adapter: adapter(), + env: { + dir: "../../", + }, + }, }; export default config; - diff --git a/platforms/file-manager/tsconfig.json b/platforms/file-manager/tsconfig.json index 51db996c3..104691d2d 100644 --- a/platforms/file-manager/tsconfig.json +++ b/platforms/file-manager/tsconfig.json @@ -1,15 +1,14 @@ { - "extends": "./.svelte-kit/tsconfig.json", - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "moduleResolution": "bundler" - } + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } } - diff --git a/platforms/file-manager/vite.config.ts b/platforms/file-manager/vite.config.ts index 0c8f96ab1..083ef2d11 100644 --- a/platforms/file-manager/vite.config.ts +++ b/platforms/file-manager/vite.config.ts @@ -1,15 +1,14 @@ -import tailwindcss from '@tailwindcss/vite'; -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import tailwindcss from "@tailwindcss/vite"; +import { sveltekit } from "@sveltejs/kit/vite"; +import { defineConfig } from "vite"; export default defineConfig({ - plugins: [tailwindcss(), sveltekit()], - server: { - allowedHosts: [ - 'file-manager.w3ds-prototype.merul.org', - 'file-manager.staging.metastate.foundation', - 'file-manager.w3ds.metastate.foundation' - ] - } + plugins: [tailwindcss(), sveltekit()], + server: { + allowedHosts: [ + "file-manager.w3ds-prototype.merul.org", + "file-manager.staging.metastate.foundation", + "file-manager.w3ds.metastate.foundation", + ], + }, }); -