feat(card): show cached netx skills per capability group

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
oliver 2026-10-16 23:23:40 +08:00
parent fa82f530e9
commit 056f2d4ea3
9 changed files with 285 additions and 96 deletions

View file

@ -1435,6 +1435,14 @@ function CapabilityGroupBlock(props) {
]
}),
props.targets,
props.skills ? /* @__PURE__ */ jsx_runtime.jsxs("p", {
className: "dsh-nx-hint",
children: [
props.skillsLabel ?? "Skill",
":",
props.skills.length === 0 ? props.skillsNoneLabel ?? "" : props.skills.map((skill) => `${skill.name}(${props.skillFilesLabel?.(skill.files) ?? skill.files})`).join("、")
]
}) : null,
props.tools ? /* @__PURE__ */ jsx_runtime.jsxs("details", {
className: "dsh-nx-toolList",
children: [
@ -1806,7 +1814,12 @@ function NetxopsCard(props) {
bizMonitor: catalogTools.filter((tool) => tool.group === "bizMonitor")
};
const disabledSet = new Set(parseDisabledTools(state.disabledTools.text));
const catalogSkills = state.mcpCatalog?.skills ?? [];
const skillsOf = (group) => catalogSkills.filter((skill) => skill.group === group);
const toolProps = {
skillsLabel: t("groupSkills"),
skillsNoneLabel: t("groupSkillsNone"),
skillFilesLabel: (count) => t("skillFiles").replace("{count}", String(count)),
disabledTools: disabledSet,
writeBadge: t("toolWriteBadge"),
emptyLabel: t("toolListEmpty"),
@ -1820,6 +1833,7 @@ function NetxopsCard(props) {
title: t("groupOps"),
toolCount: byGroup.ops.length,
tools: byGroup.ops,
skills: skillsOf("ops"),
targets: targets("groupOpsPresets", state.groupOpsPresets),
inPresetLabel: t("groupInPreset"),
publicLabel: t("groupPublic"),
@ -1838,6 +1852,7 @@ function NetxopsCard(props) {
title: t("groupTopology"),
toolCount: byGroup.topology.length,
tools: byGroup.topology,
skills: skillsOf("topology"),
targets: targets("groupTopologyPresets", state.groupTopologyPresets),
inPresetLabel: t("groupInPreset"),
publicLabel: t("groupPublic"),
@ -1856,6 +1871,7 @@ function NetxopsCard(props) {
title: t("groupBizMonitor"),
toolCount: byGroup.bizMonitor.length,
tools: byGroup.bizMonitor,
skills: skillsOf("bizMonitor"),
targets: targets("groupBizMonitorPresets", state.groupBizMonitorPresets),
inPresetLabel: t("groupInPreset"),
publicLabel: t("groupPublic"),
@ -2454,7 +2470,9 @@ var EMPTY3 = {
error: "",
listedAt: null,
fromCache: false,
tools: []
tools: [],
skills: [],
skillsListedAt: null
};
function asMcpCatalogView(value) {
if (value === null || typeof value !== "object" || Array.isArray(value))
@ -2478,13 +2496,28 @@ function asMcpCatalogView(value) {
});
}
}
const skills = [];
if (Array.isArray(row.skills)) {
for (const raw of row.skills) {
if (!raw || typeof raw !== "object" || Array.isArray(raw))
continue;
const s = raw;
const group = s.group === "ops" || s.group === "topology" || s.group === "bizMonitor" ? s.group : null;
const name = typeof s.name === "string" ? s.name : "";
if (!group || !name)
continue;
skills.push({ group, name, files: typeof s.files === "number" ? s.files : 0 });
}
}
return {
phase: typeof row.phase === "string" ? row.phase : "idle",
mcpUrl: typeof row.mcpUrl === "string" ? row.mcpUrl : "",
error: typeof row.error === "string" ? row.error : "",
listedAt: typeof row.listedAt === "string" ? row.listedAt : null,
fromCache: row.fromCache === true,
tools
tools,
skills,
skillsListedAt: typeof row.skillsListedAt === "string" ? row.skillsListedAt : null
};
}
async function fetchMcpCatalog(call, signal) {
@ -3243,6 +3276,9 @@ var en = {
readOnlyOnly: "Read-only tools only",
toolWriteBadge: "write",
toolListEmpty: "No tools yet",
groupSkills: "Skills",
groupSkillsNone: "None pulled from netx",
skillFiles: "{count} files",
sessionsExportCount: "{count} sessions",
sessionsExportUnavailable: "Export unavailable",
sessionsExportNoPersistence: "Session store unavailable.",
@ -3336,6 +3372,9 @@ var zh = {
readOnlyOnly: "只允许只读工具",
toolWriteBadge: "写",
toolListEmpty: "暂无工具清单",
groupSkills: "Skill",
groupSkillsNone: "未从 netx 拉到",
skillFiles: "{count} 个文件",
sessionsExportCount: "{count} 个会话",
sessionsExportUnavailable: "无法导出",
sessionsExportNoPersistence: "会话存储不可用。",