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;
Enternavigates. - Refresh / New Folder / New File / Upload Buttons.
- Root Selector Dropdown — display-name only, sourced from
- 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 (
.ziponly), Rename, Duplicate, Delete (double-click to confirm).
- Row click:
- Editor Dialog (full-width / full-height)
- Title Bar — file name + language chip + Cancel / Save / Close.
- Body —
<TextEditor>wrapping CodeMirror 6 filling the viewport.
- Toolbar
Behavior
- Path-traversal defence. Every request is resolved via
Path.GetFullPathand validated withHi.Common.PathUtils.PathUtil.IsDescendant(root, absolute)before any IO. Attempts likerelativePath=../outsideare rejected with HTTP 400. - Duplicate.
POST /copytries{name}-Copy-00through{name}-Copy-19and returns the first free slot; 400 if all 20 are taken. - UTF-8 without BOM.
WriteTextuses a cachednew 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 →EditorLanguagemapping.wwwroot-src/src/api/fileExplorer.ts— typed wrapper over/api/file-explorer/*.wwwroot-src/src/router/routes.ts—/util/file-explorerentry (route nameutil-file-explorer).wwwroot-src/src/layouts/AppMenuBar.vue—Util → File Explorerentry.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 CM6StreamLanguageG-code parser; C# needs@codemirror/legacy-modeswiring. FileExplorerConfig.ExposeAbsolutePathflag inappsettings.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.
Related Pages
- 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.