chore: add toggle loading sever MCP (#5225)
* chore: add toggle loading sever mcp * chore: remove duplicate classname * chore: remove log * chore: remove log * fix: save server config --------- Co-authored-by: Louis <louis@jan.ai>
This commit is contained in:
parent
891c149f1b
commit
8ba4b0be36
@ -2,20 +2,27 @@ import * as React from 'react'
|
|||||||
import * as SwitchPrimitive from '@radix-ui/react-switch'
|
import * as SwitchPrimitive from '@radix-ui/react-switch'
|
||||||
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
import { IconLoader2 } from '@tabler/icons-react'
|
||||||
|
|
||||||
function Switch({
|
type SwitchProps = React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
||||||
className,
|
loading?: boolean
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
|
function Switch({ loading, className, ...props }: SwitchProps) {
|
||||||
return (
|
return (
|
||||||
<SwitchPrimitive.Root
|
<SwitchPrimitive.Root
|
||||||
data-slot="switch"
|
data-slot="switch"
|
||||||
className={cn(
|
className={cn(
|
||||||
'peer cursor-pointer data-[state=checked]:bg-accent data-[state=unchecked]:bg-main-view-fg/20 focus-visible:border-none inline-flex h-[18px] w-8.5 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50',
|
'relative peer cursor-pointer data-[state=checked]:bg-accent data-[state=unchecked]:bg-main-view-fg/20 focus-visible:border-none inline-flex h-[18px] w-8.5 shrink-0 items-center rounded-full border border-transparent shadow-xs outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 transition-all',
|
||||||
|
loading && 'w-4.5 pointer-events-none',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
{loading && (
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center z-10 size-3.5 top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2">
|
||||||
|
<IconLoader2 className="animate-spin text-main-view-fg/50" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<SwitchPrimitive.Thumb
|
<SwitchPrimitive.Thumb
|
||||||
data-slot="switch-thumb"
|
data-slot="switch-thumb"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@ -216,7 +216,6 @@ const DropdownModelProvider = ({
|
|||||||
// Add the filtered items to their respective groups
|
// Add the filtered items to their respective groups
|
||||||
filteredItems.forEach((item) => {
|
filteredItems.forEach((item) => {
|
||||||
const providerKey = item.provider.provider
|
const providerKey = item.provider.provider
|
||||||
console.log(providerKey, 'providerKey')
|
|
||||||
if (!groups[providerKey]) {
|
if (!groups[providerKey]) {
|
||||||
groups[providerKey] = []
|
groups[providerKey] = []
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ type MCPServerStoreState = {
|
|||||||
mcpServers: MCPServers
|
mcpServers: MCPServers
|
||||||
loading: boolean
|
loading: boolean
|
||||||
deletedServerKeys: string[]
|
deletedServerKeys: string[]
|
||||||
|
getServerConfig: (key: string) => MCPServerConfig | undefined
|
||||||
setLeftPanel: (value: boolean) => void
|
setLeftPanel: (value: boolean) => void
|
||||||
addServer: (key: string, config: MCPServerConfig) => void
|
addServer: (key: string, config: MCPServerConfig) => void
|
||||||
editServer: (key: string, config: MCPServerConfig) => void
|
editServer: (key: string, config: MCPServerConfig) => void
|
||||||
@ -34,7 +35,11 @@ export const useMCPServers = create<MCPServerStoreState>()((set, get) => ({
|
|||||||
loading: false,
|
loading: false,
|
||||||
deletedServerKeys: [],
|
deletedServerKeys: [],
|
||||||
setLeftPanel: (value) => set({ open: value }),
|
setLeftPanel: (value) => set({ open: value }),
|
||||||
|
getServerConfig: (key) => {
|
||||||
|
const mcpServers = get().mcpServers
|
||||||
|
// Return the server configuration if it exists, otherwise return undefined
|
||||||
|
return mcpServers[key] ? mcpServers[key] : undefined
|
||||||
|
},
|
||||||
// Add a new MCP server or update if the key already exists
|
// Add a new MCP server or update if the key already exists
|
||||||
addServer: (key, config) =>
|
addServer: (key, config) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
|||||||
@ -35,6 +35,7 @@ function MCPServers() {
|
|||||||
deleteServer,
|
deleteServer,
|
||||||
syncServers,
|
syncServers,
|
||||||
syncServersAndRestart,
|
syncServersAndRestart,
|
||||||
|
getServerConfig,
|
||||||
} = useMCPServers()
|
} = useMCPServers()
|
||||||
const { allowAllMCPPermissions, setAllowAllMCPPermissions } =
|
const { allowAllMCPPermissions, setAllowAllMCPPermissions } =
|
||||||
useToolApproval()
|
useToolApproval()
|
||||||
@ -56,6 +57,9 @@ function MCPServers() {
|
|||||||
MCPServerConfig | Record<string, MCPServerConfig> | undefined
|
MCPServerConfig | Record<string, MCPServerConfig> | undefined
|
||||||
>(undefined)
|
>(undefined)
|
||||||
const [connectedServers, setConnectedServers] = useState<string[]>([])
|
const [connectedServers, setConnectedServers] = useState<string[]>([])
|
||||||
|
const [loadingServers, setLoadingServers] = useState<{
|
||||||
|
[key: string]: boolean
|
||||||
|
}>({})
|
||||||
|
|
||||||
const handleOpenDialog = (serverKey?: string) => {
|
const handleOpenDialog = (serverKey?: string) => {
|
||||||
if (serverKey) {
|
if (serverKey) {
|
||||||
@ -70,10 +74,13 @@ function MCPServers() {
|
|||||||
setOpen(true)
|
setOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaveServer = (name: string, config: MCPServerConfig) => {
|
const handleSaveServer = async (name: string, config: MCPServerConfig) => {
|
||||||
|
try {
|
||||||
|
await toggleServer(name, false)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deactivating server:', error)
|
||||||
|
}
|
||||||
if (editingKey) {
|
if (editingKey) {
|
||||||
// Edit existing server
|
|
||||||
|
|
||||||
// If server name changed, delete old one and add new one
|
// If server name changed, delete old one and add new one
|
||||||
if (editingKey !== name) {
|
if (editingKey !== name) {
|
||||||
deleteServer(editingKey)
|
deleteServer(editingKey)
|
||||||
@ -85,7 +92,9 @@ function MCPServers() {
|
|||||||
// Add new server
|
// Add new server
|
||||||
addServer(name, config)
|
addServer(name, config)
|
||||||
}
|
}
|
||||||
syncServersAndRestart()
|
|
||||||
|
syncServers()
|
||||||
|
await toggleServer(name, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEdit = (serverKey: string) => {
|
const handleEdit = (serverKey: string) => {
|
||||||
@ -105,7 +114,7 @@ function MCPServers() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOpenJsonEditor = (serverKey?: string) => {
|
const handleOpenJsonEditor = async (serverKey?: string) => {
|
||||||
if (serverKey) {
|
if (serverKey) {
|
||||||
// Edit single server JSON
|
// Edit single server JSON
|
||||||
setJsonServerName(serverKey)
|
setJsonServerName(serverKey)
|
||||||
@ -118,12 +127,19 @@ function MCPServers() {
|
|||||||
setJsonEditorOpen(true)
|
setJsonEditorOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSaveJson = (
|
const handleSaveJson = async (
|
||||||
data: MCPServerConfig | Record<string, MCPServerConfig>
|
data: MCPServerConfig | Record<string, MCPServerConfig>
|
||||||
) => {
|
) => {
|
||||||
if (jsonServerName) {
|
if (jsonServerName) {
|
||||||
|
try {
|
||||||
|
await toggleServer(jsonServerName, false)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deactivating server:', error)
|
||||||
|
}
|
||||||
// Save single server
|
// Save single server
|
||||||
editServer(jsonServerName, data as MCPServerConfig)
|
editServer(jsonServerName, data as MCPServerConfig)
|
||||||
|
syncServers()
|
||||||
|
toggleServer(jsonServerName, true)
|
||||||
} else {
|
} else {
|
||||||
// Save all servers
|
// Save all servers
|
||||||
// Clear existing servers first
|
// Clear existing servers first
|
||||||
@ -138,23 +154,24 @@ function MCPServers() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
syncServersAndRestart()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleServer = (serverKey: string, active: boolean) => {
|
const toggleServer = (serverKey: string, active: boolean) => {
|
||||||
if (serverKey)
|
if (serverKey) {
|
||||||
if (active)
|
setLoadingServers((prev) => ({ ...prev, [serverKey]: true }))
|
||||||
|
const config = getServerConfig(serverKey)
|
||||||
|
if (active && config) {
|
||||||
invoke('activate_mcp_server', {
|
invoke('activate_mcp_server', {
|
||||||
name: serverKey,
|
name: serverKey,
|
||||||
config: {
|
config: {
|
||||||
...(mcpServers[serverKey] as MCPServerConfig),
|
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
||||||
active,
|
active,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Save single server
|
// Save single server
|
||||||
editServer(serverKey, {
|
editServer(serverKey, {
|
||||||
...(mcpServers[serverKey] as MCPServerConfig),
|
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
||||||
active,
|
active,
|
||||||
})
|
})
|
||||||
syncServers()
|
syncServers()
|
||||||
@ -164,25 +181,30 @@ function MCPServers() {
|
|||||||
getConnectedServers().then(setConnectedServers)
|
getConnectedServers().then(setConnectedServers)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
editServer(serverKey, {
|
||||||
|
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
||||||
|
active: false,
|
||||||
|
})
|
||||||
toast.error(error, {
|
toast.error(error, {
|
||||||
description:
|
description:
|
||||||
'Please check the parameters according to the tutorial.',
|
'Please check the parameters according to the tutorial.',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
else {
|
.finally(() => {
|
||||||
|
setLoadingServers((prev) => ({ ...prev, [serverKey]: false }))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
editServer(serverKey, {
|
editServer(serverKey, {
|
||||||
...(mcpServers[serverKey] as MCPServerConfig),
|
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
||||||
active,
|
active,
|
||||||
})
|
})
|
||||||
syncServers()
|
syncServers()
|
||||||
invoke('deactivate_mcp_server', { name: serverKey })
|
invoke('deactivate_mcp_server', { name: serverKey }).finally(() => {
|
||||||
.catch((error) => {
|
getConnectedServers().then(setConnectedServers)
|
||||||
toast.error(`Failed to deactivate server ${serverKey}: ${error}`)
|
setLoadingServers((prev) => ({ ...prev, [serverKey]: false }))
|
||||||
})
|
})
|
||||||
.finally(() => {
|
|
||||||
getConnectedServers().then(setConnectedServers)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -334,7 +356,8 @@ function MCPServers() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="ml-2">
|
<div className="ml-2">
|
||||||
<Switch
|
<Switch
|
||||||
checked={config.active === false ? false : true}
|
checked={config.active}
|
||||||
|
loading={!!loadingServers[key]}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
toggleServer(key, checked)
|
toggleServer(key, checked)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user