@red-hat-developer-hub/backstage-plugin-intelligent-assistant 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/CHANGELOG.md +681 -0
  2. package/README.md +378 -0
  3. package/config.d.ts +70 -0
  4. package/dist/alpha.d.ts +285 -0
  5. package/dist/alpha.esm.js +3 -0
  6. package/dist/alpha.esm.js.map +1 -0
  7. package/dist/api/LightspeedApiClient.esm.js +234 -0
  8. package/dist/api/LightspeedApiClient.esm.js.map +1 -0
  9. package/dist/api/NotebooksApiClient.esm.js +179 -0
  10. package/dist/api/NotebooksApiClient.esm.js.map +1 -0
  11. package/dist/api/api.esm.js +8 -0
  12. package/dist/api/api.esm.js.map +1 -0
  13. package/dist/api/notebooksApi.esm.js +10 -0
  14. package/dist/api/notebooksApi.esm.js.map +1 -0
  15. package/dist/components/Attachment.esm.js +108 -0
  16. package/dist/components/Attachment.esm.js.map +1 -0
  17. package/dist/components/AttachmentContext.esm.js +125 -0
  18. package/dist/components/AttachmentContext.esm.js.map +1 -0
  19. package/dist/components/CollapsedHistoryStrip.esm.js +87 -0
  20. package/dist/components/CollapsedHistoryStrip.esm.js.map +1 -0
  21. package/dist/components/DeleteModal.esm.js +92 -0
  22. package/dist/components/DeleteModal.esm.js.map +1 -0
  23. package/dist/components/FilePreview.esm.js +49 -0
  24. package/dist/components/FilePreview.esm.js.map +1 -0
  25. package/dist/components/LightSpeedChat.esm.js +1898 -0
  26. package/dist/components/LightSpeedChat.esm.js.map +1 -0
  27. package/dist/components/LightspeedChatBox.esm.js +252 -0
  28. package/dist/components/LightspeedChatBox.esm.js.map +1 -0
  29. package/dist/components/LightspeedChatBoxHeader.esm.js +210 -0
  30. package/dist/components/LightspeedChatBoxHeader.esm.js.map +1 -0
  31. package/dist/components/LightspeedChatContainer.esm.js +162 -0
  32. package/dist/components/LightspeedChatContainer.esm.js.map +1 -0
  33. package/dist/components/LightspeedChatModelsState.esm.js +198 -0
  34. package/dist/components/LightspeedChatModelsState.esm.js.map +1 -0
  35. package/dist/components/LightspeedDrawerContext.esm.js +15 -0
  36. package/dist/components/LightspeedDrawerContext.esm.js.map +1 -0
  37. package/dist/components/LightspeedDrawerProvider.esm.js +44 -0
  38. package/dist/components/LightspeedDrawerProvider.esm.js.map +1 -0
  39. package/dist/components/LightspeedDrawerStateExposer.esm.js +34 -0
  40. package/dist/components/LightspeedDrawerStateExposer.esm.js.map +1 -0
  41. package/dist/components/LightspeedFAB.esm.js +6 -0
  42. package/dist/components/LightspeedFAB.esm.js.map +1 -0
  43. package/dist/components/LightspeedFABContent.esm.js +65 -0
  44. package/dist/components/LightspeedFABContent.esm.js.map +1 -0
  45. package/dist/components/LightspeedIcon.esm.js +46 -0
  46. package/dist/components/LightspeedIcon.esm.js.map +1 -0
  47. package/dist/components/LightspeedPage.esm.js +31 -0
  48. package/dist/components/LightspeedPage.esm.js.map +1 -0
  49. package/dist/components/McpServersSettings.esm.js +953 -0
  50. package/dist/components/McpServersSettings.esm.js.map +1 -0
  51. package/dist/components/McpSettingsIcon.esm.js +18 -0
  52. package/dist/components/McpSettingsIcon.esm.js.map +1 -0
  53. package/dist/components/MessageBarModelSelector.esm.js +92 -0
  54. package/dist/components/MessageBarModelSelector.esm.js.map +1 -0
  55. package/dist/components/PermissionRequiredIcon.esm.js +18 -0
  56. package/dist/components/PermissionRequiredIcon.esm.js.map +1 -0
  57. package/dist/components/PermissionRequiredState.esm.js +88 -0
  58. package/dist/components/PermissionRequiredState.esm.js.map +1 -0
  59. package/dist/components/RenameConversationModal.esm.js +157 -0
  60. package/dist/components/RenameConversationModal.esm.js.map +1 -0
  61. package/dist/components/Router.esm.js +35 -0
  62. package/dist/components/Router.esm.js.map +1 -0
  63. package/dist/components/SourcesChipModal.esm.js +124 -0
  64. package/dist/components/SourcesChipModal.esm.js.map +1 -0
  65. package/dist/components/ToolCallContent.esm.js +208 -0
  66. package/dist/components/ToolCallContent.esm.js.map +1 -0
  67. package/dist/components/Trans.esm.js +33 -0
  68. package/dist/components/Trans.esm.js.map +1 -0
  69. package/dist/components/notebooks/AddDocumentModal.esm.js +271 -0
  70. package/dist/components/notebooks/AddDocumentModal.esm.js.map +1 -0
  71. package/dist/components/notebooks/DeleteDocumentModal.esm.js +131 -0
  72. package/dist/components/notebooks/DeleteDocumentModal.esm.js.map +1 -0
  73. package/dist/components/notebooks/DeleteNotebookModal.esm.js +143 -0
  74. package/dist/components/notebooks/DeleteNotebookModal.esm.js.map +1 -0
  75. package/dist/components/notebooks/DocumentSidebar.esm.js +235 -0
  76. package/dist/components/notebooks/DocumentSidebar.esm.js.map +1 -0
  77. package/dist/components/notebooks/FileListItem.esm.js +94 -0
  78. package/dist/components/notebooks/FileListItem.esm.js.map +1 -0
  79. package/dist/components/notebooks/FileTypeIcon.esm.js +59 -0
  80. package/dist/components/notebooks/FileTypeIcon.esm.js.map +1 -0
  81. package/dist/components/notebooks/NotebookCard.esm.js +118 -0
  82. package/dist/components/notebooks/NotebookCard.esm.js.map +1 -0
  83. package/dist/components/notebooks/NotebookView.esm.js +681 -0
  84. package/dist/components/notebooks/NotebookView.esm.js.map +1 -0
  85. package/dist/components/notebooks/NotebooksTab.esm.js +71 -0
  86. package/dist/components/notebooks/NotebooksTab.esm.js.map +1 -0
  87. package/dist/components/notebooks/OverwriteConfirmModal.esm.js +142 -0
  88. package/dist/components/notebooks/OverwriteConfirmModal.esm.js.map +1 -0
  89. package/dist/components/notebooks/RenameNotebookModal.esm.js +187 -0
  90. package/dist/components/notebooks/RenameNotebookModal.esm.js.map +1 -0
  91. package/dist/components/notebooks/SidebarCollapseIcon.esm.js +50 -0
  92. package/dist/components/notebooks/SidebarCollapseIcon.esm.js.map +1 -0
  93. package/dist/components/notebooks/UploadResourceScreen.esm.js +79 -0
  94. package/dist/components/notebooks/UploadResourceScreen.esm.js.map +1 -0
  95. package/dist/const.esm.js +74 -0
  96. package/dist/const.esm.js.map +1 -0
  97. package/dist/dev.d.ts +2 -0
  98. package/dist/dev.esm.js +48 -0
  99. package/dist/dev.esm.js.map +1 -0
  100. package/dist/hooks/notebooks/useCreateNotebook.esm.js +19 -0
  101. package/dist/hooks/notebooks/useCreateNotebook.esm.js.map +1 -0
  102. package/dist/hooks/notebooks/useCreateNotebookMessage.esm.js +24 -0
  103. package/dist/hooks/notebooks/useCreateNotebookMessage.esm.js.map +1 -0
  104. package/dist/hooks/notebooks/useDeleteNotebook.esm.js +19 -0
  105. package/dist/hooks/notebooks/useDeleteNotebook.esm.js.map +1 -0
  106. package/dist/hooks/notebooks/useDocumentStatusPolling.esm.js +40 -0
  107. package/dist/hooks/notebooks/useDocumentStatusPolling.esm.js.map +1 -0
  108. package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js +15 -0
  109. package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js.map +1 -0
  110. package/dist/hooks/notebooks/useNotebookDocuments.esm.js +18 -0
  111. package/dist/hooks/notebooks/useNotebookDocuments.esm.js.map +1 -0
  112. package/dist/hooks/notebooks/useNotebookSession.esm.js +18 -0
  113. package/dist/hooks/notebooks/useNotebookSession.esm.js.map +1 -0
  114. package/dist/hooks/notebooks/useNotebookSessions.esm.js +18 -0
  115. package/dist/hooks/notebooks/useNotebookSessions.esm.js.map +1 -0
  116. package/dist/hooks/notebooks/useRenameNotebook.esm.js +19 -0
  117. package/dist/hooks/notebooks/useRenameNotebook.esm.js.map +1 -0
  118. package/dist/hooks/notebooks/useUploadDocument.esm.js +28 -0
  119. package/dist/hooks/notebooks/useUploadDocument.esm.js.map +1 -0
  120. package/dist/hooks/toolCallsCacheStore.esm.js +61 -0
  121. package/dist/hooks/toolCallsCacheStore.esm.js.map +1 -0
  122. package/dist/hooks/useAllModels.esm.js +20 -0
  123. package/dist/hooks/useAllModels.esm.js.map +1 -0
  124. package/dist/hooks/useAutoScroll.esm.js +78 -0
  125. package/dist/hooks/useAutoScroll.esm.js.map +1 -0
  126. package/dist/hooks/useBackstageUserIdentity.esm.js +14 -0
  127. package/dist/hooks/useBackstageUserIdentity.esm.js.map +1 -0
  128. package/dist/hooks/useBufferedMessages.esm.js +27 -0
  129. package/dist/hooks/useBufferedMessages.esm.js.map +1 -0
  130. package/dist/hooks/useCaptureFeedback.esm.js +21 -0
  131. package/dist/hooks/useCaptureFeedback.esm.js.map +1 -0
  132. package/dist/hooks/useConversationMessages.esm.js +544 -0
  133. package/dist/hooks/useConversationMessages.esm.js.map +1 -0
  134. package/dist/hooks/useConversations.esm.js +25 -0
  135. package/dist/hooks/useConversations.esm.js.map +1 -0
  136. package/dist/hooks/useCreateCoversationMessage.esm.js +33 -0
  137. package/dist/hooks/useCreateCoversationMessage.esm.js.map +1 -0
  138. package/dist/hooks/useDeleteConversation.esm.js +39 -0
  139. package/dist/hooks/useDeleteConversation.esm.js.map +1 -0
  140. package/dist/hooks/useDisplayModeSettings.esm.js +57 -0
  141. package/dist/hooks/useDisplayModeSettings.esm.js.map +1 -0
  142. package/dist/hooks/useFeedbackActions.esm.js +275 -0
  143. package/dist/hooks/useFeedbackActions.esm.js.map +1 -0
  144. package/dist/hooks/useFeedbackState.esm.js +93 -0
  145. package/dist/hooks/useFeedbackState.esm.js.map +1 -0
  146. package/dist/hooks/useFeedbackStatus.esm.js +14 -0
  147. package/dist/hooks/useFeedbackStatus.esm.js.map +1 -0
  148. package/dist/hooks/useIsMobile.esm.js +14 -0
  149. package/dist/hooks/useIsMobile.esm.js.map +1 -0
  150. package/dist/hooks/useLastOpenedConversation.esm.js +51 -0
  151. package/dist/hooks/useLastOpenedConversation.esm.js.map +1 -0
  152. package/dist/hooks/useLightspeedDeletePermission.esm.js +12 -0
  153. package/dist/hooks/useLightspeedDeletePermission.esm.js.map +1 -0
  154. package/dist/hooks/useLightspeedDrawerContext.esm.js +15 -0
  155. package/dist/hooks/useLightspeedDrawerContext.esm.js.map +1 -0
  156. package/dist/hooks/useLightspeedProviderState.esm.js +277 -0
  157. package/dist/hooks/useLightspeedProviderState.esm.js.map +1 -0
  158. package/dist/hooks/useLightspeedUpdatePermission.esm.js +12 -0
  159. package/dist/hooks/useLightspeedUpdatePermission.esm.js.map +1 -0
  160. package/dist/hooks/useLightspeedViewPermission.esm.js +18 -0
  161. package/dist/hooks/useLightspeedViewPermission.esm.js.map +1 -0
  162. package/dist/hooks/useNotebookConversationIds.esm.js +19 -0
  163. package/dist/hooks/useNotebookConversationIds.esm.js.map +1 -0
  164. package/dist/hooks/useNotebookWelcomePrompts.esm.js +14 -0
  165. package/dist/hooks/useNotebookWelcomePrompts.esm.js.map +1 -0
  166. package/dist/hooks/usePinnedChatsSettings.esm.js +118 -0
  167. package/dist/hooks/usePinnedChatsSettings.esm.js.map +1 -0
  168. package/dist/hooks/useQuestionValidation.esm.js +16 -0
  169. package/dist/hooks/useQuestionValidation.esm.js.map +1 -0
  170. package/dist/hooks/useRenameConversation.esm.js +44 -0
  171. package/dist/hooks/useRenameConversation.esm.js.map +1 -0
  172. package/dist/hooks/useSortSettings.esm.js +60 -0
  173. package/dist/hooks/useSortSettings.esm.js.map +1 -0
  174. package/dist/hooks/useStopConversation.esm.js +18 -0
  175. package/dist/hooks/useStopConversation.esm.js.map +1 -0
  176. package/dist/hooks/useTranslation.esm.js +7 -0
  177. package/dist/hooks/useTranslation.esm.js.map +1 -0
  178. package/dist/hooks/useWelcomePrompts.esm.js +36 -0
  179. package/dist/hooks/useWelcomePrompts.esm.js.map +1 -0
  180. package/dist/images/bot-avatar-dark.svg +4 -0
  181. package/dist/images/bot-avatar.svg +4 -0
  182. package/dist/images/permission-required.svg +319 -0
  183. package/dist/images/user-avatar.svg +4 -0
  184. package/dist/index.d.ts +113 -0
  185. package/dist/index.esm.js +137 -0
  186. package/dist/index.esm.js.map +1 -0
  187. package/dist/intelligent-assistant-fab-module.d.ts +4 -0
  188. package/dist/intelligent-assistant-fab-module.esm.js +2 -0
  189. package/dist/intelligent-assistant-fab-module.esm.js.map +1 -0
  190. package/dist/intelligent-assistant-translations-module.d.ts +4 -0
  191. package/dist/intelligent-assistant-translations-module.esm.js +2 -0
  192. package/dist/intelligent-assistant-translations-module.esm.js.map +1 -0
  193. package/dist/legacy.d.ts +75 -0
  194. package/dist/legacy.esm.js +13 -0
  195. package/dist/legacy.esm.js.map +1 -0
  196. package/dist/plugin.esm.js +84 -0
  197. package/dist/plugin.esm.js.map +1 -0
  198. package/dist/routes.esm.js +23 -0
  199. package/dist/routes.esm.js.map +1 -0
  200. package/dist/translations/de.esm.js +278 -0
  201. package/dist/translations/de.esm.js.map +1 -0
  202. package/dist/translations/es.esm.js +278 -0
  203. package/dist/translations/es.esm.js.map +1 -0
  204. package/dist/translations/fr.esm.js +278 -0
  205. package/dist/translations/fr.esm.js.map +1 -0
  206. package/dist/translations/index.esm.js +16 -0
  207. package/dist/translations/index.esm.js.map +1 -0
  208. package/dist/translations/it.esm.js +278 -0
  209. package/dist/translations/it.esm.js.map +1 -0
  210. package/dist/translations/ja.esm.js +278 -0
  211. package/dist/translations/ja.esm.js.map +1 -0
  212. package/dist/translations/ref.esm.js +315 -0
  213. package/dist/translations/ref.esm.js.map +1 -0
  214. package/dist/types.esm.js +9 -0
  215. package/dist/types.esm.js.map +1 -0
  216. package/dist/utils/attachment-utils.esm.js +30 -0
  217. package/dist/utils/attachment-utils.esm.js.map +1 -0
  218. package/dist/utils/formatToolResponseForMarkdown.esm.js +98 -0
  219. package/dist/utils/formatToolResponseForMarkdown.esm.js.map +1 -0
  220. package/dist/utils/generateClassName.esm.js +12 -0
  221. package/dist/utils/generateClassName.esm.js.map +1 -0
  222. package/dist/utils/lightspeed-chatbox-utils.esm.js +232 -0
  223. package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -0
  224. package/dist/utils/notebook-upload-utils.esm.js +48 -0
  225. package/dist/utils/notebook-upload-utils.esm.js.map +1 -0
  226. package/dist/utils/notebooks-utils.esm.js +25 -0
  227. package/dist/utils/notebooks-utils.esm.js.map +1 -0
  228. package/dist/utils/prompt-utils.esm.js +17 -0
  229. package/dist/utils/prompt-utils.esm.js.map +1 -0
  230. package/dist/utils/queryClient.esm.js +6 -0
  231. package/dist/utils/queryClient.esm.js.map +1 -0
  232. package/dist/utils/reasoningParser.esm.js +33 -0
  233. package/dist/utils/reasoningParser.esm.js.map +1 -0
  234. package/dist/utils/toolCallMapper.esm.js +15 -0
  235. package/dist/utils/toolCallMapper.esm.js.map +1 -0
  236. package/dist/utils/user-utils.esm.js +7 -0
  237. package/dist/utils/user-utils.esm.js.map +1 -0
  238. package/package.json +182 -0
@@ -0,0 +1,953 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useCallback, useEffect, useMemo } from 'react';
3
+ import { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';
4
+ import { usePermission } from '@backstage/plugin-permission-react';
5
+ import { makeStyles } from '@material-ui/core';
6
+ import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
7
+ import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined';
8
+ import IconButton from '@mui/material/IconButton';
9
+ import InputAdornment from '@mui/material/InputAdornment';
10
+ import TextField from '@mui/material/TextField';
11
+ import Typography from '@mui/material/Typography';
12
+ import { Title, Button, Alert, Switch, Tooltip, Modal } from '@patternfly/react-core';
13
+ import { TimesIcon, SortAmountDownIcon, SortAmountUpIcon, PencilAltIcon, LockIcon, KeyIcon, InfoCircleIcon, ExclamationCircleIcon, CheckCircleIcon } from '@patternfly/react-icons';
14
+ import { Table, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
15
+ import { lightspeedMcpManagePermission } from '@red-hat-developer-hub/backstage-plugin-intelligent-assistant-common';
16
+ import { useTranslation } from '../hooks/useTranslation.esm.js';
17
+
18
+ const SAVED_TOKEN_MASK = "********************";
19
+ const useStyles = makeStyles((theme) => ({
20
+ "@global": {
21
+ ".pf-v6-c-backdrop": {
22
+ zIndex: "1400 !important"
23
+ },
24
+ ".pf-v5-c-backdrop": {
25
+ zIndex: "1400 !important"
26
+ }
27
+ },
28
+ root: {
29
+ padding: 0,
30
+ height: "100%",
31
+ minHeight: "100%",
32
+ width: "100%",
33
+ overflow: "auto"
34
+ },
35
+ headerRow: {
36
+ display: "flex",
37
+ alignItems: "flex-start",
38
+ justifyContent: "space-between",
39
+ marginBottom: theme.spacing(2),
40
+ marginTop: theme.spacing(2),
41
+ marginLeft: theme.spacing(3),
42
+ marginRight: theme.spacing(2)
43
+ },
44
+ selectedCount: {
45
+ color: theme.palette.text.secondary,
46
+ marginTop: theme.spacing(0.5),
47
+ fontSize: "0.75rem"
48
+ },
49
+ title: {
50
+ fontSize: "1.125rem"
51
+ },
52
+ closeButton: {
53
+ marginTop: -theme.spacing(1),
54
+ marginRight: -theme.spacing(1),
55
+ color: theme.palette.text.primary
56
+ },
57
+ nameHeaderButton: {
58
+ paddingLeft: 0,
59
+ paddingTop: 0,
60
+ paddingBottom: 0,
61
+ marginLeft: "-0.85rem",
62
+ fontWeight: 600,
63
+ fontSize: "0.75rem",
64
+ lineHeight: "1.25rem",
65
+ minHeight: "auto",
66
+ color: theme.palette.text.primary,
67
+ textDecoration: "none !important",
68
+ display: "inline-flex",
69
+ alignItems: "center"
70
+ },
71
+ nameHeaderText: {
72
+ paddingLeft: "7px",
73
+ fontSize: "0.75rem",
74
+ lineHeight: "1.25rem",
75
+ fontWeight: 600
76
+ },
77
+ nameCell: {
78
+ paddingLeft: "8px !important"
79
+ },
80
+ statusHeader: {
81
+ paddingLeft: "0 !important"
82
+ },
83
+ statusColumnCell: {
84
+ paddingLeft: "0 !important"
85
+ },
86
+ rowName: {
87
+ fontSize: "1rem",
88
+ fontWeight: 500,
89
+ whiteSpace: "nowrap"
90
+ },
91
+ nameValue: {
92
+ fontSize: "0.875rem",
93
+ fontWeight: 500
94
+ },
95
+ statusCell: {
96
+ display: "flex",
97
+ alignItems: "center",
98
+ gap: theme.spacing(1),
99
+ whiteSpace: "nowrap"
100
+ },
101
+ statusValue: {
102
+ fontSize: "0.875rem"
103
+ },
104
+ statusOk: {
105
+ color: "#147878"
106
+ },
107
+ statusWarn: {
108
+ color: "#B1380B"
109
+ },
110
+ statusDisabled: {
111
+ color: theme.palette.type === "dark" ? "var(--pf-t--global--text--color--subtle, #c7c7c7)" : "var(--pf-t--global--text--color--subtle, #4d4d4d)"
112
+ },
113
+ actionButton: {
114
+ color: theme.palette.text.secondary,
115
+ opacity: 0,
116
+ transition: "opacity 0.15s ease-in-out"
117
+ },
118
+ tableRow: {
119
+ "&:hover $actionButton, &:focus-within $actionButton": {
120
+ opacity: 1
121
+ }
122
+ },
123
+ modalDescription: {
124
+ color: theme.palette.text.secondary,
125
+ fontSize: "0.875rem",
126
+ marginTop: theme.spacing(2),
127
+ marginBottom: theme.spacing(2)
128
+ },
129
+ modalContent: {
130
+ position: "relative",
131
+ padding: theme.spacing(3, 0, 3, 3),
132
+ marginRight: theme.spacing(3)
133
+ },
134
+ modalCustomCloseButton: {
135
+ position: "absolute",
136
+ top: theme.spacing(2),
137
+ right: theme.spacing(-0.5),
138
+ color: theme.palette.text.primary
139
+ },
140
+ modalHeading: {
141
+ display: "flex",
142
+ alignItems: "center",
143
+ gap: theme.spacing(0.75),
144
+ marginBottom: theme.spacing(1),
145
+ fontSize: "1.25rem",
146
+ lineHeight: 1.4,
147
+ fontWeight: 500,
148
+ "& .v5-MuiTypography-root": {
149
+ fontSize: "1.25rem",
150
+ lineHeight: 1.4,
151
+ fontWeight: 500
152
+ }
153
+ },
154
+ tokenRow: {
155
+ position: "relative"
156
+ },
157
+ tokenClearButton: {
158
+ position: "absolute",
159
+ right: theme.spacing(1),
160
+ top: "50%",
161
+ transform: "translateY(-50%)",
162
+ zIndex: 1,
163
+ color: theme.palette.action.active
164
+ },
165
+ tokenHelper: {
166
+ color: theme.palette.text.secondary,
167
+ fontSize: "0.75rem",
168
+ marginTop: theme.spacing(0.5)
169
+ },
170
+ tokenInput: {
171
+ marginTop: "1rem !important",
172
+ "& .MuiOutlinedInput-root": {
173
+ height: "3.5rem"
174
+ },
175
+ "& .MuiOutlinedInput-input": {
176
+ padding: "0 0.875rem"
177
+ },
178
+ "& .MuiInputLabel-root": {
179
+ fontSize: "0.875rem"
180
+ }
181
+ },
182
+ tokenInputSuccess: {
183
+ "& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {
184
+ borderColor: "#3E8635",
185
+ borderWidth: 1
186
+ },
187
+ "& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline": {
188
+ borderColor: "#3E8635"
189
+ },
190
+ "& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline": {
191
+ borderColor: "#3E8635"
192
+ },
193
+ "& .MuiInputLabel-root.Mui-focused": {
194
+ color: "#3E8635"
195
+ }
196
+ },
197
+ tokenInputError: {
198
+ "& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {
199
+ borderColor: "#C9190B",
200
+ borderWidth: 1
201
+ },
202
+ "& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline": {
203
+ borderColor: "#C9190B"
204
+ },
205
+ "& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline": {
206
+ borderColor: "#C9190B"
207
+ },
208
+ "& .MuiInputLabel-root.Mui-focused": {
209
+ color: "#C9190B"
210
+ }
211
+ },
212
+ modalActions: {
213
+ marginTop: theme.spacing(3),
214
+ display: "flex",
215
+ gap: theme.spacing(1)
216
+ },
217
+ modalActionButton: {
218
+ fontSize: "1rem"
219
+ },
220
+ modalCancelButton: {
221
+ fontSize: "1rem"
222
+ },
223
+ forgetTokenButton: {
224
+ fontSize: "1rem",
225
+ border: "1px solid #B1380B",
226
+ borderRadius: "1.25rem",
227
+ padding: "0.375rem 1rem",
228
+ color: "#B1380B",
229
+ backgroundColor: "transparent",
230
+ marginLeft: theme.spacing(1),
231
+ marginRight: theme.spacing(1),
232
+ boxShadow: "none",
233
+ "&:hover": {
234
+ backgroundColor: "rgba(201, 25, 11, 0.08)"
235
+ }
236
+ },
237
+ configureModal: {
238
+ "& .pf-v6-c-modal-box": {
239
+ width: "608px",
240
+ maxWidth: "608px",
241
+ height: "326px",
242
+ minHeight: "326px"
243
+ },
244
+ "& .pf-v6-c-modal-box__title, & .pf-v6-c-modal-box__title-text, & .pf-v5-c-modal-box__title, & .pf-v5-c-modal-box__title-text": {
245
+ fontSize: "1.25rem !important",
246
+ lineHeight: "1.4 !important"
247
+ },
248
+ "& .pf-v6-c-modal-box__close": {
249
+ display: "none"
250
+ },
251
+ "& .pf-v5-c-modal-box__close": {
252
+ display: "none"
253
+ },
254
+ "& .pf-v6-c-button__icon": {
255
+ paddingTop: "5px !important",
256
+ fontSize: "1.25rem !important"
257
+ }
258
+ },
259
+ toggleCell: {
260
+ paddingRight: "0 !important"
261
+ },
262
+ table: {
263
+ width: "100%",
264
+ backgroundColor: "transparent",
265
+ "--pf-v6-c-table--BackgroundColor": "transparent",
266
+ "--pf-v5-c-table--BackgroundColor": "transparent",
267
+ "& table, & thead, & tbody, & tr, & th, & td": {
268
+ backgroundColor: "transparent !important"
269
+ },
270
+ "& th": {
271
+ borderBottom: 0,
272
+ fontSize: "0.75rem",
273
+ fontWeight: 600,
274
+ color: theme.palette.text.primary,
275
+ whiteSpace: "nowrap",
276
+ textAlign: "left"
277
+ },
278
+ "& td": {
279
+ borderBottom: 0,
280
+ paddingTop: theme.spacing(1.5),
281
+ paddingBottom: theme.spacing(1.5),
282
+ verticalAlign: "middle"
283
+ }
284
+ },
285
+ alert: {
286
+ marginLeft: theme.spacing(3),
287
+ marginRight: theme.spacing(3),
288
+ marginBottom: theme.spacing(2)
289
+ }
290
+ }));
291
+ const getStatusIcon = (status, className) => {
292
+ if (status === "tokenRequired") return /* @__PURE__ */ jsx(KeyIcon, { className });
293
+ if (status === "disabled") return /* @__PURE__ */ jsx(InfoCircleIcon, { className });
294
+ if (status === "failed")
295
+ return /* @__PURE__ */ jsx(ExclamationCircleIcon, { className });
296
+ return /* @__PURE__ */ jsx(CheckCircleIcon, { className });
297
+ };
298
+ const getDisplayStatus = (server) => {
299
+ if (!server.hasToken) return "tokenRequired";
300
+ if (!server.enabled) return "disabled";
301
+ if (server.status === "error") return "failed";
302
+ if (server.status === "connected") return "ok";
303
+ return "unknown";
304
+ };
305
+ const toUiServer = (server, validationError) => ({
306
+ id: server.name,
307
+ name: server.name,
308
+ url: server.url,
309
+ enabled: server.enabled,
310
+ status: server.status,
311
+ toolCount: server.toolCount,
312
+ hasToken: server.hasToken,
313
+ hasUserToken: server.hasUserToken,
314
+ validationError: server.status === "error" ? validationError : void 0,
315
+ auth: server.auth
316
+ });
317
+ const McpServersSettings = ({
318
+ onClose,
319
+ backgroundColor
320
+ }) => {
321
+ const classes = useStyles();
322
+ const { t } = useTranslation();
323
+ const configApi = useApi(configApiRef);
324
+ const fetchApi = useApi(fetchApiRef);
325
+ const mcpManagePermission = usePermission({
326
+ permission: lightspeedMcpManagePermission
327
+ });
328
+ const canManageMcp = mcpManagePermission.allowed;
329
+ const [servers, setServers] = useState([]);
330
+ const [sortAsc, setSortAsc] = useState(true);
331
+ const [isLoading, setIsLoading] = useState(true);
332
+ const [isSaving, setIsSaving] = useState({});
333
+ const [error, setError] = useState(null);
334
+ const [editingServerId, setEditingServerId] = useState(null);
335
+ const [tokenInputValue, setTokenInputValue] = useState("");
336
+ const [hasSavedTokenInModal, setHasSavedTokenInModal] = useState(false);
337
+ const [canRemovePersonalToken, setCanRemovePersonalToken] = useState(false);
338
+ const [tokenValidationState, setTokenValidationState] = useState("idle");
339
+ const [tokenValidationMessage, setTokenValidationMessage] = useState("");
340
+ const getBaseUrl = useCallback(() => {
341
+ return `${configApi.getString("backend.baseUrl")}/api/intelligent-assistant`;
342
+ }, [configApi]);
343
+ const fetchJson = useCallback(
344
+ async (url, init) => {
345
+ const response = await fetchApi.fetch(url, {
346
+ headers: {
347
+ "Content-Type": "application/json"
348
+ },
349
+ ...init
350
+ });
351
+ if (!response.ok) {
352
+ let message = `${response.status} ${response.statusText}`;
353
+ try {
354
+ const bodyText = await response.text();
355
+ if (bodyText) {
356
+ const parsed = JSON.parse(bodyText);
357
+ if (parsed?.error) {
358
+ message = parsed.error;
359
+ }
360
+ }
361
+ } catch {
362
+ }
363
+ throw new Error(message);
364
+ }
365
+ const text = await response.text();
366
+ return text ? JSON.parse(text) : {};
367
+ },
368
+ [fetchApi]
369
+ );
370
+ const validateServer = useCallback(
371
+ async (serverName) => {
372
+ const baseUrl = getBaseUrl();
373
+ const data = await fetchJson(
374
+ `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}/validate`,
375
+ {
376
+ method: "POST"
377
+ }
378
+ );
379
+ setServers(
380
+ (prev) => prev.map(
381
+ (server) => server.name === serverName ? {
382
+ ...server,
383
+ status: data.status,
384
+ toolCount: data.toolCount,
385
+ validationError: data.status === "error" ? data.validation?.error ?? "Validation failed" : void 0
386
+ } : server
387
+ )
388
+ );
389
+ return data;
390
+ },
391
+ [fetchJson, getBaseUrl]
392
+ );
393
+ const validateCredentials = useCallback(
394
+ async (url, token) => {
395
+ const baseUrl = getBaseUrl();
396
+ return await fetchJson(
397
+ `${baseUrl}/mcp-servers/validate`,
398
+ {
399
+ method: "POST",
400
+ body: JSON.stringify({ url, token })
401
+ }
402
+ );
403
+ },
404
+ [fetchJson, getBaseUrl]
405
+ );
406
+ const loadServers = useCallback(async () => {
407
+ setIsLoading(true);
408
+ setError(null);
409
+ try {
410
+ const baseUrl = getBaseUrl();
411
+ const data = await fetchJson(
412
+ `${baseUrl}/mcp-servers`
413
+ );
414
+ const uiServers = (data.servers ?? []).map((server) => toUiServer(server));
415
+ setServers(uiServers);
416
+ if (canManageMcp) {
417
+ const serversToValidate = uiServers.filter((server) => server.hasToken);
418
+ void Promise.allSettled(
419
+ serversToValidate.map(async (server) => {
420
+ try {
421
+ await validateServer(server.name);
422
+ } catch (validationError) {
423
+ setError(
424
+ (prev) => prev ?? (validationError instanceof Error ? validationError.message : `Failed to validate ${server.name}`)
425
+ );
426
+ }
427
+ })
428
+ );
429
+ }
430
+ } catch (e) {
431
+ setError(
432
+ e instanceof Error ? e.message : "Failed to load MCP server settings"
433
+ );
434
+ } finally {
435
+ setIsLoading(false);
436
+ }
437
+ }, [canManageMcp, fetchJson, getBaseUrl, validateServer]);
438
+ useEffect(() => {
439
+ loadServers();
440
+ }, [loadServers]);
441
+ const patchServer = useCallback(
442
+ async (serverName, body) => {
443
+ if (!canManageMcp) {
444
+ return;
445
+ }
446
+ setError(null);
447
+ setIsSaving((prev) => ({ ...prev, [serverName]: true }));
448
+ try {
449
+ const baseUrl = getBaseUrl();
450
+ const data = await fetchJson(
451
+ `${baseUrl}/mcp-servers/${encodeURIComponent(serverName)}`,
452
+ {
453
+ method: "PATCH",
454
+ body: JSON.stringify(body)
455
+ }
456
+ );
457
+ if (data.server) {
458
+ setServers(
459
+ (prev) => prev.map(
460
+ (server) => server.name === serverName ? toUiServer(data.server, data.validation?.error) : server
461
+ )
462
+ );
463
+ } else {
464
+ await loadServers();
465
+ }
466
+ } catch (e) {
467
+ setError(
468
+ e instanceof Error ? e.message : `Failed to update ${serverName} settings`
469
+ );
470
+ throw e;
471
+ } finally {
472
+ setIsSaving((prev) => ({ ...prev, [serverName]: false }));
473
+ }
474
+ },
475
+ [canManageMcp, fetchJson, getBaseUrl, loadServers]
476
+ );
477
+ const editingServer = useMemo(
478
+ () => servers.find((server) => server.id === editingServerId),
479
+ [servers, editingServerId]
480
+ );
481
+ const selectedCount = useMemo(
482
+ () => servers.filter((server) => {
483
+ const displayStatus = getDisplayStatus(server);
484
+ const isUnavailable = displayStatus === "failed" || displayStatus === "tokenRequired";
485
+ return server.enabled && !isUnavailable;
486
+ }).length,
487
+ [servers]
488
+ );
489
+ const sortedServers = useMemo(() => {
490
+ const next = [...servers];
491
+ next.sort(
492
+ (a, b) => sortAsc ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name)
493
+ );
494
+ return next;
495
+ }, [servers, sortAsc]);
496
+ const getDisplayDetail = useCallback(
497
+ (server, displayStatus) => {
498
+ if (displayStatus === "disabled")
499
+ return t("mcp.settings.status.disabled");
500
+ if (displayStatus === "tokenRequired")
501
+ return t("mcp.settings.status.tokenRequired");
502
+ if (displayStatus === "failed") return t("mcp.settings.status.failed");
503
+ if (displayStatus === "ok") {
504
+ if (server.toolCount === 1) {
505
+ return t("mcp.settings.status.oneTool", {
506
+ count: String(server.toolCount)
507
+ });
508
+ }
509
+ return t("mcp.settings.status.manyTools", {
510
+ count: String(server.toolCount)
511
+ });
512
+ }
513
+ return t("mcp.settings.status.unknown");
514
+ },
515
+ [t]
516
+ );
517
+ const closeConfigureModal = useCallback(() => {
518
+ setEditingServerId(null);
519
+ setTokenInputValue("");
520
+ setHasSavedTokenInModal(false);
521
+ setCanRemovePersonalToken(false);
522
+ setTokenValidationState("idle");
523
+ setTokenValidationMessage("");
524
+ }, []);
525
+ const openConfigureModal = (server) => {
526
+ setEditingServerId(server.id);
527
+ const hasSavedToken = server.hasToken;
528
+ setHasSavedTokenInModal(hasSavedToken);
529
+ setCanRemovePersonalToken(server.hasUserToken);
530
+ setTokenInputValue(hasSavedToken ? SAVED_TOKEN_MASK : "");
531
+ if (server.status === "error" && server.validationError) {
532
+ setTokenValidationState("error");
533
+ setTokenValidationMessage(server.validationError);
534
+ } else {
535
+ setTokenValidationState("idle");
536
+ setTokenValidationMessage("");
537
+ }
538
+ };
539
+ const onTokenInputChange = (value) => {
540
+ if (hasSavedTokenInModal && value !== SAVED_TOKEN_MASK) {
541
+ setHasSavedTokenInModal(false);
542
+ }
543
+ setTokenInputValue(value);
544
+ setTokenValidationState("idle");
545
+ setTokenValidationMessage("");
546
+ };
547
+ const clearTokenInput = () => {
548
+ if (hasSavedTokenInModal) {
549
+ setHasSavedTokenInModal(false);
550
+ }
551
+ setTokenInputValue("");
552
+ setTokenValidationState("idle");
553
+ setTokenValidationMessage("");
554
+ };
555
+ let tokenInputStateClass = "";
556
+ let tokenHelperColor;
557
+ if (tokenValidationState === "success") {
558
+ tokenInputStateClass = classes.tokenInputSuccess;
559
+ tokenHelperColor = "#3E8635";
560
+ } else if (tokenValidationState === "error") {
561
+ tokenInputStateClass = classes.tokenInputError;
562
+ tokenHelperColor = "#C9190B";
563
+ }
564
+ let tokenInputAdornment = /* @__PURE__ */ jsx(
565
+ IconButton,
566
+ {
567
+ "aria-label": t("mcp.settings.token.clearAriaLabel"),
568
+ size: "small",
569
+ className: classes.tokenClearButton,
570
+ onClick: clearTokenInput,
571
+ children: /* @__PURE__ */ jsx(
572
+ CancelOutlinedIcon,
573
+ {
574
+ style: {
575
+ fontSize: 24,
576
+ width: 24,
577
+ height: 24
578
+ }
579
+ }
580
+ )
581
+ }
582
+ );
583
+ if (tokenValidationState === "success") {
584
+ tokenInputAdornment = /* @__PURE__ */ jsx(
585
+ CheckCircleIcon,
586
+ {
587
+ style: {
588
+ color: "#3E8635",
589
+ fontSize: 20,
590
+ width: 20,
591
+ height: 20,
592
+ marginRight: 3
593
+ }
594
+ }
595
+ );
596
+ } else if (tokenValidationState === "error") {
597
+ tokenInputAdornment = /* @__PURE__ */ jsx(
598
+ ExclamationCircleIcon,
599
+ {
600
+ style: {
601
+ color: "#C9190B",
602
+ fontSize: 20,
603
+ width: 20,
604
+ height: 20,
605
+ marginRight: 3
606
+ }
607
+ }
608
+ );
609
+ }
610
+ const isUsingOrganizationCredentialInModal = hasSavedTokenInModal && !canRemovePersonalToken;
611
+ const saveServerToken = useCallback(async () => {
612
+ if (!editingServer || !canManageMcp) return;
613
+ if (hasSavedTokenInModal && tokenInputValue === SAVED_TOKEN_MASK) {
614
+ closeConfigureModal();
615
+ return;
616
+ }
617
+ const token = tokenInputValue.trim();
618
+ const hasToken = token.length > 0;
619
+ setTokenValidationState("validating");
620
+ setTokenValidationMessage(t("mcp.settings.token.validating"));
621
+ try {
622
+ if (hasToken) {
623
+ if (!editingServer.url) {
624
+ setTokenValidationState("error");
625
+ setTokenValidationMessage(
626
+ t("mcp.settings.token.urlUnavailableForValidation")
627
+ );
628
+ return;
629
+ }
630
+ const credentialValidation = await validateCredentials(
631
+ editingServer.url,
632
+ token
633
+ );
634
+ if (!credentialValidation.valid) {
635
+ setTokenValidationState("error");
636
+ setTokenValidationMessage(
637
+ credentialValidation.error ?? t("mcp.settings.token.invalidCredentials")
638
+ );
639
+ return;
640
+ }
641
+ }
642
+ setTokenValidationMessage(t("mcp.settings.token.savingAndValidating"));
643
+ await patchServer(editingServer.name, {
644
+ enabled: editingServer.enabled,
645
+ token: hasToken ? token : null
646
+ });
647
+ const validationResult = await validateServer(editingServer.name);
648
+ if (validationResult.status === "error") {
649
+ setTokenValidationState("error");
650
+ setTokenValidationMessage(
651
+ validationResult.validation?.error ?? t("mcp.settings.token.validationFailed")
652
+ );
653
+ return;
654
+ }
655
+ setTokenValidationState("success");
656
+ setTokenValidationMessage(t("mcp.settings.token.connectionSuccessful"));
657
+ closeConfigureModal();
658
+ } catch (e) {
659
+ setTokenValidationState("error");
660
+ setTokenValidationMessage(
661
+ e instanceof Error ? e.message : `Failed to update ${editingServer.name} token`
662
+ );
663
+ }
664
+ }, [
665
+ canManageMcp,
666
+ closeConfigureModal,
667
+ editingServer,
668
+ hasSavedTokenInModal,
669
+ patchServer,
670
+ t,
671
+ tokenInputValue,
672
+ validateCredentials,
673
+ validateServer
674
+ ]);
675
+ const removePersonalToken = () => {
676
+ setHasSavedTokenInModal(false);
677
+ setCanRemovePersonalToken(false);
678
+ setTokenInputValue("");
679
+ setTokenValidationState("idle");
680
+ setTokenValidationMessage("");
681
+ };
682
+ return /* @__PURE__ */ jsxs(
683
+ "div",
684
+ {
685
+ className: classes.root,
686
+ style: backgroundColor ? { backgroundColor } : void 0,
687
+ children: [
688
+ /* @__PURE__ */ jsxs("div", { className: classes.headerRow, children: [
689
+ /* @__PURE__ */ jsxs("div", { children: [
690
+ /* @__PURE__ */ jsx(Title, { headingLevel: "h2", size: "xl", className: classes.title, children: t("mcp.settings.title") }),
691
+ /* @__PURE__ */ jsx("div", { className: classes.selectedCount, children: t("mcp.settings.selectedCount", {
692
+ selectedCount: String(selectedCount),
693
+ totalCount: String(servers.length)
694
+ }) })
695
+ ] }),
696
+ /* @__PURE__ */ jsx(
697
+ Button,
698
+ {
699
+ "aria-label": t("mcp.settings.closeAriaLabel"),
700
+ icon: /* @__PURE__ */ jsx(TimesIcon, {}),
701
+ variant: "plain",
702
+ className: classes.closeButton,
703
+ onClick: onClose
704
+ }
705
+ )
706
+ ] }),
707
+ error && /* @__PURE__ */ jsx(
708
+ Alert,
709
+ {
710
+ variant: "danger",
711
+ isInline: true,
712
+ title: error,
713
+ className: classes.alert
714
+ }
715
+ ),
716
+ !mcpManagePermission.loading && !canManageMcp && /* @__PURE__ */ jsx(
717
+ Alert,
718
+ {
719
+ variant: "info",
720
+ isInline: true,
721
+ title: t("mcp.settings.readOnlyAccess"),
722
+ className: classes.alert
723
+ }
724
+ ),
725
+ /* @__PURE__ */ jsxs(
726
+ Table,
727
+ {
728
+ variant: "compact",
729
+ "aria-label": t("mcp.settings.tableAriaLabel"),
730
+ className: classes.table,
731
+ children: [
732
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
733
+ /* @__PURE__ */ jsx(Th, { width: 10, screenReaderText: t("mcp.settings.enabled") }),
734
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
735
+ Button,
736
+ {
737
+ variant: "link",
738
+ className: classes.nameHeaderButton,
739
+ icon: sortAsc ? /* @__PURE__ */ jsx(SortAmountDownIcon, {}) : /* @__PURE__ */ jsx(SortAmountUpIcon, {}),
740
+ iconPosition: "right",
741
+ onClick: () => setSortAsc((prev) => !prev),
742
+ children: /* @__PURE__ */ jsx(Typography, { component: "span", className: classes.nameHeaderText, children: t("mcp.settings.name") })
743
+ }
744
+ ) }),
745
+ /* @__PURE__ */ jsx(Th, { className: classes.statusHeader, children: t("mcp.settings.status") }),
746
+ /* @__PURE__ */ jsx(Th, { screenReaderText: t("mcp.settings.edit") })
747
+ ] }) }),
748
+ /* @__PURE__ */ jsxs(Tbody, { children: [
749
+ isLoading && /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 4, children: t("mcp.settings.loading") }) }),
750
+ !isLoading && sortedServers.length === 0 && /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 4, children: t("mcp.settings.noneAvailable") }) }),
751
+ sortedServers.map((server) => {
752
+ const displayStatus = getDisplayStatus(server);
753
+ const displayDetail = getDisplayDetail(server, displayStatus);
754
+ let statusClass = classes.statusWarn;
755
+ if (displayStatus === "ok") {
756
+ statusClass = classes.statusOk;
757
+ } else if (displayStatus === "disabled") {
758
+ statusClass = classes.statusDisabled;
759
+ }
760
+ return /* @__PURE__ */ jsxs(Tr, { className: classes.tableRow, children: [
761
+ /* @__PURE__ */ jsx(Td, { width: 10, className: classes.toggleCell, children: (() => {
762
+ const isUnavailable = displayStatus === "failed" || displayStatus === "tokenRequired";
763
+ const isChecked = isUnavailable ? false : server.enabled;
764
+ const isRowSaving = Boolean(isSaving[server.name]);
765
+ const isToggleDisabled = isUnavailable || isRowSaving || !canManageMcp;
766
+ const switchControl = /* @__PURE__ */ jsx(
767
+ Switch,
768
+ {
769
+ id: `mcp-switch-${server.id}`,
770
+ "aria-label": t(
771
+ "mcp.settings.toggleServerAriaLabel",
772
+ {
773
+ serverName: server.name
774
+ }
775
+ ),
776
+ isChecked,
777
+ isDisabled: isToggleDisabled,
778
+ onChange: (_event, checked) => {
779
+ void patchServer(server.name, {
780
+ enabled: checked
781
+ }).catch(() => {
782
+ });
783
+ }
784
+ }
785
+ );
786
+ if (!isToggleDisabled) {
787
+ return switchControl;
788
+ }
789
+ return /* @__PURE__ */ jsx(Tooltip, { content: displayDetail, children: /* @__PURE__ */ jsx(Typography, { component: "span", children: switchControl }) });
790
+ })() }),
791
+ /* @__PURE__ */ jsx(
792
+ Td,
793
+ {
794
+ width: 35,
795
+ className: `${classes.rowName} ${classes.nameCell}`,
796
+ children: /* @__PURE__ */ jsx(Typography, { component: "span", className: classes.nameValue, children: server.name })
797
+ }
798
+ ),
799
+ /* @__PURE__ */ jsx(Td, { width: 40, className: classes.statusColumnCell, children: /* @__PURE__ */ jsxs("div", { className: classes.statusCell, children: [
800
+ getStatusIcon(displayStatus, statusClass),
801
+ displayStatus === "failed" ? /* @__PURE__ */ jsx(
802
+ Tooltip,
803
+ {
804
+ content: server.validationError ?? t("mcp.settings.token.validationFailed"),
805
+ children: /* @__PURE__ */ jsx(
806
+ Typography,
807
+ {
808
+ component: "span",
809
+ className: classes.statusValue,
810
+ children: displayDetail
811
+ }
812
+ )
813
+ }
814
+ ) : /* @__PURE__ */ jsx(
815
+ Typography,
816
+ {
817
+ component: "span",
818
+ className: classes.statusValue,
819
+ children: displayDetail
820
+ }
821
+ )
822
+ ] }) }),
823
+ /* @__PURE__ */ jsx(Td, { width: 15, isActionCell: true, style: { textAlign: "right" }, children: /* @__PURE__ */ jsx(
824
+ Button,
825
+ {
826
+ "aria-label": t("mcp.settings.editServerAriaLabel", {
827
+ serverName: server.name
828
+ }),
829
+ icon: /* @__PURE__ */ jsx(PencilAltIcon, {}),
830
+ variant: "plain",
831
+ className: classes.actionButton,
832
+ isDisabled: !canManageMcp,
833
+ onClick: () => openConfigureModal(server)
834
+ }
835
+ ) })
836
+ ] }, server.id);
837
+ })
838
+ ] })
839
+ ]
840
+ }
841
+ ),
842
+ /* @__PURE__ */ jsx(
843
+ Modal,
844
+ {
845
+ variant: "small",
846
+ title: t("mcp.settings.configureServerTitle", {
847
+ serverName: editingServer?.name ?? ""
848
+ }),
849
+ isOpen: Boolean(editingServer),
850
+ onClose: closeConfigureModal,
851
+ className: classes.configureModal,
852
+ children: /* @__PURE__ */ jsxs("div", { className: classes.modalContent, children: [
853
+ /* @__PURE__ */ jsx(
854
+ IconButton,
855
+ {
856
+ "aria-label": t("mcp.settings.closeConfigureModalAriaLabel"),
857
+ size: "small",
858
+ className: classes.modalCustomCloseButton,
859
+ onClick: closeConfigureModal,
860
+ children: /* @__PURE__ */ jsx(CloseOutlinedIcon, {})
861
+ }
862
+ ),
863
+ /* @__PURE__ */ jsxs("div", { className: classes.modalHeading, children: [
864
+ /* @__PURE__ */ jsx(LockIcon, {}),
865
+ /* @__PURE__ */ jsx(Typography, { component: "div", children: t("mcp.settings.configureServerTitle", {
866
+ serverName: editingServer?.name ?? ""
867
+ }) })
868
+ ] }),
869
+ editingServer?.auth === "dcr" ? /* @__PURE__ */ jsxs(Fragment, { children: [
870
+ /* @__PURE__ */ jsx("div", { className: classes.modalDescription, children: t("mcp.settings.modalDescriptionDcr") }),
871
+ /* @__PURE__ */ jsx("div", { className: classes.modalActions, children: /* @__PURE__ */ jsx(
872
+ Button,
873
+ {
874
+ variant: "primary",
875
+ onClick: closeConfigureModal,
876
+ className: classes.modalActionButton,
877
+ children: t("common.cancel")
878
+ },
879
+ "close"
880
+ ) })
881
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
882
+ /* @__PURE__ */ jsx("div", { className: classes.modalDescription, children: t("mcp.settings.modalDescription") }),
883
+ /* @__PURE__ */ jsxs("div", { className: classes.tokenRow, children: [
884
+ /* @__PURE__ */ jsx(
885
+ TextField,
886
+ {
887
+ id: "mcp-pat-input",
888
+ type: "password",
889
+ variant: "outlined",
890
+ fullWidth: true,
891
+ value: tokenInputValue,
892
+ onChange: (event) => onTokenInputChange(event.target.value),
893
+ className: `${classes.tokenInput} ${tokenInputStateClass}`,
894
+ label: hasSavedTokenInModal ? t("mcp.settings.savedToken") : t("mcp.settings.personalAccessToken"),
895
+ InputProps: {
896
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: tokenInputAdornment })
897
+ }
898
+ }
899
+ ),
900
+ (isUsingOrganizationCredentialInModal || !hasSavedTokenInModal || tokenValidationState !== "idle") && /* @__PURE__ */ jsx(
901
+ "div",
902
+ {
903
+ className: classes.tokenHelper,
904
+ style: { color: tokenHelperColor },
905
+ children: tokenValidationMessage || (isUsingOrganizationCredentialInModal ? t("mcp.settings.usingAdminCredential") : t("mcp.settings.enterToken"))
906
+ }
907
+ )
908
+ ] }),
909
+ /* @__PURE__ */ jsxs("div", { className: classes.modalActions, children: [
910
+ /* @__PURE__ */ jsx(
911
+ Button,
912
+ {
913
+ variant: "primary",
914
+ onClick: () => void saveServerToken(),
915
+ isDisabled: !canManageMcp || Boolean(isSaving[editingServer?.name ?? ""]) || tokenValidationState === "validating",
916
+ className: classes.modalActionButton,
917
+ children: t("modal.save")
918
+ },
919
+ "save"
920
+ ),
921
+ canRemovePersonalToken && hasSavedTokenInModal && /* @__PURE__ */ jsx(
922
+ Button,
923
+ {
924
+ variant: "plain",
925
+ onClick: removePersonalToken,
926
+ isDisabled: !canManageMcp || Boolean(isSaving[editingServer?.name ?? ""]) || tokenValidationState === "validating",
927
+ className: classes.forgetTokenButton,
928
+ children: t("mcp.settings.removePersonalToken")
929
+ },
930
+ "forget-token"
931
+ ),
932
+ /* @__PURE__ */ jsx(
933
+ Button,
934
+ {
935
+ variant: "link",
936
+ onClick: closeConfigureModal,
937
+ className: classes.modalCancelButton,
938
+ children: t("common.cancel")
939
+ },
940
+ "cancel"
941
+ )
942
+ ] })
943
+ ] })
944
+ ] })
945
+ }
946
+ )
947
+ ]
948
+ }
949
+ );
950
+ };
951
+
952
+ export { McpServersSettings };
953
+ //# sourceMappingURL=McpServersSettings.esm.js.map