fix(ui): give running tasks priority in the background-tasks rail (#113928)

This commit is contained in:
Peter Steinberger
2026-07-25 18:30:03 -07:00
committed by GitHub
parent 467d1d1f11
commit 9349a0e880
4 changed files with 36 additions and 5 deletions

View File

@@ -160,6 +160,12 @@ describeControlUiE2e("Control UI chat background-tasks rail mocked Gateway E2E",
const rail = page.locator(".chat-tasks-rail");
await rail.locator('[data-task-id="task-subagent"]').waitFor({ state: "visible" });
await rail.locator('[data-task-id="task-cron"]').waitFor({ state: "visible" });
// Finished history starts collapsed: only the section header with the
// count renders until it is expanded.
const finishedToggle = rail.getByRole("button", { name: "Finished (1)" });
await finishedToggle.waitFor({ state: "visible" });
expect(await rail.locator('[data-task-id="task-cli"]').count()).toBe(0);
await finishedToggle.click();
await rail.locator('[data-task-id="task-cli"]').waitFor({ state: "visible" });
const railText = await rail.textContent();
expect(railText).toContain("Reading provider catalogs");

View File

@@ -87,6 +87,7 @@ describe("background tasks rail state", () => {
const props = createBackgroundTasksProps(host, openSession);
expect(props.collapsed).toBe(true);
expect(props.finishedCollapsed).toBe(true);
expect(request).toHaveBeenCalledTimes(2);
expect(props.tasks?.map((task) => task.id)).toEqual(["task-1"]);
});
@@ -201,9 +202,10 @@ describe("background tasks rail state", () => {
);
};
host.requestUpdate = renderRail;
// finishedCollapsed defaults to true; back-navigation from a finished
// detail must expand the section so the returned-to row stays visible.
const initialProps = createBackgroundTasksProps(host, openSession);
initialProps.onToggleCollapsed();
initialProps.onToggleFinished();
renderRail();
const disclosure = container.querySelector<HTMLButtonElement>(

View File

@@ -82,7 +82,9 @@ function getBackgroundTasksState(host: BackgroundTasksHost): BackgroundTasksStat
// agent switches and only reload the task list for the new scope.
collapsed: current?.collapsed ?? true,
error: null,
finishedCollapsed: current?.finishedCollapsed ?? false,
// Finished history starts collapsed so active work owns the rail; the
// section header still shows the count for discoverability.
finishedCollapsed: current?.finishedCollapsed ?? true,
loadedClient: null,
loading: false,
pendingReload: false,
@@ -588,7 +590,7 @@ export function renderBackgroundTasksRail(
${empty
? html`<div class="chat-tasks-rail__state">${t("chat.backgroundTasks.empty")}</div>`
: nothing}
<div class="chat-tasks-rail__scroll">
<div class="chat-tasks-rail__scroll chat-tasks-rail__scroll--split">
${active.length > 0
? html`
<section class="chat-tasks-rail__section" data-tasks-section="running">

View File

@@ -39,13 +39,13 @@
rules sit after the collapse/dock modifiers so the extra column wins at
equal specificity. */
.chat-workbench--tasks-open {
grid-template-columns: minmax(0, 1fr) minmax(230px, 280px);
grid-template-columns: minmax(0, 1fr) minmax(270px, 330px);
}
.chat-workbench--tasks-open:not(.chat-workbench--workspace-collapsed):not(
.chat-workbench--dock-bottom
) {
grid-template-columns: minmax(0, 1fr) minmax(230px, 280px) minmax(230px, 280px);
grid-template-columns: minmax(0, 1fr) minmax(230px, 280px) minmax(270px, 330px);
}
/* Compact icon button shared by the pane header actions. Sizing only — chrome
@@ -873,6 +873,13 @@ openclaw-chat-sidebar-region,
overflow: auto;
}
/* List mode splits scrolling per section: running work owns the rail and the
finished history pins to the bottom, so a long history can never clip the
active tasks (each section scrolls on its own instead of the container). */
.chat-tasks-rail__scroll--split {
overflow: hidden;
}
.chat-tasks-rail__section {
display: flex;
flex: 0 1 auto;
@@ -882,6 +889,16 @@ openclaw-chat-sidebar-region,
padding-top: 8px;
}
.chat-tasks-rail__scroll--split > [data-tasks-section="running"] {
flex: 1 1 auto;
}
/* Cap only when running work is present; alone, finished may fill the rail. */
.chat-tasks-rail__scroll--split > [data-tasks-section="running"] + [data-tasks-section="finished"] {
max-height: 50%;
border-top: 1px solid color-mix(in srgb, var(--border) 42%, transparent);
}
.chat-tasks-rail__section-title {
color: var(--muted);
font-size: var(--control-ui-text-xs);
@@ -1836,6 +1853,10 @@ openclaw-session-discussion {
flex: 1 0 260px;
min-width: 0;
overflow-y: auto;
/* Undo the vertical split's bottom-pin cap: strip sections are full-height
columns and separate with border-left instead. */
max-height: none;
border-top: none;
}
.chat-workbench--tasks-dock-bottom