@red-hat-developer-hub/backstage-plugin-intelligent-assistant 3.1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +10 -7
- package/config.d.ts +42 -13
- package/dist/alpha.d.ts +22 -7
- package/dist/api/NotebooksApiClient.esm.js +10 -0
- package/dist/api/NotebooksApiClient.esm.js.map +1 -1
- package/dist/api/notebooksApi.esm.js.map +1 -1
- package/dist/components/LightSpeedChat.esm.js +55 -53
- package/dist/components/LightSpeedChat.esm.js.map +1 -1
- package/dist/components/LightspeedChatContainer.esm.js +7 -5
- package/dist/components/LightspeedChatContainer.esm.js.map +1 -1
- package/dist/components/LightspeedDrawerContext.esm.js.map +1 -1
- package/dist/components/McpServersSettings.esm.js +4 -3
- package/dist/components/McpServersSettings.esm.js.map +1 -1
- package/dist/components/MessageBarModelSelector.esm.js +16 -5
- package/dist/components/MessageBarModelSelector.esm.js.map +1 -1
- package/dist/components/mcpServersDisplayUtils.esm.js.map +1 -1
- package/dist/components/notebooks/AddDocumentModal.esm.js +181 -66
- package/dist/components/notebooks/AddDocumentModal.esm.js.map +1 -1
- package/dist/components/notebooks/DocumentSidebar.esm.js +258 -27
- package/dist/components/notebooks/DocumentSidebar.esm.js.map +1 -1
- package/dist/components/notebooks/FileListItem.esm.js +15 -9
- package/dist/components/notebooks/FileListItem.esm.js.map +1 -1
- package/dist/components/notebooks/NotebookCard.esm.js +71 -14
- package/dist/components/notebooks/NotebookCard.esm.js.map +1 -1
- package/dist/components/notebooks/NotebookView.esm.js +202 -42
- package/dist/components/notebooks/NotebookView.esm.js.map +1 -1
- package/dist/components/notebooks/NotebooksTab.esm.js.map +1 -1
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js +122 -42
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js.map +1 -1
- package/dist/components/notebooks/UploadResourceScreen.esm.js +0 -1
- package/dist/components/notebooks/UploadResourceScreen.esm.js.map +1 -1
- package/dist/const.esm.js +2 -1
- package/dist/const.esm.js.map +1 -1
- package/dist/hooks/notebooks/useInlineEdit.esm.js +60 -0
- package/dist/hooks/notebooks/useInlineEdit.esm.js.map +1 -0
- package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js +4 -3
- package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js.map +1 -1
- package/dist/hooks/notebooks/useRenameDocument.esm.js +50 -0
- package/dist/hooks/notebooks/useRenameDocument.esm.js.map +1 -0
- package/dist/hooks/notebooks/useRenameNotebook.esm.js +48 -1
- package/dist/hooks/notebooks/useRenameNotebook.esm.js.map +1 -1
- package/dist/hooks/notebooks/useRenameNotebookWithAlert.esm.js +34 -0
- package/dist/hooks/notebooks/useRenameNotebookWithAlert.esm.js.map +1 -0
- package/dist/hooks/useLightspeedDeletePermission.esm.js +2 -2
- package/dist/hooks/useLightspeedDeletePermission.esm.js.map +1 -1
- package/dist/hooks/useLightspeedUpdatePermission.esm.js +2 -2
- package/dist/hooks/useLightspeedUpdatePermission.esm.js.map +1 -1
- package/dist/hooks/useLightspeedViewPermission.esm.js +6 -4
- package/dist/hooks/useLightspeedViewPermission.esm.js.map +1 -1
- package/dist/translations/de.esm.js +32 -17
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +32 -17
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +32 -17
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +32 -17
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +32 -17
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +34 -18
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/types.esm.js.map +1 -1
- package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
- package/dist/utils/notebook-upload-runner.esm.js +16 -0
- package/dist/utils/notebook-upload-runner.esm.js.map +1 -0
- package/package.json +5 -4
- package/dist/components/notebooks/RenameNotebookModal.esm.js +0 -187
- package/dist/components/notebooks/RenameNotebookModal.esm.js.map +0 -1
|
@@ -35,7 +35,12 @@ const LightspeedChatContainerInner = () => {
|
|
|
35
35
|
isError: modelsError,
|
|
36
36
|
refetch: refetchModels
|
|
37
37
|
} = useAllModels();
|
|
38
|
-
const {
|
|
38
|
+
const {
|
|
39
|
+
allowed: hasViewAccess,
|
|
40
|
+
loading,
|
|
41
|
+
iaChatAccessPermissionName,
|
|
42
|
+
iaChatUsePermissionName
|
|
43
|
+
} = useLightspeedViewPermission();
|
|
39
44
|
const { value: profile, loading: profileLoading } = useAsync(
|
|
40
45
|
async () => await identityApi.getProfileInfo()
|
|
41
46
|
);
|
|
@@ -107,10 +112,7 @@ const LightspeedChatContainerInner = () => {
|
|
|
107
112
|
PermissionRequiredState,
|
|
108
113
|
{
|
|
109
114
|
subject: t("permission.subject.plugin"),
|
|
110
|
-
permissions: [
|
|
111
|
-
"intelligent-assistant.chat.read",
|
|
112
|
-
"intelligent-assistant.chat.create"
|
|
113
|
-
],
|
|
115
|
+
permissions: [iaChatAccessPermissionName, iaChatUsePermissionName],
|
|
114
116
|
action: /* @__PURE__ */ jsxs(
|
|
115
117
|
Button,
|
|
116
118
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LightspeedChatContainer.esm.js","sources":["../../src/components/LightspeedChatContainer.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport '@patternfly/react-core/dist/styles/base-no-reset.css';\nimport '@patternfly/chatbot/dist/css/main.css';\n\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { Button } from '@material-ui/core';\nimport {\n StylesProvider as StylesProviderV4,\n useTheme,\n} from '@material-ui/core/styles';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { StylesProvider } from '@mui/styles';\nimport { QueryClientProvider } from '@tanstack/react-query';\n\nimport { useAllModels } from '../hooks/useAllModels';\nimport { useLightspeedViewPermission } from '../hooks/useLightspeedViewPermission';\nimport { useTopicRestrictionStatus } from '../hooks/useQuestionValidation';\nimport { useTranslation } from '../hooks/useTranslation';\nimport {\n generateClassName,\n generateClassNameV4,\n} from '../utils/generateClassName';\nimport queryClient from '../utils/queryClient';\nimport FileAttachmentContextProvider from './AttachmentContext';\nimport { LightspeedChat } from './LightSpeedChat';\nimport {\n LcoreNotConfiguredEmptyState,\n LightspeedChatModelsLoading,\n ModelsLoadErrorEmptyState,\n} from './LightspeedChatModelsState';\nimport PermissionRequiredState from './PermissionRequiredState';\n\nconst THEME_DARK = 'dark';\nconst THEME_DARK_CLASS = 'pf-v6-theme-dark';\nconst LAST_SELECTED_MODEL_KEY = 'lastSelectedModel';\n\n/**\n * Inner component that contains all the Lightspeed chat rendering logic\n */\nconst LightspeedChatContainerInner = () => {\n const {\n palette: { type },\n } = useTheme();\n const { t } = useTranslation();\n\n const identityApi = useApi(identityApiRef);\n\n const {\n data: models,\n isLoading: modelsLoading,\n isError: modelsError,\n refetch: refetchModels,\n } = useAllModels();\n\n const { allowed: hasViewAccess, loading } = useLightspeedViewPermission();\n\n const { value: profile, loading: profileLoading } = useAsync(\n async () => await identityApi.getProfileInfo(),\n );\n\n const [selectedModel, setSelectedModel] = useState('');\n const [selectedProvider, setSelectedProvider] = useState('');\n\n const { data: topicRestrictionEnabled } = useTopicRestrictionStatus();\n\n const modelsItems = useMemo(\n () =>\n models\n ? models\n .filter(model => model.model_type === 'llm')\n .map(m => ({\n label: m.provider_resource_id,\n value: m.provider_resource_id,\n provider: m.provider_id,\n }))\n : [],\n [models],\n );\n\n useLayoutEffect(() => {\n const htmlTagElement = document.documentElement;\n if (type === THEME_DARK) {\n htmlTagElement.classList.add(THEME_DARK_CLASS);\n } else {\n htmlTagElement.classList.remove(THEME_DARK_CLASS);\n }\n }, [type]);\n\n // Load last selected model from localStorage\n useEffect(() => {\n if (modelsItems.length > 0) {\n try {\n const storedData = localStorage.getItem(LAST_SELECTED_MODEL_KEY);\n const parsedData = storedData ? JSON.parse(storedData) : null;\n\n const storedModel = parsedData?.model\n ? modelsItems.find(m => m.value === parsedData.model)\n : null;\n\n if (storedModel) {\n setSelectedModel(storedModel.value);\n setSelectedProvider(storedModel.provider);\n } else {\n setSelectedModel(modelsItems[0].value);\n setSelectedProvider(modelsItems[0].provider);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\n 'Error loading last selected model from localStorage:',\n error,\n );\n setSelectedModel(modelsItems[0].value);\n setSelectedProvider(modelsItems[0].provider);\n }\n }\n }, [modelsItems]);\n\n // Save selected model to localStorage\n useEffect(() => {\n if (selectedModel && selectedProvider) {\n try {\n localStorage.setItem(\n LAST_SELECTED_MODEL_KEY,\n JSON.stringify({\n model: selectedModel,\n provider: selectedProvider,\n }),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\n 'Error saving last selected model to localStorage:',\n error,\n );\n }\n }\n }, [selectedModel, selectedProvider]);\n\n if (loading) {\n // Never return null inside the overlay modal: PatternFly's focus-trap requires at least\n // one tabbable node (e.g. after removing the modal close button). Locale switches can\n // briefly re-enter this loading state.\n return <LightspeedChatModelsLoading />;\n }\n\n if (!hasViewAccess) {\n return (\n <PermissionRequiredState\n subject={t('permission.subject.plugin')}\n permissions={[\n 'intelligent-assistant.chat.read',\n 'intelligent-assistant.chat.create',\n ]}\n action={\n <Button\n variant=\"outlined\"\n color=\"primary\"\n target=\"_blank\"\n href=\"https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/intelligent-assistant/plugins/intelligent-assistant/README.md#permission-framework-support\"\n >\n {t('common.readMore')} <OpenInNewIcon />\n </Button>\n }\n />\n );\n }\n\n if (modelsLoading) {\n return <LightspeedChatModelsLoading />;\n }\n\n // TanStack Query can keep the last successful `data` while `isError` is true after a\n // failed refetch. Prefer showing chat when we still have LLM rows; only use the full-page\n // error state when there is nothing usable to render.\n if (modelsError && modelsItems.length === 0) {\n return <ModelsLoadErrorEmptyState onRetry={() => refetchModels()} />;\n }\n\n if (modelsItems.length === 0) {\n return <LcoreNotConfiguredEmptyState />;\n }\n\n return (\n <FileAttachmentContextProvider>\n <LightspeedChat\n selectedModel={selectedModel}\n selectedProvider={selectedProvider}\n topicRestrictionEnabled={topicRestrictionEnabled ?? false}\n handleSelectedModel={item => {\n setSelectedModel(item);\n setSelectedProvider(\n modelsItems.find((m: any) => m.value === item)?.provider || '',\n );\n }}\n models={modelsItems}\n userName={profile?.displayName}\n avatar={profile?.picture}\n profileLoading={profileLoading}\n />\n </FileAttachmentContextProvider>\n );\n};\n\n/**\n * @public\n */\nexport const LightspeedChatContainer = () => {\n return (\n <StylesProvider generateClassName={generateClassName}>\n <StylesProviderV4 generateClassName={generateClassNameV4}>\n <QueryClientProvider client={queryClient}>\n <LightspeedChatContainerInner />\n </QueryClientProvider>\n </StylesProviderV4>\n </StylesProvider>\n );\n};\n"],"names":["StylesProviderV4"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LightspeedChatContainer.esm.js","sources":["../../src/components/LightspeedChatContainer.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport '@patternfly/react-core/dist/styles/base-no-reset.css';\nimport '@patternfly/chatbot/dist/css/main.css';\n\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { Button } from '@material-ui/core';\nimport {\n StylesProvider as StylesProviderV4,\n useTheme,\n} from '@material-ui/core/styles';\nimport OpenInNewIcon from '@mui/icons-material/OpenInNew';\nimport { StylesProvider } from '@mui/styles';\nimport { QueryClientProvider } from '@tanstack/react-query';\n\nimport { useAllModels } from '../hooks/useAllModels';\nimport { useLightspeedViewPermission } from '../hooks/useLightspeedViewPermission';\nimport { useTopicRestrictionStatus } from '../hooks/useQuestionValidation';\nimport { useTranslation } from '../hooks/useTranslation';\nimport {\n generateClassName,\n generateClassNameV4,\n} from '../utils/generateClassName';\nimport queryClient from '../utils/queryClient';\nimport FileAttachmentContextProvider from './AttachmentContext';\nimport { LightspeedChat } from './LightSpeedChat';\nimport {\n LcoreNotConfiguredEmptyState,\n LightspeedChatModelsLoading,\n ModelsLoadErrorEmptyState,\n} from './LightspeedChatModelsState';\nimport PermissionRequiredState from './PermissionRequiredState';\n\nconst THEME_DARK = 'dark';\nconst THEME_DARK_CLASS = 'pf-v6-theme-dark';\nconst LAST_SELECTED_MODEL_KEY = 'lastSelectedModel';\n\n/**\n * Inner component that contains all the Lightspeed chat rendering logic\n */\nconst LightspeedChatContainerInner = () => {\n const {\n palette: { type },\n } = useTheme();\n const { t } = useTranslation();\n\n const identityApi = useApi(identityApiRef);\n\n const {\n data: models,\n isLoading: modelsLoading,\n isError: modelsError,\n refetch: refetchModels,\n } = useAllModels();\n\n const {\n allowed: hasViewAccess,\n loading,\n iaChatAccessPermissionName,\n iaChatUsePermissionName,\n } = useLightspeedViewPermission();\n\n const { value: profile, loading: profileLoading } = useAsync(\n async () => await identityApi.getProfileInfo(),\n );\n\n const [selectedModel, setSelectedModel] = useState('');\n const [selectedProvider, setSelectedProvider] = useState('');\n\n const { data: topicRestrictionEnabled } = useTopicRestrictionStatus();\n\n const modelsItems = useMemo(\n () =>\n models\n ? models\n .filter(model => model.model_type === 'llm')\n .map(m => ({\n label: m.provider_resource_id,\n value: m.provider_resource_id,\n provider: m.provider_id,\n }))\n : [],\n [models],\n );\n\n useLayoutEffect(() => {\n const htmlTagElement = document.documentElement;\n if (type === THEME_DARK) {\n htmlTagElement.classList.add(THEME_DARK_CLASS);\n } else {\n htmlTagElement.classList.remove(THEME_DARK_CLASS);\n }\n }, [type]);\n\n // Load last selected model from localStorage\n useEffect(() => {\n if (modelsItems.length > 0) {\n try {\n const storedData = localStorage.getItem(LAST_SELECTED_MODEL_KEY);\n const parsedData = storedData ? JSON.parse(storedData) : null;\n\n const storedModel = parsedData?.model\n ? modelsItems.find(m => m.value === parsedData.model)\n : null;\n\n if (storedModel) {\n setSelectedModel(storedModel.value);\n setSelectedProvider(storedModel.provider);\n } else {\n setSelectedModel(modelsItems[0].value);\n setSelectedProvider(modelsItems[0].provider);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\n 'Error loading last selected model from localStorage:',\n error,\n );\n setSelectedModel(modelsItems[0].value);\n setSelectedProvider(modelsItems[0].provider);\n }\n }\n }, [modelsItems]);\n\n // Save selected model to localStorage\n useEffect(() => {\n if (selectedModel && selectedProvider) {\n try {\n localStorage.setItem(\n LAST_SELECTED_MODEL_KEY,\n JSON.stringify({\n model: selectedModel,\n provider: selectedProvider,\n }),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error(\n 'Error saving last selected model to localStorage:',\n error,\n );\n }\n }\n }, [selectedModel, selectedProvider]);\n\n if (loading) {\n // Never return null inside the overlay modal: PatternFly's focus-trap requires at least\n // one tabbable node (e.g. after removing the modal close button). Locale switches can\n // briefly re-enter this loading state.\n return <LightspeedChatModelsLoading />;\n }\n\n if (!hasViewAccess) {\n return (\n <PermissionRequiredState\n subject={t('permission.subject.plugin')}\n permissions={[iaChatAccessPermissionName, iaChatUsePermissionName]}\n action={\n <Button\n variant=\"outlined\"\n color=\"primary\"\n target=\"_blank\"\n href=\"https://github.com/redhat-developer/rhdh-plugins/blob/main/workspaces/intelligent-assistant/plugins/intelligent-assistant/README.md#permission-framework-support\"\n >\n {t('common.readMore')} <OpenInNewIcon />\n </Button>\n }\n />\n );\n }\n\n if (modelsLoading) {\n return <LightspeedChatModelsLoading />;\n }\n\n // TanStack Query can keep the last successful `data` while `isError` is true after a\n // failed refetch. Prefer showing chat when we still have LLM rows; only use the full-page\n // error state when there is nothing usable to render.\n if (modelsError && modelsItems.length === 0) {\n return <ModelsLoadErrorEmptyState onRetry={() => refetchModels()} />;\n }\n\n if (modelsItems.length === 0) {\n return <LcoreNotConfiguredEmptyState />;\n }\n\n return (\n <FileAttachmentContextProvider>\n <LightspeedChat\n selectedModel={selectedModel}\n selectedProvider={selectedProvider}\n topicRestrictionEnabled={topicRestrictionEnabled ?? false}\n handleSelectedModel={item => {\n setSelectedModel(item);\n setSelectedProvider(\n modelsItems.find((m: any) => m.value === item)?.provider || '',\n );\n }}\n models={modelsItems}\n userName={profile?.displayName}\n avatar={profile?.picture}\n profileLoading={profileLoading}\n />\n </FileAttachmentContextProvider>\n );\n};\n\n/**\n * @public\n */\nexport const LightspeedChatContainer = () => {\n return (\n <StylesProvider generateClassName={generateClassName}>\n <StylesProviderV4 generateClassName={generateClassNameV4}>\n <QueryClientProvider client={queryClient}>\n <LightspeedChatContainerInner />\n </QueryClientProvider>\n </StylesProviderV4>\n </StylesProvider>\n );\n};\n"],"names":["StylesProviderV4"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LightspeedDrawerContext.esm.js","sources":["../../src/components/LightspeedDrawerContext.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { createContext } from 'react';\n\nimport { ChatbotDisplayMode } from '@patternfly/chatbot';\n\nimport { FileContent } from '../types';\n\n/**\n * When switching to fullscreen (embedded), open the notebooks list or a specific session.\n *\n * @public\n */\nexport type LightspeedEmbeddedNotebooksTarget =\n
|
|
1
|
+
{"version":3,"file":"LightspeedDrawerContext.esm.js","sources":["../../src/components/LightspeedDrawerContext.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { createContext } from 'react';\n\nimport { ChatbotDisplayMode } from '@patternfly/chatbot';\n\nimport { FileContent } from '../types';\n\n/**\n * When switching to fullscreen (embedded), open the notebooks list or a specific session.\n *\n * @public\n */\nexport type LightspeedEmbeddedNotebooksTarget =\n 'notebooks' | { notebookSessionId: string };\n\n/**\n * Type for LightspeedDrawerContext\n *\n * @public\n */\nexport interface LightspeedDrawerContextType {\n /**\n * Whether the chatbot is active\n */\n isChatbotActive: boolean;\n /**\n * Toggle the chatbot open/closed\n */\n toggleChatbot: () => void;\n /**\n * The current display mode\n */\n displayMode: ChatbotDisplayMode;\n /**\n * Set the display mode (overlay, docked, or fullscreen/embedded).\n * When entering embedded mode, optional `embeddedNotebooks` navigates to\n * `/lightspeed/notebooks` (or a session URL) instead of the chat route.\n * Leaving embedded for overlay or docked resets the shell tab to Chat\n * (Notebooks is only available in fullscreen).\n */\n setDisplayMode: (\n mode: ChatbotDisplayMode,\n conversationIdParam?: string,\n embeddedNotebooks?: LightspeedEmbeddedNotebooksTarget,\n ) => void;\n /**\n * The drawer width (for docked mode)\n */\n drawerWidth: number;\n /**\n * The function for setting the drawer width\n */\n setDrawerWidth: React.Dispatch<React.SetStateAction<number>>;\n /**\n * The current conversation ID\n */\n currentConversationId?: string;\n /**\n * Set the current conversation ID and update the route if in embedded mode\n * Pass undefined to clear the conversation (example: for new chat)\n */\n setCurrentConversationId: (id: string | undefined) => void;\n /**\n * The message in the chat input box\n * Used to preserve input content when switching between display modes\n */\n draftMessage: string;\n /**\n * To save the input message as a draft when switching modes\n */\n setDraftMessage: (message: string) => void;\n /**\n * The file attachments in the chat input\n * Used to preserve file attachments when switching between display modes\n */\n draftFileContents: FileContent[];\n /**\n * To save file attachments as a draft when switching modes\n */\n setDraftFileContents: (files: FileContent[]) => void;\n /**\n * @internal After leaving fullscreen for overlay/docked, the next overlay/docked chat\n * mount should seed the thread from currentConversationId (or TEMP) instead of storage\n * lastOpened. Returns true at most once per handoff.\n */\n consumePendingOverlayThreadHandoff?: () => boolean;\n /**\n * Chat tab is 0, Notebooks tab is 1. Persisted across overlay/docked/fullscreen remounts\n * (each display mode mounts its own `LightspeedChat` tree).\n */\n shellViewTab: number;\n setShellViewTab: (tab: number) => void;\n}\n\nconst CONTEXT_KEY = '__lightspeed_drawer_context__' as keyof typeof globalThis;\n\nfunction getOrCreateContext() {\n const existing = (globalThis as any)[CONTEXT_KEY];\n if (existing)\n return existing as React.Context<LightspeedDrawerContextType | undefined>;\n const ctx = createContext<LightspeedDrawerContextType | undefined>(undefined);\n (globalThis as any)[CONTEXT_KEY] = ctx;\n return ctx;\n}\n\n/**\n * @public\n */\nexport const LightspeedDrawerContext = getOrCreateContext();\n"],"names":[],"mappings":";;AA6GA,MAAM,WAAA,GAAc,+BAAA;AAEpB,SAAS,kBAAA,GAAqB;AAC5B,EAAA,MAAM,QAAA,GAAY,WAAmB,WAAW,CAAA;AAChD,EAAA,IAAI,QAAA;AACF,IAAA,OAAO,QAAA;AACT,EAAA,MAAM,GAAA,GAAM,cAAuD,MAAS,CAAA;AAC5E,EAAC,UAAA,CAAmB,WAAW,CAAA,GAAI,GAAA;AACnC,EAAA,OAAO,GAAA;AACT;AAKO,MAAM,0BAA0B,kBAAA;;;;"}
|
|
@@ -7,7 +7,7 @@ import Typography from '@mui/material/Typography';
|
|
|
7
7
|
import { Title, Button, Alert, Switch, Tooltip } from '@patternfly/react-core';
|
|
8
8
|
import { TimesIcon, PencilAltIcon, SortAmountDownIcon, KeyIcon, InfoCircleIcon, ExclamationCircleIcon, CheckCircleIcon, SortAmountUpIcon } from '@patternfly/react-icons';
|
|
9
9
|
import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
|
|
10
|
-
import {
|
|
10
|
+
import { iaMcpManagePermission } from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';
|
|
11
11
|
import { useMcpConfigureModal } from '../hooks/useMcpConfigureModal.esm.js';
|
|
12
12
|
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
13
13
|
import { McpConfigureServerModal } from './McpConfigureServerModal.esm.js';
|
|
@@ -25,7 +25,8 @@ const useStyles = makeStyles((theme) => ({
|
|
|
25
25
|
root: {
|
|
26
26
|
padding: 0,
|
|
27
27
|
height: "100%",
|
|
28
|
-
minHeight:
|
|
28
|
+
minHeight: 0,
|
|
29
|
+
flex: 1,
|
|
29
30
|
width: "100%",
|
|
30
31
|
overflow: "auto"
|
|
31
32
|
},
|
|
@@ -197,7 +198,7 @@ const McpServersSettings = ({
|
|
|
197
198
|
const configApi = useApi(configApiRef);
|
|
198
199
|
const fetchApi = useApi(fetchApiRef);
|
|
199
200
|
const mcpManagePermission = usePermission({
|
|
200
|
-
permission:
|
|
201
|
+
permission: iaMcpManagePermission
|
|
201
202
|
});
|
|
202
203
|
const canManageMcp = mcpManagePermission.allowed;
|
|
203
204
|
const [servers, setServers] = useState([]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpServersSettings.esm.js","sources":["../../src/components/McpServersSettings.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { configApiRef, fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { usePermission } from '@backstage/plugin-permission-react';\n\nimport { makeStyles } from '@material-ui/core';\nimport Typography from '@mui/material/Typography';\nimport { Alert, Button, Switch, Title, Tooltip } from '@patternfly/react-core';\nimport {\n CheckCircleIcon,\n ExclamationCircleIcon,\n InfoCircleIcon,\n KeyIcon,\n PencilAltIcon,\n SortAmountDownIcon,\n SortAmountUpIcon,\n TimesIcon,\n} from '@patternfly/react-icons';\nimport { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';\n\nimport { lightspeedMcpManagePermission } from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { useMcpConfigureModal } from '../hooks/useMcpConfigureModal';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { McpConfigureServerModal } from './McpConfigureServerModal';\nimport {\n compareMcpServers,\n formatApiError,\n getDisplayDetail,\n getDisplayStatus,\n getEnabledToggleChecked,\n isEnabledToggleUnavailable,\n type McpConfigureServer,\n type McpServerSortColumn,\n type ServerStatus,\n} from './mcpServersDisplayUtils';\n\ntype McpServer = McpConfigureServer;\n\ntype McpServersSettingsProps = {\n onClose: () => void;\n backgroundColor?: string;\n};\n\nconst useStyles = makeStyles(theme => ({\n '@global': {\n '.pf-v6-c-backdrop': {\n zIndex: '1400 !important',\n },\n '.pf-v5-c-backdrop': {\n zIndex: '1400 !important',\n },\n },\n root: {\n padding: 0,\n height: '100%',\n minHeight: '100%',\n width: '100%',\n overflow: 'auto',\n },\n headerRow: {\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n marginBottom: theme.spacing(2),\n marginTop: theme.spacing(2),\n marginLeft: theme.spacing(3),\n marginRight: theme.spacing(2),\n },\n selectedCount: {\n color: theme.palette.text.secondary,\n marginTop: theme.spacing(0.5),\n fontSize: '0.75rem',\n },\n title: {\n fontSize: '1.125rem',\n },\n closeButton: {\n marginTop: -theme.spacing(1),\n marginRight: -theme.spacing(1),\n color: theme.palette.text.primary,\n },\n nameHeaderButton: {\n paddingLeft: 0,\n paddingTop: 0,\n paddingBottom: 0,\n marginLeft: '-0.85rem',\n fontWeight: 600,\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n minHeight: 'auto',\n color: theme.palette.text.primary,\n textDecoration: 'none !important',\n display: 'inline-flex',\n alignItems: 'center',\n },\n statusHeaderButton: {\n paddingLeft: 0,\n paddingTop: 0,\n paddingBottom: 0,\n fontWeight: 600,\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n minHeight: 'auto',\n color: theme.palette.text.primary,\n textDecoration: 'none !important',\n display: 'inline-flex',\n alignItems: 'center',\n },\n sortHeaderIconActive: {\n color: 'var(--pf-t--global--icon--color--brand--default)',\n },\n sortHeaderIconInactive: {\n color: 'var(--pf-t--global--icon--color--subtle)',\n },\n nameHeaderText: {\n paddingLeft: '7px',\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n fontWeight: 600,\n },\n nameCell: {\n paddingLeft: '8px !important',\n },\n statusHeader: {\n paddingLeft: '0 !important',\n },\n statusColumnCell: {\n paddingLeft: '0 !important',\n },\n rowName: {\n fontSize: '1rem',\n fontWeight: 500,\n whiteSpace: 'nowrap',\n },\n nameValue: {\n fontSize: '0.875rem',\n fontWeight: 500,\n },\n statusCell: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n whiteSpace: 'nowrap',\n },\n statusValue: {\n fontSize: '0.875rem',\n },\n statusOk: {\n color: 'var(--pf-t--global--icon--color--status--custom--default)',\n },\n statusWarn: {\n color: 'var(--pf-t--global--icon--color--status--danger--default)',\n },\n statusDisabled: {\n color: 'var(--pf-t--global--icon--color--subtle)',\n },\n actionButton: {\n color: theme.palette.text.secondary,\n opacity: 0,\n transition: 'opacity 0.15s ease-in-out',\n },\n tableRow: {\n '&:hover $actionButton, &:focus-within $actionButton': {\n opacity: 1,\n },\n },\n toggleCell: {\n paddingRight: '0 !important',\n },\n table: {\n width: '100%',\n backgroundColor: 'transparent',\n '--pf-v6-c-table--BackgroundColor': 'transparent',\n '--pf-v5-c-table--BackgroundColor': 'transparent',\n '& table, & thead, & tbody, & tr, & th, & td': {\n backgroundColor: 'transparent !important',\n },\n '& th': {\n borderBottom: 0,\n fontSize: '0.75rem',\n fontWeight: 600,\n color: theme.palette.text.primary,\n whiteSpace: 'nowrap',\n textAlign: 'left',\n },\n '& td': {\n borderBottom: 0,\n paddingTop: theme.spacing(1.5),\n paddingBottom: theme.spacing(1.5),\n verticalAlign: 'middle',\n },\n },\n alert: {\n marginLeft: theme.spacing(3),\n marginRight: theme.spacing(3),\n marginBottom: theme.spacing(2),\n },\n}));\n\ntype McpServerResponse = {\n name: string;\n url?: string;\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n hasToken: boolean;\n hasUserToken: boolean;\n hasOrgToken: boolean;\n auth?: string;\n};\n\ntype McpServersListResponse = {\n servers?: McpServerResponse[];\n};\n\ntype McpServersPatchResponse = {\n server?: McpServerResponse;\n validation?: {\n error?: string;\n };\n};\n\ntype McpToolInfo = {\n name: string;\n description?: string;\n};\n\ntype McpServersValidateResponse = {\n name: string;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n validation?: {\n error?: unknown;\n tools?: McpToolInfo[];\n };\n};\n\ntype McpCredentialsValidateResponse = {\n valid: boolean;\n error?: unknown;\n toolCount: number;\n tools?: McpToolInfo[];\n};\n\nconst getStatusIcon = (status: ServerStatus, className: string) => {\n if (status === 'tokenRequired') return <KeyIcon className={className} />;\n if (status === 'disabled') return <InfoCircleIcon className={className} />;\n if (status === 'failed')\n return <ExclamationCircleIcon className={className} />;\n return <CheckCircleIcon className={className} />;\n};\n\nconst toUiServer = (\n server: McpServerResponse,\n validationError?: string,\n): McpServer => ({\n id: server.name,\n name: server.name,\n url: server.url,\n enabled: server.enabled,\n status: server.status,\n toolCount: server.toolCount,\n hasToken: server.hasToken,\n hasUserToken: server.hasUserToken,\n hasOrgToken: server.hasOrgToken,\n validationError: server.status === 'error' ? validationError : undefined,\n auth: server.auth,\n});\nexport const McpServersSettings = ({\n onClose,\n backgroundColor,\n}: McpServersSettingsProps) => {\n const classes = useStyles();\n const { t } = useTranslation();\n const configApi = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const mcpManagePermission = usePermission({\n permission: lightspeedMcpManagePermission,\n });\n const canManageMcp = mcpManagePermission.allowed;\n const [servers, setServers] = useState<McpServer[]>([]);\n const [sortColumn, setSortColumn] = useState<McpServerSortColumn>('name');\n const [sortAsc, setSortAsc] = useState(true);\n const [isLoading, setIsLoading] = useState(true);\n const [isSaving, setIsSaving] = useState<Record<string, boolean>>({});\n const [error, setError] = useState<string | null>(null);\n\n const getBaseUrl = useCallback(() => {\n return `${configApi.getString('backend.baseUrl')}/api/intelligent-assistant`;\n }, [configApi]);\n\n const fetchJson = useCallback(\n async <T,>(url: string, init?: RequestInit): Promise<T> => {\n const response = await fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n ...init,\n });\n if (!response.ok) {\n let message = `${response.status} ${response.statusText}`;\n try {\n const bodyText = await response.text();\n if (bodyText) {\n const parsed = JSON.parse(bodyText);\n if (parsed?.error) {\n message = parsed.error;\n }\n }\n } catch {\n // Keep default message when parsing fails.\n }\n throw new Error(message);\n }\n\n const text = await response.text();\n return (text ? JSON.parse(text) : {}) as T;\n },\n [fetchApi],\n );\n\n const fetchServerValidation = useCallback(\n async (serverName: string) => {\n const baseUrl = getBaseUrl();\n return fetchJson<McpServersValidateResponse>(\n `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}/validate`,\n {\n method: 'POST',\n },\n );\n },\n [fetchJson, getBaseUrl],\n );\n\n const validateServer = useCallback(\n async (serverName: string) => {\n const data = await fetchServerValidation(serverName);\n\n setServers(prev =>\n prev.map(server =>\n server.name === serverName\n ? {\n ...server,\n status: data.status,\n toolCount: data.toolCount,\n validationError:\n data.status === 'error'\n ? formatApiError(data.validation?.error) ||\n 'Validation failed'\n : undefined,\n }\n : server,\n ),\n );\n return data;\n },\n [fetchServerValidation],\n );\n\n const validateCredentials = useCallback(\n async (url: string, token: string) => {\n const baseUrl = getBaseUrl();\n return await fetchJson<McpCredentialsValidateResponse>(\n `${baseUrl}/mcp-servers/validate`,\n {\n method: 'POST',\n body: JSON.stringify({ url, token }),\n },\n );\n },\n [fetchJson, getBaseUrl],\n );\n const loadServers = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n try {\n const baseUrl = getBaseUrl();\n const data = await fetchJson<McpServersListResponse>(\n `${baseUrl}/mcp-servers`,\n );\n const uiServers = (data.servers ?? []).map(server => toUiServer(server));\n setServers(uiServers);\n\n if (canManageMcp) {\n const serversToValidate = uiServers.filter(server => server.hasToken);\n void Promise.allSettled(\n serversToValidate.map(async server => {\n try {\n await validateServer(server.name);\n } catch (validationError) {\n setError(\n prev =>\n prev ??\n (validationError instanceof Error\n ? validationError.message\n : `Failed to validate ${server.name}`),\n );\n }\n }),\n );\n }\n } catch (e) {\n setError(\n e instanceof Error ? e.message : 'Failed to load MCP server settings',\n );\n } finally {\n setIsLoading(false);\n }\n }, [canManageMcp, fetchJson, getBaseUrl, validateServer]);\n\n useEffect(() => {\n loadServers();\n }, [loadServers]);\n\n const patchServer = useCallback(\n async (\n serverName: string,\n body: { enabled?: boolean; token?: string | null },\n ) => {\n if (!canManageMcp) {\n return;\n }\n setError(null);\n setIsSaving(prev => ({ ...prev, [serverName]: true }));\n try {\n const baseUrl = getBaseUrl();\n const data = await fetchJson<McpServersPatchResponse>(\n `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}`,\n {\n method: 'PATCH',\n body: JSON.stringify(body),\n },\n );\n\n if (data.server) {\n setServers(prev =>\n prev.map(server =>\n server.name === serverName\n ? toUiServer(data.server!, data.validation?.error)\n : server,\n ),\n );\n } else {\n await loadServers();\n }\n } catch (e) {\n setError(\n e instanceof Error\n ? e.message\n : `Failed to update ${serverName} settings`,\n );\n throw e;\n } finally {\n setIsSaving(prev => ({ ...prev, [serverName]: false }));\n }\n },\n [canManageMcp, fetchJson, getBaseUrl, loadServers],\n );\n\n const configureModal = useMcpConfigureModal({\n servers,\n canManageMcp,\n isSaving,\n patchServer,\n validateServer,\n validateCredentials,\n fetchServerValidation,\n });\n\n const selectedCount = servers.filter(server => {\n const displayStatus = getDisplayStatus(server);\n const isUnavailable =\n displayStatus === 'failed' || displayStatus === 'tokenRequired';\n return server.enabled && !isUnavailable;\n }).length;\n\n const sortedServers = [...servers].sort((a, b) =>\n compareMcpServers(a, b, sortColumn, sortAsc),\n );\n\n const onSortColumnClick = (column: McpServerSortColumn) => {\n if (sortColumn === column) {\n setSortAsc(prev => !prev);\n return;\n }\n setSortColumn(column);\n setSortAsc(true);\n };\n\n const renderSortIcon = (column: McpServerSortColumn) => {\n const isActive = sortColumn === column;\n let Icon = SortAmountDownIcon;\n if (isActive && !sortAsc) {\n Icon = SortAmountUpIcon;\n }\n\n return (\n <Icon\n className={\n isActive\n ? classes.sortHeaderIconActive\n : classes.sortHeaderIconInactive\n }\n />\n );\n };\n\n return (\n <div\n className={classes.root}\n style={backgroundColor ? { backgroundColor } : undefined}\n >\n <div className={classes.headerRow}>\n <div>\n <Title headingLevel=\"h2\" size=\"xl\" className={classes.title}>\n {t('mcp.settings.title')}\n </Title>\n <div className={classes.selectedCount}>\n {t('mcp.settings.selectedCount' as any, {\n selectedCount: String(selectedCount),\n totalCount: String(servers.length),\n })}\n </div>\n </div>\n <Button\n aria-label={t('mcp.settings.closeAriaLabel')}\n icon={<TimesIcon />}\n variant=\"plain\"\n className={classes.closeButton}\n onClick={onClose}\n />\n </div>\n {error && (\n <Alert\n variant=\"danger\"\n isInline\n title={error}\n className={classes.alert}\n />\n )}\n {!mcpManagePermission.loading && !canManageMcp && (\n <Alert\n variant=\"info\"\n isInline\n title={t('mcp.settings.readOnlyAccess')}\n className={classes.alert}\n />\n )}\n\n <Table\n variant=\"compact\"\n aria-label={t('mcp.settings.tableAriaLabel')}\n className={classes.table}\n >\n <Thead>\n <Tr>\n <Th width={10} screenReaderText={t('mcp.settings.enabled')} />\n <Th>\n <Button\n variant=\"link\"\n className={classes.nameHeaderButton}\n icon={renderSortIcon('name')}\n iconPosition=\"right\"\n onClick={() => onSortColumnClick('name')}\n >\n <Typography component=\"span\" className={classes.nameHeaderText}>\n {t('mcp.settings.name')}\n </Typography>\n </Button>\n </Th>\n <Th className={classes.statusHeader}>\n <Button\n variant=\"link\"\n className={classes.statusHeaderButton}\n icon={renderSortIcon('status')}\n iconPosition=\"right\"\n onClick={() => onSortColumnClick('status')}\n >\n <Typography component=\"span\" className={classes.nameHeaderText}>\n {t('mcp.settings.status')}\n </Typography>\n </Button>\n </Th>\n <Th screenReaderText={t('mcp.settings.edit')} />\n </Tr>\n </Thead>\n <Tbody>\n {isLoading && (\n <Tr>\n <Td colSpan={4}>{t('mcp.settings.loading')}</Td>\n </Tr>\n )}\n {!isLoading && sortedServers.length === 0 && (\n <Tr>\n <Td colSpan={4}>{t('mcp.settings.noneAvailable')}</Td>\n </Tr>\n )}\n {sortedServers.map(server => {\n const displayStatus = getDisplayStatus(server);\n const displayDetail = getDisplayDetail(server, displayStatus, t);\n let statusClass = classes.statusWarn;\n if (displayStatus === 'ok') {\n statusClass = classes.statusOk;\n } else if (displayStatus === 'disabled') {\n statusClass = classes.statusDisabled;\n }\n\n return (\n <Tr key={server.id} className={classes.tableRow}>\n <Td width={10} className={classes.toggleCell}>\n {(() => {\n const isUnavailable =\n isEnabledToggleUnavailable(displayStatus);\n const isChecked = getEnabledToggleChecked(\n server,\n displayStatus,\n );\n const isRowSaving = Boolean(isSaving[server.name]);\n const isToggleDisabled =\n isUnavailable || isRowSaving || !canManageMcp;\n const switchControl = (\n <Switch\n id={`mcp-switch-${server.id}`}\n aria-label={t(\n 'mcp.settings.toggleServerAriaLabel' as any,\n {\n serverName: server.name,\n },\n )}\n isChecked={isChecked}\n isDisabled={isToggleDisabled}\n onChange={(_event, checked) => {\n void patchServer(server.name, {\n enabled: checked,\n }).catch(() => {\n // patchServer already updates component error state.\n // Swallow here to avoid unhandled promise rejections\n // from event-handler fire-and-forget usage.\n });\n }}\n />\n );\n\n if (!isToggleDisabled) {\n return switchControl;\n }\n\n return (\n <Tooltip content={displayDetail}>\n <Typography component=\"span\">\n {switchControl}\n </Typography>\n </Tooltip>\n );\n })()}\n </Td>\n <Td\n width={35}\n className={`${classes.rowName} ${classes.nameCell}`}\n >\n <Typography component=\"span\" className={classes.nameValue}>\n {server.name}\n </Typography>\n </Td>\n <Td width={40} className={classes.statusColumnCell}>\n <div className={classes.statusCell}>\n {getStatusIcon(displayStatus, statusClass)}\n {displayStatus === 'failed' ? (\n <Tooltip\n content={\n server.validationError ??\n t('mcp.settings.token.validationFailed')\n }\n >\n <Typography\n component=\"span\"\n className={classes.statusValue}\n >\n {displayDetail}\n </Typography>\n </Tooltip>\n ) : (\n <Typography\n component=\"span\"\n className={classes.statusValue}\n >\n {displayDetail}\n </Typography>\n )}\n </div>\n </Td>\n <Td width={15} isActionCell style={{ textAlign: 'right' }}>\n <Button\n aria-label={t('mcp.settings.editServerAriaLabel' as any, {\n serverName: server.name,\n })}\n icon={<PencilAltIcon />}\n variant=\"plain\"\n className={classes.actionButton}\n isDisabled={!canManageMcp}\n onClick={() => configureModal.open(server)}\n />\n </Td>\n </Tr>\n );\n })}\n </Tbody>\n </Table>\n <McpConfigureServerModal {...configureModal} />\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"McpServersSettings.esm.js","sources":["../../src/components/McpServersSettings.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { configApiRef, fetchApiRef, useApi } from '@backstage/core-plugin-api';\nimport { usePermission } from '@backstage/plugin-permission-react';\n\nimport { makeStyles } from '@material-ui/core';\nimport Typography from '@mui/material/Typography';\nimport { Alert, Button, Switch, Title, Tooltip } from '@patternfly/react-core';\nimport {\n CheckCircleIcon,\n ExclamationCircleIcon,\n InfoCircleIcon,\n KeyIcon,\n PencilAltIcon,\n SortAmountDownIcon,\n SortAmountUpIcon,\n TimesIcon,\n} from '@patternfly/react-icons';\nimport { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';\n\nimport { iaMcpManagePermission } from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';\n\nimport { useMcpConfigureModal } from '../hooks/useMcpConfigureModal';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { McpConfigureServerModal } from './McpConfigureServerModal';\nimport {\n compareMcpServers,\n formatApiError,\n getDisplayDetail,\n getDisplayStatus,\n getEnabledToggleChecked,\n isEnabledToggleUnavailable,\n type McpConfigureServer,\n type McpServerSortColumn,\n type ServerStatus,\n} from './mcpServersDisplayUtils';\n\ntype McpServer = McpConfigureServer;\n\ntype McpServersSettingsProps = {\n onClose: () => void;\n backgroundColor?: string;\n};\n\nconst useStyles = makeStyles(theme => ({\n '@global': {\n '.pf-v6-c-backdrop': {\n zIndex: '1400 !important',\n },\n '.pf-v5-c-backdrop': {\n zIndex: '1400 !important',\n },\n },\n root: {\n padding: 0,\n height: '100%',\n minHeight: 0,\n flex: 1,\n width: '100%',\n overflow: 'auto',\n },\n headerRow: {\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'space-between',\n marginBottom: theme.spacing(2),\n marginTop: theme.spacing(2),\n marginLeft: theme.spacing(3),\n marginRight: theme.spacing(2),\n },\n selectedCount: {\n color: theme.palette.text.secondary,\n marginTop: theme.spacing(0.5),\n fontSize: '0.75rem',\n },\n title: {\n fontSize: '1.125rem',\n },\n closeButton: {\n marginTop: -theme.spacing(1),\n marginRight: -theme.spacing(1),\n color: theme.palette.text.primary,\n },\n nameHeaderButton: {\n paddingLeft: 0,\n paddingTop: 0,\n paddingBottom: 0,\n marginLeft: '-0.85rem',\n fontWeight: 600,\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n minHeight: 'auto',\n color: theme.palette.text.primary,\n textDecoration: 'none !important',\n display: 'inline-flex',\n alignItems: 'center',\n },\n statusHeaderButton: {\n paddingLeft: 0,\n paddingTop: 0,\n paddingBottom: 0,\n fontWeight: 600,\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n minHeight: 'auto',\n color: theme.palette.text.primary,\n textDecoration: 'none !important',\n display: 'inline-flex',\n alignItems: 'center',\n },\n sortHeaderIconActive: {\n color: 'var(--pf-t--global--icon--color--brand--default)',\n },\n sortHeaderIconInactive: {\n color: 'var(--pf-t--global--icon--color--subtle)',\n },\n nameHeaderText: {\n paddingLeft: '7px',\n fontSize: '0.75rem',\n lineHeight: '1.25rem',\n fontWeight: 600,\n },\n nameCell: {\n paddingLeft: '8px !important',\n },\n statusHeader: {\n paddingLeft: '0 !important',\n },\n statusColumnCell: {\n paddingLeft: '0 !important',\n },\n rowName: {\n fontSize: '1rem',\n fontWeight: 500,\n whiteSpace: 'nowrap',\n },\n nameValue: {\n fontSize: '0.875rem',\n fontWeight: 500,\n },\n statusCell: {\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n whiteSpace: 'nowrap',\n },\n statusValue: {\n fontSize: '0.875rem',\n },\n statusOk: {\n color: 'var(--pf-t--global--icon--color--status--custom--default)',\n },\n statusWarn: {\n color: 'var(--pf-t--global--icon--color--status--danger--default)',\n },\n statusDisabled: {\n color: 'var(--pf-t--global--icon--color--subtle)',\n },\n actionButton: {\n color: theme.palette.text.secondary,\n opacity: 0,\n transition: 'opacity 0.15s ease-in-out',\n },\n tableRow: {\n '&:hover $actionButton, &:focus-within $actionButton': {\n opacity: 1,\n },\n },\n toggleCell: {\n paddingRight: '0 !important',\n },\n table: {\n width: '100%',\n backgroundColor: 'transparent',\n '--pf-v6-c-table--BackgroundColor': 'transparent',\n '--pf-v5-c-table--BackgroundColor': 'transparent',\n '& table, & thead, & tbody, & tr, & th, & td': {\n backgroundColor: 'transparent !important',\n },\n '& th': {\n borderBottom: 0,\n fontSize: '0.75rem',\n fontWeight: 600,\n color: theme.palette.text.primary,\n whiteSpace: 'nowrap',\n textAlign: 'left',\n },\n '& td': {\n borderBottom: 0,\n paddingTop: theme.spacing(1.5),\n paddingBottom: theme.spacing(1.5),\n verticalAlign: 'middle',\n },\n },\n alert: {\n marginLeft: theme.spacing(3),\n marginRight: theme.spacing(3),\n marginBottom: theme.spacing(2),\n },\n}));\n\ntype McpServerResponse = {\n name: string;\n url?: string;\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n hasToken: boolean;\n hasUserToken: boolean;\n hasOrgToken: boolean;\n auth?: string;\n};\n\ntype McpServersListResponse = {\n servers?: McpServerResponse[];\n};\n\ntype McpServersPatchResponse = {\n server?: McpServerResponse;\n validation?: {\n error?: string;\n };\n};\n\ntype McpToolInfo = {\n name: string;\n description?: string;\n};\n\ntype McpServersValidateResponse = {\n name: string;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n validation?: {\n error?: unknown;\n tools?: McpToolInfo[];\n };\n};\n\ntype McpCredentialsValidateResponse = {\n valid: boolean;\n error?: unknown;\n toolCount: number;\n tools?: McpToolInfo[];\n};\n\nconst getStatusIcon = (status: ServerStatus, className: string) => {\n if (status === 'tokenRequired') return <KeyIcon className={className} />;\n if (status === 'disabled') return <InfoCircleIcon className={className} />;\n if (status === 'failed')\n return <ExclamationCircleIcon className={className} />;\n return <CheckCircleIcon className={className} />;\n};\n\nconst toUiServer = (\n server: McpServerResponse,\n validationError?: string,\n): McpServer => ({\n id: server.name,\n name: server.name,\n url: server.url,\n enabled: server.enabled,\n status: server.status,\n toolCount: server.toolCount,\n hasToken: server.hasToken,\n hasUserToken: server.hasUserToken,\n hasOrgToken: server.hasOrgToken,\n validationError: server.status === 'error' ? validationError : undefined,\n auth: server.auth,\n});\nexport const McpServersSettings = ({\n onClose,\n backgroundColor,\n}: McpServersSettingsProps) => {\n const classes = useStyles();\n const { t } = useTranslation();\n const configApi = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const mcpManagePermission = usePermission({\n permission: iaMcpManagePermission,\n });\n const canManageMcp = mcpManagePermission.allowed;\n const [servers, setServers] = useState<McpServer[]>([]);\n const [sortColumn, setSortColumn] = useState<McpServerSortColumn>('name');\n const [sortAsc, setSortAsc] = useState(true);\n const [isLoading, setIsLoading] = useState(true);\n const [isSaving, setIsSaving] = useState<Record<string, boolean>>({});\n const [error, setError] = useState<string | null>(null);\n\n const getBaseUrl = useCallback(() => {\n return `${configApi.getString('backend.baseUrl')}/api/intelligent-assistant`;\n }, [configApi]);\n\n const fetchJson = useCallback(\n async <T,>(url: string, init?: RequestInit): Promise<T> => {\n const response = await fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n ...init,\n });\n if (!response.ok) {\n let message = `${response.status} ${response.statusText}`;\n try {\n const bodyText = await response.text();\n if (bodyText) {\n const parsed = JSON.parse(bodyText);\n if (parsed?.error) {\n message = parsed.error;\n }\n }\n } catch {\n // Keep default message when parsing fails.\n }\n throw new Error(message);\n }\n\n const text = await response.text();\n return (text ? JSON.parse(text) : {}) as T;\n },\n [fetchApi],\n );\n\n const fetchServerValidation = useCallback(\n async (serverName: string) => {\n const baseUrl = getBaseUrl();\n return fetchJson<McpServersValidateResponse>(\n `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}/validate`,\n {\n method: 'POST',\n },\n );\n },\n [fetchJson, getBaseUrl],\n );\n\n const validateServer = useCallback(\n async (serverName: string) => {\n const data = await fetchServerValidation(serverName);\n\n setServers(prev =>\n prev.map(server =>\n server.name === serverName\n ? {\n ...server,\n status: data.status,\n toolCount: data.toolCount,\n validationError:\n data.status === 'error'\n ? formatApiError(data.validation?.error) ||\n 'Validation failed'\n : undefined,\n }\n : server,\n ),\n );\n return data;\n },\n [fetchServerValidation],\n );\n\n const validateCredentials = useCallback(\n async (url: string, token: string) => {\n const baseUrl = getBaseUrl();\n return await fetchJson<McpCredentialsValidateResponse>(\n `${baseUrl}/mcp-servers/validate`,\n {\n method: 'POST',\n body: JSON.stringify({ url, token }),\n },\n );\n },\n [fetchJson, getBaseUrl],\n );\n const loadServers = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n try {\n const baseUrl = getBaseUrl();\n const data = await fetchJson<McpServersListResponse>(\n `${baseUrl}/mcp-servers`,\n );\n const uiServers = (data.servers ?? []).map(server => toUiServer(server));\n setServers(uiServers);\n\n if (canManageMcp) {\n const serversToValidate = uiServers.filter(server => server.hasToken);\n void Promise.allSettled(\n serversToValidate.map(async server => {\n try {\n await validateServer(server.name);\n } catch (validationError) {\n setError(\n prev =>\n prev ??\n (validationError instanceof Error\n ? validationError.message\n : `Failed to validate ${server.name}`),\n );\n }\n }),\n );\n }\n } catch (e) {\n setError(\n e instanceof Error ? e.message : 'Failed to load MCP server settings',\n );\n } finally {\n setIsLoading(false);\n }\n }, [canManageMcp, fetchJson, getBaseUrl, validateServer]);\n\n useEffect(() => {\n loadServers();\n }, [loadServers]);\n\n const patchServer = useCallback(\n async (\n serverName: string,\n body: { enabled?: boolean; token?: string | null },\n ) => {\n if (!canManageMcp) {\n return;\n }\n setError(null);\n setIsSaving(prev => ({ ...prev, [serverName]: true }));\n try {\n const baseUrl = getBaseUrl();\n const data = await fetchJson<McpServersPatchResponse>(\n `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}`,\n {\n method: 'PATCH',\n body: JSON.stringify(body),\n },\n );\n\n if (data.server) {\n setServers(prev =>\n prev.map(server =>\n server.name === serverName\n ? toUiServer(data.server!, data.validation?.error)\n : server,\n ),\n );\n } else {\n await loadServers();\n }\n } catch (e) {\n setError(\n e instanceof Error\n ? e.message\n : `Failed to update ${serverName} settings`,\n );\n throw e;\n } finally {\n setIsSaving(prev => ({ ...prev, [serverName]: false }));\n }\n },\n [canManageMcp, fetchJson, getBaseUrl, loadServers],\n );\n\n const configureModal = useMcpConfigureModal({\n servers,\n canManageMcp,\n isSaving,\n patchServer,\n validateServer,\n validateCredentials,\n fetchServerValidation,\n });\n\n const selectedCount = servers.filter(server => {\n const displayStatus = getDisplayStatus(server);\n const isUnavailable =\n displayStatus === 'failed' || displayStatus === 'tokenRequired';\n return server.enabled && !isUnavailable;\n }).length;\n\n const sortedServers = [...servers].sort((a, b) =>\n compareMcpServers(a, b, sortColumn, sortAsc),\n );\n\n const onSortColumnClick = (column: McpServerSortColumn) => {\n if (sortColumn === column) {\n setSortAsc(prev => !prev);\n return;\n }\n setSortColumn(column);\n setSortAsc(true);\n };\n\n const renderSortIcon = (column: McpServerSortColumn) => {\n const isActive = sortColumn === column;\n let Icon = SortAmountDownIcon;\n if (isActive && !sortAsc) {\n Icon = SortAmountUpIcon;\n }\n\n return (\n <Icon\n className={\n isActive\n ? classes.sortHeaderIconActive\n : classes.sortHeaderIconInactive\n }\n />\n );\n };\n\n return (\n <div\n className={classes.root}\n style={backgroundColor ? { backgroundColor } : undefined}\n >\n <div className={classes.headerRow}>\n <div>\n <Title headingLevel=\"h2\" size=\"xl\" className={classes.title}>\n {t('mcp.settings.title')}\n </Title>\n <div className={classes.selectedCount}>\n {t('mcp.settings.selectedCount' as any, {\n selectedCount: String(selectedCount),\n totalCount: String(servers.length),\n })}\n </div>\n </div>\n <Button\n aria-label={t('mcp.settings.closeAriaLabel')}\n icon={<TimesIcon />}\n variant=\"plain\"\n className={classes.closeButton}\n onClick={onClose}\n />\n </div>\n {error && (\n <Alert\n variant=\"danger\"\n isInline\n title={error}\n className={classes.alert}\n />\n )}\n {!mcpManagePermission.loading && !canManageMcp && (\n <Alert\n variant=\"info\"\n isInline\n title={t('mcp.settings.readOnlyAccess')}\n className={classes.alert}\n />\n )}\n\n <Table\n variant=\"compact\"\n aria-label={t('mcp.settings.tableAriaLabel')}\n className={classes.table}\n >\n <Thead>\n <Tr>\n <Th width={10} screenReaderText={t('mcp.settings.enabled')} />\n <Th>\n <Button\n variant=\"link\"\n className={classes.nameHeaderButton}\n icon={renderSortIcon('name')}\n iconPosition=\"right\"\n onClick={() => onSortColumnClick('name')}\n >\n <Typography component=\"span\" className={classes.nameHeaderText}>\n {t('mcp.settings.name')}\n </Typography>\n </Button>\n </Th>\n <Th className={classes.statusHeader}>\n <Button\n variant=\"link\"\n className={classes.statusHeaderButton}\n icon={renderSortIcon('status')}\n iconPosition=\"right\"\n onClick={() => onSortColumnClick('status')}\n >\n <Typography component=\"span\" className={classes.nameHeaderText}>\n {t('mcp.settings.status')}\n </Typography>\n </Button>\n </Th>\n <Th screenReaderText={t('mcp.settings.edit')} />\n </Tr>\n </Thead>\n <Tbody>\n {isLoading && (\n <Tr>\n <Td colSpan={4}>{t('mcp.settings.loading')}</Td>\n </Tr>\n )}\n {!isLoading && sortedServers.length === 0 && (\n <Tr>\n <Td colSpan={4}>{t('mcp.settings.noneAvailable')}</Td>\n </Tr>\n )}\n {sortedServers.map(server => {\n const displayStatus = getDisplayStatus(server);\n const displayDetail = getDisplayDetail(server, displayStatus, t);\n let statusClass = classes.statusWarn;\n if (displayStatus === 'ok') {\n statusClass = classes.statusOk;\n } else if (displayStatus === 'disabled') {\n statusClass = classes.statusDisabled;\n }\n\n return (\n <Tr key={server.id} className={classes.tableRow}>\n <Td width={10} className={classes.toggleCell}>\n {(() => {\n const isUnavailable =\n isEnabledToggleUnavailable(displayStatus);\n const isChecked = getEnabledToggleChecked(\n server,\n displayStatus,\n );\n const isRowSaving = Boolean(isSaving[server.name]);\n const isToggleDisabled =\n isUnavailable || isRowSaving || !canManageMcp;\n const switchControl = (\n <Switch\n id={`mcp-switch-${server.id}`}\n aria-label={t(\n 'mcp.settings.toggleServerAriaLabel' as any,\n {\n serverName: server.name,\n },\n )}\n isChecked={isChecked}\n isDisabled={isToggleDisabled}\n onChange={(_event, checked) => {\n void patchServer(server.name, {\n enabled: checked,\n }).catch(() => {\n // patchServer already updates component error state.\n // Swallow here to avoid unhandled promise rejections\n // from event-handler fire-and-forget usage.\n });\n }}\n />\n );\n\n if (!isToggleDisabled) {\n return switchControl;\n }\n\n return (\n <Tooltip content={displayDetail}>\n <Typography component=\"span\">\n {switchControl}\n </Typography>\n </Tooltip>\n );\n })()}\n </Td>\n <Td\n width={35}\n className={`${classes.rowName} ${classes.nameCell}`}\n >\n <Typography component=\"span\" className={classes.nameValue}>\n {server.name}\n </Typography>\n </Td>\n <Td width={40} className={classes.statusColumnCell}>\n <div className={classes.statusCell}>\n {getStatusIcon(displayStatus, statusClass)}\n {displayStatus === 'failed' ? (\n <Tooltip\n content={\n server.validationError ??\n t('mcp.settings.token.validationFailed')\n }\n >\n <Typography\n component=\"span\"\n className={classes.statusValue}\n >\n {displayDetail}\n </Typography>\n </Tooltip>\n ) : (\n <Typography\n component=\"span\"\n className={classes.statusValue}\n >\n {displayDetail}\n </Typography>\n )}\n </div>\n </Td>\n <Td width={15} isActionCell style={{ textAlign: 'right' }}>\n <Button\n aria-label={t('mcp.settings.editServerAriaLabel' as any, {\n serverName: server.name,\n })}\n icon={<PencilAltIcon />}\n variant=\"plain\"\n className={classes.actionButton}\n isDisabled={!canManageMcp}\n onClick={() => configureModal.open(server)}\n />\n </Td>\n </Tr>\n );\n })}\n </Tbody>\n </Table>\n <McpConfigureServerModal {...configureModal} />\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
3
|
import { makeStyles } from '@material-ui/core';
|
|
4
|
-
import { Dropdown, DropdownList, DropdownItem, MenuToggle } from '@patternfly/react-core';
|
|
4
|
+
import { Dropdown, DropdownList, DropdownItem, Tooltip, MenuToggle } from '@patternfly/react-core';
|
|
5
5
|
import { AngleDownIcon } from '@patternfly/react-icons';
|
|
6
6
|
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
7
7
|
|
|
@@ -37,11 +37,17 @@ const MessageBarModelSelector = ({
|
|
|
37
37
|
selectedModel,
|
|
38
38
|
models,
|
|
39
39
|
onSelect,
|
|
40
|
-
disabled = false
|
|
40
|
+
disabled = false,
|
|
41
|
+
disabledTooltip
|
|
41
42
|
}) => {
|
|
42
43
|
const [isOpen, setIsOpen] = useState(false);
|
|
43
44
|
const classes = useStyles();
|
|
44
45
|
const { t } = useTranslation();
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (disabled) {
|
|
48
|
+
setIsOpen(false);
|
|
49
|
+
}
|
|
50
|
+
}, [disabled]);
|
|
45
51
|
const selectedModelLabel = models.find((m) => m.value === selectedModel)?.label ?? selectedModel;
|
|
46
52
|
const toggle = (toggleRef) => /* @__PURE__ */ jsxs(
|
|
47
53
|
MenuToggle,
|
|
@@ -59,12 +65,13 @@ const MessageBarModelSelector = ({
|
|
|
59
65
|
]
|
|
60
66
|
}
|
|
61
67
|
);
|
|
62
|
-
|
|
68
|
+
const dropdown = /* @__PURE__ */ jsx(
|
|
63
69
|
Dropdown,
|
|
64
70
|
{
|
|
65
71
|
className: classes.dropdown,
|
|
66
|
-
isOpen,
|
|
72
|
+
isOpen: isOpen && !disabled,
|
|
67
73
|
onSelect: (_e, value) => {
|
|
74
|
+
if (disabled) return;
|
|
68
75
|
onSelect(value);
|
|
69
76
|
setIsOpen(false);
|
|
70
77
|
},
|
|
@@ -86,6 +93,10 @@ const MessageBarModelSelector = ({
|
|
|
86
93
|
)) })
|
|
87
94
|
}
|
|
88
95
|
);
|
|
96
|
+
if (disabled && disabledTooltip) {
|
|
97
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: disabledTooltip, children: /* @__PURE__ */ jsx("span", { children: dropdown }) });
|
|
98
|
+
}
|
|
99
|
+
return dropdown;
|
|
89
100
|
};
|
|
90
101
|
|
|
91
102
|
export { MessageBarModelSelector };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageBarModelSelector.esm.js","sources":["../../src/components/MessageBarModelSelector.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Ref, useState } from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n Dropdown,\n DropdownItem,\n DropdownList,\n MenuToggle,\n MenuToggleElement,\n} from '@patternfly/react-core';\nimport { AngleDownIcon } from '@patternfly/react-icons';\n\nimport { useTranslation } from '../hooks/useTranslation';\n\ntype MessageBarModelSelectorProps = {\n selectedModel: string;\n models: { label: string; value: string; provider: string }[];\n onSelect: (model: string) => void;\n disabled?: boolean;\n};\n\nconst useStyles = makeStyles(theme => ({\n selectorToggle: {\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n color: theme.palette.text.secondary,\n fontSize: 14,\n fontWeight: 500,\n cursor: 'pointer',\n padding: '4px 8px',\n borderRadius: 8,\n border: 'none',\n background: 'transparent',\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n '&:disabled': {\n cursor: 'not-allowed',\n opacity: 0.5,\n },\n },\n dropdown: {\n '& ul, & li': {\n padding: 0,\n margin: 0,\n },\n },\n}));\n\nexport const MessageBarModelSelector = ({\n selectedModel,\n models,\n onSelect,\n disabled = false,\n}: MessageBarModelSelectorProps) => {\n const [isOpen, setIsOpen] = useState(false);\n const classes = useStyles();\n const { t } = useTranslation();\n\n const selectedModelLabel =\n models.find(m => m.value === selectedModel)?.label ?? selectedModel;\n\n const toggle = (toggleRef: Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n isExpanded={isOpen}\n isDisabled={disabled}\n variant=\"plain\"\n className={classes.selectorToggle}\n aria-label={t('aria.chatbotSelector')}\n >\n {selectedModelLabel}\n <AngleDownIcon />\n </MenuToggle>\n );\n\n
|
|
1
|
+
{"version":3,"file":"MessageBarModelSelector.esm.js","sources":["../../src/components/MessageBarModelSelector.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Ref, useEffect, useState } from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n Dropdown,\n DropdownItem,\n DropdownList,\n MenuToggle,\n MenuToggleElement,\n Tooltip,\n} from '@patternfly/react-core';\nimport { AngleDownIcon } from '@patternfly/react-icons';\n\nimport { useTranslation } from '../hooks/useTranslation';\n\ntype MessageBarModelSelectorProps = {\n selectedModel: string;\n models: { label: string; value: string; provider: string }[];\n onSelect: (model: string) => void;\n disabled?: boolean;\n disabledTooltip?: string;\n};\n\nconst useStyles = makeStyles(theme => ({\n selectorToggle: {\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n color: theme.palette.text.secondary,\n fontSize: 14,\n fontWeight: 500,\n cursor: 'pointer',\n padding: '4px 8px',\n borderRadius: 8,\n border: 'none',\n background: 'transparent',\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n '&:disabled': {\n cursor: 'not-allowed',\n opacity: 0.5,\n },\n },\n dropdown: {\n '& ul, & li': {\n padding: 0,\n margin: 0,\n },\n },\n}));\n\nexport const MessageBarModelSelector = ({\n selectedModel,\n models,\n onSelect,\n disabled = false,\n disabledTooltip,\n}: MessageBarModelSelectorProps) => {\n const [isOpen, setIsOpen] = useState(false);\n const classes = useStyles();\n const { t } = useTranslation();\n\n useEffect(() => {\n if (disabled) {\n setIsOpen(false);\n }\n }, [disabled]);\n\n const selectedModelLabel =\n models.find(m => m.value === selectedModel)?.label ?? selectedModel;\n\n const toggle = (toggleRef: Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n isExpanded={isOpen}\n isDisabled={disabled}\n variant=\"plain\"\n className={classes.selectorToggle}\n aria-label={t('aria.chatbotSelector')}\n >\n {selectedModelLabel}\n <AngleDownIcon />\n </MenuToggle>\n );\n\n const dropdown = (\n <Dropdown\n className={classes.dropdown}\n isOpen={isOpen && !disabled}\n onSelect={(_e, value) => {\n if (disabled) return;\n onSelect(value as string);\n setIsOpen(false);\n }}\n onOpenChange={open => setIsOpen(open)}\n popperProps={{ position: 'left' }}\n shouldFocusToggleOnSelect\n shouldFocusFirstItemOnOpen={false}\n toggle={toggle}\n isScrollable={models.length > 10}\n maxMenuHeight={models.length > 10 ? '240px' : undefined}\n >\n <DropdownList>\n {models.map(model => (\n <DropdownItem\n value={model.value}\n key={model.value}\n isSelected={selectedModel === model.value}\n >\n {model.label}\n </DropdownItem>\n ))}\n </DropdownList>\n </Dropdown>\n );\n\n if (disabled && disabledTooltip) {\n return (\n <Tooltip content={disabledTooltip}>\n <span>{dropdown}</span>\n </Tooltip>\n );\n }\n\n return dropdown;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpServersDisplayUtils.esm.js","sources":["../../src/components/mcpServersDisplayUtils.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type ServerStatus =\n | 'tokenRequired'\n | 'disabled'\n | 'ok'\n | 'failed'\n | 'unknown';\n\nexport type McpServerSortColumn = 'name' | 'status';\n\nexport type CredentialMode = 'organization' | 'personal';\n\nexport type McpServerDisplayInput = {\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n hasToken: boolean;\n};\n\n/** Shared server shape used by the configure-server modal and its hook. */\nexport type McpConfigureServer = {\n id: string;\n name: string;\n url?: string;\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n hasToken: boolean;\n hasUserToken: boolean;\n hasOrgToken: boolean;\n validationError?: string;\n /** 'dcr' = tokens are minted automatically (no manual token needed). */\n auth?: string;\n};\n\nexport const formatApiError = (error: unknown): string => {\n if (typeof error === 'string') {\n return error;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (error && typeof error === 'object') {\n if ('message' in error && typeof error.message === 'string') {\n return error.message;\n }\n if ('error' in error) {\n return formatApiError((error as { error: unknown }).error);\n }\n }\n return '';\n};\n\nexport const getDisplayStatus = (\n server: McpServerDisplayInput,\n): ServerStatus => {\n if (!server.hasToken) return 'tokenRequired';\n if (!server.enabled) return 'disabled';\n if (server.status === 'error') return 'failed';\n if (server.status === 'connected') return 'ok';\n return 'unknown';\n};\n\nexport const getStatusSortRank = (status: ServerStatus): number => {\n switch (status) {\n case 'ok':\n return 0;\n case 'disabled':\n return 1;\n case 'unknown':\n return 2;\n case 'tokenRequired':\n return 3;\n case 'failed':\n return 4;\n default:\n return 5;\n }\n};\n\nexport type McpServerSortInput = McpServerDisplayInput & {\n name: string;\n toolCount?: number;\n};\n\nexport const compareMcpServers = (\n a: McpServerSortInput,\n b: McpServerSortInput,\n sortColumn: McpServerSortColumn,\n sortAsc: boolean,\n): number => {\n const direction = sortAsc ? 1 : -1;\n\n if (sortColumn === 'name') {\n return direction * a.name.localeCompare(b.name);\n }\n\n const statusCompare =\n getStatusSortRank(getDisplayStatus(a)) -\n getStatusSortRank(getDisplayStatus(b));\n if (statusCompare !== 0) {\n return direction * statusCompare;\n }\n\n const toolCompare = (a.toolCount ?? 0) - (b.toolCount ?? 0);\n if (toolCompare !== 0) {\n return direction * toolCompare;\n }\n\n return direction * a.name.localeCompare(b.name);\n};\n\nexport const isEnabledToggleUnavailable = (\n displayStatus: ServerStatus,\n): boolean => displayStatus === 'failed' || displayStatus === 'tokenRequired';\n\nexport const getEnabledToggleChecked = (\n server: McpServerDisplayInput,\n displayStatus: ServerStatus,\n): boolean =>\n isEnabledToggleUnavailable(displayStatus) ? false : server.enabled;\n\nexport const getInitialCredentialMode = (server: {\n hasUserToken: boolean;\n hasOrgToken: boolean;\n}): CredentialMode => {\n if (server.hasUserToken) {\n return 'personal';\n }\n if (server.hasOrgToken) {\n return 'organization';\n }\n return 'personal';\n};\n\nexport const getModalEffectiveHasToken = ({\n hasOrgToken,\n credentialMode,\n tokenInputValue,\n hasSavedPersonalTokenInModal,\n}: {\n hasOrgToken: boolean;\n credentialMode: CredentialMode;\n tokenInputValue: string;\n hasSavedPersonalTokenInModal: boolean;\n}): boolean => {\n if (credentialMode === 'organization') {\n return hasOrgToken;\n }\n return tokenInputValue.trim().length > 0 || hasSavedPersonalTokenInModal;\n};\n\nexport const getModalVerifiedHasToken = ({\n hasOrgToken,\n credentialMode,\n hasSavedPersonalTokenInModal,\n}: {\n hasOrgToken: boolean;\n credentialMode: CredentialMode;\n hasSavedPersonalTokenInModal: boolean;\n}): boolean => {\n if (credentialMode === 'organization') {\n return hasOrgToken;\n }\n return hasSavedPersonalTokenInModal;\n};\n\nexport const getModalDisplayHasToken = ({\n modalVerifiedHasToken,\n modalEnabled,\n serverHasToken,\n}: {\n modalVerifiedHasToken: boolean;\n modalEnabled: boolean;\n serverHasToken: boolean;\n}): boolean => modalVerifiedHasToken || (!modalEnabled && serverHasToken);\n\nexport const hasModalUnsavedChanges = ({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n}: {\n tokenInputValue: string;\n initialTokenInputValue: string;\n modalEnabled: boolean;\n serverEnabled: boolean;\n credentialMode?: CredentialMode;\n initialCredentialMode?: CredentialMode;\n}): boolean =>\n tokenInputValue !== initialTokenInputValue ||\n modalEnabled !== serverEnabled ||\n (credentialMode !== undefined &&\n initialCredentialMode !== undefined &&\n credentialMode !== initialCredentialMode);\n\nexport type TokenValidationState = 'idle' | 'validating' | 'success' | 'error';\n\nexport const isSaveTokenDisabled = ({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n hasOrgToken,\n hasSavedPersonalTokenInModal,\n tokenValidationState = 'idle',\n hasRemovedPersonalToken = false,\n isDcrServer = false,\n}: {\n tokenInputValue: string;\n initialTokenInputValue: string;\n modalEnabled: boolean;\n serverEnabled: boolean;\n credentialMode: CredentialMode;\n initialCredentialMode: CredentialMode;\n hasOrgToken: boolean;\n hasSavedPersonalTokenInModal: boolean;\n tokenValidationState?: TokenValidationState;\n hasRemovedPersonalToken?: boolean;\n isDcrServer?: boolean;\n}): boolean => {\n if (\n tokenValidationState === 'error' &&\n tokenInputValue === initialTokenInputValue\n ) {\n return true;\n }\n\n if (hasRemovedPersonalToken) {\n return false;\n }\n\n if (\n !hasModalUnsavedChanges({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n })\n ) {\n return true;\n }\n\n if (isDcrServer) {\n return false;\n }\n\n if (credentialMode === 'personal') {\n return !getModalEffectiveHasToken({\n hasOrgToken,\n credentialMode,\n tokenInputValue,\n hasSavedPersonalTokenInModal,\n });\n }\n\n return false;\n};\n\nexport type McpServerModalInput = McpServerDisplayInput & {\n hasUserToken?: boolean;\n};\n\nexport const hasModalEnabledStateChange = ({\n server,\n modalEnabled,\n}: {\n server?: McpServerModalInput;\n modalEnabled: boolean;\n}): boolean => Boolean(server && modalEnabled !== server.enabled);\n\nexport const getModalDisplayStatus = (\n server: McpServerDisplayInput,\n modalEnabled: boolean,\n): ServerStatus => getDisplayStatus({ ...server, enabled: modalEnabled });\n\nexport type ModalEnabledDescriptionKey =\n | 'mcp.settings.modal.enabledDescription'\n | 'mcp.settings.modal.enabledDescriptionOff'\n | 'mcp.settings.modal.enabledDescriptionTokenRequired';\n\nexport const getModalEnabledDescriptionKey = (\n isChecked: boolean,\n displayStatus: ServerStatus,\n): ModalEnabledDescriptionKey => {\n if (isChecked) {\n return 'mcp.settings.modal.enabledDescription';\n }\n if (displayStatus === 'tokenRequired') {\n return 'mcp.settings.modal.enabledDescriptionTokenRequired';\n }\n return 'mcp.settings.modal.enabledDescriptionOff';\n};\n\nexport const isModalEnabledChecked = ({\n displayStatus,\n modalEnabled,\n}: {\n displayStatus: ServerStatus;\n modalEnabled: boolean;\n}): boolean =>\n isEnabledToggleUnavailable(displayStatus) ? false : modalEnabled;\n\n/** Translation function shape accepted by {@link getDisplayDetail}. */\ntype TranslateFn = (key: any, options?: any) => string;\n\nexport const getDisplayDetail = (\n server: { toolCount: number },\n displayStatus: ServerStatus,\n t: TranslateFn,\n): string => {\n if (displayStatus === 'disabled') return t('mcp.settings.status.disabled');\n if (displayStatus === 'tokenRequired')\n return t('mcp.settings.status.tokenRequired');\n if (displayStatus === 'failed') return t('mcp.settings.status.failed');\n if (displayStatus === 'ok') {\n if (server.toolCount === 1) {\n return t('mcp.settings.status.oneTool', {\n count: String(server.toolCount),\n });\n }\n return t('mcp.settings.status.manyTools', {\n count: String(server.toolCount),\n });\n }\n return t('mcp.settings.status.unknown');\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcpServersDisplayUtils.esm.js","sources":["../../src/components/mcpServersDisplayUtils.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport type ServerStatus =\n 'tokenRequired' | 'disabled' | 'ok' | 'failed' | 'unknown';\n\nexport type McpServerSortColumn = 'name' | 'status';\n\nexport type CredentialMode = 'organization' | 'personal';\n\nexport type McpServerDisplayInput = {\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n hasToken: boolean;\n};\n\n/** Shared server shape used by the configure-server modal and its hook. */\nexport type McpConfigureServer = {\n id: string;\n name: string;\n url?: string;\n enabled: boolean;\n status: 'connected' | 'error' | 'unknown';\n toolCount: number;\n hasToken: boolean;\n hasUserToken: boolean;\n hasOrgToken: boolean;\n validationError?: string;\n /** 'dcr' = tokens are minted automatically (no manual token needed). */\n auth?: string;\n};\n\nexport const formatApiError = (error: unknown): string => {\n if (typeof error === 'string') {\n return error;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (error && typeof error === 'object') {\n if ('message' in error && typeof error.message === 'string') {\n return error.message;\n }\n if ('error' in error) {\n return formatApiError((error as { error: unknown }).error);\n }\n }\n return '';\n};\n\nexport const getDisplayStatus = (\n server: McpServerDisplayInput,\n): ServerStatus => {\n if (!server.hasToken) return 'tokenRequired';\n if (!server.enabled) return 'disabled';\n if (server.status === 'error') return 'failed';\n if (server.status === 'connected') return 'ok';\n return 'unknown';\n};\n\nexport const getStatusSortRank = (status: ServerStatus): number => {\n switch (status) {\n case 'ok':\n return 0;\n case 'disabled':\n return 1;\n case 'unknown':\n return 2;\n case 'tokenRequired':\n return 3;\n case 'failed':\n return 4;\n default:\n return 5;\n }\n};\n\nexport type McpServerSortInput = McpServerDisplayInput & {\n name: string;\n toolCount?: number;\n};\n\nexport const compareMcpServers = (\n a: McpServerSortInput,\n b: McpServerSortInput,\n sortColumn: McpServerSortColumn,\n sortAsc: boolean,\n): number => {\n const direction = sortAsc ? 1 : -1;\n\n if (sortColumn === 'name') {\n return direction * a.name.localeCompare(b.name);\n }\n\n const statusCompare =\n getStatusSortRank(getDisplayStatus(a)) -\n getStatusSortRank(getDisplayStatus(b));\n if (statusCompare !== 0) {\n return direction * statusCompare;\n }\n\n const toolCompare = (a.toolCount ?? 0) - (b.toolCount ?? 0);\n if (toolCompare !== 0) {\n return direction * toolCompare;\n }\n\n return direction * a.name.localeCompare(b.name);\n};\n\nexport const isEnabledToggleUnavailable = (\n displayStatus: ServerStatus,\n): boolean => displayStatus === 'failed' || displayStatus === 'tokenRequired';\n\nexport const getEnabledToggleChecked = (\n server: McpServerDisplayInput,\n displayStatus: ServerStatus,\n): boolean =>\n isEnabledToggleUnavailable(displayStatus) ? false : server.enabled;\n\nexport const getInitialCredentialMode = (server: {\n hasUserToken: boolean;\n hasOrgToken: boolean;\n}): CredentialMode => {\n if (server.hasUserToken) {\n return 'personal';\n }\n if (server.hasOrgToken) {\n return 'organization';\n }\n return 'personal';\n};\n\nexport const getModalEffectiveHasToken = ({\n hasOrgToken,\n credentialMode,\n tokenInputValue,\n hasSavedPersonalTokenInModal,\n}: {\n hasOrgToken: boolean;\n credentialMode: CredentialMode;\n tokenInputValue: string;\n hasSavedPersonalTokenInModal: boolean;\n}): boolean => {\n if (credentialMode === 'organization') {\n return hasOrgToken;\n }\n return tokenInputValue.trim().length > 0 || hasSavedPersonalTokenInModal;\n};\n\nexport const getModalVerifiedHasToken = ({\n hasOrgToken,\n credentialMode,\n hasSavedPersonalTokenInModal,\n}: {\n hasOrgToken: boolean;\n credentialMode: CredentialMode;\n hasSavedPersonalTokenInModal: boolean;\n}): boolean => {\n if (credentialMode === 'organization') {\n return hasOrgToken;\n }\n return hasSavedPersonalTokenInModal;\n};\n\nexport const getModalDisplayHasToken = ({\n modalVerifiedHasToken,\n modalEnabled,\n serverHasToken,\n}: {\n modalVerifiedHasToken: boolean;\n modalEnabled: boolean;\n serverHasToken: boolean;\n}): boolean => modalVerifiedHasToken || (!modalEnabled && serverHasToken);\n\nexport const hasModalUnsavedChanges = ({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n}: {\n tokenInputValue: string;\n initialTokenInputValue: string;\n modalEnabled: boolean;\n serverEnabled: boolean;\n credentialMode?: CredentialMode;\n initialCredentialMode?: CredentialMode;\n}): boolean =>\n tokenInputValue !== initialTokenInputValue ||\n modalEnabled !== serverEnabled ||\n (credentialMode !== undefined &&\n initialCredentialMode !== undefined &&\n credentialMode !== initialCredentialMode);\n\nexport type TokenValidationState = 'idle' | 'validating' | 'success' | 'error';\n\nexport const isSaveTokenDisabled = ({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n hasOrgToken,\n hasSavedPersonalTokenInModal,\n tokenValidationState = 'idle',\n hasRemovedPersonalToken = false,\n isDcrServer = false,\n}: {\n tokenInputValue: string;\n initialTokenInputValue: string;\n modalEnabled: boolean;\n serverEnabled: boolean;\n credentialMode: CredentialMode;\n initialCredentialMode: CredentialMode;\n hasOrgToken: boolean;\n hasSavedPersonalTokenInModal: boolean;\n tokenValidationState?: TokenValidationState;\n hasRemovedPersonalToken?: boolean;\n isDcrServer?: boolean;\n}): boolean => {\n if (\n tokenValidationState === 'error' &&\n tokenInputValue === initialTokenInputValue\n ) {\n return true;\n }\n\n if (hasRemovedPersonalToken) {\n return false;\n }\n\n if (\n !hasModalUnsavedChanges({\n tokenInputValue,\n initialTokenInputValue,\n modalEnabled,\n serverEnabled,\n credentialMode,\n initialCredentialMode,\n })\n ) {\n return true;\n }\n\n if (isDcrServer) {\n return false;\n }\n\n if (credentialMode === 'personal') {\n return !getModalEffectiveHasToken({\n hasOrgToken,\n credentialMode,\n tokenInputValue,\n hasSavedPersonalTokenInModal,\n });\n }\n\n return false;\n};\n\nexport type McpServerModalInput = McpServerDisplayInput & {\n hasUserToken?: boolean;\n};\n\nexport const hasModalEnabledStateChange = ({\n server,\n modalEnabled,\n}: {\n server?: McpServerModalInput;\n modalEnabled: boolean;\n}): boolean => Boolean(server && modalEnabled !== server.enabled);\n\nexport const getModalDisplayStatus = (\n server: McpServerDisplayInput,\n modalEnabled: boolean,\n): ServerStatus => getDisplayStatus({ ...server, enabled: modalEnabled });\n\nexport type ModalEnabledDescriptionKey =\n | 'mcp.settings.modal.enabledDescription'\n | 'mcp.settings.modal.enabledDescriptionOff'\n | 'mcp.settings.modal.enabledDescriptionTokenRequired';\n\nexport const getModalEnabledDescriptionKey = (\n isChecked: boolean,\n displayStatus: ServerStatus,\n): ModalEnabledDescriptionKey => {\n if (isChecked) {\n return 'mcp.settings.modal.enabledDescription';\n }\n if (displayStatus === 'tokenRequired') {\n return 'mcp.settings.modal.enabledDescriptionTokenRequired';\n }\n return 'mcp.settings.modal.enabledDescriptionOff';\n};\n\nexport const isModalEnabledChecked = ({\n displayStatus,\n modalEnabled,\n}: {\n displayStatus: ServerStatus;\n modalEnabled: boolean;\n}): boolean =>\n isEnabledToggleUnavailable(displayStatus) ? false : modalEnabled;\n\n/** Translation function shape accepted by {@link getDisplayDetail}. */\ntype TranslateFn = (key: any, options?: any) => string;\n\nexport const getDisplayDetail = (\n server: { toolCount: number },\n displayStatus: ServerStatus,\n t: TranslateFn,\n): string => {\n if (displayStatus === 'disabled') return t('mcp.settings.status.disabled');\n if (displayStatus === 'tokenRequired')\n return t('mcp.settings.status.tokenRequired');\n if (displayStatus === 'failed') return t('mcp.settings.status.failed');\n if (displayStatus === 'ok') {\n if (server.toolCount === 1) {\n return t('mcp.settings.status.oneTool', {\n count: String(server.toolCount),\n });\n }\n return t('mcp.settings.status.manyTools', {\n count: String(server.toolCount),\n });\n }\n return t('mcp.settings.status.unknown');\n};\n"],"names":[],"mappings":"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"}
|