mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 00:15:23 +02:00
feat: add useMCPDeepLink hook and MCPDeepLinkDialog for deep link state handling
This commit is contained in:
parent
180c023af9
commit
d67669768a
4 changed files with 84 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ import type { TMessage } from 'librechat-data-provider';
|
|||
import type { ChatFormValues } from '~/common';
|
||||
import { ChatContext, AddedChatContext, useFileMapContext, ChatFormProvider } from '~/Providers';
|
||||
import { useAddedResponse, useResumeOnLoad, useAdaptiveSSE, useChatHelpers } from '~/hooks';
|
||||
import MCPDeepLinkDialog from '~/components/SidePanel/MCPBuilder/MCPDeepLinkDialog';
|
||||
import ConversationStarters from './Input/ConversationStarters';
|
||||
import { useGetMessagesByConvoId } from '~/data-provider';
|
||||
import MessagesView from './Messages/MessagesView';
|
||||
|
|
@ -80,6 +81,7 @@ function ChatView({ index = 0 }: { index?: number }) {
|
|||
<ChatFormProvider {...methods}>
|
||||
<ChatContext.Provider value={chatHelpers}>
|
||||
<AddedChatContext.Provider value={addedChatHelpers}>
|
||||
<MCPDeepLinkDialog />
|
||||
<Presentation>
|
||||
<div className="relative flex h-full w-full flex-col">
|
||||
{!isLoading && <Header />}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import { useMCPDeepLink, useHasAccess } from '~/hooks';
|
||||
import MCPServerDialog from './MCPServerDialog';
|
||||
|
||||
export default function MCPDeepLinkDialog() {
|
||||
const { isOpen, initialValues, onOpenChange } = useMCPDeepLink();
|
||||
|
||||
const hasCreateAccess = useHasAccess({
|
||||
permissionType: PermissionTypes.MCP_SERVERS,
|
||||
permission: Permissions.CREATE,
|
||||
});
|
||||
|
||||
if (!hasCreateAccess) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MCPServerDialog open={isOpen} onOpenChange={onOpenChange} initialValues={initialValues} />
|
||||
);
|
||||
}
|
||||
|
|
@ -3,3 +3,4 @@ export * from './useMCPSelect';
|
|||
export * from './useVisibleTools';
|
||||
export * from './useMCPServerManager';
|
||||
export { useRemoveMCPTool } from './useRemoveMCPTool';
|
||||
export { default as useMCPDeepLink } from './useMCPDeepLink';
|
||||
|
|
|
|||
61
client/src/hooks/MCP/useMCPDeepLink.ts
Normal file
61
client/src/hooks/MCP/useMCPDeepLink.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import type { MCPServerFormData } from '~/components/SidePanel/MCPBuilder/MCPServerDialog/hooks/useMCPServerForm';
|
||||
|
||||
const VALID_TRANSPORTS = new Set<MCPServerFormData['type']>(['streamable-http', 'sse']);
|
||||
|
||||
interface MCPDeepLinkState {
|
||||
mcpName?: string;
|
||||
mcpUrl?: string;
|
||||
mcpTransport?: string;
|
||||
}
|
||||
|
||||
interface MCPDeepLinkResult {
|
||||
isOpen: boolean;
|
||||
initialValues: Partial<MCPServerFormData> | undefined;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export default function useMCPDeepLink(): MCPDeepLinkResult {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [initialValues, setInitialValues] = useState<Partial<MCPServerFormData> | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const state = location.state as MCPDeepLinkState | null;
|
||||
if (!state?.mcpName && !state?.mcpUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const values: Partial<MCPServerFormData> = {};
|
||||
if (state.mcpName) {
|
||||
values.title = state.mcpName;
|
||||
}
|
||||
if (state.mcpUrl) {
|
||||
values.url = state.mcpUrl;
|
||||
}
|
||||
if (
|
||||
state.mcpTransport &&
|
||||
VALID_TRANSPORTS.has(state.mcpTransport as MCPServerFormData['type'])
|
||||
) {
|
||||
values.type = state.mcpTransport as MCPServerFormData['type'];
|
||||
}
|
||||
|
||||
setInitialValues(values);
|
||||
setIsOpen(true);
|
||||
|
||||
navigate(location.pathname, { replace: true, state: {} });
|
||||
}, [location.state, location.pathname, navigate]);
|
||||
|
||||
const onOpenChange = useCallback((open: boolean) => {
|
||||
setIsOpen(open);
|
||||
if (!open) {
|
||||
setInitialValues(undefined);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { isOpen, initialValues, onOpenChange };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue