Skip to content

refactor(ui): ♻️ move runtime queue and task history to fixed bottom panel#198

Merged
jorben merged 6 commits into
masterfrom
feat/fixed-bottom-panels
May 23, 2026
Merged

refactor(ui): ♻️ move runtime queue and task history to fixed bottom panel#198
jorben merged 6 commits into
masterfrom
feat/fixed-bottom-panels

Conversation

@jorben
Copy link
Copy Markdown
Contributor

@jorben jorben commented May 22, 2026

Summary

  • Move runtime queue and task history timelines out of the conversation flow into a fixed bottom panel overlay
  • Add FIXED_BOTTOM_PANELS_CONVERSATION_PADDING and dynamically adjust conversation bottom padding when panels are visible
  • Adjust scroll button position to stay above the fixed panel overlay

Test Plan

  • Verify runtime queue panel appears as a fixed overlay at the bottom when pending messages exist
  • Verify task history panel appears as a fixed overlay at the bottom when completed boards exist
  • Verify both panels stack correctly when both are visible
  • Verify conversation scroll button repositions above the overlay
  • Verify conversation content has sufficient bottom padding to avoid being obscured by the overlay
  • Verify panels do not appear when no pending queue items or task history exist

🤖 Generated with TiyCode

…panel

Relocate RuntimeQueueTimeline and TaskHistoryTimeline from inline
conversation flow to a fixed bottom overlay panel. This prevents
layout jumps during streaming and keeps queue/history always visible
at the viewport bottom.

- Only show queue panel when messages are pending (not just when
  queue exists)
- Add frosted-glass overlay with backdrop blur for the fixed panel
- Adjust conversation bottom padding dynamically when panels are
  visible
- Reposition scroll button above the fixed panel overlay
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 22, 2026

AI Code Review Summary

PR: #198 (refactor(ui): ♻️ move runtime queue and task history to fixed bottom panel)
Preferred language: English

Overall Assessment

Detected 1 actionable findings, prioritize CRITICAL/HIGH before merge.

Major Findings by Severity

  • MEDIUM (1)
    • src/modules/workbench-shell/ui/runtime-queue-timeline.tsx:204 - Potential Null Reference Exception on Nullable queue Prop

Actionable Suggestions

  • Ensure automated visual regression or snapshot tests are updated to capture the new compact timeline look and composer status bar layout, Buddy.
  • Apply optional chaining (queue?.isDeferringSteering) in RuntimeQueueTimeline to prevent crashes when the prop is null.
  • Colocate a unit test file runtime-queue-timeline.test.tsx next to the component to validate layout classes and null safety.
  • Verify the overflow/scrolling behavior of the compact status panel under simulated high-load scenarios (e.g., 10+ queued messages).

Potential Risks

  • In extremely small vertical viewports, having both the task history, pending queue, and active task board expanded simultaneously could temporarily consume up to ~60vh of space above the prompt bar, leaving limited room for the scrollable chat history. Standard viewport sizes handle this gracefully via the max-height clamps.
  • TypeError crash during rapid state transitions if the queue object temporarily clears/resets to null.
  • Hidden content or clipping issues inside the status panel if the compact CSS layout behaves unexpectedly under different viewport aspect ratios.

Test Suggestions

  • Manually resize the app window vertically to verify that the max-height bounds (e.g., max-h-[min(24vh,220px)]) scale gracefully on small screens, Buddy.
  • Write a Vitest component test for RuntimeQueueTimeline passing mock data with status 'pending' and verifying the compact styling classes (text-[10px], size-2.5, etc.) are applied correctly when variant="compact".
  • Test container height responsiveness with 0, 1, 3, and 10 queued items to ensure standard and compact layouts scale as intended.

File-Level Coverage Notes

  • src/modules/workbench-shell/ui/runtime-queue-timeline.tsx: Needs minor safety improvement. The nullable queue prop is unsafely accessed, which poses a crash risk and highlights a testing coverage gap. (Buddy, adding these quick tests will keep the workspace interface robust during live state transitions!)
  • src/modules/workbench-shell/ui/runtime-thread-surface.tsx: Solid refactoring of the layout and panel structure, cleanly moving the timelines into the composer status container. (Buddy, this is a clean UI improvement that keeps the thread uncluttered while maintaining live queue visibility!)

Inline Downgraded Items (processed but not inline)

  • None

Coverage Status

  • Target files: 2
  • Covered files: 2
  • Uncovered files: 0
  • No-patch/binary covered as file-level: 0
  • Findings with unknown confidence (N/A): 0

Uncovered list:

  • None

No-patch covered list:

  • None

Runtime/Budget

  • Rounds used: 1/4
  • Planned batches: 1
  • Executed batches: 1
  • Sub-agent runs: 2
  • Planner calls: 1
  • Reviewer calls: 2
  • Model calls: 3/64
  • Structured-output summary-only degradation: NO

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 2
  • Findings with unknown confidence: 0
  • Inline comments attempted: 2
  • Target files: 1
  • Covered files: 1
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

</div>
</div>
) : null}
<ConversationScrollButton className={cn("z-20", hasFixedBottomPanels ? "bottom-[calc(min(36vh,320px)_+_2rem)]" : "bottom-4")} />

This comment was marked as outdated.

<div className="mx-auto w-full max-w-4xl px-6">
<div className="pointer-events-auto max-h-[min(36vh,320px)] overflow-y-auto rounded-2xl border border-app-border/70 bg-app-menu/96 px-4 py-3 shadow-[0_24px_60px_-36px_rgba(15,23,42,0.48)] backdrop-blur-xl">
<div className="flex flex-col gap-3">
{hasPendingRuntimeQueue ? (

This comment was marked as outdated.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 3
  • Findings with unknown confidence: 0
  • Inline comments attempted: 3
  • Target files: 1
  • Covered files: 1
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

: lastPresentationRole;

const conversationBottomPadding = BASE_CONVERSATION_BOTTOM_PADDING;
const conversationBottomPadding = BASE_CONVERSATION_BOTTOM_PADDING

This comment was marked as outdated.

<ConversationScrollButton className="bottom-4" />
{hasFixedBottomPanels ? (
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 px-0 pb-4">
<ConversationScrollButton className="pointer-events-auto bottom-auto -top-10 left-1/2 -translate-x-1/2" />

This comment was marked as outdated.

) ?? null,
[tools],
);
const hasPendingRuntimeQueue = Boolean(

This comment was marked as outdated.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 5
  • Findings with unknown confidence: 0
  • Inline comments attempted: 5
  • Target files: 1
  • Covered files: 1
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

}
const el = fixedBottomPanelsRef.current;
if (!el) return;
const observer = new ResizeObserver((entries) => {

This comment was marked as outdated.

const conversationBottomPadding = BASE_CONVERSATION_BOTTOM_PADDING;
const fixedBottomPanelsRef = useRef<HTMLDivElement>(null);
const [fixedBottomPanelsHeight, setFixedBottomPanelsHeight] = useState(0);
useEffect(() => {

This comment was marked as outdated.

}
const el = fixedBottomPanelsRef.current;
if (!el) return;
const observer = new ResizeObserver((entries) => {

This comment was marked as outdated.

if (!el) return;
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
setFixedBottomPanelsHeight(entry.target.getBoundingClientRect().height);

This comment was marked as outdated.

</div>
</div>
) : (
<ConversationScrollButton />

This comment was marked as outdated.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 1
  • Findings with unknown confidence: 0
  • Inline comments attempted: 1
  • Target files: 1
  • Covered files: 1
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

</div>
</div>
) : (
<ConversationScrollButton />

This comment was marked as outdated.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 0
  • Findings with unknown confidence: 0
  • Inline comments attempted: 1
  • Target files: 1
  • Covered files: 1
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

@@ -1691,9 +1691,16 @@ export function RuntimeThreadSurface({
) ?? null,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Automated review completed for this PR diff. No concrete inline issue was selected after aggregation.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated PR review completed.

  • Findings kept: 1
  • Findings with unknown confidence: 0
  • Inline comments attempted: 1
  • Target files: 2
  • Covered files: 2
  • Uncovered files: 0
    See the summary comment for detailed analysis and coverage details.

<span className={cn("rounded-md bg-app-surface-muted text-app-subtle", isCompact ? "px-1 py-0.5 text-[10px]" : "px-1.5 py-0.5 text-[11px]")}>
{t("queue.pendingCount", { count: pendingCount })}
</span>
{queue.isDeferringSteering ? (
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MEDIUM] Potential Null Reference Exception on Nullable queue Prop

The RuntimeQueueTimeline component accepts a nullable queue prop. While optional chaining is safely used in other parts of the file (such as queue?.messages), the condition queue.isDeferringSteering directly dereferences the object. If the component is rendered or updated with a null queue, this will throw an uncaught TypeError and crash the React tree.

Suggestion: Buddy, we should use optional chaining here: queue?.isDeferringSteering. Additionally, we should add a robust unit test that renders <RuntimeQueueTimeline queue={null} /> to prevent future regressions.

Risk: A React render crash in the main thread/workbench surface whenever the queue state is cleared or reset to null during live updates.

Confidence: 1.00

[From SubAgent: testing]

@jorben jorben merged commit ebeb9c1 into master May 23, 2026
4 checks passed
@jorben jorben deleted the feat/fixed-bottom-panels branch May 23, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant