Archived
509 lines
30 KiB
HTML
509 lines
30 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Tree Ids and Routes | HiAPI-C# 2025 </title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="title" content="Tree Ids and Routes | HiAPI-C# 2025 ">
|
|
|
|
|
|
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
|
<link rel="stylesheet" href="../../public/docfx.min.css">
|
|
<link rel="stylesheet" href="../../public/main.css">
|
|
<meta name="docfx:navrel" content="../../toc.html">
|
|
<meta name="docfx:tocrel" content="toc.html">
|
|
|
|
<meta name="docfx:rel" content="../../">
|
|
|
|
|
|
|
|
<meta name="loc:inThisArticle" content="In this article">
|
|
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
|
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
|
<meta name="loc:tocFilter" content="Filter by title">
|
|
<meta name="loc:nextArticle" content="Next">
|
|
<meta name="loc:prevArticle" content="Previous">
|
|
<meta name="loc:themeLight" content="Light">
|
|
<meta name="loc:themeDark" content="Dark">
|
|
<meta name="loc:themeAuto" content="Auto">
|
|
<meta name="loc:changeTheme" content="Change theme">
|
|
<meta name="loc:copy" content="Copy">
|
|
<meta name="loc:downloadPdf" content="Download PDF">
|
|
|
|
<script type="module" src="./../../public/docfx.min.js"></script>
|
|
|
|
<script>
|
|
const theme = localStorage.getItem('theme') || 'auto'
|
|
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
|
<header class="bg-body border-bottom">
|
|
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
|
<div class="container-xxl flex-nowrap">
|
|
<a class="navbar-brand" href="../../index.html">
|
|
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
|
|
|
</a>
|
|
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
|
<i class="bi bi-three-dots"></i>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navpanel">
|
|
<div id="navbar">
|
|
<form class="search" role="search" id="search">
|
|
<i class="bi bi-search"></i>
|
|
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main class="container-xxl">
|
|
<div class="toc-offcanvas">
|
|
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
|
<div class="offcanvas-header">
|
|
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<nav class="toc" id="toc"></nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<div class="actionbar">
|
|
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
|
<i class="bi bi-list"></i>
|
|
</button>
|
|
|
|
<nav id="breadcrumb"></nav>
|
|
</div>
|
|
|
|
<article data-uid="Anatomy-TreeIdsAndRoutes">
|
|
<h1 id="tree-ids-and-routes">Tree Ids and Routes</h1>
|
|
|
|
<p>The web client addresses itself with two things: a vue-router path, and — on the two Control-Tree
|
|
pages — a <code>tree</code> query argument naming the selected tree node, as in
|
|
<code>/general-setup?tree=equipment/fixture/geometry</code>. This page is the reference for both surfaces: the
|
|
route table, the redirect-only paths that keep older bookmarks resolving, the id-migration chain,
|
|
and the resolver that decides which page owns a given <code>?tree=</code> id. The router runs in HTML5 history
|
|
mode, so every one of these paths is a real URL the server has to answer.</p>
|
|
<div class="IMPORTANT">
|
|
<h5>Important</h5>
|
|
<p>Nothing here promises that a Control-Tree id is stable. The guarantee is narrower and exact: an
|
|
id keeps <strong>resolving</strong>, because every regroup adds a migration hop to <code>migrateLegacyTreeId</code>
|
|
rather than rewriting the previous one. The ids themselves have moved repeatedly, and a page that
|
|
quotes one is quoting a value that can move again.</p>
|
|
</div>
|
|
<h2 id="the-route-table">The Route Table</h2>
|
|
<p><code>/</code> is the shell-layout record itself; every route below it except the login and catch-all records
|
|
is one of its children, so each renders inside the Main Panel's frame and menu bar.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Path</th>
|
|
<th>Route name</th>
|
|
<th>What it owns</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>/</code></td>
|
|
<td>—</td>
|
|
<td>The shell layout. It carries no page of its own; its empty child redirects to the Execution route.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/execution</code></td>
|
|
<td><code>execution</code></td>
|
|
<td>The run cockpit and the Execution Control Tree, whose selection rides <code>?tree=execution/…</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/general-setup</code></td>
|
|
<td><code>general-setup</code></td>
|
|
<td>The equipment Control Tree, whose selection rides <code>?tree=equipment/…</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/machine-tool</code></td>
|
|
<td><code>machine-tool</code></td>
|
|
<td>The machining chain on a canvas of its own, beside a left column that shows either a read-only identity panel or the chain's XML source — two states of one column, chosen with a GUI/XML toggle. A load button installs a chain file into the project. Carries no Page-menu entry and is reached by URL.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/tool-house/:toolId(\d+)?/:tab?/:subtab?</code></td>
|
|
<td><code>tool-house</code></td>
|
|
<td>The tool library and the per-tool editor. The three optional segments carry the selected tool and the two nested tab levels.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/preference/log</code></td>
|
|
<td><code>preference-log</code></td>
|
|
<td>The Log Viewer, reached from the menu bar's <code>Show Log</code> button. It is not under <code>/util/</code>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/util/file-explorer/:location(.*)*</code></td>
|
|
<td><code>util-file-explorer</code></td>
|
|
<td>The File Explorer. Its catch-all mirrors the browsed location — root display name followed by the relative segments — into the path.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/util/mech-builder</code></td>
|
|
<td><code>util-mech-builder</code></td>
|
|
<td>The Mechanism Builder.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/login</code></td>
|
|
<td><code>login</code></td>
|
|
<td>The sign-in form. It sits outside the shell layout and carries its own Quasar layout.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/:catchAll(.*)*</code></td>
|
|
<td>—</td>
|
|
<td>The 404 page, likewise outside the shell layout: it prints the unmatched full path and offers one button back to the Execution route.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The menu bar's Page dropdown holds every one of these that is menu-reachable, in setup order: Tool
|
|
House, General Setup and Execution, then File Explorer and Mechanism Builder below a separator. The
|
|
Log Viewer has a button of its own rather than a menu entry, and <code>/machine-tool</code> has neither — it is
|
|
reached by URL.</p>
|
|
<p>The Tool House route's tool segment is constrained to digits, but all three of its segments are
|
|
optional, so a non-numeric segment in the tool position is not rejected: the router skips the tool
|
|
parameter and reads that segment as the tab, which is what makes <code>/tool-house/cutter</code> a working tab
|
|
deep link with no tool named. The consequence is that the record absorbs three segments when the
|
|
first is a number and only two when it is not, and a URL carrying more than the record can absorb —
|
|
<code>/tool-house/abc/def/ghi</code> — falls through to the catch-all. An unrecognised tab name is not an error
|
|
either: the page canonicalises it to that level's default, as
|
|
<a href="#the-tool-house-translation">The Tool House Translation</a> sets out.</p>
|
|
<h2 id="redirect-only-paths">Redirect-Only Paths</h2>
|
|
<p>These records carry no component. They exist so that a link minted before the corresponding editor
|
|
moved into a Control Tree still lands on the editor.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Path</th>
|
|
<th>Lands on</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>/controller/:rest(.*)*</code></td>
|
|
<td><code>/general-setup?tree=equipment/controller</code> — any trailing path is discarded, the retired Controller page's <code>/<tab></code> segment included, so every form lands on the branch root.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/spindle-capability/:tab?</code></td>
|
|
<td><code>/general-setup?tree=equipment/spindle</code>, with <code>/<tab></code> appended when the segment is one of <code>thermal</code>, <code>gear-shift</code>, <code>dry-run</code>, <code>power</code>, <code>torque</code>. An unrecognised segment is dropped and the branch root is selected.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/equipment/spindle</code></td>
|
|
<td><code>/general-setup?tree=equipment/spindle</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/fixture/:rest(.*)*</code></td>
|
|
<td><code>/general-setup?tree=equipment/fixture</code> — any trailing path is discarded.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/workpiece/:rest(.*)*</code></td>
|
|
<td><code>/general-setup?tree=equipment/workpiece</code> — any trailing path is discarded.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/equipment/background-coolant</code></td>
|
|
<td><code>/general-setup?tree=equipment/background</code>. Background and Coolant are two separate tree nodes; the redirect picks Background.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>/mission</code></td>
|
|
<td><code>/execution?tree=execution/mission</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The five spindle tab names are declared in <code>treeRoutes.ts</code> as <code>SPINDLE_TABS</code>, and imported by
|
|
<code>wwwroot-src/src/router/routes.ts</code> — which is the list the redirect tests its <code>:tab?</code> segment
|
|
against. The equipment tree does not import that constant: it spells the same five segments as
|
|
literals while building the <code>equipment/spindle/<seg></code> children, so redirect and branch agree by
|
|
convention rather than through a shared list — renaming a spindle section is therefore an edit in
|
|
two places. The Tool House name lists below are the other case, genuinely shared.</p>
|
|
<h2 id="the-tree-query">The <code>?tree=</code> Query</h2>
|
|
<p>Selection and URL are synced two ways by the Control-Tree host, one instance per tree page.</p>
|
|
<p><strong>URL to selection.</strong> A watcher on the query drives <code>applyRouteSelection()</code>, and it is registered
|
|
<code>immediate</code>, so an id belonging to another page redirects on the first tick rather than after this
|
|
page's first tree build. The host also calls the same function once the tree has actually been
|
|
built, which is when a deep link can finally be honoured.</p>
|
|
<p><strong>Selection to URL.</strong> A watcher on the selected id replaces the <code>tree</code> argument, preserving the
|
|
rest of the query. It uses <code>router.replace</code>, so browsing the tree does not fill the browser's
|
|
history with one entry per node. The comparison that breaks the loop is made against the <strong>raw</strong>
|
|
query rather than the migrated form, which is what makes an older id canonicalise: opening
|
|
<code>?tree=controller</code> selects the node and then rewrites the URL to <code>?tree=equipment/controller</code>.</p>
|
|
<p>Neither watcher touches the URL unless the current route name is the page's own. The shell layout
|
|
keeps every visited page alive, so a host whose page is not showing keeps receiving route changes,
|
|
and without the guard it would write another page's URL. The selection watcher does one thing
|
|
before that guard: it records the id as this page's last selection. That ordering is load-bearing,
|
|
because a selection can move while its page is off screen — unticking a CSV or CL Controller
|
|
checkbox steps the equipment host off that node onto the equipment root, and the Preference menu
|
|
that carries those checkboxes is open on every page — and the landing selection has to have
|
|
followed it.</p>
|
|
<p>That same checkbox flip is a third writer of the <code>tree</code> argument, and the one place the guard is
|
|
absent. The equipment host watches both checkboxes, and when the standing selection is a node the
|
|
flip removes, it replaces <code>tree</code> with <code>equipment</code> — the rest of the query preserved — before
|
|
stepping the selection off. The route name is not consulted there, so the replacement goes to
|
|
whichever route is showing.</p>
|
|
<h3 id="what-applyrouteselection-does">What <code>applyRouteSelection</code> Does</h3>
|
|
<ol>
|
|
<li>The change is ignored unless this page owns the current route.</li>
|
|
<li>The raw query is migrated into today's id. If its first segment names a <strong>different</strong> page and
|
|
that segment is one of the known roots, the location is replaced with the route that owns it and
|
|
the pass stops.</li>
|
|
<li>An empty query falls back to the landing selection: the persisted last id for this page when
|
|
that id exists in the tree just built, otherwise the page's root node — which is always present
|
|
once the tree is built, so the editor column always has something to show.</li>
|
|
<li>An id the built tree does not contain is <strong>ignored</strong> — the current selection stands and the URL
|
|
keeps the unrecognised value until the next selection overwrites it. This is deliberate: the
|
|
redirect in step 2 fires only for known roots, because sending an unroutable id back to the same
|
|
page would loop.</li>
|
|
<li>Otherwise every ancestor prefix of the id is added to the expanded set so the node is visible,
|
|
and the selection is requested through the same gate a tree click uses. A panel holding unsaved
|
|
edits may refuse the switch, and a refusal re-points the URL at the selection that actually
|
|
stands.</li>
|
|
</ol>
|
|
<h3 id="the-id-the-url-names-before-the-tree-exists">The Id the URL Names, Before the Tree Exists</h3>
|
|
<p><code>treePathOfRoute()</code> — the raw query put through <code>migrateLegacyTreeId</code> — is not read only by the
|
|
selection logic. The equipment tree consults it while it is being <strong>built</strong>, to decide whether to
|
|
materialise the CSV Controller and CL Controller nodes: each is normally shown only when its
|
|
Preference checkbox is ticked, and a URL naming one reveals it regardless. That reveal has to
|
|
happen at build time precisely because step 4 above refuses an id the built tree lacks, so a
|
|
bookmark to a switched-off node would otherwise dead-end. Only the URL reveals a node this way; the
|
|
persisted last selection does not, so a node the user has just unticked while standing on it does
|
|
not resurrect itself.</p>
|
|
<h2 id="id-migration">Id Migration</h2>
|
|
<p><code>migrateLegacyTreeId</code> is one pass of ordered guards over the whole id; the first that matches
|
|
returns, and an id matching none is returned unchanged.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>An id shaped like</th>
|
|
<th>Becomes</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>controller</code>, <code>controller/…</code></td>
|
|
<td><code>equipment/controller</code>, <code>equipment/controller/…</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>spindle</code>, <code>spindle/…</code></td>
|
|
<td><code>equipment/spindle</code>, <code>equipment/spindle/…</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>mission</code>, <code>mission/…</code></td>
|
|
<td><code>execution/mission</code>, <code>execution/mission/…</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>equipment/mission</code>, <code>equipment/mission/…</code></td>
|
|
<td><code>execution/mission</code>, <code>execution/mission/…</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>any id ending in <code>/contours/tray</code>, or containing <code>/contours/tray/</code></td>
|
|
<td>the same id with that segment spelled <code>fluting</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The last rule renames one segment in place and leaves its children — <code>baseline</code>, <code>flute-<i></code>,
|
|
<code>side</code>, <code>bottom</code> — untouched, so a deep link into a flute contour survives the engine's Fluting
|
|
type naming. The two mission rules cover the two id shapes separately rather than chaining, because
|
|
the first matching guard returns.</p>
|
|
<p>The function is applied at four points, which is what makes the guarantee hold in practice:</p>
|
|
<ul>
|
|
<li>to the raw <code>?tree=</code> query, on every read;</li>
|
|
<li>to the persisted last selection, before it is looked up in the tree;</li>
|
|
<li>to the persisted list of expanded node ids, once when a host is constructed, so an older
|
|
expansion set still unfolds the branches it names;</li>
|
|
<li>as the first step of <code>routeForTreeId</code>, so the id-to-page resolver never sees an unmigrated id.</li>
|
|
</ul>
|
|
<p>Note what the first rule implies: a bare <code>?tree=controller</code> selects the <code>equipment/controller</code>
|
|
branch — the controller editor on the General Setup page — and the redirect-only <code>/controller</code> path
|
|
above lands on the same branch, so a bookmark from the retired Controller page's era resolves in
|
|
either form.</p>
|
|
<h2 id="landing-an-id-on-its-page">Landing an Id on Its Page</h2>
|
|
<p><code>TREE_PAGE_ROOTS</code> lists the first segments that name a page: <code>execution</code>, <code>equipment</code> and
|
|
<code>toolhouse</code>. <code>spindle</code> is absent on purpose — migration folds it into <code>equipment/…</code> before any root
|
|
check runs, so no root check ever sees it.</p>
|
|
<p><code>routeForTreeId</code> migrates the id, then dispatches on its first segment:</p>
|
|
<ul>
|
|
<li><code>toolhouse</code> — the Tool House route, with the id's segments translated into path params (below).</li>
|
|
<li><code>equipment</code> — the General Setup route, carrying the migrated id as <code>?tree=</code>.</li>
|
|
<li>anything else — the Execution route, carrying the migrated id as <code>?tree=</code>. This is a
|
|
fall-through, not a test for <code>execution</code>, so an unrecognised id handed to this function lands on
|
|
the Execution page. Reaching it with a genuinely unroutable id is prevented upstream: the host
|
|
calls the function only for ids whose root is in <code>TREE_PAGE_ROOTS</code>.</li>
|
|
</ul>
|
|
<p>The returned location replaces the whole current location. Only the <code>tree</code> argument survives the
|
|
hop; any other query argument on the URL being redirected away from is dropped, and the Tool House
|
|
form carries no query at all.</p>
|
|
<h2 id="the-tool-house-translation">The Tool House Translation</h2>
|
|
<p>The Tool House page keeps its state in path segments rather than a query, so an id arriving from
|
|
another page has to be translated. <code>routeForTreeId</code> walks the segments of
|
|
<code>toolhouse/tool-<n>/<tab>/<subtab></code>:</p>
|
|
<ul>
|
|
<li>segment two contributes <code>toolId</code> when it is <code>tool-</code> followed by an integer;</li>
|
|
<li>segment three contributes <code>tab</code> when it is one of <code>general</code>, <code>cutter</code>, <code>holder</code>, <code>clamping</code>,
|
|
<code>intelligent</code>;</li>
|
|
<li>segment four contributes <code>subtab</code> when it is one of the cutter sections — <code>material</code>, <code>profile</code>,
|
|
<code>contours</code>, <code>upper-beam</code>, <code>opt</code> — or one of the holder sections, <code>geometry</code> and <code>resolution</code>.</li>
|
|
</ul>
|
|
<p>Only the sub-tab step is nested inside the tab step: an unrecognised tab discards the sub-tab with
|
|
it, whereas the tool step is tested on its own, so a second segment that is not <code>tool-<n></code> costs the
|
|
<code>toolId</code> param alone and the tab still translates. Everything deeper than the last segment the URL
|
|
can carry is discarded either way — an id pointing at a single flute contour under
|
|
<code>…/cutter/contours/fluting/…</code> lands on the nearest tab the URL can express. The same three name
|
|
lists are imported by the page itself, so the tab set and the translation cannot drift apart.</p>
|
|
<p>Once on the page, the tab segments are kept in step with the tabs by <code>useRouteTabs</code>, a composable
|
|
whose only consumer this page is. It gives each tab level one route param, a valid-name set and a
|
|
default; a nested level may declare which parent values make it apply, and while its parent is
|
|
something else the level is <strong>dormant</strong> — its segment is dropped from the URL while its reference
|
|
quietly remembers the last value, so returning to that parent tab returns to the sub-tab it had.
|
|
The Tool House sub-tab level applies under <code>cutter</code> and <code>holder</code> only, and both its valid set and
|
|
its default depend on which of the two is showing. A segment the level does not recognise resolves
|
|
to that default rather than failing. Canonicalisation runs on the first mount and on every
|
|
keep-alive re-entry, which is why a bare <code>/tool-house</code> acquires its tab segments. The tool segment
|
|
is not one of the composable's levels: the page fills it in itself, adopting the URL's tool when the
|
|
project holds it and the first tool in the list otherwise, then replacing the URL with what it
|
|
adopted. That resolver reacts to the
|
|
<code>toolId</code> param and to the tool list rather than to page activation, so it also re-points the URL
|
|
when the list changes underneath it.</p>
|
|
<p>The Tool House page never reads or writes <code>?tree=</code>. A <code>toolhouse/…</code> id reaches it only by way of
|
|
the redirect above, which is issued by one of the two tree pages' hosts.</p>
|
|
<h2 id="reading-an-id">Reading an Id</h2>
|
|
<p>An id's first segment names the page that owns it, and therefore the folder that documents it:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th><code>?tree=</code> root</th>
|
|
<th>Route</th>
|
|
<th>Documented under</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>execution/…</code></td>
|
|
<td><code>/execution</code></td>
|
|
<td><a class="xref" href="../execution/index.html">Execution Page</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>equipment/…</code></td>
|
|
<td><code>/general-setup</code></td>
|
|
<td><a class="xref" href="../general-setup/index.html">General Setup Page</a></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>toolhouse/…</code></td>
|
|
<td><code>/tool-house/…</code></td>
|
|
<td><a class="xref" href="../tool-house/index.html">Tool House Page</a></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>The remaining segments are the branch path, one segment per level of the tree, and the branch's own
|
|
page sits in that folder — <code>equipment/workpiece/material/cutting-parameter</code> is the Cutting Parameter
|
|
item of the Workpiece branch on the General Setup page. Most segments are kebab-case role names;
|
|
the two list-backed branches, Mission entries and Program files, use a positional index instead.</p>
|
|
<p>Every segment comes from the <strong>node id</strong>, never from the label the user reads: the General Setup
|
|
page's root node is labelled <code>General Setup</code> and carries the id <code>equipment</code>. A label is a display
|
|
string — the translation of the node's <code>labelKey</code> where it has one, and otherwise raw data such as
|
|
an NC file name or a mission command's user-typed title, as <a class="xref" href="control-tree.html">Control Tree</a>
|
|
sets out — while an id is neither translated nor taken from data. Two consequences follow. A
|
|
<code>?tree=</code> link is locale-independent, and an id can never be read off what is on screen.</p>
|
|
<h2 id="titles">Titles</h2>
|
|
<p>A route's <code>meta.title</code> holds an i18n <strong>key</strong>, such as <code>routes.execution</code>, not a title. The router
|
|
resolves it through the active locale in an <code>afterEach</code> hook and sets the document title to the
|
|
translated name followed by <code> - HiNC</code>; a route with no key — the catch-all — leaves the bare
|
|
product name. The sibling <code>name:</code> is the route id used by every programmatic navigation and is
|
|
never translated; the two must not be confused, which is why the route table above lists them side
|
|
by side.</p>
|
|
<p>The same resolver is handed to the i18n module through <code>registerRetitle</code>, so that switching
|
|
language re-titles a parked tab without a navigation. The registration is indirect because the
|
|
router already imports the i18n module for its translation function, and importing back would close
|
|
a cycle.</p>
|
|
<h2 id="serving-these-urls">Serving These URLs</h2>
|
|
<p>History mode means the browser sends the whole path to the server on a refresh or a pasted link, so
|
|
the back end maps two SPA fallbacks. The bare fallback carries an implicit constraint that rejects
|
|
any URL whose last segment contains a dot, which is exactly the shape a File Explorer deep link
|
|
takes, since those mirror real file names. An explicit fallback for the explorer's path is
|
|
therefore mapped ahead of it with no such constraint. Static assets cannot be shadowed by either,
|
|
because static-file serving runs earlier in the pipeline. Both fallbacks allow anonymous access, so
|
|
the SPA itself always loads and the sign-in decision is made in the client.</p>
|
|
<p>That decision is a navigation guard: it hydrates the authentication status once, lets every
|
|
navigation through when the back end reports the feature disabled, and otherwise sends an
|
|
unauthenticated visitor to the login route with the original full path — <code>?tree=</code> included — parked
|
|
in a <code>redirect</code> query. A successful sign-in replays that path as a full page load rather than a
|
|
router navigation, so the application re-initialises with the cookie present. A visitor who is
|
|
already signed in, or who arrives while the feature is off, is sent straight back out of the login
|
|
route to the same parked path.</p>
|
|
<h2 id="source-code-path">Source Code Path</h2>
|
|
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
|
<h3 id="web-application">Web Application</h3>
|
|
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
|
|
<ul>
|
|
<li><code>wwwroot-src/src/router/routes.ts</code> — the route table, the redirect-only records, the login route
|
|
outside the shell layout, and the trailing catch-all.</li>
|
|
<li><code>wwwroot-src/src/router/treeRoutes.ts</code> — <code>migrateLegacyTreeId</code>, <code>TREE_PAGE_ROOTS</code>,
|
|
<code>routeForTreeId</code>, the three tab-name lists it shares with the Tool House page, and
|
|
<code>SPINDLE_TABS</code>, which only the spindle redirect reads.</li>
|
|
<li><code>wwwroot-src/src/router/index.ts</code> — the history-mode router factory, the authentication guard,
|
|
and the retitle hook registered with the i18n module.</li>
|
|
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the tree-page host:
|
|
<code>rawTreePathOfRoute</code>, <code>treePathOfRoute</code>, the two selection/URL watchers and the unguarded
|
|
controller-checkbox watcher beside them, <code>landingSelection</code>, <code>applyRouteSelection</code> and
|
|
<code>syncUrlBack</code>, plus the build-time reveal of a URL-named CSV or CL controller node.</li>
|
|
<li><code>wwwroot-src/src/composables/useRouteTabs.ts</code> — the tab-to-param sync the Tool House route uses,
|
|
including dormant levels and the keep-alive re-entry canonicalisation.</li>
|
|
<li><code>wwwroot-src/src/pages/ToolHousePage.vue</code> — consumes the shared tab lists, resolves the tool from
|
|
its path param, and navigates by route name when the tool changes.</li>
|
|
<li><code>wwwroot-src/src/pages/FileExplorerPage.vue</code> — mirrors the browsed location into the route's
|
|
catch-all param and back.</li>
|
|
<li><code>wwwroot-src/src/pages/MachineToolPage.vue</code> — the component behind the URL-only machine-tool
|
|
route.</li>
|
|
<li><code>wwwroot-src/src/pages/NotFoundPage.vue</code> — the catch-all component, carrying its own layout.</li>
|
|
<li><code>wwwroot-src/src/pages/LoginPage.vue</code> — reads the guard's <code>redirect</code> argument and replays it.</li>
|
|
<li><code>wwwroot-src/src/composables/useViewPrefs.ts</code> — the browser-local store holding the per-page last
|
|
selected id and the expanded-node list that migration is applied to.</li>
|
|
<li><code>wwwroot-src/src/components/AppMenuBar.vue</code> — the menu entries that navigate by route name.</li>
|
|
<li><code>wwwroot-src/src/i18n/en/routes.ts</code> — the English strings the <code>meta.title</code> keys resolve to.</li>
|
|
<li><code>wwwroot-src/src/i18n/index.ts</code> — <code>registerRetitle</code> and the locale switch that calls it.</li>
|
|
<li><code>wwwroot-src/quasar.config.ts</code> — selects history mode and names the build output folder the
|
|
server serves.</li>
|
|
<li><code>Program.cs</code> — the two SPA fallbacks, the explorer-specific one ahead of the bare one.</li>
|
|
</ul>
|
|
<h2 id="see-also">See Also</h2>
|
|
<ul>
|
|
<li><a class="xref" href="control-tree.html">Control Tree</a> — the tree these ids name: how a node id is formed and what a branch
|
|
is made of</li>
|
|
<li><a class="xref" href="../shell/main-panel.html">Main Panel</a> — the shell whose menus navigate to these routes and whose keep-alive
|
|
cache makes the route-name guards necessary</li>
|
|
<li><a class="xref" href="../execution/index.html">Execution Page</a> — the busiest consumer of <code>?tree=</code>, and the page a fall-through id lands
|
|
on</li>
|
|
</ul>
|
|
|
|
</article>
|
|
|
|
<div class="contribution d-print-none">
|
|
</div>
|
|
|
|
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
|
|
|
</div>
|
|
|
|
<div class="affix">
|
|
<nav id="affix"></nav>
|
|
</div>
|
|
</main>
|
|
|
|
<div class="container-xxl search-results" id="search-results"></div>
|
|
|
|
<footer class="border-top text-secondary">
|
|
<div class="container-xxl">
|
|
<div class="flex-fill">
|
|
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|