mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 03:45:46 -06:00
b8ff4fe3d7
* fix: show sessions waiting for concurrency slots * test: align queued session integration fixtures * test: distinguish queued and reactivated followups * fix: preserve queued state in workboard and android * fix: project queued status through chat history * test(ui): keep queued sidebar case under line cap
104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
import { html, nothing } from "lit";
|
|
import { t } from "../i18n/index.ts";
|
|
import type { SidebarRecentSession, SidebarSessionAttention } from "./app-sidebar-session-types.ts";
|
|
import { icons } from "./icons.ts";
|
|
import { resolveSessionAttentionIcon } from "./session-attention-icon-registry.ts";
|
|
|
|
export function renderSessionAttentionIcon(attention: SidebarSessionAttention) {
|
|
if (attention.kind === "none") {
|
|
return nothing;
|
|
}
|
|
const icon =
|
|
attention.kind === "question"
|
|
? icons.hand
|
|
: attention.kind === "approval"
|
|
? icons.shieldQuestion
|
|
: attention.kind === "agent"
|
|
? resolveSessionAttentionIcon(attention.icon)
|
|
: icons.alertTriangle;
|
|
return html`<span
|
|
class="sidebar-session-attention__icon sidebar-session-attention__icon--${attention.kind}"
|
|
data-session-attention=${attention.kind}
|
|
aria-hidden="true"
|
|
>${icon}</span
|
|
>`;
|
|
}
|
|
|
|
export function sessionAttentionSubtitle(attention: SidebarSessionAttention): string | undefined {
|
|
switch (attention.kind) {
|
|
case "question":
|
|
return t("sessionsView.waitingForAnswer");
|
|
case "approval":
|
|
return t("sessionsView.waitingForApproval");
|
|
case "error":
|
|
return t("sessionsView.runFailedReason", { reason: attention.reason });
|
|
case "agent":
|
|
return attention.note;
|
|
case "none":
|
|
return undefined;
|
|
default:
|
|
return attention satisfies never;
|
|
}
|
|
}
|
|
|
|
export function renderSessionUnreadState(session: SidebarRecentSession) {
|
|
return !session.isChild && session.unread
|
|
? html`<span
|
|
class="session-unread-dot sidebar-recent-session__unread"
|
|
role="img"
|
|
aria-label=${t("sessionsView.unread")}
|
|
></span>`
|
|
: nothing;
|
|
}
|
|
|
|
export function renderSessionRunSpinner(showTitle = true) {
|
|
return html`<span
|
|
class="session-run-spinner sidebar-recent-session__state"
|
|
role="img"
|
|
aria-label=${t("sessionsView.activeRun")}
|
|
title=${showTitle ? t("sessionsView.activeRun") : nothing}
|
|
></span>`;
|
|
}
|
|
|
|
export function renderSessionState(session: SidebarRecentSession, showTitle = true) {
|
|
if (session.hasActiveRun) {
|
|
if (session.status === "queued") {
|
|
const label = t("sessionsView.statusQueued");
|
|
return html`<span
|
|
class="sidebar-child-session__status sidebar-child-session__status--queued"
|
|
role="img"
|
|
aria-label=${label}
|
|
title=${showTitle ? label : nothing}
|
|
>${icons.hourglass}</span
|
|
>`;
|
|
}
|
|
return renderSessionRunSpinner(showTitle);
|
|
}
|
|
if (!session.isChild) {
|
|
return renderSessionUnreadState(session);
|
|
}
|
|
const status = session.status;
|
|
if (!status) {
|
|
return nothing;
|
|
}
|
|
const statusBadge =
|
|
status === "done"
|
|
? { icon: icons.check, label: t("sessionsView.statusDone") }
|
|
: status === "killed"
|
|
? { icon: icons.stop, label: t("sessionsView.statusKilled") }
|
|
: status === "timeout"
|
|
? { icon: icons.alertTriangle, label: t("sessionsView.statusTimeout") }
|
|
: status === "failed"
|
|
? { icon: icons.alertTriangle, label: t("sessionsView.statusFailed") }
|
|
: null;
|
|
return statusBadge
|
|
? html`<span
|
|
class="sidebar-child-session__status sidebar-child-session__status--${status}"
|
|
role="img"
|
|
aria-label=${statusBadge.label}
|
|
title=${statusBadge.label}
|
|
>${statusBadge.icon}</span
|
|
>`
|
|
: nothing;
|
|
}
|