fix: keep current worker visible in collapsed sidebar
This commit is contained in:
@@ -11,7 +11,12 @@
|
||||
workspaceWorkersStore,
|
||||
type SidebarWorker,
|
||||
} from './worker-subscription';
|
||||
import { canShowWorkerInSidebar, sidebarWorkerActivity } from './workers';
|
||||
import {
|
||||
canShowWorkerInSidebar,
|
||||
sidebarWorkerActivity,
|
||||
visibleWorkersForSidebar,
|
||||
workerOwnsSidebarPath,
|
||||
} from './workers';
|
||||
import { sidebarWorkdirMeta } from './worker-workdir-meta';
|
||||
|
||||
const COLLAPSED_WORKER_COUNT = 6;
|
||||
@@ -32,7 +37,12 @@
|
||||
let menuTrigger = $state<HTMLButtonElement | null>(null);
|
||||
let busyAction = $state<{ workerKey: string; kind: WorkerActionKind } | null>(null);
|
||||
let visibleWorkers = $derived(
|
||||
expanded ? workers : workers.slice(0, COLLAPSED_WORKER_COUNT),
|
||||
visibleWorkersForSidebar(workers, {
|
||||
workspaceId,
|
||||
currentPath,
|
||||
expanded,
|
||||
limit: COLLAPSED_WORKER_COUNT,
|
||||
}),
|
||||
);
|
||||
let hiddenWorkerCount = $derived(
|
||||
Math.max(0, workers.length - COLLAPSED_WORKER_COUNT),
|
||||
@@ -173,13 +183,14 @@
|
||||
{@const activity = sidebarWorkerActivity(worker)}
|
||||
{@const key = workerKey(worker)}
|
||||
{@const label = worker.display_name || worker.label}
|
||||
{@const active = workerOwnsSidebarPath(workspaceId, worker, currentPath)}
|
||||
{@const workdir = sidebarWorkdirMeta(worker.workdir_attachments)}
|
||||
<li class="worker-nav-item" data-worker-actions={key}>
|
||||
<a
|
||||
href={href}
|
||||
class="worker-nav-link"
|
||||
class:active={currentPath === href}
|
||||
aria-current={currentPath === href ? 'page' : undefined}
|
||||
class:active
|
||||
aria-current={active ? 'page' : undefined}
|
||||
>
|
||||
<span class="worker-status-indicator">
|
||||
{#if activity === 'worker-running'}
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
canShowWorkerInSidebar,
|
||||
compareWorkersForSidebar,
|
||||
sidebarWorkerActivity,
|
||||
visibleWorkersForSidebar,
|
||||
workerOwnsSidebarPath,
|
||||
} from "./workers.ts";
|
||||
import type { Worker } from "./types.ts";
|
||||
|
||||
@@ -79,6 +81,39 @@ Deno.test("sidebar workers sort running then idle then stopped", () => {
|
||||
assertEquals(workers.map((candidate) => candidate.worker_id).join(","), "2,1,4,3");
|
||||
});
|
||||
|
||||
Deno.test("collapsed sidebar keeps the current Worker visible", () => {
|
||||
const workers = Array.from({ length: 8 }, (_, index) =>
|
||||
worker({
|
||||
worker_id: String(index + 1),
|
||||
resource_key: `W-${index + 1}`,
|
||||
display_name: `Worker ${index + 1}`,
|
||||
}));
|
||||
const currentPath = "/w/workspace-1/workers/W-8-worker-8/console";
|
||||
|
||||
assertEquals(
|
||||
workerOwnsSidebarPath("workspace-1", workers[7], currentPath),
|
||||
true,
|
||||
);
|
||||
assertEquals(
|
||||
visibleWorkersForSidebar(workers, {
|
||||
workspaceId: "workspace-1",
|
||||
currentPath,
|
||||
expanded: false,
|
||||
limit: 6,
|
||||
}).map((candidate) => candidate.resource_key).join(","),
|
||||
"W-1,W-2,W-3,W-4,W-5,W-8",
|
||||
);
|
||||
assertEquals(
|
||||
visibleWorkersForSidebar(workers, {
|
||||
workspaceId: "workspace-1",
|
||||
currentPath,
|
||||
expanded: true,
|
||||
limit: 6,
|
||||
}).length,
|
||||
8,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("fatal child stop clears the sidebar SubWorker spinner activity", () => {
|
||||
const parent = { state: "idle", has_running_internal_workers: true };
|
||||
assertEquals(sidebarWorkerActivity(parent), "subworker-running");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { workerHref } from '../resource-links';
|
||||
import { ownsRoutePath } from './route-ownership';
|
||||
import type { Worker } from './types';
|
||||
|
||||
export type SidebarWorkerActivity =
|
||||
@@ -31,6 +33,38 @@ export function canOpenWorkerConsole(
|
||||
return canShowWorkerInSidebar(worker);
|
||||
}
|
||||
|
||||
type SidebarWorkerLink = Pick<Worker, 'resource_key' | 'display_name'>;
|
||||
|
||||
export function workerOwnsSidebarPath(
|
||||
workspaceId: string,
|
||||
worker: SidebarWorkerLink,
|
||||
currentPath: string,
|
||||
): boolean {
|
||||
return ownsRoutePath(workerHref(workspaceId, worker), currentPath);
|
||||
}
|
||||
|
||||
export function visibleWorkersForSidebar<T extends SidebarWorkerLink>(
|
||||
workers: readonly T[],
|
||||
options: {
|
||||
workspaceId: string;
|
||||
currentPath: string;
|
||||
expanded: boolean;
|
||||
limit: number;
|
||||
},
|
||||
): readonly T[] {
|
||||
if (options.expanded || workers.length <= options.limit) return workers;
|
||||
if (options.limit <= 0) return [];
|
||||
|
||||
const visible = workers.slice(0, options.limit);
|
||||
const currentIndex = workers.findIndex((worker) =>
|
||||
workerOwnsSidebarPath(options.workspaceId, worker, options.currentPath)
|
||||
);
|
||||
if (currentIndex < options.limit) return visible;
|
||||
|
||||
visible[visible.length - 1] = workers[currentIndex];
|
||||
return visible;
|
||||
}
|
||||
|
||||
type SortableWorker = Pick<
|
||||
Worker,
|
||||
'state' | 'display_name' | 'runtime_id' | 'worker_id'
|
||||
|
||||
Reference in New Issue
Block a user