refactor: normalize skills UI status keys

This commit is contained in:
Peter Steinberger
2026-01-08 20:13:21 +00:00
parent 5a2242ee92
commit 0c74ef25d6
3 changed files with 35 additions and 18 deletions

View File

@@ -396,11 +396,12 @@ export function renderApp(state: AppViewState) {
messages: state.skillMessages,
busyKey: state.skillsBusyKey,
onFilterChange: (next) => (state.skillsFilter = next),
onRefresh: () => loadSkills(state),
onRefresh: () => loadSkills(state, { clearMessages: true }),
onToggle: (key, enabled) => updateSkillEnabled(state, key, enabled),
onEdit: (key, value) => updateSkillEdit(state, key, value),
onSaveKey: (key) => saveSkillApiKey(state, key),
onInstall: (name, installId) => installSkill(state, name, installId),
onInstall: (skillKey, name, installId) =>
installSkill(state, skillKey, name, installId),
})
: nothing}

View File

@@ -19,6 +19,10 @@ export type SkillMessage = {
export type SkillMessageMap = Record<string, SkillMessage>;
type LoadSkillsOptions = {
clearMessages?: boolean;
};
function setSkillMessage(state: SkillsState, key: string, message?: SkillMessage) {
if (!key.trim()) return;
const next = { ...state.skillMessages };
@@ -27,7 +31,15 @@ function setSkillMessage(state: SkillsState, key: string, message?: SkillMessage
state.skillMessages = next;
}
export async function loadSkills(state: SkillsState) {
function getErrorMessage(err: unknown) {
if (err instanceof Error) return err.message;
return String(err);
}
export async function loadSkills(state: SkillsState, options?: LoadSkillsOptions) {
if (options?.clearMessages && Object.keys(state.skillMessages).length > 0) {
state.skillMessages = {};
}
if (!state.client || !state.connected) return;
if (state.skillsLoading) return;
state.skillsLoading = true;
@@ -38,7 +50,7 @@ export async function loadSkills(state: SkillsState) {
| undefined;
if (res) state.skillsReport = res;
} catch (err) {
state.skillsError = String(err);
state.skillsError = getErrorMessage(err);
} finally {
state.skillsLoading = false;
}
@@ -68,10 +80,11 @@ export async function updateSkillEnabled(
message: enabled ? "Skill enabled" : "Skill disabled",
});
} catch (err) {
state.skillsError = String(err);
const message = getErrorMessage(err);
state.skillsError = message;
setSkillMessage(state, skillKey, {
kind: "error",
message: String(err),
message,
});
} finally {
state.skillsBusyKey = null;
@@ -91,10 +104,11 @@ export async function saveSkillApiKey(state: SkillsState, skillKey: string) {
message: "API key saved",
});
} catch (err) {
state.skillsError = String(err);
const message = getErrorMessage(err);
state.skillsError = message;
setSkillMessage(state, skillKey, {
kind: "error",
message: String(err),
message,
});
} finally {
state.skillsBusyKey = null;
@@ -103,11 +117,12 @@ export async function saveSkillApiKey(state: SkillsState, skillKey: string) {
export async function installSkill(
state: SkillsState,
skillKey: string,
name: string,
installId: string,
) {
if (!state.client || !state.connected) return;
state.skillsBusyKey = name;
state.skillsBusyKey = skillKey;
state.skillsError = null;
try {
const result = (await state.client.request("skills.install", {
@@ -116,15 +131,16 @@ export async function installSkill(
timeoutMs: 120000,
})) as { ok?: boolean; message?: string };
await loadSkills(state);
setSkillMessage(state, name, {
setSkillMessage(state, skillKey, {
kind: "success",
message: result?.message ?? "Installed",
});
} catch (err) {
state.skillsError = String(err);
setSkillMessage(state, name, {
const message = getErrorMessage(err);
state.skillsError = message;
setSkillMessage(state, skillKey, {
kind: "error",
message: String(err),
message,
});
} finally {
state.skillsBusyKey = null;

View File

@@ -17,7 +17,7 @@ export type SkillsProps = {
onToggle: (skillKey: string, enabled: boolean) => void;
onEdit: (skillKey: string, value: string) => void;
onSaveKey: (skillKey: string) => void;
onInstall: (name: string, installId: string) => void;
onInstall: (skillKey: string, name: string, installId: string) => void;
};
export function renderSkills(props: SkillsProps) {
@@ -73,10 +73,9 @@ export function renderSkills(props: SkillsProps) {
}
function renderSkill(skill: SkillStatusEntry, props: SkillsProps) {
const busy = props.busyKey === skill.skillKey || props.busyKey === skill.name;
const busy = props.busyKey === skill.skillKey;
const apiKey = props.edits[skill.skillKey] ?? "";
const message =
props.messages[skill.skillKey] ?? props.messages[skill.name] ?? null;
const message = props.messages[skill.skillKey] ?? null;
const canInstall =
skill.install.length > 0 && skill.missing.bins.length > 0;
const missing = [
@@ -130,7 +129,8 @@ function renderSkill(skill: SkillStatusEntry, props: SkillsProps) {
? html`<button
class="btn"
?disabled=${busy}
@click=${() => props.onInstall(skill.name, skill.install[0].id)}
@click=${() =>
props.onInstall(skill.skillKey, skill.name, skill.install[0].id)}
>
${busy ? "Installing…" : skill.install[0].label}
</button>`