fix: address Skill Workshop UI check failures

This commit is contained in:
Shakker
2026-05-31 22:43:58 +01:00
committed by Shakker
parent 025bb01268
commit 2976db4b2c
9 changed files with 66 additions and 40 deletions

View File

@@ -1061,7 +1061,7 @@ describe("switchChatSession", () => {
loadChatHistoryMock.mockResolvedValue(undefined);
loadSessionsMock.mockResolvedValue(undefined);
switchChatSession(state, "agent:main:test-b");
void switchChatSession(state, "agent:main:test-b");
await Promise.resolve();
expect(state.chatQueue).toStrictEqual([]);
@@ -1133,10 +1133,10 @@ describe("switchChatSession", () => {
loadChatHistoryMock.mockResolvedValue(undefined);
loadSessionsMock.mockResolvedValue(undefined);
switchChatSession(state, "agent:main:other");
void switchChatSession(state, "agent:main:other");
expect(state.chatQueue).toStrictEqual([]);
switchChatSession(state, "main");
void switchChatSession(state, "main");
expect(state.chatQueue).toEqual([{ id: "queued-1", text: "message B", createdAt: 1 }]);
});
@@ -1180,7 +1180,7 @@ describe("switchChatSession", () => {
loadChatHistoryMock.mockResolvedValue(undefined);
loadSessionsMock.mockResolvedValue(undefined);
switchChatSession(state, "main");
void switchChatSession(state, "main");
await Promise.resolve();
expect(

View File

@@ -282,7 +282,13 @@ function renderCronFilterIcon(hiddenCount: number) {
}
export function renderChatSessionSelect(state: AppViewState) {
return renderChatSessionSelectBase(state, switchChatSession, { surface: "desktop" });
return renderChatSessionSelectBase(
state,
(targetState, nextSessionKey) => {
void switchChatSession(targetState, nextSessionKey);
},
{ surface: "desktop" },
);
}
function chatAutoScrollLabel(mode: ChatAutoScrollMode) {
@@ -586,7 +592,13 @@ export function renderChatMobileToggle(state: AppViewState) {
}}
>
<div class="chat-controls">
${renderChatSessionSelectBase(state, switchChatSession, { surface: "mobile" })}
${renderChatSessionSelectBase(
state,
(targetState, nextSessionKey) => {
void switchChatSession(targetState, nextSessionKey);
},
{ surface: "mobile" },
)}
<div class="chat-controls__thinking">
${renderChatAutoScrollToggle(state)}
<button
@@ -771,7 +783,7 @@ export async function createChatSession(state: AppViewState): Promise<boolean> {
const preservedDraft = state.chatMessage;
const preservedAttachments = state.chatAttachments;
switchChatSession(state, nextSessionKey);
void switchChatSession(state, nextSessionKey);
state.chatMessage = preservedDraft;
state.chatAttachments = preservedAttachments;
return true;

View File

@@ -214,7 +214,7 @@ let pendingUpdate: (() => void) | undefined;
const notifyLazyViewChanged = () => pendingUpdate?.();
function runUiTask<Args extends unknown[]>(
function runUiTask<Args extends readonly unknown[]>(
task: (...args: Args) => Promise<unknown>,
): (...args: Args) => void {
return (...args) => {
@@ -423,7 +423,7 @@ function renderSidebarRecentSession(state: AppViewState, row: GatewaySessionRow)
}
event.preventDefault();
if (row.key !== state.sessionKey) {
switchChatSession(state, row.key);
void switchChatSession(state, row.key);
}
state.setTab("chat" as import("./navigation.ts").Tab);
}}
@@ -793,9 +793,9 @@ function applySkillWorkshopReviewState<T extends SkillWorkshopReviewableProposal
}));
}
function rememberSkillWorkshopProposalReviewed<T extends SkillWorkshopReviewableProposal>(
function rememberSkillWorkshopProposalReviewed(
reviewedKeys: string[],
proposal: T,
proposal: SkillWorkshopReviewableProposal,
): string[] {
const key = skillWorkshopReviewKey(proposal);
if (reviewedKeys.includes(key)) {
@@ -2423,12 +2423,17 @@ export function renderApp(state: AppViewState) {
<div class="nav-section__items">
${group.tabs
.filter((tab) => !isChildTab(tab))
.flatMap((tab) => [
renderTab(state, tab, { collapsed: navCollapsed }),
...childTabsOf(tab).map((child) =>
renderTab(state, child, { collapsed: navCollapsed, child: true }),
),
])}
.flatMap((tab) => {
const renderedTabs = [
renderTab(state, tab, { collapsed: navCollapsed }),
];
for (const child of childTabsOf(tab)) {
renderedTabs.push(
renderTab(state, child, { collapsed: navCollapsed, child: true }),
);
}
return renderedTabs;
})}
</div>
</section>
`;
@@ -2594,7 +2599,7 @@ export function renderApp(state: AppViewState) {
onSettingsChange: (next) => state.applySettings(next),
onPasswordChange: (next) => (state.password = next),
onSessionKeyChange: (next) => {
switchChatSession(state, next);
void switchChatSession(state, next);
},
onToggleGatewayTokenVisibility: () => {
state.overviewShowGatewayToken = !state.overviewShowGatewayToken;
@@ -2803,7 +2808,7 @@ export function renderApp(state: AppViewState) {
}
}),
onNavigateToChat: (sessionKey) => {
switchChatSession(state, sessionKey);
void switchChatSession(state, sessionKey);
state.setTab("chat" as import("./navigation.ts").Tab);
},
onAddToWorkboard:
@@ -2827,7 +2832,7 @@ export function renderApp(state: AppViewState) {
checkpointId,
);
if (nextKey) {
switchChatSession(state, nextKey);
void switchChatSession(state, nextKey);
state.setTab("chat" as import("./navigation.ts").Tab);
}
}),
@@ -2852,7 +2857,7 @@ export function renderApp(state: AppViewState) {
agentsList: state.agentsList,
sessions: state.sessionsResult?.sessions ?? [],
onOpenSession: (sessionKey) => {
switchChatSession(state, sessionKey);
void switchChatSession(state, sessionKey);
state.setTab("chat" as import("./navigation.ts").Tab);
},
onRequestUpdate: requestHostUpdate,
@@ -2986,7 +2991,7 @@ export function renderApp(state: AppViewState) {
await loadCronRuns(state, state.cronRunsJobId);
}),
onNavigateToChat: (sessionKey) => {
switchChatSession(state, sessionKey);
void switchChatSession(state, sessionKey);
state.setTab("chat" as import("./navigation.ts").Tab);
},
}),
@@ -3384,8 +3389,10 @@ export function renderApp(state: AppViewState) {
);
const currentIndex = visibleProposals.findIndex((p) => p.key === selectedKey);
const goto = (offset: number) => {
if (visibleProposals.length === 0) return;
const idx = currentIndex < 0 ? 0 : currentIndex;
if (visibleProposals.length === 0) {
return;
}
const idx = Math.max(0, currentIndex);
const next = (idx + offset + visibleProposals.length) % visibleProposals.length;
const proposal = visibleProposals[next];
selectSkillWorkshopProposal(state, proposal.key);
@@ -3583,7 +3590,7 @@ export function renderApp(state: AppViewState) {
renderChat({
sessionKey: state.sessionKey,
onSessionKeyChange: (next) => {
switchChatSession(state, next);
void switchChatSession(state, next);
},
thinkingLevel: state.chatThinkingLevel,
showThinking,
@@ -3698,14 +3705,14 @@ export function renderApp(state: AppViewState) {
currentAgentId: resolvedAgentId ?? "main",
fullMessageAgentId: scopedAgentParamsForSession(state, state.sessionKey).agentId,
onAgentChange: (agentId: string) => {
switchChatSession(state, buildAgentMainSessionKey({ agentId }));
void switchChatSession(state, buildAgentMainSessionKey({ agentId }));
},
onNavigateToAgent: () => {
state.agentsSelectedId = resolvedAgentId;
state.setTab("agents" as import("./navigation.ts").Tab);
},
onSessionSelect: (key: string) => {
switchChatSession(state, key);
void switchChatSession(state, key);
},
showNewMessages: state.chatNewMessagesBelow && !state.chatManualRefreshInFlight,
onScrollToBottom: () => state.scrollToBottom(),
@@ -3821,7 +3828,7 @@ export function renderApp(state: AppViewState) {
onRefresh: refreshDreaming,
onSelectAgent: (agentId: string) => {
state.selectedAgentId = agentId;
switchChatSession(state, resolvePreferredSessionForAgent(state, agentId));
void switchChatSession(state, resolvePreferredSessionForAgent(state, agentId));
void loadDreamingStatus(state);
void loadDreamDiary(state);
},

View File

@@ -106,7 +106,10 @@ vi.mock("../tool-display.ts", () => ({
icon: "zap",
detail:
args && typeof args === "object" && ("detail" in args || "action" in args)
? String((args as { detail?: unknown; action?: unknown }).detail ?? args.action)
? String(
(args as { detail?: unknown; action?: unknown }).detail ??
(args as { action?: unknown }).action,
)
: undefined,
}),
}));

View File

@@ -467,13 +467,13 @@ export class OpenClawFilePreviewModal extends LitElement {
}
private filterFiles(): FilePreviewModalFile[] {
const query = this.query.trim().toLowerCase();
if (!query) {
const normalizedQuery = this.query.trim().toLowerCase();
if (!normalizedQuery) {
return this.files;
}
return this.files.filter((file) => {
const haystack = `${file.path}\n${file.contents}`.toLowerCase();
return haystack.includes(query);
return haystack.includes(normalizedQuery);
});
}
@@ -492,12 +492,12 @@ export class OpenClawFilePreviewModal extends LitElement {
}
private handleQueryInput = (event: Event) => {
const query = (event.target as HTMLInputElement).value ?? "";
const nextQuery = (event.target as HTMLInputElement).value ?? "";
this.dispatchEvent(
new CustomEvent<string>("file-preview-query-change", {
bubbles: true,
composed: true,
detail: query,
detail: nextQuery,
}),
);
};
@@ -518,9 +518,7 @@ export class OpenClawFilePreviewModal extends LitElement {
return;
case "ArrowUp":
this.moveSelection(-1, event);
return;
default:
return;
}
};

View File

@@ -10,7 +10,7 @@ export type ControlUiPublicAsset =
type WindowWithControlUiBasePath = Window &
typeof globalThis & {
__OPENCLAW_CONTROL_UI_BASE_PATH__?: string;
[key: string]: unknown;
};
export function controlUiPublicAssetPath(
@@ -40,7 +40,7 @@ function readConfiguredBasePath(): string | null {
if (typeof window === "undefined") {
return null;
}
const value = (window as WindowWithControlUiBasePath).__OPENCLAW_CONTROL_UI_BASE_PATH__;
const value = (window as WindowWithControlUiBasePath)["__OPENCLAW_CONTROL_UI_BASE_PATH__"];
return typeof value === "string" ? value : null;
}

View File

@@ -2091,7 +2091,7 @@ describe("chat session controls", () => {
]),
);
switchChatSession(state, "agent:ops:main");
void switchChatSession(state, "agent:ops:main");
expect(state.chatSessionPickerResult).toBeNull();
expect(state.chatSessionPickerAppliedQuery).toBe("");

View File

@@ -256,7 +256,7 @@ describe("renderQuickSettings", () => {
);
expect(container.querySelector(".qs-assistant-avatar")?.getAttribute("src")).toBe(
"apple-touch-icon.png",
"/apple-touch-icon.png",
);
expect(expectAssistantAvatarSource(container)).toEqual({
label: "IDENTITY.md",

View File

@@ -566,6 +566,11 @@ function resolveBoardEmptyState(props: SkillWorkshopProps): {
body: "Skill Workshop proposals will appear here when your agent drafts them.",
};
}
return {
icon: "search",
title: "No proposals here",
body: "Skill Workshop proposals will appear here when your agent drafts them.",
};
}
function renderEmptyStateIcon(icon: SkillWorkshopEmptyIcon) {
@@ -614,6 +619,7 @@ function renderEmptyStateIcon(icon: SkillWorkshopEmptyIcon) {
</svg>
`;
}
return nothing;
}
function renderWorkshopEmptyState(props: SkillWorkshopProps) {