Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"rollForward": false
},
"demaconsulting.sysml2tools.tool": {
"version": "0.1.0",
"version": "0.2.0-beta.2",
"commands": [
"sysml2tools"
],
Expand Down
13 changes: 7 additions & 6 deletions .reviewmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ reviews:
- src/**/AppShellSubsystem/QueryDialogView.axaml
- src/**/AppShellSubsystem/QueryDialogView.axaml.cs
- test/**/AppShellSubsystem/QueryDialogViewModelTests.cs
- test/**/AppShellSubsystem/QueryDialogUiTests.cs
- id: SysML2Workbench-ElementPickerSubsystem
title: Review that SysML2Workbench ElementPickerSubsystem Implementation is Correct
context:
Expand Down Expand Up @@ -426,15 +427,15 @@ reviews:
- id: OTS-DemaConsultingSysML2Tools
title: Review that DemaConsulting.SysML2Tools Provides Required Functionality
paths:
- docs/reqstream/ots/demaconsulting-sysml2tools.yaml
- docs/design/ots/demaconsulting-sysml2tools.md
- docs/verification/ots/demaconsulting-sysml2tools.md
- docs/reqstream/ots/sysml2-tools.yaml
- docs/design/ots/sysml2-tools.md
- docs/verification/ots/sysml2-tools.md
- id: OTS-DemaConsultingRendering
title: Review that DemaConsulting.Rendering Provides Required Functionality
paths:
- docs/reqstream/ots/demaconsulting-rendering.yaml
- docs/design/ots/demaconsulting-rendering.md
- docs/verification/ots/demaconsulting-rendering.md
- docs/reqstream/ots/rendering.yaml
- docs/design/ots/rendering.md
- docs/verification/ots/rendering.md
- id: OTS-Avalonia
title: Review that Avalonia Provides Required Functionality
paths:
Expand Down
16 changes: 16 additions & 0 deletions docs/design/ots/sysml2-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ and UI behavior instead of duplicating language infrastructure.
named view usage directly into finished SVG output in one call; the
workbench never sees an intermediate layout graph or a public layout
strategy registry.
- **Element querying** — `QueryEngine` runs the verb-scoped queries the Query
dialog exposes, including connection-aware impact analysis: an opt-in that
traverses connector (`connect`/`bind`) relationships undirected in addition
to the resolved reference edges the impact walk follows by default. The
library also reports per-entry traversal metadata (depth, the resolved
relation kind that reached the entry, and the far endpoint behind a
connection roll-up) which the dialog surfaces directly.

### Integration Pattern

Expand All @@ -42,3 +49,12 @@ cannot express), LayoutInvoker instead constructs an ephemeral
before rendering. Initialization is limited to constructing the required
workspace and render inputs; no separate service process or background
daemon is introduced.

QueryDialog is the one place where the workbench builds a library option
object directly rather than through an adapter unit: it composes a
`QueryOptions` from the dialog's form state and hands it to `QueryEngine`,
gating each verb-specific option (hierarchy direction, impact walk depth,
impact connection-awareness) on the selected verb so no other verb's option
payload is affected. Result entries are projected once into a flattened
row record for display, reading the library's machine-readable traversal
metadata rather than parsing its human-readable detail text.
63 changes: 52 additions & 11 deletions docs/design/sysml2-workbench/app-shell-subsystem/query-dialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,23 @@ workspace through a single, always-visible adaptive form — there is no
box, plus a selectable candidate list used as the target-element
selector).
- Verb-specific extra controls appear only when relevant: a "Direction"
combo for `Hierarchy`, and a "Walk depth" text box for `Impact`.
combo for `Hierarchy`, and — for `Impact` — a "Walk depth" text box plus
an "Include connections (connect/bind)" checkbox. The walk-depth label
states the single meaning of a blank value: unlimited, for every
relationship kind the walk traverses.
- Every interaction — Query Type selection, chip add/remove, search text,
element selection, Direction change, Walk depth text change, or the
Include-standard-library toggle — immediately recomputes and displays the
result synchronously; there is no "Run Query" button.
element selection, Direction change, Walk depth text change, the
Include-connections toggle, or the Include-standard-library toggle —
immediately recomputes and displays the result synchronously; there is no
"Run Query" button.

Results feed the same shared results panel: a summary bullet list plus a
`Grid`-based (not `DataGrid`) entries table with columns for Qualified Name,
Kind, Detail, and a Direction column shown only when the current result is a
`dependencies` verb result. There is no toolbar: "Copy as Markdown" and
`DataGrid` entries table whose always-visible columns are Qualified Name,
Kind, and Detail, followed by four optional columns. Direction is shown only
when the current result is a `dependencies` verb result; Depth, Relation, and
Via are data-driven, shown only when at least one displayed row actually
carries that value, so verbs that do not traverse render exactly the same
three-column panel as before. There is no toolbar: "Copy as Markdown" and
"Copy as JSON" are right-click `ContextMenu` items on the results panel,
wired to `QueryResultRenderer.RenderMarkdown`/`RenderJson` via the same
`AvaloniaClipboardService` pattern `DiagramDocumentView` uses for its "Copy
Expand Down Expand Up @@ -88,15 +95,26 @@ attached to `QueryOptions.Direction` when `SelectedQueryType` is `Hierarchy`.
optional walk-depth bound. Only parsed for `Impact`, and only when it parses
cleanly as a non-negative integer.

**IncludeConnections**: `bool` — the Impact verb's "Include connections"
checkbox state, requesting that connector (`connect`/`bind`) relationships be
traversed in addition to resolved reference edges. Only attached to
`QueryOptions.IncludeConnections` when `SelectedQueryType` is `Impact`;
defaults to `false`, matching the engine's own default. Independent of
`WalkDepthText`: the flag selects only which edges the walk may traverse,
never how far it goes, and a connector edge costs the same single unit of
depth as any other relationship.

**CurrentResult**: `QueryResult?` — the most recently produced `QueryResult`
(either List's client-built list result or the engine's response), or
`null` when an element-scoped Query Type has no selection yet. Feeds the
shared results panel.

**CurrentResultRows**: `IReadOnlyList<QueryResultRow>` — a flattened,
view-friendly projection of `CurrentResult.Entries` (empty strings replacing
nullable fields, `Direction` mapped to a human-readable label, notes joined
into a tooltip string), bound directly by the results-panel `ItemsControl`.
nullable fields, `Direction` mapped to a human-readable label, traversal
depth, resolved relation kind, and connection roll-up far endpoint flattened
to plain strings, notes joined into a tooltip string), bound directly by the
results-panel `ItemsControl`.

**StatusMessage**: `string?` — user-visible error/hint text set on every
recoverable failure or prompt (no workspace, no selection yet, engine
Expand Down Expand Up @@ -131,7 +149,8 @@ the shell's current workspace, then recomputes the result.
**RecomputeResult**: Recomputes `CurrentResult`/`CurrentResultRows` for the
currently selected `SelectedQueryType`. This is the redesign's entire
"no explicit Run gesture" mechanism, invoked automatically by every relevant
property change (Query Type, Hierarchy direction, Walk depth text, and — via
property change (Query Type, Hierarchy direction, Walk depth text, the
Include-connections toggle, and — via
`FilterOnly`'s and `Picker`'s `PropertyChanged` subscriptions —
`FilterOnly.DisplayedItems`/`Picker.DisplayedItems`/`Picker.SelectedQualifiedName`).

Expand Down Expand Up @@ -161,7 +180,24 @@ form's verb-specific state.
- *Parameters*: `string qualifiedName` — the resolved target's qualified name.
- *Returns*: `QueryOptions` — always carries `IncludeStdlib`; attaches
`Direction` only for `Hierarchy`; parses `WalkDepth` only for `Impact` and
only when the text parses cleanly.
only when the text parses cleanly; sets `IncludeConnections` only for
`Impact`, so leaving the checkbox ticked and switching Query Type never
changes another verb's option payload.

**BuildRow**: Projects one engine-produced result entry into the flattened
`QueryResultRow` the results panel binds to.

- *Parameters*: `QueryResultEntry entry` — the entry to project; must not be
`null`.
- *Returns*: `QueryResultRow` — every field is a non-null string except the
tooltip `Notes`, so the AXAML binds directly without value converters.
Traversal depth is taken from the entry's machine-readable depth value and
is never parsed out of the entry's human-readable detail text; the resolved
relation kind is rendered as its enum member name (for example `Connect`);
the connection roll-up far endpoint is rendered as its qualified name.
Entries carrying none of these leave all three fields empty.
- *Postconditions*: A pure static function with no view-model state, exposed
publicly so tests can assert the projection contract directly.

**CopyResultAsMarkdownAsync** / **CopyResultAsJsonAsync**: Copy
`CurrentResult` to the clipboard through `QueryResultRenderer` and
Expand All @@ -185,6 +221,11 @@ behavior, every one of these paths also clears `CurrentResult`/
`CurrentResultRows` so the results panel never shows a stale result left
over from a previous Query Type or selection.

The one deliberate exception is `BuildRow`'s null-entry guard: a `null`
result entry is a programming error in the caller, not a user-reachable
condition, so it throws `ArgumentNullException` rather than being reported
through `StatusMessage`.

#### Dependencies

- **MainWindowShell** — supplies `CurrentWorkspace` for candidate resolution
Expand Down
45 changes: 34 additions & 11 deletions docs/design/sysml2-workbench/app-shell-subsystem/workspace-panel.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ and `required IReadOnlyList<WorkspaceTreeNode> Children` — a source's node.
`Folder`-kind source it holds one entry per top-level subfolder
(`WorkspaceFolderNode`) or file (`WorkspaceFileNode`) directly under that
folder, preserving its on-disk hierarchy rather than flattening every
discovered file into a single list.
discovered file into a single list. Because a `File`-kind source has no
`WorkspaceFileNode` beneath it, its source node is itself the only tree
representation of that file, and is therefore openable in its own right (see
`ResolveOpenableFilePath`).

**WorkspaceFolderNode**: `WorkspaceTreeNode` with `required string Name` (the
folder's own last path segment, not its full path) and
Expand All @@ -40,11 +43,13 @@ already covers everything beneath it).
**WorkspaceFileNode**: `WorkspaceTreeNode` with `required string FilePath`,
`required string SourceId`, and a computed `Name` (`Path.GetFileName(FilePath)`,
shown in the tree since ancestor nodes already convey the file's directory) —
a leaf node for one file. `FilePath` is a stable identity used by
`WorkspacePanelToolView`'s double-click handler to open a `.sysml` file's
a leaf node for one file discovered under a `Folder`-kind source. `FilePath` is
a stable identity used by `ResolveOpenableFilePath` (and through it
`WorkspacePanelToolView`'s double-click handler) to open a `.sysml` file's
read-only source-text tab via `MainWindowShell.OpenSourceTextTab`; it is
preserved even though nothing else currently reads it beyond display and
that handler.
that handler. It is not the only openable node kind — a `File`-kind
`WorkspaceSourceNode` is openable too, via its `Source.Path`.

**SelectedNode**: `WorkspaceTreeNode?` — the tree node currently selected by
the user, used to resolve which source `RemoveSelected` acts on.
Expand Down Expand Up @@ -96,13 +101,31 @@ into `MainWindowShell.AddFileSourceAsync` / `AddFolderSourceAsync`.
and surfaced via `StatusMessage` rather than propagated, since a failed
remove should not crash the shell.

`WorkspacePanelToolView`'s code-behind also wires a `DoubleTapped` handler on
its `TreeView` directly to `MainWindowShell.OpenSourceTextTab`: when the
selected item is a `WorkspaceFileNode` whose `FilePath` ends in `.sysml`
(case-insensitive), double-clicking it opens the file's read-only
source-text tab. No view-model method backs this - it follows the same
"view calls `Shell` directly" pattern already used by the Add File/Add
Folder picker flows, and is thin enough that it is not unit tested (see
**ResolveOpenableFilePath**: Decides which file, if any, a selected workspace
tree node should open in a read-only source-text tab.

- *Parameters*: `node` (`WorkspaceTreeNode?`) — the currently selected node, or
`null` when nothing is selected.
- *Returns*: `string?` — the absolute path to open, or `null` when the node
denotes no single file or denotes a non-`.sysml` file.
- *Postconditions*: A `WorkspaceFileNode` resolves to its `FilePath`, and a
`File`-kind `WorkspaceSourceNode` resolves to its `Source.Path` — a workspace
file has two possible tree representations and both must be openable. A
`WorkspaceFolderNode` and a `Folder`-kind `WorkspaceSourceNode` resolve to
`null`, since they denote a set of files rather than one. The `.sysml`
extension filter (case-insensitive) is applied uniformly to both openable
kinds because the source-text viewer only renders SysML v2 textual sources.
Pure and side-effect free — it reads only its argument and touches neither
the file system nor view-model state.

`WorkspacePanelToolView`'s code-behind wires a `DoubleTapped` handler on its
`TreeView` that calls `ResolveOpenableFilePath` for the currently selected node
and forwards any non-null result to `MainWindowShell.OpenSourceTextTab`. The
decision lives on the view model - rather than inline in the handler as it did
originally - so it is a pure function unit-testable without an Avalonia view;
the handler itself remains thin view-layer wiring following the same "view
calls `Shell` directly" pattern already used by the Add File/Add Folder picker
flows, and is not itself unit tested (see
`docs/verification/sysml2-workbench/app-shell-subsystem/workspace-panel.md`).

#### Error Handling
Expand Down
12 changes: 10 additions & 2 deletions docs/reqstream/ots/sysml2-tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@ sections:
- 'LoadWorkspaceModel_ParsesAndResolvesImports'

- id: 'SysML2Tools-GenerateViewLayouts'
title: 'The SysML2Workbench shall use SysML2Tools to generate layout data for supported predefined and custom views.'
title: 'The SysML2Workbench shall use SysML2Tools to render a named predefined or custom view usage into finished diagram output in a single call.'
justification: |
The product depends on the existing SysML2Tools layout strategies to produce diagram structure for rendering.
The workbench deliberately holds no layout or diagram-rendering implementation of its own, so what it actually requires of the dependency is the observable end product: a named view usage in, finished renderable output out. Stating it that way keeps the requirement verifiable against the real DiagramRenderer.RenderWorkspace contract - the library exposes no intermediate layout graph or public layout-strategy registry for the workbench to consume, so a requirement phrased in terms of "layout data" could never be verified as written.
tests:
- 'RenderView_GeneratesLayoutGraph'

- id: 'SysML2Tools-ConnectionAwareImpactAnalysis'
title: 'The SysML2Workbench shall use SysML2Tools to perform impact analysis that optionally traverses connector (connect/bind) relationships in addition to resolved reference edges, bounded by a walk depth that applies uniformly to every relationship kind.'
justification: |
The impact walk now follows resolved reference edges only by default, so the connector reachability the workbench previously obtained implicitly must be requested explicitly; the dependency's opt-in behavior, and the traversal metadata it reports for connector-reached elements, are therefore the evidence target. The workbench's walk-depth control tells the user a blank value means unlimited, so the dependency's uniform treatment of connector edges under that bound is itself part of the contract being relied upon.
tests:
- 'ImpactQuery_IncludeConnections_TraversesConnectorEdges'
- 'ImpactQuery_WalkDepth_BoundsConnectorTraversalUniformly'
Loading
Loading