feat: project SubWorker activity in sidebar

This commit is contained in:
2026-08-21 07:12:04 +09:00
parent 8bedfcda84
commit 18112d29a6
9 changed files with 409 additions and 26 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ runtime_id?: string | null,
/**
* Producer-owned monotonic revision for this Worker subject.
*/
subject_revision: number, state: SubscriptionWorkerState, workspace_id?: string | null, display_name?: string | null, profile?: string | null, repository_id?: string | null, working_directory_id?: SubscriptionWorkdirId | null, };
subject_revision: number, state: SubscriptionWorkerState, has_running_internal_workers: boolean, workspace_id?: string | null, display_name?: string | null, profile?: string | null, repository_id?: string | null, working_directory_id?: SubscriptionWorkdirId | null, };
export type SubscriptionWorkdir = { working_directory_id: SubscriptionWorkdirId, repository_id: string, state: string, primary_worker_id?: SubscriptionWorkerId | null, };
@@ -29,7 +29,7 @@
<style>
.spinner {
display: inline-flex;
color: var(--accent);
color: var(--spinner-color, var(--accent));
line-height: 1;
}
</style>
@@ -1,4 +1,5 @@
<script lang="ts">
import Spinner from '$lib/workspace/console/Spinner.svelte';
import { workerConsoleHref } from '$lib/workspace/console/model';
import {
workspaceWorkersStore,
@@ -76,10 +77,12 @@
aria-current={currentPath === href ? 'page' : undefined}
>
<span class="worker-status-indicator">
{#if worker.state === 'idle'}
{#if worker.state === 'running'}
<span class="worker-status-spinner"><Spinner label="Running" /></span>
{:else if worker.has_running_internal_workers}
<span class="worker-status-spinner is-subworker"><Spinner label="SubWorker running" /></span>
{:else if worker.state === 'idle'}
<span class="worker-status-dot" aria-label="Idle"></span>
{:else if worker.state === 'running'}
<span class="worker-status-spinner" aria-label="Running"></span>
{/if}
</span>
<span class="worker-nav-label">{worker.display_name || worker.label}</span>
@@ -267,12 +267,17 @@
background: var(--success);
}
.worker-status-spinner {
width: 0.625rem;
height: 0.625rem;
border: 0.125rem solid color-mix(in oklch, var(--accent) 25%, transparent);
border-top-color: var(--accent);
border-radius: 50%;
animation: worker-status-spin 0.8s linear infinite;
--spinner-color: var(--success);
display: inline-flex;
align-items: center;
justify-content: center;
width: 0.75rem;
font-size: 0.7rem;
line-height: 1;
}
.worker-status-spinner.is-subworker {
--spinner-color: var(--tui-magenta);
}
.worker-nav-label {
grid-column: 2;
@@ -339,16 +344,6 @@
.worker-overflow-toggle[aria-expanded="true"] .worker-overflow-chevron {
transform: rotate(180deg);
}
@keyframes worker-status-spin {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.worker-status-spinner {
animation: none;
}
}
@media (max-width: 760px) {
.sidebar-frame,
@@ -20,6 +20,7 @@ function worker(runtimeId: string, workerId: string, revision: number): Subscrip
runtime_id: runtimeId,
subject_revision: revision,
state: 'idle',
has_running_internal_workers: false,
workspace_id: 'workspace-test',
display_name: null,
profile: null,
@@ -11,6 +11,7 @@ import type { Worker } from './types';
export type SidebarWorker = Worker & {
repository_id: string | null;
working_directory_id: string | null;
has_running_internal_workers: boolean;
};
export type WorkspaceWorkersState = {
@@ -96,6 +97,7 @@ function projectWorker(worker: SubscriptionWorker): SidebarWorker {
},
repository_id: worker.repository_id ?? null,
working_directory_id: worker.working_directory_id ?? null,
has_running_internal_workers: worker.has_running_internal_workers,
working_directory: null,
diagnostics: [],
};