Skip to content

fix(webui): keep message actions visible - #6955

Merged
serrrfirat merged 1 commit into
mainfrom
codex/always-show-message-actions
Jul 31, 2026
Merged

serrrfirat merged 1 commit into
mainfrom
codex/always-show-message-actions

Conversation

@serrrfirat

Copy link
Copy Markdown
Collaborator

Summary

  • Keeps each message timestamp and action row visible without requiring pointer hover or keyboard focus.
  • Preserves the existing muted default color, per-icon hover feedback, action gating, disabled states, and tooltips.
  • Adds a regression assertion that prevents the hover-only opacity classes from returning.

Change Type

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • CI/Infrastructure
  • Security
  • Dependencies

Linked Issue

None — requested as a focused WebUI visibility correction.

Validation

  • cargo fmt --all -- --check — Not applicable: no Rust changed.
  • cargo clippy --all --benches --tests --examples --all-features -- -D warnings — Not applicable: no Rust changed.
  • pnpm lint (lint:conventions + tsc --noEmit)
  • pnpm test — 117 files / 986 tests
  • pnpm build — includes enforced bundle budgets
  • cargo test --features integration — Not applicable: no database or integration behavior changed.
  • Manual testing — Not performed; the component-level class contract covers this presentation-only change.
  • review-pr / pr-shepherd --fix — Not run for this two-file presentation fix.

Test Strategy

User behavior: Given a rendered user or final assistant message, when the pointer is not hovering the message and no action has focus, then its timestamp and permitted message action icons remain visible.

Risk areas:

  • Model behavior
  • Browser
  • Side effect
  • Persistence
  • Security or permissions
  • External provider
  • Cross-component behavior

Tests added or updated:

  • Unit or contract: Updated message-bubble.test.ts to require the always-visible meta-row classes and reject opacity-0, group-hover:opacity-100, or focus-within:opacity-100 visibility gating.
  • Reborn integration: Not applicable: no turn, runner, product workflow, or backend behavior changed.
  • Recorded fixture: Not applicable: no model choice or request shape changed.
  • Browser E2E: Not added: the existing component contract directly covers the rendered class behavior; no interaction flow changed.
  • Backend or runtime: Not applicable: no backend or runtime behavior changed.
  • Live canary: Not applicable: no model or provider behavior changed.

What the tests prove: message timestamps and permitted action icons remain in the rendered meta row without hover/focus opacity gating, while the existing action layout and icon-only controls remain intact.

Commands run:

  • pnpm exec vitest run src/pages/chat/components/message-bubble.test.ts
  • pnpm lint
  • pnpm test
  • pnpm build

Security Impact

None. Existing action availability and export feature gates are unchanged.

Reborn Trust-Boundary Checklist

N/A — presentation-only frontend class change; no trust, ingress, runtime, persistence, or policy boundary changed.

Database Impact

None.

Blast Radius

Limited to the timestamp/action meta row for user and final assistant message bubbles. A regression could affect visual density, but not whether an action is authorized or executable.

Rollback Plan

Revert the single commit to restore hover/focus-only visibility.

Review Follow-Through

No known follow-up. Reviewer judgment is limited to the always-visible visual density.


Review track: A (presentational WebUI bug fix with focused regression coverage)

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@railway-app

railway-app Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-6955 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Jul 31, 2026 at 9:43 am

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6955 July 31, 2026 09:34 Destroyed
@coderabbitai

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • UI Improvements
    • Message timestamps and available actions are now always visible, making chat controls easier to discover and use.
  • Tests
    • Updated coverage to verify that message metadata and action controls remain visible.

Walkthrough

The message metadata and action row is now always visible. The component removes hover/focus opacity utilities, and its tests verify the updated visibility and control-sizing expectations.

Changes

Message metadata visibility

Layer / File(s) Summary
Always-visible metadata row
crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.tsx, crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts
The metadata row no longer uses transparent or hover-transition classes. Tests verify that timestamps and actions remain visible without hover or keyboard focus.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested reviewers: benkurrek

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and clearly describes the change to keep WebUI message actions visible.
Description check ✅ Passed The description completes the required sections and documents scope, validation, test strategy, security, database impact, rollback, and review follow-through.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size: XS < 10 changed lines (excluding docs) risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Jul 31, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts (1)

551-570: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale assertion message.

The message at Line 560 still says “hover meta row”. Change it to “always-visible meta row” so test failures describe the current contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts`
around lines 551 - 570, Update the assertion message in the test named “message
timestamp and actions share an always-visible meta row” from “hover meta row” to
“always-visible meta row”; leave the assertion and implementation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts`:
- Around line 567-570: Update the visibility assertion in the message-bubble
test to first extract the metadata-row class expression from
messageBubbleSource, then assert that this extracted expression contains none of
the prohibited opacity utilities regardless of class order. Replace the current
text-iron-400-anchored regular expression while preserving the existing failure
message and visibility requirements.

---

Outside diff comments:
In
`@crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts`:
- Around line 551-570: Update the assertion message in the test named “message
timestamp and actions share an always-visible meta row” from “hover meta row” to
“always-visible meta row”; leave the assertion and implementation unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1cb43dfb-a215-4a77-a96f-e5f096d72ff3

📥 Commits

Reviewing files that changed from the base of the PR and between 945d926 and 60ec71e.

📒 Files selected for processing (2)
  • crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts
  • crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.tsx

Comment on lines +567 to +570
assert.doesNotMatch(
messageBubbleSource,
/text-iron-400[^"\n]*(?:opacity-0|group-hover:opacity-100|focus-within:opacity-100)/,
"message actions should not depend on hover or keyboard focus for visibility",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the visibility assertion independent of class order.

The regular expression at Line 569 only detects opacity utilities after text-iron-400. If a future edit places opacity-0 before that token, the test passes while the row is hidden. Extract the metadata-row class expression first, then assert that it contains none of the prohibited opacity utilities.

Proposed test adjustment
+  const metaRowStart = messageBubbleSource.indexOf('"mt-1 flex min-h-7');
+  const metaRowEnd = messageBubbleSource.indexOf('].join(" ")', metaRowStart);
+  const metaRowSource = messageBubbleSource.slice(metaRowStart, metaRowEnd);
   assert.doesNotMatch(
-    messageBubbleSource,
-    /text-iron-400[^"\n]*(?:opacity-0|group-hover:opacity-100|focus-within:opacity-100)/,
+    metaRowSource,
+    /opacity-0|group-hover:opacity-100|focus-within:opacity-100/,
     "message actions should not depend on hover or keyboard focus for visibility",
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert.doesNotMatch(
messageBubbleSource,
/text-iron-400[^"\n]*(?:opacity-0|group-hover:opacity-100|focus-within:opacity-100)/,
"message actions should not depend on hover or keyboard focus for visibility",
const metaRowStart = messageBubbleSource.indexOf('"mt-1 flex min-h-7');
const metaRowEnd = messageBubbleSource.indexOf('].join(" ")', metaRowStart);
const metaRowSource = messageBubbleSource.slice(metaRowStart, metaRowEnd);
assert.doesNotMatch(
metaRowSource,
/opacity-0|group-hover:opacity-100|focus-within:opacity-100/,
"message actions should not depend on hover or keyboard focus for visibility",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@crates/ironclaw_webui/frontend/src/pages/chat/components/message-bubble.test.ts`
around lines 567 - 570, Update the visibility assertion in the message-bubble
test to first extract the metadata-row class expression from
messageBubbleSource, then assert that this extracted expression contains none of
the prohibited opacity utilities regardless of class order. Replace the current
text-iron-400-anchored regular expression while preserving the existing failure
message and visibility requirements.

@ironloopai

ironloopai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #6955

🟢 Completed · Review submitted

Submitted review →

Reviewed the complete trusted base-to-head comparison. The focused WebUI change correctly removes hover/focus opacity gating from the message metadata row while preserving action availability, alignment, disabled states, and icon controls. The regression test covers the intended class contract. No actionable findings identified.

Automatic · PR opened + CI failed · attempt 1 of 3 · completed in 1m 9s

Run details
  • Repository: nearai/ironclaw
  • Base: main at 945d926
  • Head: codex/always-show-message-actions at 60ec71e
  • Created: Jul 31, 2026, 9:39 AM UTC
  • Updated: Jul 31, 2026, 9:40 AM UTC
  • Run: 9065a074-9dee-4364-9bdd-d1bfbb73e346
  • Latest attempt: 1 · Completed · d1fea5c4-cdbd-411d-b529-3114a534c57f

@ironloopai ironloopai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Review complete · PR #6955

✅ No actionable findings

Reviewed the complete trusted base-to-head comparison. The focused WebUI change correctly removes hover/focus opacity gating from the message metadata row while preserving action availability, alignment, disabled states, and icon controls. The regression test covers the intended class contract. No actionable findings identified.

Validation and technical details
  • Verified trusted refs: base 945d926 and head 60ec71e.
  • Inspected the complete two-file diff and surrounding MessageBubble rendering/action-gating logic.
  • Confirmed the reviewed files in the checkout match refs/ironloop/head.
  • git diff --check refs/ironloop/base refs/ironloop/head passed.
  • Focused Vitest run passed: 1 file, 18 tests. The environment reported Node 24.18.0 despite the package requesting Node >=22 <23.
  • Base: main
  • Head: codex/always-show-message-actions at 60ec71e
  • Run: 9065a074-9dee-4364-9bdd-d1bfbb73e346

@serrrfirat serrrfirat added the skip-regression-check Bypass regression test CI gate (tests exist but not in tests/ dir) label Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage ratchet

Ratchet mode: ENFORCING

RATCHET PASS: global
  observed: 86.6% (322406 / 372279 lines)
  floor:    85.54% (tolerance 0.5pp -> effective floor 85.04%)
  denominator: 372279 lines now vs 368757 at floor capture (+3522 lines, +0.96%) — not a material change

RATCHET PASS: ironclaw_runner
  observed: 87.35% (15146 / 17339 lines)
  floor:    86.87% (tolerance 0.5pp -> effective floor 86.37%)
  floor_covered_lines: 14669 (tolerance 20 lines -> effective floor 14649)
  denominator: 17339 lines now vs 16887 at floor capture (+452 lines, +2.68%) — not a material change

RATCHET PASS: ironclaw_processes
  observed: 88.93% (5896 / 6630 lines)
  floor:    88.07% (tolerance 0.5pp -> effective floor 87.57%)
  floor_covered_lines: 5839 (tolerance 20 lines -> effective floor 5819)
  denominator: 6630 lines now vs 6630 at floor capture (+0 lines, +0%) — not a material change

RATCHET PASS: ironclaw_turns
  observed: 87.64% (9829 / 11215 lines)
  floor:    86.21% (tolerance 0.5pp -> effective floor 85.71%)
  floor_covered_lines: 9453 (tolerance 20 lines -> effective floor 9433)
  denominator: 11215 lines now vs 10965 at floor capture (+250 lines, +2.28%) — not a material change

Reborn integration-tier coverage

Line coverage (Reborn crates): 86.6% — 322406 / 372279 lines

Per-crate breakdown (60 crates, lowest-covered first)
Crate Line % Covered / Total
ironclaw_host_ingress 42.5% 17 / 40
ironclaw_memory 54.6% 635 / 1163
ironclaw_projects 72.59% 233 / 321
ironclaw_trust 73.87% 670 / 907
ironclaw_capabilities 74.89% 2854 / 3811
ironclaw_observability 76.19% 32 / 42
ironclaw_filesystem 76.31% 5757 / 7544
ironclaw_extractors 77.3% 538 / 696
ironclaw_reborn_cli 77.99% 10859 / 13923
ironclaw_wasm 79.1% 704 / 890
ironclaw_llm 81.17% 22539 / 27769
ironclaw_events 81.35% 1256 / 1544
ironclaw_auth 81.61% 6027 / 7385
ironclaw_memory_native 81.99% 2951 / 3599
ironclaw_first_party_extensions 82.7% 6760 / 8174
ironclaw_libsql_runtime 84.21% 384 / 456
ironclaw_host_api 84.24% 9818 / 11655
ironclaw_extension_host 84.69% 22163 / 26170
ironclaw_operator 85.33% 5309 / 6222
ironclaw_network 85.67% 891 / 1040
ironclaw_reborn_event_store 85.81% 1222 / 1424
ironclaw_authorization 85.83% 715 / 833
ironclaw_reborn_composition 86.1% 21785 / 25303
ironclaw_secrets 86.15% 2843 / 3300
ironclaw_hooks 86.25% 9915 / 11496
ironclaw_reborn_config 86.4% 2091 / 2420
ironclaw_common 87.15% 1783 / 2046
ironclaw_runner 87.35% 15146 / 17339
ironclaw_skills 87.38% 4820 / 5516
ironclaw_turns 87.64% 9829 / 11215
ironclaw_scripts 87.87% 420 / 478
ironclaw_extensions 87.87% 4780 / 5440
ironclaw_product 87.98% 22795 / 25909
ironclaw_event_projections 88.12% 1372 / 1557
ironclaw_webui 88.22% 11836 / 13416
ironclaw_reborn_traces 88.49% 11665 / 13183
ironclaw_threads 88.62% 5179 / 5844
ironclaw_process_sandbox 88.64% 281 / 317
ironclaw_telegram_extension 88.7% 589 / 664
ironclaw_processes 88.93% 5896 / 6630
ironclaw_host_runtime 89.17% 21073 / 23632
ironclaw_reborn_openai_compat 89.73% 3643 / 4060
ironclaw_telegram_v2_adapter 90.12% 1560 / 1731
ironclaw_wasm_limiter 90.24% 74 / 82
ironclaw_loop_host 91.11% 18048 / 19809
ironclaw_approvals 91.21% 1816 / 1991
ironclaw_reborn_identity 91.3% 451 / 494
ironclaw_resources 91.49% 4085 / 4465
ironclaw_conversations 92.45% 2387 / 2582
ironclaw_event_streams 92.5% 1048 / 1133
ironclaw_mcp 92.62% 1317 / 1422
ironclaw_agent_loop 94.29% 10416 / 11047
ironclaw_slack_extension 94.48% 3678 / 3893
ironclaw_triggers 94.96% 3091 / 3255
ironclaw_first_party_extension_ports 95.06% 3752 / 3947
ironclaw_outbound 95.1% 4267 / 4487
ironclaw_safety 95.69% 4458 / 4659
ironclaw_prompt_envelope 97.96% 192 / 196
ironclaw_runtime_policy 98.63% 862 / 874
ironclaw_attachments 98.81% 829 / 839

This table itself is informational and never gates the PR on its own — not the percentage, not the per-crate holes, not the 0-coverage callout. A separate coverage ratchet (dry-run until enforce=true; see tests/integration/coverage-floor.toml) can fail the build on specific configured floors.

Exemptions (18 entry/entries excluded from the accounting above)
Module / Crate Reason Issue
crate: ironclaw_embeddings v1-only: consumed only by root ironclaw (src/app.rs, src/tools/builtin/memory.rs, src/workspace/mod.rs, src/config/{mod,embeddings}.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_gateway v1-only: consumed only by root ironclaw (src/channels/web/platform/static_files.rs, src/channels/web/handlers/frontend.rs); no crates/* dependents. Covered by "Tests (Legacy)". #5657
crate: ironclaw_tui v1-only: consumed only by root ironclaw (src/main.rs, src/channels/tui.rs); no crates/* dependents. Crate's own doc comment confirms it bridges INTO v1, not Reborn. Covered by "Tests (Legacy)". #5657
crates/ironclaw_attachments/src/lib.rs Declarative crate facade: module declarations, constants, and re-exports only; executable attachment modules remain covered. #6524
crates/ironclaw_extension_host/src/ingress/mod.rs Declarative ingress module facade and documentation only; executable router modules remain covered. #6524
crates/ironclaw_host_api/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable host API modules remain covered. #6524
crates/ironclaw_host_api/src/product_adapter/mod.rs Declarative product-adapter facade: module declarations and re-exports only; executable adapter modules remain covered. #6524
crates/ironclaw_llm/src/rig_adapter/tests/finish_reason_tests.rs Test-only module stored under src/ for private adapter access; cargo-llvm-cov omits test harness source from production LCOV while the exercised rig_adapter.rs production lines remain coverage-gated. #6284
crates/ironclaw_outbound/src/error.rs Declarative error vocabulary only; variants have no LLVM-instrumentable production statements. #6524
crates/ironclaw_outbound/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable outbound modules remain covered. #6524
crates/ironclaw_product/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable product behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_product/src/lib.rs Declarative crate facade: module declarations and re-exports only; executable product modules remain covered. #6524
crates/ironclaw_product/src/scoped_fs/mod.rs Declarative scoped-filesystem facade and documentation only; executable scoped filesystem modules remain covered. #6524
crates/ironclaw_reborn_composition/src/support/fs/mod.rs Declarative composition support facade: module declarations and re-exports only; executable filesystem adapters remain covered. #6524
crates/ironclaw_slack_extension/src/lib.rs Declarative Slack crate facade: module declarations and re-exports only; executable Slack modules remain covered. #6524
crates/ironclaw_telegram_extension/src/lib.rs Declarative Telegram crate facade: module declarations and re-exports only; executable Telegram modules remain covered. #6524
crates/ironclaw_threads/src/lib.rs Declaration-only public facade with no executable Rust statements; rustc emits no LCOV source record. Executable thread behavior remains covered in the owned implementation modules. #6524
crates/ironclaw_webui/src/webui_v2/mod.rs Declaration-only WebUI v2 facade with no executable Rust statements; rustc emits no LCOV source record. Executable route behavior remains covered in the owned implementation modules. #6524

@serrrfirat
serrrfirat merged commit ba57d8e into main Jul 31, 2026
57 of 60 checks passed
@serrrfirat
serrrfirat deleted the codex/always-show-message-actions branch July 31, 2026 10:19
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-6955 — 60ec71eb Deployed Jul 31, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules size: XS < 10 changed lines (excluding docs) skip-regression-check Bypass regression test CI gate (tests exist but not in tests/ dir)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant