From f1978d9dda895399b28ebddf29d514b55b4493ab Mon Sep 17 00:00:00 2001 From: Curry Yang <163384738+CurryYangxx@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:43:23 +0800 Subject: [PATCH] feat: integrate rjsf (#9120) --- package-lock.json | 176 ++++++++++++++++++ packages/insomnia/package.json | 3 + ....$projectId.workspace.$workspaceId.mcp.tsx | 10 +- .../ui/components/mcp/mcp-request-pane.tsx | 47 ++++- .../insomnia/src/ui/components/rjsf/index.tsx | 5 + .../insomnia/src/ui/components/rjsf/theme.tsx | 22 +++ 6 files changed, 255 insertions(+), 8 deletions(-) create mode 100644 packages/insomnia/src/ui/components/rjsf/index.tsx create mode 100644 packages/insomnia/src/ui/components/rjsf/theme.tsx diff --git a/package-lock.json b/package-lock.json index 3c3d387bb5..c6326108cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7687,6 +7687,73 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@rjsf/core": { + "version": "6.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@rjsf/core/-/core-6.0.0-beta.15.tgz", + "integrity": "sha512-VF6o/tetnYxgdv19qDgTdElkLQlPHH/2yn0Tyz7J8lUVucmYuPEctV6qo88NJUAtvts9EFLr7SYKaMQpfNJonQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "markdown-to-jsx": "^7.7.13", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@rjsf/utils": "^6.0.0-beta.15", + "react": ">=18" + } + }, + "node_modules/@rjsf/utils": { + "version": "6.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-6.0.0-beta.15.tgz", + "integrity": "sha512-AWF0/OVRpdkxNrp1JIrTL+ryzGGffm/IXSICq+c0Ju3HIdcV0kvRDrlQtmdgbIbjdcWogS1Gg97cFhk/DzgjhQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "fast-uri": "^3.0.6", + "json-schema-merge-allof": "^0.8.1", + "jsonpointer": "^5.0.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "react": ">=18" + } + }, + "node_modules/@rjsf/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rjsf/validator-ajv8": { + "version": "6.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-6.0.0-beta.15.tgz", + "integrity": "sha512-M40hmygBfR8NlaR3JEiBJIqs03Qli7F5DRS7ypFDBDsZLcSm1Kd6BWbjC3EM2IutYyTgxg6lvi1lQw95PqqcYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^2.1.1", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@rjsf/utils": "^6.0.0-beta.15" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.32", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz", @@ -13260,6 +13327,29 @@ "node": ">= 0.6" } }, + "node_modules/compute-gcd": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", + "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", + "dev": true, + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, + "node_modules/compute-lcm": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", + "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", + "dev": true, + "dependencies": { + "compute-gcd": "^1.2.1", + "validate.io-array": "^1.0.3", + "validate.io-function": "^1.0.2", + "validate.io-integer-array": "^1.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -19185,6 +19275,31 @@ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "license": "(AFL-2.1 OR BSD-3-Clause)" }, + "node_modules/json-schema-compare": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", + "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.4" + } + }, + "node_modules/json-schema-merge-allof": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", + "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "compute-lcm": "^1.1.2", + "json-schema-compare": "^0.2.2", + "lodash": "^4.17.20" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/json-schema-ref-parser": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", @@ -19916,6 +20031,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -20203,6 +20325,19 @@ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==" }, + "node_modules/markdown-to-jsx": { + "version": "7.7.13", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.7.13.tgz", + "integrity": "sha512-DiueEq2bttFcSxUs85GJcQVrOr0+VVsPfj9AEUPqmExJ3f8P/iQNvZHltV4tm1XVhu1kl0vWBZWT3l99izRMaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/marked": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/marked/-/marked-5.1.2.tgz", @@ -26890,6 +27025,44 @@ "builtins": "^1.0.3" } }, + "node_modules/validate.io-array": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", + "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate.io-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", + "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==", + "dev": true + }, + "node_modules/validate.io-integer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", + "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", + "dev": true, + "dependencies": { + "validate.io-number": "^1.0.3" + } + }, + "node_modules/validate.io-integer-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", + "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", + "dev": true, + "dependencies": { + "validate.io-array": "^1.0.3", + "validate.io-integer": "^1.0.4" + } + }, + "node_modules/validate.io-number": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", + "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==", + "dev": true + }, "node_modules/validator": { "version": "13.15.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.0.tgz", @@ -28390,6 +28563,9 @@ "@react-router/fs-routes": "^7.7.0", "@react-router/node": "^7.7.0", "@react-router/serve": "^7.7.0", + "@rjsf/core": "^6.0.0-beta.15", + "@rjsf/utils": "^6.0.0-beta.15", + "@rjsf/validator-ajv8": "^6.0.0-beta.15", "@sentry/electron": "^6.5.0", "@tailwindcss/typography": "^0.5.16", "@tanstack/react-virtual": "3.13.6", diff --git a/packages/insomnia/package.json b/packages/insomnia/package.json index 3c6b66eb6d..81e387515c 100644 --- a/packages/insomnia/package.json +++ b/packages/insomnia/package.json @@ -115,6 +115,9 @@ "@react-router/fs-routes": "^7.7.0", "@react-router/node": "^7.7.0", "@react-router/serve": "^7.7.0", + "@rjsf/core": "^6.0.0-beta.15", + "@rjsf/utils": "^6.0.0-beta.15", + "@rjsf/validator-ajv8": "^6.0.0-beta.15", "@sentry/electron": "^6.5.0", "@tailwindcss/typography": "^0.5.16", "@tanstack/react-virtual": "3.13.6", diff --git a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp.tsx b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp.tsx index 673e28a723..ab9fa01d0d 100644 --- a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp.tsx +++ b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp.tsx @@ -46,7 +46,7 @@ type ToolItem = Tool & { type: 'tools' } & CommonItemProps; type ResourceItem = Resource & { type: 'resources' } & CommonItemProps; type ResourceTemplateItem = ResourceTemplate & { type: 'resources' } & CommonItemProps; type PromptItem = Prompt & { type: 'prompts' } & CommonItemProps; -type PrimitiveSubItemTypes = ToolItem | ResourceItem | ResourceTemplateItem | PromptItem; +export type PrimitiveSubItemTypes = ToolItem | ResourceItem | ResourceTemplateItem | PromptItem; interface PrimitiveTypeItem extends CommonItemProps { type: McpServerPrimitiveTypes; name: string; @@ -88,7 +88,7 @@ const McpPage = () => { const [mcpServerData, setMcpServerData] = useState(null); const [collapsedPrimitives, setCollapsedPrimitives] = useState([]); const [selectedPrimitiveItem, setSelectedPrimitiveItem] = useState(null); - + console.log('selectedPrimitiveItem', selectedPrimitiveItem); const getPrimitiveCollection = () => { const collection: (PrimitiveTypeItem | PrimitiveSubItemTypes)[] = []; if (mcpServerData) { @@ -437,7 +437,11 @@ const McpPage = () => { - + diff --git a/packages/insomnia/src/ui/components/mcp/mcp-request-pane.tsx b/packages/insomnia/src/ui/components/mcp/mcp-request-pane.tsx index 169fcf60a6..6d6feee514 100644 --- a/packages/insomnia/src/ui/components/mcp/mcp-request-pane.tsx +++ b/packages/insomnia/src/ui/components/mcp/mcp-request-pane.tsx @@ -1,13 +1,19 @@ -import React, { type FC } from 'react'; +import type { IChangeEvent } from '@rjsf/core'; +import type { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; +import React, { type FC, useEffect, useRef, useState } from 'react'; import { Button, Heading, Tab, TabList, TabPanel, Tabs } from 'react-aria-components'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; +import type { PrimitiveSubItemTypes } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp'; +import { InsomniaRjsfForm } from '~/ui/components/rjsf'; + import { type AuthTypes } from '../../../common/constants'; import type { Environment } from '../../../models/environment'; import { getAuthObjectOrNull } from '../../../network/authentication'; import { useMcpRequestLoaderData } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mcp.request.$requestId'; import { useRequestPatcher } from '../../hooks/use-request'; -import { CodeEditor } from '../.client/codemirror/code-editor'; +import { CodeEditor, type CodeEditorHandle } from '../.client/codemirror/code-editor'; import { AuthWrapper } from '../editors/auth/auth-wrapper'; import { readOnlyWebsocketPairs, RequestHeadersEditor } from '../editors/request-headers-editor'; import { Pane } from '../panes/pane'; @@ -35,10 +41,13 @@ const PaneReadOnlyBanner = () => { interface Props { environment: Environment | null; readyState: boolean; + selectedPrimitiveItem?: PrimitiveSubItemTypes | null; } -export const McpRequestPane: FC = ({ environment, readyState }) => { +export const McpRequestPane: FC = ({ environment, readyState, selectedPrimitiveItem }) => { const { activeRequest } = useMcpRequestLoaderData()!; + const [formData, setFormData] = useState({}); + const paramEditorRef = useRef(null); const requestId = activeRequest._id; const headersCount = activeRequest.headers.filter(h => !h.disabled).length + readOnlyWebsocketPairs.length; @@ -48,6 +57,25 @@ export const McpRequestPane: FC = ({ environment, readyState }) => { const uniqueKey = `${environment?.modified}::${requestId}`; const requestAuth = getAuthObjectOrNull(activeRequest.authentication); const isNoneOrInherited = requestAuth?.type === 'none' || requestAuth === null; + const toolsSchema = selectedPrimitiveItem?.type === 'tools' ? selectedPrimitiveItem.inputSchema : undefined; + + const handleRjsfFormChange = (e: IChangeEvent) => { + setFormData(e.formData); + paramEditorRef.current?.setValue(JSON.stringify(e.formData, null, 2)); + }; + + useEffect(() => { + setFormData({}); + paramEditorRef.current?.setValue(''); + }, [selectedPrimitiveItem]); + + const handleSend = () => { + window.main.mcp.primitive.callTool({ + name: selectedPrimitiveItem?.name || '', + parameters: formData, + requestId: requestId, + }); + }; return ( @@ -110,14 +138,22 @@ export const McpRequestPane: FC = ({ environment, readyState }) => { Parameter Builder
- TODO Parameter Builder UI + {toolsSchema && ( + + )}
@@ -126,6 +162,7 @@ export const McpRequestPane: FC = ({ environment, readyState }) => { Parameter Overview
{ + return ( + props.onChange(e.target.value)} + /> + ); +}; + +const themeWidgets: RegistryWidgetsType = { + TextWidget: CustomTextWidget, +}; +const themeTemplates = {}; + +const ThemeObject: ThemeProps = { + widgets: themeWidgets, + templates: themeTemplates, +}; +export default ThemeObject;