Mission Root Panel
The Mission branch root of the Execution page's Control Tree: route
/execution, Control-Tree path execution/mission, panel MissionRootPanel.vue. /mission
resolves to the same place — it redirects onto /execution?tree=execution/mission.
The node roots one list of commands: the mission's own command, which is always a ListCommand. Its entries are the node's tree children, in run order, and the row operations that rewrite the list — Add Command, drag, move up, move down, duplicate, delete — live on the Control Tree rows and run in the tree host; no panel carries a second copy of them. The one panel-side insert is the Program File editor's multi-pick: picking several files at once keeps the first on that command and adds one Program File command per further file right after it, in its own list, then hands the host the inserted range so the same busy gate and id translation cover the rebuild. The root's own panel is informational: the command count and the run-order hint. Editing a command is not this node's job either: selecting a command row opens that command's own editor on its node's panel.
Command nodes are addressed by index-derived tree ids and by dotted API paths ("0", "1", nested
"0.2"). A command node id extends its parent's, so a root entry is execution/mission/{index} and
an entry inside a nested list is execution/mission/{index}/{index}; a command's section children
extend it once more, as execution/mission/{index}/{id} keyed on the section. Both forms shift on
every structural change — deleting entry 2 slides the next command into path "2" — so each branch
build stamps its nodes afresh and the editor panels remount onto the new paths, and the host carries
its own index-based ids — the expansion set, the Add focus and the selection — through every row op
so they follow the rows rather than the slots.
Key Models
- Primary: PlayerCommand — the mission's command,
always a
ListCommand. - Supporting:
- MachiningProject
- ListCommand — the root command and every nested one. CommandEntryList is the row list, and a run walks it top-down.
- EnablingWrapper — one entry: the command plus IsEnabled.
- CommandCatalogAttribute and CommandCategory — what Add Command offers, and the group it is offered under.
Layout
- Mission Root Panel
- No-Project Caption
- “No project loaded. Open or create a project first.” while nothing is open; the head line, separator and empty state are withheld with it.
- Head Line
- Commands Caption
- Command Count Badge
- The root list's own entries — the node's command children. Outlined, and grey rather than primary while the list is empty.
- Separator
- Empty State
- “No commands yet. Click Add Command to create one.” while the list is empty.
- Run-Order Hint
- Always present. It names the row affordances: commands run top-down in the Control Tree; add one with + on the Mission or a List row; drag a row to reorder it; a row's own buttons move, duplicate or delete it; its checkbox enables or disables it.
- No-Project Caption
- Mission Root Row (Control Tree)
- Add Command Button
- The
+, always visible and pinned to the row's right edge. Opens the Add Command dialog scoped to the root list. Disabled while no project is open, and while the busy gate is held — a mission op, or a checkbox toggle's save, in flight. - The row carries no drag handle and no command ops. It is a drop target: anywhere on its height lands the dragged command in the root list.
- The
- Add Command Button
- (Each) Command Row
- Enable Checkbox
- The tree's tick, and the command's enable switch; a disabled command's label is dimmed.
- Drag Handle Icon
- The whole row is draggable; the handle is the affordance for it. Plain and List command rows carry one; the root row does not.
- Command Label
- A real link to the node's
?tree=URL, so the browser's context menu can open it in a new tab, while a plain click keeps the in-app selection. The text is the command's title as the engine composes it: the kind's localized display name, with the command's key value appended in brackets where the kind has one — a List's or Script's typed title, a Program File's file, a resolution's millimetres, a switch's On / Off.
- A real link to the node's
- Move Up Button / Move Down Button / Duplicate Button / Delete Button
- Hidden at rest, revealed on hover and on the selected row, and always shown where there is no hover to reveal them with (touch). Move Up is disabled on the first entry and Move Down on the last; all four while the busy gate is held — a mission op, or a checkbox toggle's save, in flight.
- Add Command Button
- On a List row only: the same
+, scoped to that list, to the right of the row buttons.
- On a List row only: the same
- Drop Indicator
- A primary edge line for a before / after landing, a tinted row for a landing into a list; the dragged row itself dims.
- Enable Checkbox
Enable/disable is not a control on any panel. It is the tree item's checkbox on the command node; a
disabled command is skipped when the mission plays and stays fully editable. A toggle PUTs straight
to the Mission API and flips the node's own state, with no rebuild; on failure the checkbox snaps
back. The toggle holds the same busy gate as the structural ops while its save is on the wire — a
row op sent meanwhile could be applied first server-side and land the flag on whichever command
slid into the ticked path — so until the save lands every row button and + is disabled, no drag
starts, the tree selection is refused, an op that still reaches the host returns silently, and a
further checkbox click snaps back. The gate holds in the other direction too: the checkboxes and
the tree selection are read-only while a mission op is in flight, since a tick would address the
node's pre-op path.
Add Command
The + on the Mission root row, or on any List row, opens a search-first picker. The search box
matches a command's display label, its kind key, or one of its declared aliases — each alias
searchable both by its English key and by its word in the request language. Arrow keys walk the
results and Enter takes the highlighted one. Results are grouped by category, in the catalog's own
display order. One pick per opening: a second click or Enter before the dialog has closed adds
nothing.
The picked command is inserted right after the focused command when that command is a direct
entry of the list the + is scoped to, and at that list's tail otherwise. The focus is one for the
whole mission, not one per list: the most recently selected command anywhere in the tree (a section
row counts for its owning command), or the last command an Add landed on. So the Mission row's +
never chases a focus inside a nested list — and once a nested command has been selected, the root
row's + appends at the root's tail rather than after whichever root command was selected before
it. The branch rebuilds in place, the new row is revealed and becomes the focus, so a run of adds
lands in order below it, and the selection stays where it was rather than jumping into the new
command's panel.
The addable set is served by the backend rather than mirrored in a frontend menu. Every engine
command carrying [CommandCatalog] is reflected into the catalog, so attributing a new engine
command is all it takes for it to appear in the dialog. Thirteen kinds ship:
- Setup — Machining Resolution, Machining Motion Resolution, Collision Detection, Pause on Failure, Physics
- Program — Program File, NC Code, Script
- Optimization — NC Optimization Config
- Output — Post-Execution, Record Meshed Geometry, Export Meshed Geometry (STL)
- Flow — List
Note
Program File plays NC, CL or CSV. The runner is picked from the file extension, and the command can override that choice.
Ordering, Duplicating and Deleting
Every structural op runs through one path in the tree host: a busy gate that holds every row affordance, the tree selection and the checkboxes read-only while the op is in flight — the one gate a checkbox toggle also holds while its save is on the wire, so an op and a tick never interleave on the server; the open editor's dirty flush — an editor with staged edits (Script, NC Code, a List's title) saves or resolves them first, waiting for a save already on the wire, and a refused flush drops the op with a notice rather than silently; the API call; a rebuild scoped to the list the op rewrote; then the post-op selection. The selection follows the acted-on row only when it already rode on it — that row, or a node under it — and otherwise stays on its own re-indexed row, so the editor the user is in is left alone.
Move Up and Move Down move an entry within its own list; they never change which list owns it. Duplicate deep-clones the entry through the same XML round-trip the project file uses — so a nested list copies with its whole subtree — and the clone lands right after the source; a selection riding on the source moves onto the clone. Delete asks for confirmation in a dialog naming the command, before the dirty gate runs, so a cancelled delete forces no save prompt on the open editor; a selection riding on the deleted row lands on the nearest remaining entry of that list, or on the list node itself once the list is empty, where Add Command waits.
Dragging a row has three landings:
- On a command row's edge — before or after it. A plain command row splits at its midline; a List row's outer quarters are its edges. When both rows share a list this is a reorder, and the whole new order is sent as one ordered path list; when they do not, the entry relocates into the target's list at that slot — which is also the way out of a nested list.
- On the middle band of a List row — move the entry inside that list, at its tail.
- On the Mission root row — anywhere on its height moves the entry into the root list, at its tail.
Which call a landing makes depends on whether the entry changes list, not on where the pointer sat. A landing that keeps the list — an edge in the entry's own list, or an into-landing on the list that already holds it (a List row's middle band, or the Mission root row for a root entry), which sends it to the tail — is the reorder call, the whole new order as one ordered path list; a landing that changes the list — into a list the entry is not in, or an edge in another list — is the reparent call. The client refuses to drop a row onto itself or into its own subtree, starts no drag while the busy gate is held — an op, or a checkbox toggle's save, in flight — and abandons a drop whose row was re-stamped by a rebuild mid-drag. The server resolves both lists 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. A move across lists rebuilds from the nearest list above both, and the selection follows the dragged command when it rode on it.
Nesting
A list entry grows the same structure one level down: its children are its own entries, so nested
lists read as sub-trees at any depth, and the very same row affordances act on them. The difference
is the scope — the root list, versus the node's own dotted path: each List row's + inserts into
its own list, and a drop into either lands there. A nested list's panel is the optional title alone,
and that title is appended to the List name in the tree label.
Because the mission's own command is always a list, the root and a nested list are one row shape at two scopes. A project file whose stored command is something else loads with that command wrapped into the root list, so the branch always has a list to root.
Where a Command Is Edited
A command's editor renders on its own tree node; the row operations that rewrite the parent list stay on the tree row:
- Nine kinds have a bespoke editor: General Config, Machining Motion Resolution, Program File, NC Code, Script, NC Optimization Config, Post-Execution, Record Meshed Geometry and Export Meshed Geometry.
listshows only its optional title on its node; its entries are its tree children, and List Command Panel covers what a list is and what moving in and out of one costs.- The four remaining Setup kinds — Machining Resolution, Collision Detection, Pause on Failure and
Physics — are served by the generic field editor, which renders the command's reflected
[CommandField]scalars with server-localized labels. That is what the app does instead of shipping one panel per kind: a catalog kind needs frontend code only when it wants a richer editor.
General Config is the one asymmetry. Its editor ships and reads a command, but the catalog does not offer it: a project file that stores the bundle loads as the individual commands it stands for, and the panel serves projects that construct one through the API.
The multi-card kinds — General Config, NC Optimization Config and Post-Execution — put their extra cards on section child nodes of the command, one node per card. Where a card has its own enable flag — General Config's Meshed Geometry section and each of Post-Execution's five — that flag is the section node's tree checkbox; NC Optimization Config's five sections (Distances, Feedrate, Motion Dynamics, Force & Safety, Compensation) carry no checkbox — its enable switches sit on the command node's own panel instead. Post-Execution's Shot Files Output and Optimization Output sections appear only while the physics preference is on.
Source Code Path
See HiNC App Anatomy for git repository links.
Web Application
wwwroot-src/src/components/controlTree/MissionRootPanel.vue— this panel, informational only: whether a project is open, the command count, the empty state and the run-order hint. It changes nothing and emits nothing.wwwroot-src/src/components/controlTree/ControlTreePanel.vue— the tree pane that renders the Mission rows' affordances: the drag handle, the hover-revealed move / duplicate / delete buttons on every command row, the+on every list row (the Mission root included) and the Add Command dialog it opens, plus the drop-indicator styles.wwwroot-src/src/components/controlTree/useMissionTreeDrag.ts— the HTML5 drag-and-drop bookkeeping between Mission rows: which rows drag, which receive, the before / after / into mode from the pointer position, and the stamp check that abandons a drop after a mid-drag rebuild.wwwroot-src/src/components/controlTree/useControlTreeHost.ts— builds the page's two roots, Mission above Program; owns the five mission row ops — add, drag move, step, duplicate, delete — through onemissionRowOphelper (the busy gate, the open panel's dirty flush, the API call, the scoped rebuild, the post-op selection) and the index translation that carries the expansion set, the Add focus and the selection through each op; drives the command and section checkboxes, holding the same busy gate while a tick's PUTs are on the wire.wwwroot-src/src/components/controlTree/AddCommandDialog.vue— the search-first catalog picker; one pick per opening.wwwroot-src/src/components/controlTree/MissionCommandSlavePanel.vue— one entry's panel: the kind's editor, or the optional title input alone for alistentry. It forwards the editor's dirty-switch gate — and flushes a pending title save — to the host, and relays the Program File editor's multi-pick as a structure change on the parent list carrying the inserted range.wwwroot-src/src/components/controlTree/MissionSectionPanel.vue— the panel of a command's section child, rendering that one card.wwwroot-src/src/components/controlTree/missionItemTypes.ts— the Mission wave of the Control Tree: the item types, the child builders that carry the recursion, the per-kind editor map, and the section definitions and their enable flags.wwwroot-src/src/components/controlTree/missionKindIcons.ts— the kind and category icons the Add Command dialog shows.wwwroot-src/src/api/mission.ts— typed wrapper over/api/Mission/*:listCommandEntries,addEntry(with an optional insert index, resolving to the new entry's path),removeEntry,moveEntry,duplicateEntry,reparentEntry,reorderEntries,setListTitle,getCommandCatalog,loadCommandFields/setCommandField, and the per-kind readers and writers.wwwroot-src/src/components/mission/GenericCommandPanel.vue— the fallback editor for a catalog kind with no bespoke panel: the command's reflected[CommandField]scalars.- The bespoke editors:
wwwroot-src/src/components/mission/PreSettingCommandPanel.vuewwwroot-src/src/components/mission/MachiningMotionResolutionCommandPanel.vuewwwroot-src/src/components/mission/NcFileCommandPanel.vue— also the one panel-side insert: its multi-pick adds the extra files as new Program File commands right after its own, throughaddEntryat an insert index.wwwroot-src/src/components/mission/NcCodeCommandPanel.vuewwwroot-src/src/components/mission/ScriptCommandPanel.vuewwwroot-src/src/components/mission/NcOptOptionCommandPanel.vuewwwroot-src/src/components/mission/PostExecutionCommandPanel.vuewwwroot-src/src/components/mission/RecordMeshedGeomCommandPanel.vuewwwroot-src/src/components/mission/ExportMeshedGeomCommandPanel.vue
wwwroot-src/src/i18n/en/tree.ts— thetree.mission.*strings: Add Command, the Commands caption, the no-commands-yet state, the run-order hint that names the row affordances, the disabled-command hint, the cancelled-op notice, the kind display names, the section names and the op-context phrases.wwwroot-src/src/i18n/en/common.ts— the row buttons' titles (Move up, Move down, Duplicate, Delete), the List title's label and the no-project caption.wwwroot-src/src/i18n/en/dialog.ts— the Delete Command confirmation.wwwroot-src/src/router/routes.ts— resolves/missiononto/execution?tree=execution/mission.Missions/MissionController.cs— the entry lifecycle (GET list-command/entries,POST list-command/entriesandPOST list-command/entries/{path}to add at the root or inside a nested list — at an optionalinsertIndex, answering the new entry's index and path —DELETE list-command/entries/{path},POST list-command/entries/{path}/move,PUT list-command/reorder,POST list-command/entries/{path}/duplicateandPOST list-command/entries/{path}/reparent), theGET command-catalogthe Add Command dialog reads, and the per-command endpoints including the genericcommands/{path}/fields[/{key}]pair.reparentis what backs a drop that changes the entry's list — into another list, or an edge in another list — and it is the endpoint that rejects moving a list into itself or its own descendants; a drop that keeps the list, the tail landing included, goes throughreorder.Missions/MissionCommandCatalog.cs— reflects every[CommandCatalog]command into the addable set served to Add Command, and creates the picked kind.Missions/MissionCommandFields.cs— the reflection layer behind the generic field endpoints: it describes and updates a command's[CommandField]scalars.Missions/NcOptOptionEndpoints.cs— the NC Optimization Config per-property PUT endpoints.
HiAPI Engine
HiNc/SessionCommands/CommandCatalogAttribute.cs—CommandCategoryand the[CommandCatalog]attribute (category, order, kind key, aliases), plus the class-name-minus-Commandderivation of the kind key. This is what makes the addable set backend-owned.HiNc/SessionCommands/ListCommand.cs— the container command: the entry list a run walks top-down, skipping disabled entries.HiNc/MachiningProcs/MachiningProject.cs— declares the mission's command as a list and keeps it one when a project is read.
See Also
- Program Branch — the read-only inspection twin of this list: what a run actually read, one node per NC source file
- List Command Panel — the same rows one level down, and what moving an entry in or out of a nested list costs
- Building a Mission — the task this branch serves, as a procedure