Skip to content

feat: session context menu (kebab + right-click) on the Sessions page#102564

Merged
steipete merged 2 commits into
mainfrom
claude/openclaw-similar-menu-ed01e0
Jul 9, 2026
Merged

feat: session context menu (kebab + right-click) on the Sessions page#102564
steipete merged 2 commits into
mainfrom
claude/openclaw-similar-menu-ed01e0

Conversation

@steipete

@steipete steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Closes #102540

What Problem This Solves

The Sessions page table renders five separate icon buttons per row (mark unread, fork, pin, archive, add-to-workboard), which is visually noisy and still leaves common actions unreachable from a row: rename is buried in the details drawer and delete requires checkbox selection plus the bulk bar. The app sidebar already solved this with a session context menu (kebab + right-click), so the two surfaces behave inconsistently.

Why This Change Was Made

Extracts the sidebar session menu into a shared <openclaw-session-menu> component (light-DOM Lit, discriminated-union action callbacks) and uses it on the Sessions page: one kebab button per row plus right-click anywhere on the row. The per-row icon buttons are removed; the details chevron and bulk-selection checkbox stay. The archive/delete guard policy (agent main sessions, active runs, global/unknown kinds) now flows through the existing canArchiveSessionRow helper on both surfaces instead of a duplicated inline condition, and the .sidebar-session-menu* CSS block is renamed to .session-menu* with unchanged declarations. The sidebar keeps its behavior and gains an "Open chat" item, a pin-state icon, and kebab click-to-toggle.

User Impact

  • Sessions page rows are cleaner: details chevron + one menu instead of five hover buttons.
  • Right-clicking a session row opens the full action menu at the cursor, matching the sidebar.
  • Rename, Open chat, Move to group, and per-row Delete (with confirmation) are now reachable directly from the table, including for archived sessions (Restore + Delete).
  • Menu strings are localized; one new key (sessionsView.openChat) synced across locale bundles.

Evidence

  • ui/src/components/session-menu.test.ts (new): item order, conditional items, archived/guard disable states, close-before-dispatch ordering, group submenu actions, Escape/outside-pointerdown dismissal with trigger exclusion.
  • ui/src/pages/sessions/view.test.ts: kebab has aria-haspopup and reports row/position/trigger; row contextmenu opens the menu at cursor coordinates and prevents the native menu.
  • ui/src/e2e/session-management.e2e.test.ts (mocked gateway): right-click opens the menu, Escape closes it, kebab reopens it, and "Archive session" issues the expected sessions.patch; existing sidebar-menu e2e tests guard the extraction.
  • Focused run: node scripts/run-vitest.mjs run ui/src/components/session-menu.test.ts ui/src/pages/sessions/view.test.ts → 2 files, 37 tests passed.
  • Full remote proof (check lanes, ui suite, ui e2e) recorded in PR comments before landing.

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 9, 2026, 5:13 AM ET / 09:13 UTC.

Summary
The PR extracts the sidebar session menu into a shared Control UI component, replaces Sessions-page row action buttons with a kebab/right-click menu, adds localized Open chat text, and updates focused UI/e2e tests.

PR surface: Source +297, Tests +197. Total +494 across 70 files.

Reproducibility: yes. at source level: render the new menu with session.archived=true and archiveAllowed=false and the Delete button is enabled by the changed condition. I did not execute the UI locally because this review is read-only.

Review metrics: 1 noteworthy metric.

  • Destructive session menu guard: 1 shared Delete path introduced. The PR moves row deletion into a shared menu, so preserving the existing protected-session guard is merge-critical.

Stored data model
Persistent data-model change detected: persistent cache schema: ui/src/i18n/.i18n/ar.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/de.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/es.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/fa.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/fr.tm.jsonl, persistent cache schema: ui/src/i18n/.i18n/hi.tm.jsonl, and 27 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #102540
Summary: This PR is the direct implementation candidate for the focused Sessions-page context-menu issue; the chat realtime test issue is only adjacent validation context.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🌊 off-meta tidepool
Patch quality: 🦐 gold shrimp
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Fix the Delete eligibility condition and update the session-menu tests for archived protected rows.

Risk before merge

  • [P1] Merging as-is can expose a Delete action for archived protected rows where archiveAllowed is false, including rows the shared policy treats as main, global, unknown, or active-run protected.
  • [P1] The added component test currently asserts the unsafe archived/protected Delete state, so ordinary green CI would not catch the regression.

Maintainer options:

  1. Restore the destructive-action guard (recommended)
    Require archiveAllowed for Delete even when the row is archived, while keeping Restore available for archived rows.
  2. Pause for UX ownership
    Hold the PR if maintainers want to revisit whether archived protected rows should ever expose destructive row actions.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Keep archived-row Restore enabled, but gate Delete on archiveAllowed even when session.archived is true; update session-menu tests to cover archived allowed rows and archived protected rows.

Next step before merge

  • [P1] A narrow automated repair can preserve the shared menu while fixing the Delete guard and its tests; product approval still remains a maintainer merge decision.

Maintainer decision needed

  • Question: After the delete-guard fix, should this PR be the canonical Sessions-page row-action UX for [Feature]: Sessions page: per-row context menu (kebab + right-click) instead of icon-button row #102540?
  • Rationale: The mechanical guard bug is clear, but the linked issue is a protected Control UI UX change and already carries a product-decision signal, so maintainers should confirm the permanent action set before merge.
  • Likely owner: steipete — steipete opened the linked issue/PR and has the strongest recent history on the sidebar session menu surface.
  • Options:
    • Fix guard and continue (recommended): Repair the Delete eligibility bug, keep this shared menu as the canonical implementation, and merge after the exact head is clean.
    • Narrow the menu actions: Keep the shared component but remove or defer any row actions maintainers do not want exposed on the Sessions page yet.
    • Pause this UX direction: Close or defer this PR if maintainers want a broader session-management redesign before replacing the row icon actions.

Security
Cleared: No concrete security or supply-chain regression was found; the destructive-session concern is handled as a functional session-state finding.

Review findings

  • [P2] Keep Delete behind the shared archive guard — ui/src/components/session-menu.ts:308
Review details

Best possible solution:

Keep the shared menu extraction, but preserve the existing destructive-action policy by allowing Restore for archived rows while still requiring archiveAllowed for Delete, with regression coverage for archived protected rows.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level: render the new menu with session.archived=true and archiveAllowed=false and the Delete button is enabled by the changed condition. I did not execute the UI locally because this review is read-only.

Is this the best way to solve the issue?

No, not yet: the shared component is the right owner-boundary shape, but Delete must still honor archiveAllowed for protected rows while Restore remains available for archived rows.

Full review comments:

  • [P2] Keep Delete behind the shared archive guard — ui/src/components/session-menu.ts:308
    archiveAllowed is the shared guard for rows that must not be casually retired, and the existing sidebar disables Delete when it is false. This condition enables Delete for every archived row even when the host passed archiveAllowed=false, so archived main/global/unknown or otherwise protected rows can show a destructive action that should stay blocked; update the test that currently expects this enabled state.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f141af7fd774.

Label changes

Label changes:

  • add P2: The PR is a normal-priority UI feature with one concrete destructive-action guard regression, not an outage or security incident.
  • add merge-risk: 🚨 session-state: Merging as-is could expose session deletion for rows that the existing UI policy treats as protected.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: The PR carries the protected maintainer label, so the external-contributor real-behavior proof gate does not apply; the author also posted remote check/UI/e2e validation context.

Label justifications:

  • P2: The PR is a normal-priority UI feature with one concrete destructive-action guard regression, not an outage or security incident.
  • merge-risk: 🚨 session-state: Merging as-is could expose session deletion for rows that the existing UI policy treats as protected.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: The PR carries the protected maintainer label, so the external-contributor real-behavior proof gate does not apply; the author also posted remote check/UI/e2e validation context.
Evidence reviewed

PR surface:

Source +297, Tests +197. Total +494 across 70 files.

View PR surface stats
Area Files Added Removed Net
Source 66 736 439 +297
Tests 4 272 75 +197
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 70 1008 514 +494

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs run ui/src/components/session-menu.test.ts ui/src/pages/sessions/view.test.ts.
  • [P1] vitest --config test/vitest/vitest.ui-e2e.config.ts ui/src/e2e/session-management.e2e.test.ts.

What I checked:

  • Protected row delete becomes enabled in the PR merge result: The new shared menu disables Delete only when neither archived nor archiveAllowed is true, so any archived row can delete even when the host passes archiveAllowed=false for a protected row. (ui/src/components/session-menu.ts:308, 6b2d49b803f8)
  • The new component test locks in the unsafe case: The added test expects Delete to stay enabled for an archived session while archiveAllowed is false, which means green tests would preserve the guard bypass. (ui/src/components/session-menu.test.ts:109, 6b2d49b803f8)
  • Current sidebar guard treats archiveAllowed as both Archive and Delete protection: Current main documents that archiveAllowed protects both Archive and Delete for main sessions and active runs, and the existing sidebar disables both actions when it is false. (ui/src/components/app-sidebar.ts:1014, f141af7fd774)
  • Sessions page wiring otherwise follows the requested shared menu path: The PR renders openclaw-session-menu from the Sessions page, passes canArchiveSessionRow as archiveAllowed, and dispatches the row menu actions through the page owner. (ui/src/pages/sessions/sessions-page.ts:820, 6b2d49b803f8)
  • Row entry points are covered by focused view and e2e tests: The PR adds coverage for kebab/contextmenu wiring and a mocked browser E2E path that archives from the Sessions-page menu. (ui/src/e2e/session-management.e2e.test.ts:367, 6b2d49b803f8)
  • Three-way merge check avoids stale-base false positives: The GitHub merge result changes only the intended UI/i18n/test files; stale head-only package differences are not present in the actual merge result. (6b2d49b803f8)

Likely related people:

  • steipete: Peter Steinberger authored the recent merged sidebar session-controls work and opened the linked Sessions-page issue and this implementation PR. (role: recent feature owner and likely follow-up owner; confidence: high; commits: ecc2cffad8aa, ec6c3d1ca849, d45a855a38b0; files: ui/src/components/app-sidebar.ts, ui/src/components/session-menu.ts, ui/src/pages/sessions/sessions-page.ts)
  • NianJiu: The shallow available history blames the current Sessions-page view and canArchiveSessionRow helper to NianJiu's baseline commit, so they are an adjacent history owner for the guard contract. (role: introduced current Sessions-page and session-key baseline in available history; confidence: medium; commits: 67be0cda4460; files: ui/src/pages/sessions/view.ts, ui/src/pages/sessions/sessions-page.ts, ui/src/lib/sessions/session-key.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Land-ready verification (head 9ec9aeb8314, rebased onto ccdb60e5db5):

Remote proof (Blacksmith Testbox):

Local focused runs: node scripts/run-vitest.mjs run ui/src/components/session-menu.test.ts ui/src/pages/sessions/view.test.ts — 44/44 (covers menu item order/guards/dismissal and the kebab/right-click wiring, including the sessions-page redesign's new view tests post-rebase).

Review: structured Codex autoreview ran three times (initial, after fixing its accepted P2 — deleting the currently targeted session now retargets the gateway to the agent main session in deleteSessions, covering bulk delete too — and after the rebase). Final result: clean, "patch is correct (0.9)", no actionable findings.

Known proof gaps: ui/src/pages/chat/chat-realtime.test.ts failed once on a pre-rebase Testbox run; it fails identically at the merge base and on origin/main in the same environments (4/4 locally on macOS) and passed in the final rebased-head suite run — unrelated, tracked in #102568.

steipete added 2 commits July 9, 2026 02:04
Extract the sidebar session menu into a shared <openclaw-session-menu>
component and open it from a kebab button or row right-click on the
Sessions page, replacing the per-row unread/fork/pin/archive/workboard
icon buttons. Adds Open chat, Rename, Move to group, and per-row Delete
to the page; guards (main/global/active-run) now flow through
canArchiveSessionRow on both surfaces.
…from the sessions page

Deleting the currently selected session via the new row menu (or the
bulk bar) left gateway.snapshot.sessionKey pointing at the deleted key;
fall back to the agent main session, mirroring the archive path and the
sidebar delete path.
@steipete
steipete force-pushed the claude/openclaw-similar-menu-ed01e0 branch from 9ec9aeb to d45a855 Compare July 9, 2026 09:04
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jul 9, 2026
@steipete
steipete merged commit e500a4f into main Jul 9, 2026
90 of 94 checks passed
@steipete
steipete deleted the claude/openclaw-similar-menu-ed01e0 branch July 9, 2026 09:15
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

steipete added a commit that referenced this pull request Jul 9, 2026
…runtime

Feedback pass on the sessions redesign: status pills become a plain colored
dot + label (green pulse for live, green dot with neutral label for done,
muted idle, red failed) in both the roster and the drawer hero, and the
Runtime column moves out of the table into the row drawer as Runtime (agent
runtime) plus Run duration. Runtime stays searchable. Responsive breakpoints
reflow for the 7-column roster and the actions column shrinks to the chevron
and row menu that landed in #102564.

Closes #102654
steipete added a commit that referenced this pull request Jul 9, 2026
…runtime (#102664)

Feedback pass on the sessions redesign: status pills become a plain colored
dot + label (green pulse for live, green dot with neutral label for done,
muted idle, red failed) in both the roster and the drawer hero, and the
Runtime column moves out of the table into the row drawer as Runtime (agent
runtime) plus Run duration. Runtime stays searchable. Responsive breakpoints
reflow for the 7-column roster and the actions column shrinks to the chevron
and row menu that landed in #102564.

Closes #102654
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…openclaw#102564)

* feat(ui): add session context menu to sessions page rows

Extract the sidebar session menu into a shared <openclaw-session-menu>
component and open it from a kebab button or row right-click on the
Sessions page, replacing the per-row unread/fork/pin/archive/workboard
icon buttons. Adds Open chat, Rename, Move to group, and per-row Delete
to the page; guards (main/global/active-run) now flow through
canArchiveSessionRow on both surfaces.

* fix(ui): retarget gateway session after deleting the current session from the sessions page

Deleting the currently selected session via the new row menu (or the
bulk bar) left gateway.snapshot.sessionKey pointing at the deleted key;
fall back to the agent main session, mirroring the archive path and the
sidebar delete path.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…runtime (openclaw#102664)

Feedback pass on the sessions redesign: status pills become a plain colored
dot + label (green pulse for live, green dot with neutral label for done,
muted idle, red failed) in both the roster and the drawer hero, and the
Runtime column moves out of the table into the row drawer as Runtime (agent
runtime) plus Run duration. Runtime stays searchable. Responsive breakpoints
reflow for the 7-column roster and the actions column shrinks to the chevron
and row menu that landed in openclaw#102564.

Closes openclaw#102654
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui maintainer Maintainer-authored PR merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: XL status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Sessions page: per-row context menu (kebab + right-click) instead of icon-button row

1 participant