fix(designer): correct pinned dual-pane close/unpin behavior and add v2 pinned-action border#9337
Conversation
… view In the Standard dual-pane operation panel, both panes' close (x) buttons were wired to the same onClose handler, which collapsed the entire drawer. Closing a non-pinned action therefore also closed the pinned action (#9304). Route each pane's close button to close only its own action: the pinned pane's x unpins, and the selected pane's x uses clearPanel (which preserves a pinned alternate) so the pinned action stays open and pinned. PanelContainer now also renders a pinned action on its own at single-pane width. Fixes #9304 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🤖 AI PR Validation ReportPR Review ResultsThank you for your submission! Here's detailed feedback on your PR title and body compliance:✅ PR Title
✅ Commit Type
✅ Risk Level
✅ What & Why
✅ Impact of Change
✅ Test Plan
✅ Contributors
✅ Screenshots/Videos
Summary Table
Overall, this PR passes review. The advised risk level remains
|
📊 Coverage CheckThe following changed files need attention: ❌
Please add tests for the uncovered files before merging. |
There was a problem hiding this comment.
Pull request overview
Fixes a UX bug in the Standard “new view” dual-pane (pinned) operation details panel so that the close (x) button only closes the pane it belongs to, rather than collapsing the entire drawer and dismissing the pinned pane.
Changes:
- Updated
PanelContainerto better distinguish dual-pane vs pinned-only rendering, and to route close handling per-pane (selected vs pinned). - Updated
NodeDetailsPanel(designer + designer-v2) close behavior to preserve a pinned alternate action when closing the selected action. - Added/extended unit tests covering pinned close behavior in the panel slice and the panel container rendering rules.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| libs/designer/src/lib/ui/panel/nodeDetailsPanel/nodeDetailsPanel.tsx | Adjusts close behavior to keep pinned pane open when closing the selected pane (and updates unpin to update open state). |
| libs/designer/src/lib/core/state/panel/test/panelSlice.pinned.spec.ts | Adds reducer tests for pinned/selected close behavior combinations. |
| libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/nodeDetailsPanel.tsx | Mirrors the designer close/unpin behavior changes in designer-v2. |
| libs/designer-v2/src/lib/core/state/panel/test/panelSlice.pinned.spec.ts | Adds the same pinned/selected reducer tests for designer-v2. |
| libs/designer-ui/src/lib/panel/panelcontainer.tsx | Adds dual-view detection, pinned-only render support, and per-pane close routing in the shared UI container. |
| libs/designer-ui/src/lib/panel/test/panelcontainer.spec.tsx | Adds tests for dual-view width/classing and pinned-only single-pane rendering behavior. |
Gate pinned pane close routing on the normalized alternate node so the selected pane still closes when the pinned node matches it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e selected node When a user pins the currently selected action, the pinned alternate and the selected node share the same nodeId and the view is single-pane. The onClose handler dispatched clearPanel(), which preserves any pinned alternate and kept the panel open, so the x button did not close it. Only route close to clearPanel when the pinned node differs from the selected node; otherwise collapse. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a pinned action is also the currently selected node (single-pane view, e.g. right after pinning the open action), clicking the panel close (x) button collapsed the drawer via collapsePanel but never cleared the pinned alternate node. As a result, reopening that action's context menu still showed 'Unpin' even though the panel was closed. The close handler now unpins the action (setAlternateSelectedNode with an empty nodeId) before collapsing in that case, so the menu correctly resets to 'Pin'. Mirrored in designer and designer-v2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… selected The canvas selection border used 'selected' (blue) precedence over 'pinned' (orange), so a pinned action that was also the active/selected node - the common single-pane case right after pinning the open action - showed the blue selected border instead of the orange pinned border. Give 'pinned' precedence so pinned actions always display the orange selection border. Applied to the operation, scope, and subgraph card nodes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nce change Ports the orange pinned selection border to designer-v2 cards (ActionCard and SubgraphCard) via a new isPinned prop wired from useIsNodePinnedToOperationPanel. Selected (blue) still takes precedence over pinned (orange), matching v1. Reverts the earlier v1 precedence flip so designer-v1 remains unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… build error canUnpin already narrows onUnpinAction to defined (aliased-condition narrowing), so the extra '&& onUnpinAction' made the check always-true and failed the designer-ui build:lib type check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ors mocks The v2 card nodes now call useIsNodePinnedToOperationPanel for the pinned border. Extend the panelSelectors vi.mock in OperationCardNode, ScopeCardNode, and SubgraphCardNode specs so the selector resolves during render. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Commit Type
Risk Level
What & Why
Fixes #9304. In the Standard "new view" dual-pane operation panel, a user can pin an action to keep it visible while inspecting another action. This PR fixes several issues with the pinned experience and adds a visual indicator for pinned actions in designer-v2.
1. Closing one pane closed both actions (the reported bug).
Root cause: in
PanelContainer.renderHeader, both panes' close (x) buttons were wired to the sameonClosehandler, which dispatchedcollapsePanel()and collapsed the entire drawer.Fix: route each pane's close button independently. The pinned pane's
xnow unpins only (onUnpinAction); the selected pane'sxusesonClose. Added anisDualViewflag and a pinned-only render path so a lone pinned action renders at the normal single-pane width (no leading divider / dual-view class). InnodeDetailsPanel.tsx(designer + designer-v2), the selected-paneonClosenow dispatchesclearPanel()(which preserves the pinned alternate node) when a pinned action exists, otherwise keeps the existingcollapse()behavior.unpinActionnow passesupdatePanelOpenState: trueso closing the pinned pane collapses the drawer only when no selected action remains.2. Closing a pinned action left it logically pinned.
When the pinned action was also the selected node (single pane), closing it with
xcollapsed the panel but never cleared the pinned alternate node, so re-opening the action's context menu still showed "Unpin". Fix: in the collapse branch ofnodeDetailsPanel.tsx(designer + designer-v2), when the pinned alternate node is the selected node, dispatchsetAlternateSelectedNode({ nodeId: '' })before collapsing, so the action is actually unpinned.3. Pinned actions had no visual indicator in designer-v2.
designer-v1 already draws an orange border around a pinned action; designer-v2 did not. Added an orange pinned border to the v2 cards (
ActionCardandSubgraphCard) via a newisPinnedprop wired fromuseIsNodePinnedToOperationPanel. Selected (blue) still takes precedence over pinned (orange), matching v1. designer-v1 is unchanged.Resulting behavior:
xon the non-pinned action -> closes only that action; the pinned action stays open and stays pinned. Selecting another action re-opens the side-by-side view.xon the pinned action -> closes only the pinned action and unpins it; the selected action stays open (panel collapses only if it was the last one).Impact of Change
PanelContainercan now render a single pinned action without a selected node; close-button routing is per-pane; v2 cards accept anisPinnedprop. No public API changes.'selected'-persistence alternate (agent-condition subgraph) andcustomContent(multi-select) paths are unaffected.Test Plan
panelSlice.pinned.spec.tsin designer and designer-v2 (8 tests each):clearPanel()keeps a pinned alternate and stays open, collapses when no pin, and clears the pin underclearPinnedState;setAlternateSelectedNode({ nodeId: '', updatePanelOpenState: true })stays open when a selected node remains and collapses otherwise; closing a pinned action that is the selected node clears the pin.panelcontainer.spec.tsx(designer-ui, 6 tests): dual-view width + dual class, pinned-only render at single-pane width (no dual class), and null render when nothing to show.Contributors
Screenshots/Videos