Table of Contents

File Explorer Page

The File Explorer page is a server-side filesystem browser covering three named roots:

  • AdminDirectory — server-wide admin area.
  • ProjectDirectory — the currently-loaded project directory (omitted from the root list when no project is loaded).
  • ResourceDir — the shared resource tree under AdminDirectory + "Resource/".
Note

Absolute filesystem paths never leave the server. The /roots endpoint returns only { name, displayName }, and every exception message is scrubbed to replace root prefixes with the tokens <Admin> / <Project> / <Resource> before it is returned to the browser.

Layout

  • File Explorer Page
    • Toolbar
      • Root Selector Dropdown — display-name only, sourced from GET /roots.
      • Up Button
      • Path Input — editable; Enter navigates.
      • Refresh / New Folder / New File / Upload Buttons.
    • Breadcrumb Row — single-click navigation up the tree.
    • Listing Table (<q-table>) — columns Name / Size / Modified / Actions. Directories first, then files, name-ascending.
      • Row click:
        • Directory → navigate into it.
        • Non-binary file → open the editor dialog.
      • Actions: Edit (non-binary files only), Download (files), Download ZIP (folders), Extract ZIP (.zip only), Rename, Duplicate, Delete (double-click to confirm).
    • Editor Dialog (full-width / full-height)
      • Title Bar — file name + language chip + Cancel / Save / Close.
      • Body — <TextEditor> wrapping CodeMirror 6 filling the viewport.

Behavior

  • Path-traversal defence. Every request is resolved via Path.GetFullPath and validated with Hi.Common.PathUtils.PathUtil.IsDescendant(root, absolute) before any IO. Attempts like relativePath=../outside are rejected with HTTP 400.
  • Duplicate. POST /copy tries {name}-Copy-00 through {name}-Copy-19 and returns the first free slot; 400 if all 20 are taken.
  • UTF-8 without BOM. WriteText uses a cached new UTF8Encoding(encoderShouldEmitUTF8Identifier: false) so round-tripped files do not accumulate a 3-byte BOM on every save.
  • Binary gating. The backend refuses to open binary files as text; the frontend also pre-filters by extension (.stl, .zip, images, DBs, …) so the Edit button only appears when the text path is likely to work.

Syntax Highlighting

components/widgets/TextEditor.vue wraps CodeMirror 6 so the editor gets real syntax highlighting for the common project-file formats listed below.

Stack:

  • codemirror + @codemirror/state + @codemirror/view (core).
  • @codemirror/lang-xml + @codemirror/lang-json + @codemirror/lang-markdown (3 language packs).

Props: modelValue (two-way), language: 'xml' | 'json' | 'markdown' | 'text' (default text), readonly. Language and readonly are swapped via Compartment.reconfigure, so the view never has to tear down on mode change.

Extension → language mapping lives in components/widgets/editorLanguage.ts (single source of truth imported by both TextEditor.vue and FileExplorerPage.vue):

Language Extensions
xml xml, hincproj, CoatingMaterial, CutterMaterial, Holder, WorkpieceMaterial, mp, MillingPara, SpindleCapability, StickMachiningTool, general-mech, mt
markdown md, markdown
json json
text (fallback) everything else, including .nc / .ptp / .mpf / .h / .cs / .csv

Source Code Path

See HiNC App Anatomy for git repository links.

WPF Application Source Code Path

  • Not implemented.

Web Page Application Source Code Path

HiNC-2025-webservice (Quasar CLI SPA):

  • wwwroot-src/src/pages/FileExplorerPage.vue — routed page at /util/file-explorer.
  • wwwroot-src/src/components/widgets/TextEditor.vue — CodeMirror 6 wrapper.
  • wwwroot-src/src/components/widgets/editorLanguage.ts — extension → EditorLanguage mapping.
  • wwwroot-src/src/api/fileExplorer.ts — typed wrapper over /api/file-explorer/*.
  • wwwroot-src/src/router/routes.ts/util/file-explorer entry (route name util-file-explorer).
  • wwwroot-src/src/layouts/AppMenuBar.vueUtil → File Explorer entry.
  • Common/FileExplorerController.cs — REST endpoints under /api/file-explorer:
Method Path Notes
GET /roots List available roots; Project is omitted when no project is loaded. Returns display names only.
GET /list?rootName=&relativePath= Directories-first, name-ascending listing.
GET /read-text?… UTF-8 text; when the file is detected as binary returns content=null, isBinary=true.
POST /write-text Body {rootName, relativePath, content}; creates parents as needed.
POST /create-file Fails if target exists.
POST /create-directory Recursive create; no-op if already a directory.
POST /rename Body {rootName, relativePath, newRelativePath}; refuses cross-root moves.
POST /copy {name}-Copy-00..-Copy-19; uses Hi.Common.FileLines.FileUtil.CopyDirectory for directories.
DELETE /delete?… Files → delete, directories → recursive; refuses to delete the root itself.
GET /download?… Streams a file as application/octet-stream.
GET /download-zip?… Zips a directory in-memory and streams application/zip.
POST /upload?… Multipart single-file upload; overwrites target.
POST /extract-zip Body {rootName, relativePath}; extracts next to the archive into <name>/.

Deferred

  • Path-embedded route like /FileExplorer/{Root}/{*path} — replaced by explicit query state for easier linking.
  • <q-tree> directory-tree sidebar — <q-table> + breadcrumb + Up button covers every navigation need.
  • Drag-and-drop upload, multi-file upload, folder upload (webkitdirectory).
  • Syntax highlighting for .nc / .cs / .csv. NC needs a CM6 StreamLanguage G-code parser; C# needs @codemirror/legacy-modes wiring.
  • FileExplorerConfig.ExposeAbsolutePath flag in appsettings.json. Default (absolute paths never leave the server) is identical to what the flag's default would be, so adding later doesn't change observable behaviour.
  • Object Management Menu Button — shares the XML editor dialog pattern and targets the same project / resource folders through a different endpoint family.
  • Mechanism Builder Page — future integration target for Mechanism Builder's Load / Save As dialogs.