Improve sidebar workspace readability and host identity (#2790)
* fix(app): align turn footer actions Keep running-turn actions in the same position as completed-turn actions and use the shared small icon size for both copy and fork controls. * feat(app): improve sidebar workspace identity Make dense sidebar workspace rows easier to scan and let each device control how connected hosts are identified. * fix(app): keep host badges readable Use a compact display menu and keep identity color on the host icon so translated controls fit and badge text retains standard contrast. * fix(app): announce selected sidebar badge mode * fix(app): retain icon-only host names for screen readers * fix(app): name hoisted workspace rows * fix(app): retain host identity in workspace labels * fix(app): retain workspace status in row labels * fix(app): defer host appearance until identity resolves * fix(app): serialize host appearance writes * fix(app): serialize host registry writes * fix(app): bound sidebar host badge labels * test(app): match workspace status labels * fix(app): consolidate sidebar identity behavior * test(app): assert status grouping behavior * fix(app): keep sidebar row actions accessible * fix(app): stabilize optimistic message layout
This commit is contained in:
@@ -176,6 +176,10 @@ function agentStreamEventKey(type: string): string {
|
||||
return `agent-stream-event:${type}`;
|
||||
}
|
||||
|
||||
function agentStreamItemKey(type: string): string {
|
||||
return `agent-stream-item:${type}`;
|
||||
}
|
||||
|
||||
function agentUpdateKey(agentId: string, status: string): string {
|
||||
return `agent-update:${agentId}:${status}`;
|
||||
}
|
||||
@@ -526,6 +530,12 @@ export async function installDaemonWebSocketGate(page: Page) {
|
||||
(message) => readAgentStreamEventType(message) === type,
|
||||
);
|
||||
},
|
||||
holdNextAgentStreamItem(type: string): void {
|
||||
pendingServerMessageHolds.set(
|
||||
agentStreamItemKey(type),
|
||||
(message) => readAgentStreamItemType(message) === type,
|
||||
);
|
||||
},
|
||||
async waitForHeldServerMessage(type?: string): Promise<void> {
|
||||
const key = type ? serverMessageKey(type) : null;
|
||||
while (!heldServerMessages.some((message) => key === null || message.key === key)) {
|
||||
@@ -574,6 +584,22 @@ export async function installDaemonWebSocketGate(page: Page) {
|
||||
heldServerMessage.browser.send(follower);
|
||||
}
|
||||
},
|
||||
async waitForHeldAgentStreamItem(type: string): Promise<void> {
|
||||
const key = agentStreamItemKey(type);
|
||||
while (!heldServerMessages.some((message) => message.key === key)) {
|
||||
await new Promise<void>((resolve) => heldServerMessageWaiters.add(resolve));
|
||||
}
|
||||
},
|
||||
releaseHeldAgentStreamItem(type: string): void {
|
||||
const key = agentStreamItemKey(type);
|
||||
const index = heldServerMessages.findIndex((message) => message.key === key);
|
||||
const [heldServerMessage] = index >= 0 ? heldServerMessages.splice(index, 1) : [];
|
||||
if (!heldServerMessage) throw new Error("No held agent stream item to release");
|
||||
heldServerMessage.browser.send(heldServerMessage.message);
|
||||
for (const follower of heldServerMessage.agentStreamFollowers) {
|
||||
heldServerMessage.browser.send(follower);
|
||||
}
|
||||
},
|
||||
requestTimelineTail(agentId: string): void {
|
||||
if (!latestServer) throw new Error("No daemon WebSocket is connected");
|
||||
latestServer.send(
|
||||
|
||||
Reference in New Issue
Block a user