Files
admin/docs/core-modules/file-manager/frontend.md
T
2026-07-10 08:47:27 +00:00

11 KiB

File Manager Frontend

The frontend module implements the admin file manager UI. It provides file browsing, previews, uploads, deletion, duplication, renaming, image editing tools, image map tools, settings, and reusable file picker widgets.

This module follows the general React frontend architecture inside its own module boundary.

Source root:

apps/admin/src/core/FileManager/

Main Principle

React Query owns server state. MobX owns local UI and operation state.

Server state examples:

  • Directory entries.
  • File details.
  • Raw file blobs.
  • Search results.
  • Create, rename, delete, duplicate, and upload mutations.

Local state examples:

  • Active path.
  • Selected paths.
  • Expanded tree paths.
  • Filter and sort controls.
  • Dialog open state.
  • Upload and delete operation progress.
  • Cached lookup of already loaded entries for UI behavior.

Directory Structure

FileManager/
  config/        Routes, menu entries, messages, translations.
  data/
    api/         Raw HTTP methods and DTOs.
    hooks/       Feature hooks that combine queries with stores.
    mappers/     DTO-to-entity mapping.
    queries/     React Query hooks, keys, mutations, and cache helpers.
    stores/      MobX local state stores.
  entities/      Domain entities and settings types.
  providers/     Feature providers and context hooks.
  pages/         Route-level screens.
  shared/        FileManager utilities that do not depend on view code.
  view/          UI components, widgets, forms, and layouts.

Routes

Frontend route config:

config/routing.tsx

Mounted module path:

/file-manager/*

Current child routes:

Route Page Purpose
/file-manager/drive/explorer/* DriveExplorerPage Browse folders and files.
/file-manager/drive/viewer/-/* DriveViewerPage View file details and preview.
/file-manager/drive/settings DriveSettingsPage Configure file-manager UI settings.
/file-manager/tools/image-editor/-/* ImageEditorPage Edit image files.
/file-manager/tools/image-map/-/* ImageMapPage Create and edit image map areas for images.

Path helpers live in:

shared/routing/driveLinks.ts
shared/routing/openEntryNewTab.ts
shared/path/leadingSlash.ts

Use these helpers instead of manually building file-manager URLs.

Menu Structure

File Manager navigation is grouped into three top-level menu entries:

  • Drive for file browsing, preview, and viewer-related flows.
  • Tools for standalone file tools such as image editing and image map editing.
  • Settings for persisted file-manager UI settings.

The Tools group currently contains:

  • ImageEditorPage
  • ImageMapPage

API Boundary

Raw backend calls are centralized in:

data/api/api.ts
data/api/dto.ts

The frontend calls the backend routes documented in backend.md:

API Method Backend Route
getEntries GET /file-manager/*
getFile GET /file-manager/files/details/*
getRawFile GET /file-manager/files/raw/*
createDirectory POST /file-manager/folders
renameEntry PUT /file-manager/entries/rename
removeEntry DELETE /file-manager/*
uploadFile POST /file-manager/files
duplicateFiles POST /file-manager/files/duplicate
searchEntries GET /file-manager/search

DTOs should be mapped before they reach UI code. Entity types live in:

entities/entry.ts
data/mappers/entryMapper.ts

Data Flow

Reading Entries

Directory entries are fetched through:

useGetEntries();

The higher-level hook:

useEntries();

does three things:

  1. Builds the query payload from ExplorerStore.
  2. Fetches entries with React Query.
  3. Syncs loaded entries into EntriesStore.

EntriesStore is not the fetch owner. It is an index of loaded entries used by the sidebar tree, selection lookups, active entry lookup, and operation state.

When opening a nested folder directly, useEntries() preloads ancestor folders through React Query. This keeps the sidebar tree and entry index usable for paths like:

/folder/subfolder/current

Mutations

Mutations use React Query hooks:

  • useCreateDirectory
  • useRenameEntry
  • useDeleteEntry
  • useDuplicateFiles
  • useUploadFile

After a successful mutation, the UI updates local cache and stores directly. It does not invalidate entries queries after every operation.

This avoids unnecessary refetches when many items are created, deleted, or uploaded in sequence.

Query Cache Updates

Entries cache helpers live in:

data/queries/cache.ts

Current helpers:

addEntriesToCache(parentPath, entries);
removeEntriesFromCache(paths);
renameEntryInCache(prevPath, renamedEntry);

These helpers update existing React Query cache data in memory. They do not trigger a network request.

Important behavior:

  • Added entries are inserted into cached lists for the matching parent folder.
  • Added entries are filter-aware.
  • Deleted entries are removed from all cached entry pages.
  • Renamed entries are updated across cached entry pages.

Tradeoff: because the module avoids refetching, exact backend sort order may not be perfect after local cache insertion until the folder is naturally refetched or reloaded.

Stores

EntriesStore

File:

data/stores/entriesStore.ts

Purpose:

  • Keep an index of loaded entries by path.
  • Provide child lookup by parent path.
  • Support selected-entry and active-entry lookup.
  • Support local remove and rename updates for already loaded subtrees.

It should not fetch data.

ExplorerStore

File:

data/stores/explorerStore.ts

Purpose:

  • Active path.
  • Selected paths.
  • Expanded tree paths.
  • Breadcrumbs.
  • Entries filter.
  • Sort field and direction.

DriveDialogStore

File:

data/stores/driveDialogStore.ts

Purpose:

  • Create-directory dialog state.
  • Rename-entry dialog state.
  • Current entry selected for rename.

UploadOperationStore

File:

data/stores/uploadOperationStore.ts

Purpose:

  • Upload queue.
  • Upload progress.
  • Upload retry, remove, and abort.
  • Upload operation card visibility.

It receives the React Query mutation function from the view layer and manages only operation state.

DeleteOperationStore

File:

data/stores/deleteOperationStore.ts

Purpose:

  • Delete queue.
  • Delete progress.
  • Delete retry and remove.
  • Delete operation card visibility.

It receives the React Query mutation function from the view layer and manages only operation state.

SettingsStore

File:

data/stores/settingsStore.ts

Purpose:

  • Persisted view mode.
  • Compact mode.
  • Sidebar visibility.
  • Grid size and related display preferences.

Providers

DriveProvider creates and exposes feature stores:

entriesStore;
explorerStore;
driveDialogStore;
uploadOperationStore;
deleteOperationStore;

Use:

const { entriesStore, explorerStore } = useDrive();

SettingsProvider owns persisted settings such as view mode, compact mode, sidebar visibility, and grid size.

Pages And Widgets

DriveExplorerPage

Main file browser page. Composes:

  • DriveProvider
  • Explorer toolbar.
  • Explorer content.
  • Explorer sidebar.
  • Footer.
  • Operation watcher.

DriveViewerPage

File details and preview page. Uses:

useGetFile();

DriveSettingsPage

Settings page for persisted file-manager UI preferences.

ImageEditorPage

Image editor page. Uses:

useGetFile();
useGetRawFile();
useUploadFile();

Image editor config and helpers live in the widget layer:

view/widgets/ImageEditor/config.ts
view/widgets/ImageEditor/helpers.ts

This prevents view code from importing from pages.

ImageMapPage

Image map page. Uses:

useGetFile();
useGetRawFile();

Image map config and helpers live in the widget layer:

view/widgets/ImageEditor/config.ts
view/widgets/ImageEditor/helpers.ts

This prevents view code from importing from pages.

FilePickerDialog

Reusable picker widgets live in:

view/widgets/FilePickerDialog/

Keep picker behavior feature-scoped, but pass reusable UI state through props and context instead of coupling low-level UI components to page-level stores.

View Layer Rules

Feature widgets may use File Manager providers such as useDrive() and useSettings().

Lower-level reusable UI components should stay prop-driven. Examples:

  • ExplorerFileEntryGrid
  • ExplorerFolderEntryList
  • ExplorerToolbarFilterDropdown
  • FileManagerFileIcon
  • FilePreview

Do not import backend DTOs into view components. View components should consume frontend entities and props.

File Types And Icons

File helpers live in:

shared/file/

File icons live in:

apps/admin/public/media/files/

To add or change an icon:

  1. Add the asset under apps/admin/public/media/files/.
  2. Update shared/file/fileTypeImportMap.ts.
  3. Confirm FileManagerFileIcon renders the expected fallback for unknown extensions.

Adding A New Query

  1. Add or reuse a method in:
data/api/api.ts
  1. Add a key in:
data/queries/keys.ts
  1. Create a query file:
data/queries/example.ts
  1. Map DTOs to entities before returning app-facing data.

Do not import MobX stores or providers inside data/queries.

Adding A New Mutation

  1. Add a raw API method in data/api/api.ts.
  2. Add a mutation hook in data/queries.
  3. In the consuming widget or operation store flow, call mutateAsync.
  4. Update EntriesStore if lookup state must change.
  5. Update data/queries/cache.ts helpers if visible query cache must change.

Do not invalidate entries queries after each operation unless a full refetch is intentionally required.

Frontend Change Checklist

Before changing frontend behavior:

  1. Identify whether the data is server state or local UI state.
  2. Keep backend calls in data/api.
  3. Keep React Query hooks free of MobX provider imports.
  4. Map DTOs before passing data to view components.
  5. Update cache helpers when mutation results should appear immediately.
  6. Update backend docs if the frontend change requires a backend contract change.