@red-hat-developer-hub/backstage-plugin-intelligent-assistant 3.0.3 → 3.1.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/alpha.d.ts +15 -1
  3. package/dist/components/LightSpeedChat.esm.js +1 -1
  4. package/dist/components/LightspeedChatContainer.esm.js +4 -2
  5. package/dist/components/LightspeedChatContainer.esm.js.map +1 -1
  6. package/dist/components/McpConfigureServerModal.esm.js +407 -0
  7. package/dist/components/McpConfigureServerModal.esm.js.map +1 -0
  8. package/dist/components/McpServersSettings.esm.js +92 -475
  9. package/dist/components/McpServersSettings.esm.js.map +1 -1
  10. package/dist/components/mcpServersDisplayUtils.esm.js +167 -0
  11. package/dist/components/mcpServersDisplayUtils.esm.js.map +1 -0
  12. package/dist/hooks/useMcpConfigureModal.esm.js +465 -0
  13. package/dist/hooks/useMcpConfigureModal.esm.js.map +1 -0
  14. package/dist/index.esm.js +5 -4
  15. package/dist/index.esm.js.map +1 -1
  16. package/dist/legacy.esm.js +0 -2
  17. package/dist/legacy.esm.js.map +1 -1
  18. package/dist/plugin.esm.js +0 -2
  19. package/dist/plugin.esm.js.map +1 -1
  20. package/dist/translations/de.esm.js +16 -2
  21. package/dist/translations/de.esm.js.map +1 -1
  22. package/dist/translations/es.esm.js +16 -2
  23. package/dist/translations/es.esm.js.map +1 -1
  24. package/dist/translations/fr.esm.js +16 -2
  25. package/dist/translations/fr.esm.js.map +1 -1
  26. package/dist/translations/it.esm.js +16 -2
  27. package/dist/translations/it.esm.js.map +1 -1
  28. package/dist/translations/ja.esm.js +16 -2
  29. package/dist/translations/ja.esm.js.map +1 -1
  30. package/dist/translations/ref.esm.js +17 -3
  31. package/dist/translations/ref.esm.js.map +1 -1
  32. package/package.json +2 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-intelligent-assistant
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 94e2278: Refactor the MCP server configure modal with PatternFly layout and improved credential management:
8
+
9
+ - Add **Use organization default token** / **Use personal token** radio selectors when an app-config default token is available, replacing the remove-personal-token flow
10
+ - Show server status, tools list, and enabled toggle with local draft state applied on Save
11
+ - Hide the tools section when the server is disabled; keep status consistent while drafting an unverified personal token
12
+ - Disable Save after a failed token validation until the input changes
13
+ - Auto-enable the server after a successful personal token save
14
+ - Add sortable **Name** and **Status** columns to the MCP servers table, with always-visible sort icons (gray when inactive, directional when active)
15
+ - Keep the DCR configure modal aligned with personal-token servers (status, tools, enabled toggle, and Save/Cancel) with an additional DCR info alert and no token input
16
+ - Show **Fetching status...** in the Status section while server tools/status are loading
17
+ - Bump `@patternfly/react-core` to 6.6.0 and add translations for new modal strings (de, es, fr, it, ja)
18
+
19
+ The backend now exposes `hasOrgToken` on MCP server list and patch responses so the UI can distinguish organization default tokens from personal-only servers.
20
+
21
+ ### Patch Changes
22
+
23
+ - 16a4d45: Scope PatternFly CSS imports to the chatbot component and use useLayoutEffect for dark theme class toggle to prevent white background leak on dark themes.
24
+ - @red-hat-developer-hub/backstage-plugin-intelligent-assistant-common@3.1.0
25
+
3
26
  ## 3.0.3
4
27
 
5
28
  ### Patch Changes
package/dist/alpha.d.ts CHANGED
@@ -235,9 +235,23 @@ declare const intelligentAssistantTranslationRef: _backstage_frontend_plugin_api
235
235
  readonly 'mcp.settings.configureServerTitle': string;
236
236
  readonly 'mcp.settings.closeConfigureModalAriaLabel': string;
237
237
  readonly 'mcp.settings.modalDescription': string;
238
+ readonly 'mcp.settings.authenticationToken': string;
239
+ readonly 'mcp.settings.modal.authenticationHeading': string;
240
+ readonly 'mcp.settings.modal.credentialMode.organization': string;
241
+ readonly 'mcp.settings.modal.credentialMode.organizationDescription': string;
242
+ readonly 'mcp.settings.modal.credentialMode.personal': string;
243
+ readonly 'mcp.settings.modal.toolsHeading': string;
244
+ readonly 'mcp.settings.modal.loadingTools': string;
245
+ readonly 'mcp.settings.modal.fetchingStatus': string;
246
+ readonly 'mcp.settings.modal.loadingStatus': string;
247
+ readonly 'mcp.settings.modal.tokenRemovedWarning': string;
248
+ readonly 'mcp.settings.modal.noToolsAvailable': string;
249
+ readonly 'mcp.settings.modal.toolsLoadFailed': string;
250
+ readonly 'mcp.settings.modal.enabledDescription': string;
251
+ readonly 'mcp.settings.modal.enabledDescriptionOff': string;
252
+ readonly 'mcp.settings.modal.enabledDescriptionTokenRequired': string;
238
253
  readonly 'mcp.settings.savedToken': string;
239
254
  readonly 'mcp.settings.personalAccessToken': string;
240
- readonly 'mcp.settings.usingAdminCredential': string;
241
255
  readonly 'mcp.settings.enterToken': string;
242
256
  readonly 'mcp.settings.removePersonalToken': string;
243
257
  readonly 'mcp.settings.token.clearAriaLabel': string;
@@ -23,13 +23,13 @@ import { useLightspeedDeletePermission } from '../hooks/useLightspeedDeletePermi
23
23
  import { useLightspeedNotebooksPermission } from '../hooks/notebooks/useLightspeedNotebooksPermission.esm.js';
24
24
  import '@backstage/plugin-permission-react';
25
25
  import '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';
26
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
26
27
  import { useNotebookConversationIds } from '../hooks/useNotebookConversationIds.esm.js';
27
28
  import { useNotebookSession } from '../hooks/notebooks/useNotebookSession.esm.js';
28
29
  import { useNotebookSessions } from '../hooks/notebooks/useNotebookSessions.esm.js';
29
30
  import { usePinnedChatsSettings } from '../hooks/usePinnedChatsSettings.esm.js';
30
31
  import { useSortSettings } from '../hooks/useSortSettings.esm.js';
31
32
  import { useStopConversation } from '../hooks/useStopConversation.esm.js';
32
- import { useTranslation } from '../hooks/useTranslation.esm.js';
33
33
  import { useCreateNotebook } from '../hooks/notebooks/useCreateNotebook.esm.js';
34
34
  import { useNotebookDocuments } from '../hooks/notebooks/useNotebookDocuments.esm.js';
35
35
  import { useLightspeedDrawerContext } from '../hooks/useLightspeedDrawerContext.esm.js';
@@ -1,5 +1,7 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { useState, useMemo, useEffect } from 'react';
2
+ import '@patternfly/react-core/dist/styles/base-no-reset.css';
3
+ import '@patternfly/chatbot/dist/css/main.css';
4
+ import { useState, useMemo, useLayoutEffect, useEffect } from 'react';
3
5
  import { useAsync } from 'react-use';
4
6
  import { useApi, identityApiRef } from '@backstage/core-plugin-api';
5
7
  import { Button } from '@material-ui/core';
@@ -48,7 +50,7 @@ const LightspeedChatContainerInner = () => {
48
50
  })) : [],
49
51
  [models]
50
52
  );
51
- useEffect(() => {
53
+ useLayoutEffect(() => {
52
54
  const htmlTagElement = document.documentElement;
53
55
  if (type === THEME_DARK) {
54
56
  htmlTagElement.classList.add(THEME_DARK_CLASS);
@@ -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 { useEffect, 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 // Handle dark theme class on document\n useEffect(() => {\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')} &nbsp; <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 { 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')} &nbsp; <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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"}
@@ -0,0 +1,407 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { makeStyles } from '@material-ui/core';
3
+ import Typography from '@mui/material/Typography';
4
+ import { Switch, Modal, ModalHeader, Button, ModalBody, Stack, StackItem, Alert, Flex, FlexItem, Tooltip, Form, FormGroup, Radio, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, FormHelperText, HelperText, HelperTextItem, ModalFooter, Spinner, List, ListItem } from '@patternfly/react-core';
5
+ import { TimesIcon, InfoCircleIcon, KeyIcon, CheckCircleIcon, ExclamationCircleIcon } from '@patternfly/react-icons';
6
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
7
+
8
+ const useStyles = makeStyles({
9
+ configureModal: {
10
+ "& .pf-v6-c-modal-box__close, & .pf-v5-c-modal-box__close": {
11
+ display: "none"
12
+ },
13
+ "& .pf-v6-c-modal-box__body, & .pf-v5-c-modal-box__body": {
14
+ paddingTop: 0
15
+ }
16
+ },
17
+ modalCloseButton: {
18
+ position: "absolute",
19
+ top: "var(--pf-v6-c-modal-box__close--InsetBlockStart, 1.5rem)",
20
+ right: "var(--pf-v6-c-modal-box__close--InsetInlineEnd, 1.5rem)",
21
+ zIndex: 1
22
+ },
23
+ modalInfoAlert: {
24
+ "--pf-v6-c-alert--m-custom--BorderColor": "var(--pf-t--global--color--status--info--default)",
25
+ "--pf-v6-c-alert--m-custom__icon--Color": "var(--pf-t--global--color--status--info--default)",
26
+ "& .pf-v6-c-alert__icon": {
27
+ alignSelf: "start",
28
+ display: "flex",
29
+ alignItems: "flex-start",
30
+ justifyContent: "center",
31
+ boxSizing: "border-box",
32
+ marginBlockStart: 0,
33
+ paddingBlockStart: "18.620px",
34
+ paddingInline: "var(--pf-t--global--spacer--md)",
35
+ paddingBlockEnd: "var(--pf-t--global--spacer--md)"
36
+ }
37
+ },
38
+ sectionTitle: {
39
+ fontSize: "0.875rem",
40
+ fontWeight: 600
41
+ },
42
+ sectionDescription: {
43
+ color: "var(--pf-t--global--text--color--subtle)",
44
+ fontSize: "0.875rem"
45
+ },
46
+ credentialRadioDescription: {
47
+ color: "var(--pf-t--global--text--color--subtle)",
48
+ fontSize: "0.875rem"
49
+ },
50
+ statusOk: {
51
+ color: "var(--pf-t--global--icon--color--status--custom--default)"
52
+ },
53
+ statusWarn: {
54
+ color: "var(--pf-t--global--icon--color--status--danger--default)"
55
+ },
56
+ statusDisabled: {
57
+ color: "var(--pf-t--global--icon--color--subtle)"
58
+ },
59
+ // Shape only; danger colors come from secondary + isDanger.
60
+ removePersonalTokenButton: {
61
+ borderRadius: "1.25rem",
62
+ boxShadow: "none"
63
+ }
64
+ });
65
+ const McpConfigureServerModal = ({
66
+ isOpen,
67
+ editingServer,
68
+ close,
69
+ save,
70
+ removePersonalToken,
71
+ canManageMcp,
72
+ configureModalTitle,
73
+ isConfigureModalSaving,
74
+ isSaveTokenButtonDisabled,
75
+ isUpdatingModalStatus,
76
+ tokenInputValue,
77
+ onTokenInputChange,
78
+ clearTokenInput,
79
+ tokenInputValidated,
80
+ tokenValidationState,
81
+ tokenHelperVariant,
82
+ showTokenHelperText,
83
+ tokenHelperText,
84
+ modalCredentialMode,
85
+ onCredentialModeChange,
86
+ showCredentialRadios,
87
+ showPersonalTokenField,
88
+ onModalEnabledChange,
89
+ isModalEnabledChecked,
90
+ isModalEnabledToggleDisabled,
91
+ modalDisplayStatus,
92
+ modalStatusDetail,
93
+ modalStatusText,
94
+ modalTools,
95
+ modalToolCount,
96
+ isLoadingModalTools,
97
+ modalToolsError,
98
+ modalToolsEmptyText,
99
+ modalVerifiedHasToken,
100
+ modalEnabledDescription,
101
+ canRemovePersonalToken,
102
+ hasSavedTokenInModal,
103
+ hasRemovedPersonalToken
104
+ }) => {
105
+ const classes = useStyles();
106
+ const { t } = useTranslation();
107
+ const renderStatusIcon = () => {
108
+ if (isUpdatingModalStatus || isLoadingModalTools) {
109
+ return /* @__PURE__ */ jsx(
110
+ Spinner,
111
+ {
112
+ size: "md",
113
+ "aria-label": isUpdatingModalStatus ? t("mcp.settings.modal.loadingStatus") : t("mcp.settings.modal.fetchingStatus")
114
+ }
115
+ );
116
+ }
117
+ if (modalDisplayStatus === "disabled") {
118
+ return /* @__PURE__ */ jsx(InfoCircleIcon, { className: classes.statusDisabled });
119
+ }
120
+ if (modalDisplayStatus === "tokenRequired") {
121
+ return /* @__PURE__ */ jsx(KeyIcon, { className: classes.statusWarn });
122
+ }
123
+ if (modalDisplayStatus === "ok" && modalTools.length > 0) {
124
+ return /* @__PURE__ */ jsx(CheckCircleIcon, { className: classes.statusOk });
125
+ }
126
+ if (modalToolsError || modalDisplayStatus === "failed") {
127
+ return /* @__PURE__ */ jsx(ExclamationCircleIcon, { className: classes.statusWarn });
128
+ }
129
+ return /* @__PURE__ */ jsx(InfoCircleIcon, { className: classes.statusDisabled });
130
+ };
131
+ const renderToolsContent = () => {
132
+ if (isLoadingModalTools) {
133
+ return /* @__PURE__ */ jsx(Spinner, { size: "md", "aria-label": t("mcp.settings.modal.loadingTools") });
134
+ }
135
+ if (modalTools.length > 0) {
136
+ return /* @__PURE__ */ jsx(
137
+ List,
138
+ {
139
+ isPlain: true,
140
+ "aria-label": t("mcp.settings.modal.toolsHeading", {
141
+ count: String(modalToolCount)
142
+ }),
143
+ children: modalTools.map((toolName) => /* @__PURE__ */ jsx(
144
+ ListItem,
145
+ {
146
+ icon: /* @__PURE__ */ jsx(CheckCircleIcon, { className: classes.statusOk }),
147
+ children: toolName
148
+ },
149
+ toolName
150
+ ))
151
+ }
152
+ );
153
+ }
154
+ return /* @__PURE__ */ jsx(
155
+ Typography,
156
+ {
157
+ component: "div",
158
+ className: `${classes.sectionDescription} pf-v6-u-mt-xs`,
159
+ children: modalToolsEmptyText
160
+ }
161
+ );
162
+ };
163
+ const enabledSwitch = /* @__PURE__ */ jsx(
164
+ Switch,
165
+ {
166
+ id: "mcp-configure-enabled-switch",
167
+ "aria-label": t("mcp.settings.toggleServerAriaLabel", {
168
+ serverName: editingServer?.name ?? ""
169
+ }),
170
+ isChecked: isModalEnabledChecked,
171
+ isDisabled: isModalEnabledToggleDisabled,
172
+ onChange: onModalEnabledChange
173
+ }
174
+ );
175
+ return /* @__PURE__ */ jsxs(
176
+ Modal,
177
+ {
178
+ variant: "small",
179
+ width: 608,
180
+ isOpen,
181
+ onClose: close,
182
+ className: classes.configureModal,
183
+ "aria-labelledby": "mcp-configure-modal",
184
+ "aria-describedby": "mcp-configure-modal-body",
185
+ children: [
186
+ /* @__PURE__ */ jsx(
187
+ ModalHeader,
188
+ {
189
+ title: configureModalTitle,
190
+ labelId: "mcp-configure-modal",
191
+ descriptorId: "mcp-configure-modal-body"
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsx(
195
+ Button,
196
+ {
197
+ variant: "plain",
198
+ icon: /* @__PURE__ */ jsx(TimesIcon, {}),
199
+ "aria-label": t("mcp.settings.closeConfigureModalAriaLabel"),
200
+ className: classes.modalCloseButton,
201
+ onClick: close
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx(ModalBody, { id: "mcp-configure-modal-body", children: /* @__PURE__ */ jsxs(Stack, { hasGutter: true, children: [
205
+ /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsx(
206
+ Alert,
207
+ {
208
+ variant: "custom",
209
+ customIcon: /* @__PURE__ */ jsx(InfoCircleIcon, {}),
210
+ title: t("mcp.settings.modalDescription"),
211
+ className: classes.modalInfoAlert,
212
+ isInline: true
213
+ }
214
+ ) }),
215
+ editingServer?.auth === "dcr" && /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsx(
216
+ Alert,
217
+ {
218
+ variant: "custom",
219
+ customIcon: /* @__PURE__ */ jsx(InfoCircleIcon, {}),
220
+ title: t("mcp.settings.modalDescriptionDcr"),
221
+ className: classes.modalInfoAlert,
222
+ isInline: true
223
+ }
224
+ ) }),
225
+ hasRemovedPersonalToken && !editingServer?.hasOrgToken && /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsx(
226
+ Alert,
227
+ {
228
+ variant: "custom",
229
+ customIcon: /* @__PURE__ */ jsx(InfoCircleIcon, {}),
230
+ title: t("mcp.settings.modal.tokenRemovedWarning"),
231
+ className: classes.modalInfoAlert,
232
+ isInline: true
233
+ }
234
+ ) }),
235
+ /* @__PURE__ */ jsxs(StackItem, { children: [
236
+ /* @__PURE__ */ jsx(
237
+ Typography,
238
+ {
239
+ component: "div",
240
+ className: `${classes.sectionTitle} pf-v6-u-mb-sm`,
241
+ children: t("mcp.settings.status")
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsxs(
245
+ Flex,
246
+ {
247
+ alignItems: { default: "alignItemsCenter" },
248
+ spaceItems: { default: "spaceItemsSm" },
249
+ children: [
250
+ /* @__PURE__ */ jsx(FlexItem, { children: renderStatusIcon() }),
251
+ /* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(Typography, { component: "span", children: modalStatusText }) })
252
+ ]
253
+ }
254
+ )
255
+ ] }),
256
+ modalVerifiedHasToken && modalDisplayStatus === "ok" && /* @__PURE__ */ jsxs(StackItem, { children: [
257
+ /* @__PURE__ */ jsx(
258
+ Typography,
259
+ {
260
+ component: "div",
261
+ className: `${classes.sectionTitle} pf-v6-u-mb-sm`,
262
+ children: t("mcp.settings.modal.toolsHeading", {
263
+ count: String(modalToolCount)
264
+ })
265
+ }
266
+ ),
267
+ renderToolsContent()
268
+ ] }),
269
+ /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsxs(
270
+ Flex,
271
+ {
272
+ justifyContent: { default: "justifyContentSpaceBetween" },
273
+ alignItems: { default: "alignItemsFlexStart" },
274
+ spaceItems: { default: "spaceItemsMd" },
275
+ children: [
276
+ /* @__PURE__ */ jsxs(FlexItem, { flex: { default: "flex_1" }, children: [
277
+ /* @__PURE__ */ jsx(
278
+ Typography,
279
+ {
280
+ component: "div",
281
+ className: `${classes.sectionTitle} pf-v6-u-mb-sm`,
282
+ children: t("mcp.settings.enabled")
283
+ }
284
+ ),
285
+ /* @__PURE__ */ jsx(
286
+ Typography,
287
+ {
288
+ component: "div",
289
+ className: `${classes.sectionDescription} pf-v6-u-mt-xs`,
290
+ children: modalEnabledDescription
291
+ }
292
+ )
293
+ ] }),
294
+ /* @__PURE__ */ jsx(FlexItem, { children: isModalEnabledToggleDisabled ? /* @__PURE__ */ jsx(Tooltip, { content: modalStatusDetail, children: /* @__PURE__ */ jsx(Typography, { component: "span", children: enabledSwitch }) }) : enabledSwitch })
295
+ ]
296
+ }
297
+ ) }),
298
+ (showCredentialRadios || showPersonalTokenField) && /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsxs(Form, { children: [
299
+ showCredentialRadios && /* @__PURE__ */ jsx(
300
+ FormGroup,
301
+ {
302
+ role: "radiogroup",
303
+ id: "mcp-credential-mode",
304
+ fieldId: "mcp-credential-mode",
305
+ label: t("mcp.settings.modal.authenticationHeading"),
306
+ children: /* @__PURE__ */ jsxs(Stack, { hasGutter: true, children: [
307
+ /* @__PURE__ */ jsxs(StackItem, { children: [
308
+ /* @__PURE__ */ jsx(
309
+ Radio,
310
+ {
311
+ id: "mcp-credential-organization",
312
+ name: "mcp-credential-mode",
313
+ label: t(
314
+ "mcp.settings.modal.credentialMode.organization"
315
+ ),
316
+ isChecked: modalCredentialMode === "organization",
317
+ onChange: () => onCredentialModeChange("organization")
318
+ }
319
+ ),
320
+ /* @__PURE__ */ jsx(
321
+ Typography,
322
+ {
323
+ component: "div",
324
+ className: `${classes.credentialRadioDescription} pf-v6-u-ml-xl pf-v6-u-mt-xs`,
325
+ children: t(
326
+ "mcp.settings.modal.credentialMode.organizationDescription"
327
+ )
328
+ }
329
+ )
330
+ ] }),
331
+ /* @__PURE__ */ jsx(StackItem, { children: /* @__PURE__ */ jsx(
332
+ Radio,
333
+ {
334
+ id: "mcp-credential-personal",
335
+ name: "mcp-credential-mode",
336
+ label: t(
337
+ "mcp.settings.modal.credentialMode.personal"
338
+ ),
339
+ isChecked: modalCredentialMode === "personal",
340
+ onChange: () => onCredentialModeChange("personal")
341
+ }
342
+ ) })
343
+ ] })
344
+ }
345
+ ),
346
+ showPersonalTokenField && /* @__PURE__ */ jsxs(
347
+ FormGroup,
348
+ {
349
+ label: t("mcp.settings.authenticationToken"),
350
+ fieldId: "mcp-pat-input",
351
+ children: [
352
+ /* @__PURE__ */ jsxs(TextInputGroup, { validated: tokenInputValidated, children: [
353
+ /* @__PURE__ */ jsx(
354
+ TextInputGroupMain,
355
+ {
356
+ inputId: "mcp-pat-input",
357
+ type: "password",
358
+ value: tokenInputValue,
359
+ onChange: (_event, value) => onTokenInputChange(value)
360
+ }
361
+ ),
362
+ (tokenValidationState === "idle" || tokenValidationState === "validating") && /* @__PURE__ */ jsx(TextInputGroupUtilities, { children: /* @__PURE__ */ jsx(
363
+ Button,
364
+ {
365
+ variant: "plain",
366
+ onClick: clearTokenInput,
367
+ "aria-label": t("mcp.settings.token.clearAriaLabel"),
368
+ icon: /* @__PURE__ */ jsx(TimesIcon, {})
369
+ }
370
+ ) })
371
+ ] }),
372
+ showTokenHelperText && /* @__PURE__ */ jsx(FormHelperText, { children: /* @__PURE__ */ jsx(HelperText, { children: /* @__PURE__ */ jsx(HelperTextItem, { variant: tokenHelperVariant, children: tokenHelperText }) }) })
373
+ ]
374
+ }
375
+ )
376
+ ] }) })
377
+ ] }) }),
378
+ /* @__PURE__ */ jsxs(ModalFooter, { children: [
379
+ /* @__PURE__ */ jsx(
380
+ Button,
381
+ {
382
+ variant: "primary",
383
+ onClick: () => void save(),
384
+ isDisabled: !canManageMcp || isConfigureModalSaving || tokenValidationState === "validating" || isSaveTokenButtonDisabled || isUpdatingModalStatus,
385
+ children: t("modal.save")
386
+ }
387
+ ),
388
+ canRemovePersonalToken && /* @__PURE__ */ jsx(
389
+ Button,
390
+ {
391
+ variant: "secondary",
392
+ isDanger: true,
393
+ onClick: () => void removePersonalToken(),
394
+ isDisabled: !canManageMcp || isConfigureModalSaving || tokenValidationState === "validating" || isUpdatingModalStatus || hasRemovedPersonalToken || !hasSavedTokenInModal,
395
+ className: classes.removePersonalTokenButton,
396
+ children: t("mcp.settings.removePersonalToken")
397
+ }
398
+ ),
399
+ /* @__PURE__ */ jsx(Button, { variant: "link", onClick: close, children: t("common.cancel") })
400
+ ] })
401
+ ]
402
+ }
403
+ );
404
+ };
405
+
406
+ export { McpConfigureServerModal };
407
+ //# sourceMappingURL=McpConfigureServerModal.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpConfigureServerModal.esm.js","sources":["../../src/components/McpConfigureServerModal.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 { makeStyles } from '@material-ui/core';\nimport Typography from '@mui/material/Typography';\nimport {\n Alert,\n Button,\n Flex,\n FlexItem,\n Form,\n FormGroup,\n FormHelperText,\n HelperText,\n HelperTextItem,\n List,\n ListItem,\n Modal,\n ModalBody,\n ModalFooter,\n ModalHeader,\n Radio,\n Spinner,\n Stack,\n StackItem,\n Switch,\n TextInputGroup,\n TextInputGroupMain,\n TextInputGroupUtilities,\n Tooltip,\n} from '@patternfly/react-core';\nimport {\n CheckCircleIcon,\n ExclamationCircleIcon,\n InfoCircleIcon,\n KeyIcon,\n TimesIcon,\n} from '@patternfly/react-icons';\n\nimport { type UseMcpConfigureModalResult } from '../hooks/useMcpConfigureModal';\nimport { useTranslation } from '../hooks/useTranslation';\n\nconst useStyles = makeStyles({\n configureModal: {\n '& .pf-v6-c-modal-box__close, & .pf-v5-c-modal-box__close': {\n display: 'none',\n },\n '& .pf-v6-c-modal-box__body, & .pf-v5-c-modal-box__body': {\n paddingTop: 0,\n },\n },\n modalCloseButton: {\n position: 'absolute',\n top: 'var(--pf-v6-c-modal-box__close--InsetBlockStart, 1.5rem)',\n right: 'var(--pf-v6-c-modal-box__close--InsetInlineEnd, 1.5rem)',\n zIndex: 1,\n },\n modalInfoAlert: {\n '--pf-v6-c-alert--m-custom--BorderColor':\n 'var(--pf-t--global--color--status--info--default)',\n '--pf-v6-c-alert--m-custom__icon--Color':\n 'var(--pf-t--global--color--status--info--default)',\n '& .pf-v6-c-alert__icon': {\n alignSelf: 'start',\n display: 'flex',\n alignItems: 'flex-start',\n justifyContent: 'center',\n boxSizing: 'border-box',\n marginBlockStart: 0,\n paddingBlockStart: '18.620px',\n paddingInline: 'var(--pf-t--global--spacer--md)',\n paddingBlockEnd: 'var(--pf-t--global--spacer--md)',\n },\n },\n sectionTitle: {\n fontSize: '0.875rem',\n fontWeight: 600,\n },\n sectionDescription: {\n color: 'var(--pf-t--global--text--color--subtle)',\n fontSize: '0.875rem',\n },\n credentialRadioDescription: {\n color: 'var(--pf-t--global--text--color--subtle)',\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 // Shape only; danger colors come from secondary + isDanger.\n removePersonalTokenButton: {\n borderRadius: '1.25rem',\n boxShadow: 'none',\n },\n});\n\ntype McpConfigureServerModalProps = UseMcpConfigureModalResult;\n\nexport const McpConfigureServerModal = ({\n isOpen,\n editingServer,\n close,\n save,\n removePersonalToken,\n canManageMcp,\n configureModalTitle,\n isConfigureModalSaving,\n isSaveTokenButtonDisabled,\n isUpdatingModalStatus,\n tokenInputValue,\n onTokenInputChange,\n clearTokenInput,\n tokenInputValidated,\n tokenValidationState,\n tokenHelperVariant,\n showTokenHelperText,\n tokenHelperText,\n modalCredentialMode,\n onCredentialModeChange,\n showCredentialRadios,\n showPersonalTokenField,\n onModalEnabledChange,\n isModalEnabledChecked,\n isModalEnabledToggleDisabled,\n modalDisplayStatus,\n modalStatusDetail,\n modalStatusText,\n modalTools,\n modalToolCount,\n isLoadingModalTools,\n modalToolsError,\n modalToolsEmptyText,\n modalVerifiedHasToken,\n modalEnabledDescription,\n canRemovePersonalToken,\n hasSavedTokenInModal,\n hasRemovedPersonalToken,\n}: McpConfigureServerModalProps) => {\n const classes = useStyles();\n const { t } = useTranslation();\n\n const renderStatusIcon = () => {\n if (isUpdatingModalStatus || isLoadingModalTools) {\n return (\n <Spinner\n size=\"md\"\n aria-label={\n isUpdatingModalStatus\n ? t('mcp.settings.modal.loadingStatus')\n : t('mcp.settings.modal.fetchingStatus')\n }\n />\n );\n }\n if (modalDisplayStatus === 'disabled') {\n return <InfoCircleIcon className={classes.statusDisabled} />;\n }\n if (modalDisplayStatus === 'tokenRequired') {\n return <KeyIcon className={classes.statusWarn} />;\n }\n if (modalDisplayStatus === 'ok' && modalTools.length > 0) {\n return <CheckCircleIcon className={classes.statusOk} />;\n }\n if (modalToolsError || modalDisplayStatus === 'failed') {\n return <ExclamationCircleIcon className={classes.statusWarn} />;\n }\n return <InfoCircleIcon className={classes.statusDisabled} />;\n };\n\n const renderToolsContent = () => {\n if (isLoadingModalTools) {\n return (\n <Spinner size=\"md\" aria-label={t('mcp.settings.modal.loadingTools')} />\n );\n }\n if (modalTools.length > 0) {\n return (\n <List\n isPlain\n aria-label={t('mcp.settings.modal.toolsHeading' as any, {\n count: String(modalToolCount),\n })}\n >\n {modalTools.map(toolName => (\n <ListItem\n key={toolName}\n icon={<CheckCircleIcon className={classes.statusOk} />}\n >\n {toolName}\n </ListItem>\n ))}\n </List>\n );\n }\n return (\n <Typography\n component=\"div\"\n className={`${classes.sectionDescription} pf-v6-u-mt-xs`}\n >\n {modalToolsEmptyText}\n </Typography>\n );\n };\n\n const enabledSwitch = (\n <Switch\n id=\"mcp-configure-enabled-switch\"\n aria-label={t('mcp.settings.toggleServerAriaLabel' as any, {\n serverName: editingServer?.name ?? '',\n })}\n isChecked={isModalEnabledChecked}\n isDisabled={isModalEnabledToggleDisabled}\n onChange={onModalEnabledChange}\n />\n );\n\n return (\n <Modal\n variant=\"small\"\n width={608}\n isOpen={isOpen}\n onClose={close}\n className={classes.configureModal}\n aria-labelledby=\"mcp-configure-modal\"\n aria-describedby=\"mcp-configure-modal-body\"\n >\n <ModalHeader\n title={configureModalTitle}\n labelId=\"mcp-configure-modal\"\n descriptorId=\"mcp-configure-modal-body\"\n />\n <Button\n variant=\"plain\"\n icon={<TimesIcon />}\n aria-label={t('mcp.settings.closeConfigureModalAriaLabel')}\n className={classes.modalCloseButton}\n onClick={close}\n />\n <ModalBody id=\"mcp-configure-modal-body\">\n <Stack hasGutter>\n <StackItem>\n <Alert\n variant=\"custom\"\n customIcon={<InfoCircleIcon />}\n title={t('mcp.settings.modalDescription')}\n className={classes.modalInfoAlert}\n isInline\n />\n </StackItem>\n {editingServer?.auth === 'dcr' && (\n <StackItem>\n <Alert\n variant=\"custom\"\n customIcon={<InfoCircleIcon />}\n title={t('mcp.settings.modalDescriptionDcr')}\n className={classes.modalInfoAlert}\n isInline\n />\n </StackItem>\n )}\n {hasRemovedPersonalToken && !editingServer?.hasOrgToken && (\n <StackItem>\n <Alert\n variant=\"custom\"\n customIcon={<InfoCircleIcon />}\n title={t('mcp.settings.modal.tokenRemovedWarning')}\n className={classes.modalInfoAlert}\n isInline\n />\n </StackItem>\n )}\n <StackItem>\n <Typography\n component=\"div\"\n className={`${classes.sectionTitle} pf-v6-u-mb-sm`}\n >\n {t('mcp.settings.status')}\n </Typography>\n <Flex\n alignItems={{ default: 'alignItemsCenter' }}\n spaceItems={{ default: 'spaceItemsSm' }}\n >\n <FlexItem>{renderStatusIcon()}</FlexItem>\n <FlexItem>\n <Typography component=\"span\">{modalStatusText}</Typography>\n </FlexItem>\n </Flex>\n </StackItem>\n {modalVerifiedHasToken && modalDisplayStatus === 'ok' && (\n <StackItem>\n <Typography\n component=\"div\"\n className={`${classes.sectionTitle} pf-v6-u-mb-sm`}\n >\n {t('mcp.settings.modal.toolsHeading' as any, {\n count: String(modalToolCount),\n })}\n </Typography>\n {renderToolsContent()}\n </StackItem>\n )}\n <StackItem>\n <Flex\n justifyContent={{ default: 'justifyContentSpaceBetween' }}\n alignItems={{ default: 'alignItemsFlexStart' }}\n spaceItems={{ default: 'spaceItemsMd' }}\n >\n <FlexItem flex={{ default: 'flex_1' }}>\n <Typography\n component=\"div\"\n className={`${classes.sectionTitle} pf-v6-u-mb-sm`}\n >\n {t('mcp.settings.enabled')}\n </Typography>\n <Typography\n component=\"div\"\n className={`${classes.sectionDescription} pf-v6-u-mt-xs`}\n >\n {modalEnabledDescription}\n </Typography>\n </FlexItem>\n <FlexItem>\n {isModalEnabledToggleDisabled ? (\n <Tooltip content={modalStatusDetail}>\n <Typography component=\"span\">{enabledSwitch}</Typography>\n </Tooltip>\n ) : (\n enabledSwitch\n )}\n </FlexItem>\n </Flex>\n </StackItem>\n {(showCredentialRadios || showPersonalTokenField) && (\n <StackItem>\n <Form>\n {showCredentialRadios && (\n <FormGroup\n role=\"radiogroup\"\n id=\"mcp-credential-mode\"\n fieldId=\"mcp-credential-mode\"\n label={t('mcp.settings.modal.authenticationHeading')}\n >\n <Stack hasGutter>\n <StackItem>\n <Radio\n id=\"mcp-credential-organization\"\n name=\"mcp-credential-mode\"\n label={t(\n 'mcp.settings.modal.credentialMode.organization',\n )}\n isChecked={modalCredentialMode === 'organization'}\n onChange={() =>\n onCredentialModeChange('organization')\n }\n />\n <Typography\n component=\"div\"\n className={`${classes.credentialRadioDescription} pf-v6-u-ml-xl pf-v6-u-mt-xs`}\n >\n {t(\n 'mcp.settings.modal.credentialMode.organizationDescription',\n )}\n </Typography>\n </StackItem>\n <StackItem>\n <Radio\n id=\"mcp-credential-personal\"\n name=\"mcp-credential-mode\"\n label={t(\n 'mcp.settings.modal.credentialMode.personal',\n )}\n isChecked={modalCredentialMode === 'personal'}\n onChange={() => onCredentialModeChange('personal')}\n />\n </StackItem>\n </Stack>\n </FormGroup>\n )}\n {showPersonalTokenField && (\n <FormGroup\n label={t('mcp.settings.authenticationToken')}\n fieldId=\"mcp-pat-input\"\n >\n <TextInputGroup validated={tokenInputValidated}>\n <TextInputGroupMain\n inputId=\"mcp-pat-input\"\n type=\"password\"\n value={tokenInputValue}\n onChange={(_event, value) => onTokenInputChange(value)}\n />\n {(tokenValidationState === 'idle' ||\n tokenValidationState === 'validating') && (\n <TextInputGroupUtilities>\n <Button\n variant=\"plain\"\n onClick={clearTokenInput}\n aria-label={t('mcp.settings.token.clearAriaLabel')}\n icon={<TimesIcon />}\n />\n </TextInputGroupUtilities>\n )}\n </TextInputGroup>\n {showTokenHelperText && (\n <FormHelperText>\n <HelperText>\n <HelperTextItem variant={tokenHelperVariant}>\n {tokenHelperText}\n </HelperTextItem>\n </HelperText>\n </FormHelperText>\n )}\n </FormGroup>\n )}\n </Form>\n </StackItem>\n )}\n </Stack>\n </ModalBody>\n <ModalFooter>\n <Button\n variant=\"primary\"\n onClick={() => void save()}\n isDisabled={\n !canManageMcp ||\n isConfigureModalSaving ||\n tokenValidationState === 'validating' ||\n isSaveTokenButtonDisabled ||\n isUpdatingModalStatus\n }\n >\n {t('modal.save')}\n </Button>\n {canRemovePersonalToken && (\n <Button\n variant=\"secondary\"\n isDanger\n onClick={() => void removePersonalToken()}\n isDisabled={\n !canManageMcp ||\n isConfigureModalSaving ||\n tokenValidationState === 'validating' ||\n isUpdatingModalStatus ||\n hasRemovedPersonalToken ||\n !hasSavedTokenInModal\n }\n className={classes.removePersonalTokenButton}\n >\n {t('mcp.settings.removePersonalToken')}\n </Button>\n )}\n <Button variant=\"link\" onClick={close}>\n {t('common.cancel')}\n </Button>\n </ModalFooter>\n </Modal>\n );\n};\n"],"names":[],"mappings":"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"}