This repository has been archived on 2026-10-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
HiNC-2025-win-desktop-Deploy/App/wwwroot/HiAPI-docsite/anatomy/execution/mission/ListCommand-panel.html
T
2026-09-15 01:12:50 +08:00

338 lines
23 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>List Command Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="List Command Panel | 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 &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<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-ListCommandPanel">
<h1 id="list-command-panel">List Command Panel</h1>
<p>A <a class="xref" href="../../../api/Hi.SessionCommands.ListCommand.html">ListCommand</a> is the container command: an optional title plus a list of
enable-wrapped commands. Running one walks
<a class="xref" href="../../../api/Hi.SessionCommands.ListCommand.html#Hi_SessionCommands_ListCommand_CommandEntryList">CommandEntryList</a> top-down and skips a disabled entry together
with everything nested under it — the wrapper yields nothing while its flag is clear. The mission's
own command is always a list, so the <a class="xref" href="mission-root-panel.html">Mission branch root</a> <em>is</em> a
list, and every nested one is the same shape one level down.</p>
<p><code>List</code> is an ordinary catalog kind — category Flow — so a list is added the way any command is, and
adding one grows a sub-tree: the node's children are its own entries, edited on their own Control
Tree rows, and the list's own panel holds only its optional title, beneath the Disabled Caption
while the command is unticked.</p>
<p>This page covers what a list is, how its title reads, and what moving commands in and out of one
costs. The Control Tree row affordances every list shares — Add Command, the row buttons, the three
drag landings — are documented once, on <a class="xref" href="mission-root-panel.html">Mission Root Panel</a>.</p>
<h2 id="key-models">Key Models</h2>
<ul>
<li><strong>Primary</strong>: <a class="xref" href="../../../api/Hi.SessionCommands.ListCommand.html">ListCommand</a> — <a class="xref" href="../../../api/Hi.SessionCommands.ListCommand.html#Hi_SessionCommands_ListCommand_Title">Title</a>
and <a class="xref" href="../../../api/Hi.SessionCommands.ListCommand.html#Hi_SessionCommands_ListCommand_CommandEntryList">CommandEntryList</a>.</li>
<li><strong>Supporting</strong>:
<ul>
<li><a class="xref" href="../../../api/Hi.SessionCommands.EnablingWrapper.html">EnablingWrapper</a> — one entry:
<a class="xref" href="../../../api/Hi.SessionCommands.EnablingWrapper.html#Hi_SessionCommands_EnablingWrapper_Command">Command</a> plus
<a class="xref" href="../../../api/Hi.SessionCommands.EnablingWrapper.html#Hi_SessionCommands_EnablingWrapper_IsEnabled">IsEnabled</a>.</li>
<li><a class="xref" href="../../../api/Hi.SessionCommands.ITitleCommand.html">ITitleCommand</a> — <code>ListCommand</code> implements it, and
<a class="xref" href="../../../api/Hi.SessionCommands.ITitleCommand.html#Hi_SessionCommands_ITitleCommand_GetCommandTitle_">GetCommandTitle</a> composes the label a row shows.</li>
<li><a class="xref" href="../../../api/Hi.MachiningProcs.MachiningProject.html#Hi_MachiningProcs_MachiningProject_PlayerCommand">PlayerCommand</a> — the mission's command, a list.</li>
<li><a class="xref" href="../../../api/Hi.SessionCommands.CommandCatalogAttribute.html">CommandCatalogAttribute</a> and <a class="xref" href="../../../api/Hi.SessionCommands.CommandCategory.html">CommandCategory</a>
— what makes <code>List</code> addable, and the group it is offered under.</li>
</ul>
</li>
</ul>
<h2 id="the-panel-of-a-list-entry">The Panel of a List Entry</h2>
<p>Selecting a list command in the Control Tree opens, top to bottom:</p>
<ul>
<li>List Entry Panel
<ul>
<li>Disabled Caption
<ul>
<li>Present only while the command is disabled: skipped during play, still editable.</li>
</ul>
</li>
<li>Title (optional) Input</li>
</ul>
</li>
</ul>
<p>Nothing else is on the panel. The list's entries are the node's children in the tree, and the
operations that rewrite the <strong>parent</strong> list — Move up, Move down, Duplicate, Delete — are the
buttons on the list's own tree row, revealed on hover and on the selected row, and always shown on
a touch or pen device, where there is no hover; Delete asks for confirmation in a dialog naming the
command. The <code>+</code> on that row adds a command into this list.</p>
<p>The Title input holds the <strong>raw</strong> title — empty when unset — while the label the tree row shows is
composed by the engine: <code>List</code> when the title is blank, <code>List [title]</code> when it is not. A
titled list still says what it is. A whitespace-only title counts as unset and is never written into
the project file: it reloads as the empty title, and the label reads <code>List</code> both before and after,
so a save cannot come back as a different label on the next load.</p>
<p>Keystrokes debounce into one title save. The same dirty gate flushes the pending save — and awaits a
save already on the wire — on two occasions: before every Control Tree row op, whose rebuild
remounts the panel and can shift the entry paths, and before a selection change, which switches
the panel away; unmount cancels it, so a late write cannot land on whichever command slides into
the old path. A flush whose save fails refuses the op or the switch, and a refused op says so in a
notice; a save that was already on the wire when the gate ran is only waited for — its failure
raises a notice of its own, and the op then proceeds regardless, leaving the title unsaved. Once
it is saved the tree label refreshes in place rather than by rebuilding the branch, which would
remount the open editor mid-edit.</p>
<p>The root list is the one list without a title input: the branch root reads <code>Mission</code>.</p>
<h2 id="enabling-and-what-a-disabled-list-skips">Enabling, and What a Disabled List Skips</h2>
<p>The enable switch is the checkbox on the command's own Control Tree row, not a control on its panel
and not one of the row's buttons. It decides only whether the command <strong>runs</strong>: while it is clear
the tree row dims, and the editor stays open and fully editable. The checkboxes are read-only while
a mission row op, or a tick's own writes, are in flight. Unticking a list dims its whole sub-tree —
the dim rides ancestor propagation in the tree while each nested entry keeps its own flag, which is
exactly what the run does: a disabled entry is skipped with everything under it.</p>
<h2 id="paths">Paths</h2>
<p>A command node's key is its Mission API path — <code>&quot;0&quot;</code>, <code>&quot;1&quot;</code>, nested <code>&quot;0.2&quot;</code> for entry 2 inside the
list at index 0. Every structural change re-mints them: deleting entry 2 slides the next command
into path <code>&quot;2&quot;</code>. Each branch build therefore stamps its nodes, so the editor panel remounts onto the
new path instead of going on showing a command the path no longer names. The host carries its own
index-based ids — the expansion set, the Add focus and the selection — through each row op, so they
follow the rows rather than the slots: a selection riding on the acted-on row follows it — the
stepped or dropped row at its new index, or the clone a Duplicate makes — except on Delete, where
no row remains to follow: it lands on the nearest remaining entry of that list, the index clamped
to the new count, or on the owning list node once the list is empty, where Add Command waits. Any
other selection keeps its own re-indexed row.</p>
<h2 id="moving-commands-in-and-out">Moving Commands In and Out</h2>
<ul>
<li><strong>Into a list</strong> — drag a command's tree row — the whole row drags; the handle icon at its left
only marks it as draggable — onto the middle band of a list row; that row's outer quarters still
reorder around it. The Mission root row is all middle band: a drop anywhere on it lands in the
root list. Either way the entry lands at that list's tail.</li>
<li><strong>Out of a list</strong> — drop the row on the edge of a command row in another list, before or after it;
the lower quarter of the list command's own row lands the entry right after the list in the
owning list.</li>
</ul>
<p>Which call a landing makes depends on whether the entry changes list, not on where the pointer
sat. A landing that changes the list — the middle band of a list the entry is not in, or an edge in
another list — is the reparent call; a landing that keeps the list — an edge in the entry's own
list, or the middle band of the list row (the Mission root row included) that already holds it,
which sends it to the tail — is the reorder call, sent as the list's whole new order. The server
resolves the source list and the target list to object references before it mutates either, so the
index shift the removal causes cannot misroute the insert, and it refuses to move a list into itself
or into one of its own descendants. That guard compares identity rather than path-string prefixes,
because <code>&quot;02&quot;</code>, <code>&quot;+2&quot;</code> and <code>&quot; 2&quot;</code> all parse to index 2.</p>
<p>Two more properties of a list follow from the same API:</p>
<ul>
<li><strong>A new command lands right after the focused command</strong> when that command is a direct entry of
the list the <code>+</code> belongs to, root or nested, and at that list's tail otherwise. The focus is one
for the whole Mission tree — the last selected or last added command, whichever list it sits in
— so each list row's <code>+</code>, scoped to its own list, ignores a focus that lies in another list.
Nothing is pinned; the order is entirely the user's, changed with the row's Move up / Move down
buttons or by dragging.</li>
<li><strong>Duplicate is a deep copy.</strong> The entry is cloned through the same XML round-trip the project file
uses, so a nested list copies with its whole sub-tree, and the clone lands right after the source.</li>
</ul>
<p>Dragging serves rearrangement only: a row accepts a drop only while a mission row is being dragged,
so a drag carrying text or files keeps the browser's no-drop cursor. To bring several program files
in at once, open a <a class="xref" href="NcFileCommand-panel.html">Program File</a> command's picker and pick them
together — the first pick lands on that command and each further pick becomes another Program File
command right after it, in pick order, inside the same list at any depth.</p>
<h2 id="which-commands-a-list-can-hold">Which Commands a List Can Hold</h2>
<p>The addable set is the server's command catalog: every engine command carrying <code>[CommandCatalog]</code>,
reflected into the picker Add Command opens, which searches by display label, kind key and alias
and takes one pick per opening.
<code>List</code> is one of those commands, which is what makes nesting an ordinary act rather than a special
case. The frontend contributes an icon per kind, and its own label where it has one; the server
supplies the localized label otherwise, so a newly attributed engine command becomes addable with no
frontend change.</p>
<p>A command without that attribute stays loadable from a project file but is never offered for
creation. General Config is the one such command with an editor of its own: it is the legacy
settings bundle, so a project file storing one loads as the individual setting commands it stands
for and saving never writes the bundle back — editable when a project still constructs one through
the API, and absent from the catalog.</p>
<p>Selecting a command's tree row opens that command's editor on its node — the kind's own panel when
one exists, otherwise a generic editor built from the scalar fields the command declares. Selection
is one row at a time: there is no multi-selection here, and every row button acts on the row that
carries it, whether or not that row is the selected one. Because the server composes every entry
label, a command carrying no title of its own still reads as its localized display name.</p>
<p>A list's entries never appear in the editor pane: they are the node's children in the Control Tree,
and the pane below the tree shows only the selected command's panel. The left-most of the Execution
page's three draggable vertical dividers sits between the left dock — the Control Tree over the
editor panel — and the central area; the divider inside that dock drags the height between the tree
and the editor.</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>
<ul>
<li><code>wwwroot-src/src/components/controlTree/MissionCommandSlavePanel.vue</code> — a list entry's panel: the
disabled caption, the optional Title input with its debounce / flush / cancel discipline and the
dirty gate it answers to the host, and the bespoke-or-generic editor choice for every other kind.</li>
<li><code>wwwroot-src/src/components/controlTree/ControlTreePanel.vue</code> — the tree rows: the draggable row
with its handle icon, the Move up / Move down / Duplicate / Delete buttons on every command row
(revealed on hover and on the selected row, always shown on a touch or pen device), the <code>+</code>
on every list row (the Mission root included) and the Add Command dialog it opens, and the
drop-indicator styles.</li>
<li><code>wwwroot-src/src/components/controlTree/useMissionTreeDrag.ts</code> — the drag bookkeeping between
mission rows: which rows drag, which receive, and the before / after / into landing read from the
pointer's position on the row.</li>
<li><code>wwwroot-src/src/components/controlTree/MissionRootPanel.vue</code> — the branch root's panel, the one
without a title input: the command count and the run-order hint.</li>
<li><code>wwwroot-src/src/components/controlTree/AddCommandDialog.vue</code> — the search-first catalog picker;
one pick per opening.</li>
<li><code>wwwroot-src/src/components/controlTree/missionItemTypes.ts</code> — the child builders that recurse
into a list's own entries, the per-kind editor override map, and the per-build stamp that forces
the panel remount.</li>
<li><code>wwwroot-src/src/components/controlTree/missionKindIcons.ts</code> — the kind and category icons the
picker shows.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the five row ops — add, drag
move, step, duplicate, delete — through one <code>missionRowOp</code> helper (the busy gate, the open panel's
dirty flush, the API call, the scoped rebuild, the post-op selection), the insert-after-focus rule
scoped to the <code>+</code>'s own list, and the index translation that carries the expansion set, the Add
focus and the selection through each op; which nodes show a checkbox, the dim that flows down a
disabled command's sub-tree, the enable write, and the in-place label refresh after a title edit
or a language switch.</li>
<li><code>wwwroot-src/src/api/mission.ts</code> — the typed wrapper over the Mission API and the path convention
(<code>root</code> or empty = the root list, <code>0.2</code> = a nested entry); <code>addEntry</code> takes the optional insert
index and resolves to the new entry's path.</li>
<li><code>wwwroot-src/src/components/mission/GenericCommandPanel.vue</code> — the editor a catalog kind gets when
it ships no bespoke panel, built from the command's declared scalar fields.</li>
<li><code>wwwroot-src/src/components/mission/NcFileCommandPanel.vue</code> — the multi-pick file dialog: the
first pick lands on the command, each further pick becomes another Program File command right
after it.</li>
<li><code>wwwroot-src/src/pages/ExecutionPage.vue</code> — the page-level splitters; the left-most parts the left
dock from the central area.</li>
<li><code>wwwroot-src/src/components/controlTree/ControlTreeDock.vue</code> — the left dock's two rows and the
height divider between the tree and the editor.</li>
<li><code>wwwroot-src/src/i18n/en/tree.ts</code> — the <code>tree.mission.*</code> strings: the kind names, the run-order
hint that names the row affordances, the disabled hint, the cancelled-op notice and the operation
labels.</li>
<li><code>wwwroot-src/src/i18n/en/common.ts</code> — the row buttons' titles and the Title (optional) label.</li>
<li><code>wwwroot-src/src/i18n/en/dialog.ts</code> — the Delete Command confirmation.</li>
<li><code>Missions/MissionController.cs</code> — the entry lifecycle: <code>GET list-command/entries</code> (recursive),
<code>POST list-command/entries</code> and <code>POST list-command/entries/{path}</code> (into the root or a nested
list, at an optional <code>insertIndex</code> clamped to the list and otherwise at its tail, answering the
new entry's index and path), <code>DELETE list-command/entries/{path}</code>,
<code>POST list-command/entries/{path}/move</code> (the row's Move up / Move down), <code>PUT list-command/reorder</code>
(a drop that keeps the owning list), <code>POST list-command/entries/{path}/duplicate</code> (the
XML-round-trip deep clone), <code>POST list-command/entries/{path}/reparent</code> (a drop that changes the
owning list, with the self/descendant guard), <code>PUT commands/{path}/listcommand</code> for the title, and
<code>PUT commands/{path}/enabled</code> for an entry's enable flag. <code>GetCommandTitle</code> composes every entry
label the tree shows.</li>
<li><code>Missions/MissionCommandCatalog.cs</code> — reflects the <code>[CommandCatalog]</code> commands into the addable
set and constructs the picked kind.</li>
</ul>
<h3 id="hiapi-engine">HiAPI Engine</h3>
<ul>
<li><code>HiNc/SessionCommands/ListCommand.cs</code> — the container: the optional title, the entry list a run
walks top-down, the whitespace-only-title-is-unset XML rule, the Flow catalog attribute, and the
<code>List</code> / <code>List [title]</code> composition.</li>
<li><code>HiNc/SessionCommands/EnablingWrapper.cs</code> — the enable flag plus the wrapped command that together
make one entry.</li>
<li><code>HiNc/SessionCommands/ITitleCommand.cs</code> — the interface a command implements to compose its own
title from the caller's vocabulary.</li>
<li><code>HiNc/SessionCommands/CommandCatalogAttribute.cs</code> — <code>CommandCategory</code> and the attribute (category,
order, kind key, aliases) that makes the addable set backend-owned.</li>
<li><code>HiNc/SessionCommands/PreSettingCommand.cs</code> — the General Config bundle: no catalog attribute, and
a loaded project expands a stored one into the split setting commands.</li>
<li><code>HiNc/MachiningProcs/MachiningProject.cs</code> — declares the mission's command and keeps it a list.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="mission-root-panel.html">Mission Root Panel</a> — the branch root, and the Control Tree row affordances every list shares, documented once</li>
<li><a href="../../../manual/run/building-a-mission.html">Building a Mission</a> — the task this command serves: grouping a mission and moving entries between groups</li>
<li><a href="index.html">Mission</a> — the rest of the command panels</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>