From 5a1a73e46d83438c27942cf6a9b60347e5124614 Mon Sep 17 00:00:00 2001
From: varkart <44122128+varkart@users.noreply.github.com>
Date: Wed, 1 Jul 2026 14:44:26 -0600
Subject: [PATCH] feat: add Add Skill / Add MCP buttons to all-skills and
all-mcps views
---
src/components/views/AllMcpsView.tsx | 18 ++++++++++++++++--
src/components/views/AllSkillsView.tsx | 18 ++++++++++++++++--
src/components/views/ViewManager.tsx | 12 ++++++++----
src/useViewRouter.ts | 11 ++++++++++-
src/viewRouter.ts | 18 ++++++++++++++++--
5 files changed, 66 insertions(+), 11 deletions(-)
diff --git a/src/components/views/AllMcpsView.tsx b/src/components/views/AllMcpsView.tsx
index 26448cd..d944a4a 100644
--- a/src/components/views/AllMcpsView.tsx
+++ b/src/components/views/AllMcpsView.tsx
@@ -9,6 +9,7 @@ interface Props {
tools: AiTool[]
onBack: () => void
onSelectMcp: (mcp: McpServer) => void
+ onAddMcp?: () => void
}
interface McpVariant extends McpServer {
@@ -41,7 +42,7 @@ function buildMcpGroups(tools: AiTool[]): McpGroup[] {
return groups.sort((a, b) => a.name.localeCompare(b.name))
}
-export default function AllMcpsView({ tools, onSelectMcp }: Props) {
+export default function AllMcpsView({ tools, onSelectMcp, onAddMcp }: Props) {
const [query, setQuery] = useState('')
const { installedTools, selectedTools, toggleTool, allSelected } = useProviderFilter(tools)
const groups = useMemo(() => buildMcpGroups(tools), [tools])
@@ -65,8 +66,21 @@ export default function AllMcpsView({ tools, onSelectMcp }: Props) {
return (
-
+
{countLabel}
+ {onAddMcp && (
+
+ )}
diff --git a/src/components/views/AllSkillsView.tsx b/src/components/views/AllSkillsView.tsx
index ceae73e..ba49240 100644
--- a/src/components/views/AllSkillsView.tsx
+++ b/src/components/views/AllSkillsView.tsx
@@ -9,6 +9,7 @@ interface Props {
tools: AiTool[]
onBack: () => void
onSelectSkill: (skill: Skill) => void
+ onAddSkill?: () => void
}
interface SkillVariant extends Skill {
@@ -41,7 +42,7 @@ function buildGroups(tools: AiTool[]): SkillGroup[] {
return groups.sort((a, b) => a.name.localeCompare(b.name))
}
-export default function AllSkillsView({ tools, onSelectSkill }: Props) {
+export default function AllSkillsView({ tools, onSelectSkill, onAddSkill }: Props) {
const [query, setQuery] = useState('')
const { installedTools, selectedTools, toggleTool, allSelected } = useProviderFilter(tools)
const groups = useMemo(() => buildGroups(tools), [tools])
@@ -68,8 +69,21 @@ export default function AllSkillsView({ tools, onSelectSkill }: Props) {
return (
-
+
{countLabel}
+ {onAddSkill && (
+
+ )}
diff --git a/src/components/views/ViewManager.tsx b/src/components/views/ViewManager.tsx
index 659f1cd..1c330ed 100644
--- a/src/components/views/ViewManager.tsx
+++ b/src/components/views/ViewManager.tsx
@@ -27,6 +27,8 @@ export default function ViewManager({
selectMcp,
openSkillsPage,
openMcpsPage,
+ openAddSkill,
+ openAddMcp,
goTo,
escape,
query,
@@ -59,7 +61,7 @@ export default function ViewManager({
return (
goTo('llms-list')}
+ onBack={() => escape()}
onCreated={handleFetchTools}
/>
)
@@ -68,7 +70,7 @@ export default function ViewManager({
return (
goTo('llms-list')}
+ onBack={() => escape()}
onAdded={handleFetchTools}
/>
)
@@ -88,7 +90,7 @@ export default function ViewManager({
tool={selectedTool}
onBack={() => escape()}
onSelectSkill={skill => selectSkill(skill, 'skills-list')}
- onAddSkill={() => goTo('add-skill')}
+ onAddSkill={openAddSkill}
/>
)
}
@@ -98,7 +100,7 @@ export default function ViewManager({
tool={selectedTool}
onBack={() => escape()}
onSelectMcp={mcp => selectMcp(mcp, 'mcps-list')}
- onAddMcp={() => goTo('add-mcp')}
+ onAddMcp={openAddMcp}
/>
)
}
@@ -108,6 +110,7 @@ export default function ViewManager({
tools={tools}
onBack={() => escape()}
onSelectSkill={skill => selectSkill(skill, 'all-skills-list')}
+ onAddSkill={openAddSkill}
/>
)
}
@@ -117,6 +120,7 @@ export default function ViewManager({
tools={tools}
onBack={() => escape()}
onSelectMcp={mcp => selectMcp(mcp, 'all-mcps-list')}
+ onAddMcp={openAddMcp}
/>
)
}
diff --git a/src/useViewRouter.ts b/src/useViewRouter.ts
index d11b436..3cf36a5 100644
--- a/src/useViewRouter.ts
+++ b/src/useViewRouter.ts
@@ -22,6 +22,8 @@ export interface UseViewRouterResult extends RouterState {
selectMcp: (mcp: McpServer, fromView?: View) => void
openSkillsPage: () => void
openMcpsPage: () => void
+ openAddSkill: () => void
+ openAddMcp: () => void
goTo: (view: View) => void
escape: () => void
refreshSelected: (tools: AiTool[]) => void
@@ -71,16 +73,21 @@ export function useViewRouter(): UseViewRouterResult {
const openMcpsPage = useCallback(() => dispatch({ type: 'OPEN_MCPS_PAGE', fromView: state.view }), [state.view])
+ const openAddSkill = useCallback(() => dispatch({ type: 'OPEN_ADD_SKILL', fromView: state.view }), [state.view])
+
+ const openAddMcp = useCallback(() => dispatch({ type: 'OPEN_ADD_MCP', fromView: state.view }), [state.view])
+
const goTo = useCallback((view: View) => dispatch({ type: 'GO_TO', view }), [])
const escape = useCallback(() => {
const result = escapeTransition(
state.view, state.skillBackView, state.mcpBackView, state.selectedTool,
state.allSkillsBackView, state.allMcpsBackView,
+ state.addSkillBackView, state.addMcpBackView,
)
if (result.type === 'navigate') dispatch({ type: 'GO_TO', view: result.to })
else invoke('hide_window').catch(() => {})
- }, [state.view, state.skillBackView, state.mcpBackView, state.selectedTool, state.allSkillsBackView, state.allMcpsBackView])
+ }, [state.view, state.skillBackView, state.mcpBackView, state.selectedTool, state.allSkillsBackView, state.allMcpsBackView, state.addSkillBackView, state.addMcpBackView])
const refreshSelected = useCallback((tools: AiTool[]) => {
dispatch({ type: 'REFRESH_SELECTED', tools })
@@ -96,6 +103,8 @@ export function useViewRouter(): UseViewRouterResult {
selectMcp,
openSkillsPage,
openMcpsPage,
+ openAddSkill,
+ openAddMcp,
goTo,
escape,
refreshSelected,
diff --git a/src/viewRouter.ts b/src/viewRouter.ts
index e46e93a..fb32d94 100644
--- a/src/viewRouter.ts
+++ b/src/viewRouter.ts
@@ -53,6 +53,8 @@ export interface RouterState {
mcpBackView: View
allSkillsBackView: View
allMcpsBackView: View
+ addSkillBackView: View
+ addMcpBackView: View
}
export type RouterAction =
@@ -66,6 +68,8 @@ export type RouterAction =
| { type: 'OPEN_SKILLS_PAGE'; fromView: View }
| { type: 'OPEN_MCPS_PAGE'; fromView: View }
| { type: 'GO_TO'; view: View }
+ | { type: 'OPEN_ADD_SKILL'; fromView: View }
+ | { type: 'OPEN_ADD_MCP'; fromView: View }
| { type: 'REFRESH_SELECTED'; tools: AiTool[] }
export type EscapeResult =
@@ -79,6 +83,8 @@ export function escapeTransition(
selectedTool: AiTool | null,
allSkillsBackView: View,
allMcpsBackView: View,
+ addSkillBackView: View = 'all-skills-list',
+ addMcpBackView: View = 'all-mcps-list',
): EscapeResult {
if (view === 'skill-detail') return { type: 'navigate', to: skillBackView }
if (view === 'mcp-detail') return { type: 'navigate', to: mcpBackView }
@@ -88,8 +94,8 @@ export function escapeTransition(
if (view === 'skills-list') return { type: 'navigate', to: 'tool-detail' }
if (view === 'mcps-list') return { type: 'navigate', to: 'tool-detail' }
if (view === 'tool-detail') return { type: 'navigate', to: 'llms-list' }
- if (view === 'add-skill') return { type: 'navigate', to: 'llms-list' }
- if (view === 'add-mcp') return { type: 'navigate', to: 'llms-list' }
+ if (view === 'add-skill') return { type: 'navigate', to: addSkillBackView }
+ if (view === 'add-mcp') return { type: 'navigate', to: addMcpBackView }
if (view === 'llms-list') return { type: 'navigate', to: 'main' }
if (view === 'settings' || view === 'notifications' || view === 'logs')
return { type: 'navigate', to: 'main' }
@@ -107,6 +113,8 @@ export function initialRouterState(hash = ''): RouterState {
mcpBackView: 'tool-detail',
allSkillsBackView: 'tool-detail',
allMcpsBackView: 'tool-detail',
+ addSkillBackView: 'all-skills-list',
+ addMcpBackView: 'all-mcps-list',
}
}
@@ -139,6 +147,12 @@ export function routerReducer(state: RouterState, action: RouterAction): RouterS
case 'OPEN_MCPS_PAGE':
return { ...state, view: 'all-mcps-list', allMcpsBackView: action.fromView }
+ case 'OPEN_ADD_SKILL':
+ return { ...state, view: 'add-skill', addSkillBackView: action.fromView }
+
+ case 'OPEN_ADD_MCP':
+ return { ...state, view: 'add-mcp', addMcpBackView: action.fromView }
+
case 'GO_TO':
return { ...state, view: action.view }