@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.
- package/CHANGELOG.md +23 -0
- package/dist/alpha.d.ts +15 -1
- package/dist/components/LightSpeedChat.esm.js +1 -1
- package/dist/components/LightspeedChatContainer.esm.js +4 -2
- package/dist/components/LightspeedChatContainer.esm.js.map +1 -1
- package/dist/components/McpConfigureServerModal.esm.js +407 -0
- package/dist/components/McpConfigureServerModal.esm.js.map +1 -0
- package/dist/components/McpServersSettings.esm.js +92 -475
- package/dist/components/McpServersSettings.esm.js.map +1 -1
- package/dist/components/mcpServersDisplayUtils.esm.js +167 -0
- package/dist/components/mcpServersDisplayUtils.esm.js.map +1 -0
- package/dist/hooks/useMcpConfigureModal.esm.js +465 -0
- package/dist/hooks/useMcpConfigureModal.esm.js.map +1 -0
- package/dist/index.esm.js +5 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/legacy.esm.js +0 -2
- package/dist/legacy.esm.js.map +1 -1
- package/dist/plugin.esm.js +0 -2
- package/dist/plugin.esm.js.map +1 -1
- package/dist/translations/de.esm.js +16 -2
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +16 -2
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +16 -2
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +16 -2
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +16 -2
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +17 -3
- package/dist/translations/ref.esm.js.map +1 -1
- 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
|
|
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
|
-
|
|
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')} <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":";;;;;;;;;;;;;;;;;;;;AAgDA,MAAM,UAAA,GAAa,MAAA;AACnB,MAAM,gBAAA,GAAmB,kBAAA;AACzB,MAAM,uBAAA,GAA0B,mBAAA;AAKhC,MAAM,+BAA+B,MAAM;AACzC,EAAA,MAAM;AAAA,IACJ,OAAA,EAAS,EAAE,IAAA;AAAK,MACd,QAAA,EAAS;AACb,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,EAAe;AAE7B,EAAA,MAAM,WAAA,GAAc,OAAO,cAAc,CAAA;AAEzC,EAAA,MAAM;AAAA,IACJ,IAAA,EAAM,MAAA;AAAA,IACN,SAAA,EAAW,aAAA;AAAA,IACX,OAAA,EAAS,WAAA;AAAA,IACT,OAAA,EAAS;AAAA,MACP,YAAA,EAAa;AAEjB,EAAA,MAAM,EAAE,OAAA,EAAS,aAAA,EAAe,OAAA,KAAY,2BAAA,EAA4B;AAExE,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS,gBAAe,GAAI,QAAA;AAAA,IAClD,YAAY,MAAM,WAAA,CAAY,cAAA;AAAe,GAC/C;AAEA,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAS,EAAE,CAAA;AACrD,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAI,SAAS,EAAE,CAAA;AAE3D,EAAA,MAAM,EAAE,IAAA,EAAM,uBAAA,EAAwB,GAAI,yBAAA,EAA0B;AAEpE,EAAA,MAAM,WAAA,GAAc,OAAA;AAAA,IAClB,MACE,MAAA,GACI,MAAA,CACG,MAAA,CAAO,CAAA,KAAA,KAAS,MAAM,UAAA,KAAe,KAAK,CAAA,CAC1C,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MACT,OAAO,CAAA,CAAE,oBAAA;AAAA,MACT,OAAO,CAAA,CAAE,oBAAA;AAAA,MACT,UAAU,CAAA,CAAE;AAAA,KACd,CAAE,IACJ,EAAC;AAAA,IACP,CAAC,MAAM;AAAA,GACT;AAGA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,iBAAiB,QAAA,CAAS,eAAA;AAChC,IAAA,IAAI,SAAS,UAAA,EAAY;AACvB,MAAA,cAAA,CAAe,SAAA,CAAU,IAAI,gBAAgB,CAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,cAAA,CAAe,SAAA,CAAU,OAAO,gBAAgB,CAAA;AAAA,IAClD;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAGT,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,MAAA,IAAI;AACF,QAAA,MAAM,UAAA,GAAa,YAAA,CAAa,OAAA,CAAQ,uBAAuB,CAAA;AAC/D,QAAA,MAAM,UAAA,GAAa,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA,GAAI,IAAA;AAEzD,QAAA,MAAM,WAAA,GAAc,UAAA,EAAY,KAAA,GAC5B,WAAA,CAAY,IAAA,CAAK,OAAK,CAAA,CAAE,KAAA,KAAU,UAAA,CAAW,KAAK,CAAA,GAClD,IAAA;AAEJ,QAAA,IAAI,WAAA,EAAa;AACf,UAAA,gBAAA,CAAiB,YAAY,KAAK,CAAA;AAClC,UAAA,mBAAA,CAAoB,YAAY,QAAQ,CAAA;AAAA,QAC1C,CAAA,MAAO;AACL,UAAA,gBAAA,CAAiB,WAAA,CAAY,CAAC,CAAA,CAAE,KAAK,CAAA;AACrC,UAAA,mBAAA,CAAoB,WAAA,CAAY,CAAC,CAAA,CAAE,QAAQ,CAAA;AAAA,QAC7C;AAAA,MACF,SAAS,KAAA,EAAO;AAEd,QAAA,OAAA,CAAQ,KAAA;AAAA,UACN,sDAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,gBAAA,CAAiB,WAAA,CAAY,CAAC,CAAA,CAAE,KAAK,CAAA;AACrC,QAAA,mBAAA,CAAoB,WAAA,CAAY,CAAC,CAAA,CAAE,QAAQ,CAAA;AAAA,MAC7C;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAGhB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,MAAA,IAAI;AACF,QAAA,YAAA,CAAa,OAAA;AAAA,UACX,uBAAA;AAAA,UACA,KAAK,SAAA,CAAU;AAAA,YACb,KAAA,EAAO,aAAA;AAAA,YACP,QAAA,EAAU;AAAA,WACX;AAAA,SACH;AAAA,MACF,SAAS,KAAA,EAAO;AAEd,QAAA,OAAA,CAAQ,KAAA;AAAA,UACN,mDAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,aAAA,EAAe,gBAAgB,CAAC,CAAA;AAEpC,EAAA,IAAI,OAAA,EAAS;AAIX,IAAA,2BAAQ,2BAAA,EAAA,EAA4B,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,uBACE,GAAA;AAAA,MAAC,uBAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,EAAE,2BAA2B,CAAA;AAAA,QACtC,WAAA,EAAa;AAAA,UACX,iCAAA;AAAA,UACA;AAAA,SACF;AAAA,QACA,MAAA,kBACE,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,OAAA,EAAQ,UAAA;AAAA,YACR,KAAA,EAAM,SAAA;AAAA,YACN,MAAA,EAAO,QAAA;AAAA,YACP,IAAA,EAAK,kKAAA;AAAA,YAEJ,QAAA,EAAA;AAAA,cAAA,CAAA,CAAE,iBAAiB,CAAA;AAAA,cAAE,QAAA;AAAA,kCAAS,aAAA,EAAA,EAAc;AAAA;AAAA;AAAA;AAC/C;AAAA,KAEJ;AAAA,EAEJ;AAEA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,2BAAQ,2BAAA,EAAA,EAA4B,CAAA;AAAA,EACtC;AAKA,EAAA,IAAI,WAAA,IAAe,WAAA,CAAY,MAAA,KAAW,CAAA,EAAG;AAC3C,IAAA,uBAAO,GAAA,CAAC,yBAAA,EAAA,EAA0B,OAAA,EAAS,MAAM,eAAc,EAAG,CAAA;AAAA,EACpE;AAEA,EAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,IAAA,2BAAQ,4BAAA,EAAA,EAA6B,CAAA;AAAA,EACvC;AAEA,EAAA,2BACG,6BAAA,EAAA,EACC,QAAA,kBAAA,GAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,aAAA;AAAA,MACA,gBAAA;AAAA,MACA,yBAAyB,uBAAA,IAA2B,KAAA;AAAA,MACpD,qBAAqB,CAAA,IAAA,KAAQ;AAC3B,QAAA,gBAAA,CAAiB,IAAI,CAAA;AACrB,QAAA,mBAAA;AAAA,UACE,WAAA,CAAY,KAAK,CAAC,CAAA,KAAW,EAAE,KAAA,KAAU,IAAI,GAAG,QAAA,IAAY;AAAA,SAC9D;AAAA,MACF,CAAA;AAAA,MACA,MAAA,EAAQ,WAAA;AAAA,MACR,UAAU,OAAA,EAAS,WAAA;AAAA,MACnB,QAAQ,OAAA,EAAS,OAAA;AAAA,MACjB;AAAA;AAAA,GACF,EACF,CAAA;AAEJ,CAAA;AAKO,MAAM,0BAA0B,MAAM;AAC3C,EAAA,uBACE,GAAA,CAAC,cAAA,EAAA,EAAe,iBAAA,EACd,QAAA,kBAAA,GAAA,CAACA,oBAAiB,iBAAA,EAAmB,mBAAA,EACnC,QAAA,kBAAA,GAAA,CAAC,mBAAA,EAAA,EAAoB,QAAQ,WAAA,EAC3B,QAAA,kBAAA,GAAA,CAAC,4BAAA,EAAA,EAA6B,CAAA,EAChC,GACF,CAAA,EACF,CAAA;AAEJ;;;;"}
|
|
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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"}
|
|
@@ -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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"}
|