Use native Table row and insertion callbacks instead of an outer drop
receiver. Resolve server rows and insertion lines to their containing
group, and root insertion points to the catalog root.
Verify insertion and server-row targets with regression tests.
Keep a stable container as the HSplitView child so node identity changes only recreate the detail session rather than resetting the user's divider position.
Validated with eight native split-view transitions including empty selection: width stayed at 519 points. Debug build passed; existing file-length lint warning remains.
Render saved node details through a shared property view with injected link actions. Keep metadata, activation feedback, and plugin parameter loading outside the renderer; retain specific plugin failures and scope command feedback to its target.
Preserve ordered and repeated plugin parameters, distinguish flags and empty values, and retain opaque raw text. Add bilingual detail copy and conversion coverage.
Validation: 981 hostless tests and 21 offline rule checks passed; Debug build passed. Native renderer checked at 720 and 360 point widths using synthetic data. Existing 22 lint warnings remain.
CatalogEntry gains createdAt/updatedAt and the catalog document moves to
v5 (reads v1-v5, writes v5). Modification time is structure-sensitive:
editing a node's own fields bumps the node, a group's direct child set
or order changes bump the group, and a moved node keeps its timestamps.
No-op writes and unchanged subscription refreshes bump nothing; the
refresh rebuild compares per node, so surviving leaves keep theirs. All
times are passed in by callers as now: Date - one moment per logical
commit, the domain layer stays clock-free. Legacy documents load with
nil (unknown, never backfilled); duplicates and imports stamp fresh
times at the moment of the operation.
Semantics are recorded as glossary term 节点时间戳 and ADR 0031. No UI
in this change.
Remove TargetTreeCard, its browsing state HomeServerListState and the
dedicated tests; home now shows mode, runtime control, terminal command
and quick action cards only. ActivationFeedbackState stays shared by
the servers sidebar and group detail activation entries.
Replace the fixed HStack + Divider layout with a draggable HSplitView:
sidebar constrained to 240-320 (ideal 280), detail pane gets a 320 min
width. Divider position is not persisted (no public API; resets on tab
switch and relaunch - accepted trade-off). Drop the sidebar list style
so the list sits on the regular window background.
The pre-filled current name in the rename alert only showed on the
first presentation: SwiftUI on macOS recycles the alert panel and its
TextField does not pick up binding changes made in the same update as
re-presenting. Swap the alert for a RenameGroupSheet modeled on
NewGroupSheet, presented via sheet(item:) so content state is rebuilt
each time and the prefill always matches the target group.
As with the creation form, a failed rename now keeps the sheet open
with the entered name instead of closing the alert first and losing
the input. The NodeContext adapter previously used by the move sheet
is shared by both presentations.
Add the manual catalog keys 重命名分组 (Rename Group) and 名称 (Name);
保存/取消 already existed.
Remove the inline name TextField and save button from GroupDetailView;
renaming stays in the sidebar context menu, and the empty-group
footnote no longer claims the name is editable.
Make the detail pane observe the catalog workflow instead of holding a
plain reference, so catalog commits made elsewhere (sidebar rename,
add/move, subscription refresh) re-render it. This fixes the stale
group title after a context-menu rename, along with the equally stale
direct-child count and activation eligibility text.
Replace the inline RulesDeletionButton with a toolbar delete button
(trash icon next to the add button). It is enabled only when the
custom-rules source is selected on the left and the selection contains
deletable custom rules; the collection must also be complete and not
committing.
The table context menu gains a destructive "删除 (N)" item after a
divider when the custom-rules source is selected, with the same
enablement conditions. Both entries share one confirmation alert now
held by RulesView.
Also inline the operation status view into the filter row and tighten
filter-area padding.