@backstage-community/plugin-mcp-chat 0.1.2 → 0.3.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.
@@ -1,22 +1,28 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useState } from 'react';
2
3
  import { useTheme } from '@mui/material/styles';
3
4
  import AddIcon from '@mui/icons-material/Add';
4
5
  import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
5
6
  import ChevronRightIcon from '@mui/icons-material/ChevronRight';
6
7
  import MemoryIcon from '@mui/icons-material/Memory';
8
+ import HistoryIcon from '@mui/icons-material/History';
9
+ import SettingsIcon from '@mui/icons-material/Settings';
7
10
  import Box from '@mui/material/Box';
8
11
  import Button from '@mui/material/Button';
9
12
  import IconButton from '@mui/material/IconButton';
10
13
  import Typography from '@mui/material/Typography';
14
+ import ToggleButton from '@mui/material/ToggleButton';
15
+ import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
11
16
  import { ActiveMcpServers } from './ActiveMcpServers.esm.js';
12
17
  import { ActiveTools } from './ActiveTools.esm.js';
13
18
  import { ProviderStatus } from './ProviderStatus.esm.js';
19
+ import { ConversationHistory } from './ConversationHistory.esm.js';
14
20
  import { BotIcon } from '../BotIcon/BotIcon.esm.js';
15
21
  import '@backstage/core-plugin-api';
16
22
  import 'react-use/esm/useAsyncRetry';
17
23
  import '../../api/index.esm.js';
18
- import 'react';
19
24
  import { useAvailableTools } from '../../hooks/useAvailableTools.esm.js';
25
+ import 'react-use/esm/useAsync';
20
26
 
21
27
  const RightPane = ({
22
28
  sidebarCollapsed,
@@ -24,10 +30,27 @@ const RightPane = ({
24
30
  onNewChat,
25
31
  mcpServers,
26
32
  onServerToggle,
27
- providerStatus
33
+ providerStatus,
34
+ starredConversations,
35
+ recentConversations,
36
+ conversationsLoading,
37
+ conversationsError,
38
+ searchQuery,
39
+ onSearchChange,
40
+ onSearchClear,
41
+ onSelectConversation,
42
+ onToggleStar,
43
+ onDeleteConversation,
44
+ selectedConversationId
28
45
  }) => {
29
46
  const theme = useTheme();
47
+ const [activeTab, setActiveTab] = useState("status");
30
48
  const { availableTools, isLoading: toolsLoading } = useAvailableTools(mcpServers);
49
+ const handleTabChange = (_event, newTab) => {
50
+ if (newTab !== null) {
51
+ setActiveTab(newTab);
52
+ }
53
+ };
31
54
  return /* @__PURE__ */ jsxs(
32
55
  Box,
33
56
  {
@@ -139,30 +162,81 @@ const RightPane = ({
139
162
  children: "New chat"
140
163
  }
141
164
  ) }),
142
- /* @__PURE__ */ jsx(
143
- ProviderStatus,
165
+ /* @__PURE__ */ jsx(Box, { sx: { padding: "8px 16px" }, children: /* @__PURE__ */ jsxs(
166
+ ToggleButtonGroup,
144
167
  {
145
- providerStatusData: providerStatus.providerStatusData,
146
- isLoading: providerStatus.isLoading,
147
- error: providerStatus.error
168
+ value: activeTab,
169
+ exclusive: true,
170
+ onChange: handleTabChange,
171
+ size: "small",
172
+ fullWidth: true,
173
+ sx: {
174
+ "& .MuiToggleButton-root": {
175
+ textTransform: "none",
176
+ fontWeight: 500,
177
+ padding: theme.spacing(0.75, 2),
178
+ "&.Mui-selected": {
179
+ backgroundColor: theme.palette.action.selected,
180
+ "&:hover": {
181
+ backgroundColor: theme.palette.action.hover
182
+ }
183
+ }
184
+ }
185
+ },
186
+ children: [
187
+ /* @__PURE__ */ jsxs(ToggleButton, { value: "status", children: [
188
+ /* @__PURE__ */ jsx(SettingsIcon, { sx: { fontSize: 18, mr: 0.5 } }),
189
+ "Status"
190
+ ] }),
191
+ /* @__PURE__ */ jsxs(ToggleButton, { value: "history", children: [
192
+ /* @__PURE__ */ jsx(HistoryIcon, { sx: { fontSize: 18, mr: 0.5 } }),
193
+ "History"
194
+ ] })
195
+ ]
148
196
  }
149
- ),
150
- /* @__PURE__ */ jsx(
151
- ActiveTools,
197
+ ) }),
198
+ activeTab === "status" && /* @__PURE__ */ jsxs(Fragment, { children: [
199
+ /* @__PURE__ */ jsx(
200
+ ProviderStatus,
201
+ {
202
+ providerStatusData: providerStatus.providerStatusData,
203
+ isLoading: providerStatus.isLoading,
204
+ error: providerStatus.error
205
+ }
206
+ ),
207
+ /* @__PURE__ */ jsx(
208
+ ActiveTools,
209
+ {
210
+ mcpServers,
211
+ availableTools,
212
+ toolsLoading
213
+ }
214
+ ),
215
+ /* @__PURE__ */ jsx(
216
+ ActiveMcpServers,
217
+ {
218
+ mcpServers,
219
+ onServerToggle
220
+ }
221
+ )
222
+ ] }),
223
+ activeTab === "history" && /* @__PURE__ */ jsx(
224
+ ConversationHistory,
152
225
  {
153
- mcpServers,
154
- availableTools,
155
- toolsLoading
226
+ starredConversations,
227
+ recentConversations,
228
+ loading: conversationsLoading,
229
+ error: conversationsError,
230
+ searchQuery,
231
+ onSearchChange,
232
+ onSearchClear,
233
+ onSelectConversation,
234
+ onToggleStar,
235
+ onDelete: onDeleteConversation,
236
+ selectedConversationId
156
237
  }
157
238
  )
158
239
  ] }),
159
- !sidebarCollapsed && /* @__PURE__ */ jsx(
160
- ActiveMcpServers,
161
- {
162
- mcpServers,
163
- onServerToggle
164
- }
165
- ),
166
240
  sidebarCollapsed && /* @__PURE__ */ jsxs(
167
241
  Box,
168
242
  {
@@ -173,34 +247,59 @@ const RightPane = ({
173
247
  height: "100%"
174
248
  },
175
249
  children: [
176
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
177
- Box,
178
- {
179
- sx: {
180
- display: "flex",
181
- justifyContent: "center",
182
- marginBottom: "16px"
183
- },
184
- children: /* @__PURE__ */ jsx(
185
- IconButton,
186
- {
187
- size: "small",
188
- onClick: onNewChat,
189
- sx: {
190
- backgroundColor: theme.palette.primary.main,
191
- color: theme.palette.primary.contrastText,
192
- transition: "all 0.2s ease",
193
- "&:hover": {
194
- backgroundColor: theme.palette.primary.dark,
195
- transform: "scale(1.05)"
196
- }
197
- },
198
- children: /* @__PURE__ */ jsx(AddIcon, {})
199
- }
200
- )
201
- }
202
- ) }),
203
250
  /* @__PURE__ */ jsxs(Box, { children: [
251
+ /* @__PURE__ */ jsx(
252
+ Box,
253
+ {
254
+ sx: {
255
+ display: "flex",
256
+ justifyContent: "center",
257
+ marginBottom: "16px"
258
+ },
259
+ children: /* @__PURE__ */ jsx(
260
+ IconButton,
261
+ {
262
+ size: "small",
263
+ onClick: onNewChat,
264
+ sx: {
265
+ backgroundColor: theme.palette.primary.main,
266
+ color: theme.palette.primary.contrastText,
267
+ transition: "all 0.2s ease",
268
+ "&:hover": {
269
+ backgroundColor: theme.palette.primary.dark,
270
+ transform: "scale(1.05)"
271
+ }
272
+ },
273
+ children: /* @__PURE__ */ jsx(AddIcon, {})
274
+ }
275
+ )
276
+ }
277
+ ),
278
+ /* @__PURE__ */ jsx(
279
+ Box,
280
+ {
281
+ sx: {
282
+ display: "flex",
283
+ justifyContent: "center",
284
+ marginBottom: "8px"
285
+ },
286
+ children: /* @__PURE__ */ jsx(
287
+ IconButton,
288
+ {
289
+ size: "small",
290
+ title: "History",
291
+ onClick: () => {
292
+ onToggleSidebar();
293
+ setActiveTab("history");
294
+ },
295
+ sx: { color: theme.palette.text.secondary },
296
+ children: /* @__PURE__ */ jsx(HistoryIcon, {})
297
+ }
298
+ )
299
+ }
300
+ )
301
+ ] }),
302
+ /* @__PURE__ */ jsxs(Box, { sx: { marginTop: "auto" }, children: [
204
303
  /* @__PURE__ */ jsx(
205
304
  Box,
206
305
  {
@@ -222,7 +321,10 @@ const RightPane = ({
222
321
  {
223
322
  size: "medium",
224
323
  title: "MCP Configuration",
225
- onClick: onToggleSidebar,
324
+ onClick: () => {
325
+ onToggleSidebar();
326
+ setActiveTab("status");
327
+ },
226
328
  sx: { color: theme.palette.text.primary },
227
329
  children: /* @__PURE__ */ jsx(MemoryIcon, {})
228
330
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RightPane.esm.js","sources":["../../../src/components/RightPane/RightPane.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\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 */\nimport { FC } from 'react';\nimport { useTheme } from '@mui/material/styles';\nimport AddIcon from '@mui/icons-material/Add';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport ChevronRightIcon from '@mui/icons-material/ChevronRight';\nimport MemoryIcon from '@mui/icons-material/Memory';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\nimport { ActiveMcpServers } from './ActiveMcpServers';\nimport { ActiveTools } from './ActiveTools';\nimport { ProviderStatus } from './ProviderStatus';\nimport { BotIcon } from '../BotIcon';\nimport { MCPServer } from '../../types';\nimport { UseProviderStatusReturn, useAvailableTools } from '../../hooks';\n\ninterface RightPaneProps {\n sidebarCollapsed: boolean;\n onToggleSidebar: () => void;\n onNewChat: () => void;\n mcpServers: MCPServer[];\n onServerToggle: (serverName: string) => void;\n providerStatus: UseProviderStatusReturn;\n}\n\nexport const RightPane: FC<RightPaneProps> = ({\n sidebarCollapsed,\n onToggleSidebar,\n onNewChat,\n mcpServers,\n onServerToggle,\n providerStatus,\n}: RightPaneProps) => {\n const theme = useTheme();\n const { availableTools, isLoading: toolsLoading } =\n useAvailableTools(mcpServers);\n\n return (\n <Box\n sx={{\n width: sidebarCollapsed ? 60 : 400,\n backgroundColor: theme.palette.background.paper,\n borderLeft: `1px solid ${theme.palette.divider}`,\n display: 'flex',\n flexDirection: 'column',\n transition: 'width 0.3s ease',\n position: 'absolute',\n top: 0,\n right: 0,\n bottom: 0,\n }}\n >\n {!sidebarCollapsed && (\n <IconButton\n sx={{\n position: 'absolute',\n top: theme.spacing(1),\n left: -20,\n backgroundColor: theme.palette.background.paper,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: '50%',\n width: 40,\n height: 40,\n zIndex: 2,\n color: theme.palette.text.primary,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n onClick={onToggleSidebar}\n size=\"small\"\n >\n <ChevronRightIcon />\n </IconButton>\n )}\n\n <Box\n sx={{\n padding: sidebarCollapsed ? theme.spacing(1) : theme.spacing(2),\n borderBottom: `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 64,\n }}\n >\n {!sidebarCollapsed && (\n <>\n <BotIcon size={25} color={theme.palette.text.primary} />\n <Typography\n variant=\"h6\"\n sx={{\n fontWeight: 600,\n marginLeft: theme.spacing(1),\n color: theme.palette.text.primary,\n }}\n >\n MCP Chat\n </Typography>\n </>\n )}\n {sidebarCollapsed && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n marginBottom: '8px',\n }}\n >\n <IconButton\n size=\"small\"\n onClick={onToggleSidebar}\n sx={{ color: theme.palette.text.primary }}\n >\n <ChevronLeftIcon />\n </IconButton>\n </Box>\n )}\n </Box>\n\n {!sidebarCollapsed && (\n <>\n <Box sx={{ padding: '16px 16px 8px' }}>\n <Button\n variant=\"contained\"\n startIcon={<AddIcon />}\n sx={{\n background: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n '&:hover': {\n background: theme.palette.primary.dark,\n },\n borderRadius: theme.spacing(1),\n textTransform: 'none',\n padding: theme.spacing(1, 2),\n fontWeight: 600,\n }}\n size=\"small\"\n fullWidth\n onClick={onNewChat}\n >\n New chat\n </Button>\n </Box>\n\n <ProviderStatus\n providerStatusData={providerStatus.providerStatusData}\n isLoading={providerStatus.isLoading}\n error={providerStatus.error}\n />\n\n {/* Active Tools Section - Now taking the main space */}\n <ActiveTools\n mcpServers={mcpServers}\n availableTools={availableTools}\n toolsLoading={toolsLoading}\n />\n </>\n )}\n\n {/* MCP Servers Section - Separate box at the bottom */}\n {!sidebarCollapsed && (\n <ActiveMcpServers\n mcpServers={mcpServers}\n onServerToggle={onServerToggle}\n />\n )}\n\n {sidebarCollapsed && (\n <Box\n sx={{\n padding: '16px 8px',\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n }}\n >\n {/* Top section - buttons that stay at top */}\n <Box>\n {/* Add button when collapsed */}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n marginBottom: '16px',\n }}\n >\n <IconButton\n size=\"small\"\n onClick={onNewChat}\n sx={{\n backgroundColor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n transition: 'all 0.2s ease',\n '&:hover': {\n backgroundColor: theme.palette.primary.dark,\n transform: 'scale(1.05)',\n },\n }}\n >\n <AddIcon />\n </IconButton>\n </Box>\n </Box>\n\n {/* Bottom section - MCP Servers */}\n <Box>\n {/* Separator line */}\n <Box\n sx={{\n borderTop: `2px solid ${theme.palette.divider}`,\n margin: '0 8px 16px 8px',\n }}\n />\n\n {/* MCP Servers Section Icon */}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <IconButton\n size=\"medium\"\n title=\"MCP Configuration\"\n onClick={onToggleSidebar}\n sx={{ color: theme.palette.text.primary }}\n >\n <MemoryIcon />\n </IconButton>\n </Box>\n </Box>\n </Box>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAyCO,MAAM,YAAgC,CAAC;AAAA,EAC5C,gBAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA,KAAsB;AACpB,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,MAAM,EAAE,cAAA,EAAgB,SAAA,EAAW,YAAA,EAAa,GAC9C,kBAAkB,UAAU,CAAA;AAE9B,EAAA,uBACE,IAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI;AAAA,QACF,KAAA,EAAO,mBAAmB,EAAA,GAAK,GAAA;AAAA,QAC/B,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAA;AAAA,QAC1C,UAAA,EAAY,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,QAC9C,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,UAAA,EAAY,iBAAA;AAAA,QACZ,QAAA,EAAU,UAAA;AAAA,QACV,GAAA,EAAK,CAAA;AAAA,QACL,KAAA,EAAO,CAAA;AAAA,QACP,MAAA,EAAQ;AAAA,OACV;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,CAAC,gBAAA,oBACA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI;AAAA,cACF,QAAA,EAAU,UAAA;AAAA,cACV,GAAA,EAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,cACpB,IAAA,EAAM,GAAA;AAAA,cACN,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,UAAA,CAAW,KAAA;AAAA,cAC1C,MAAA,EAAQ,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,cAC1C,YAAA,EAAc,KAAA;AAAA,cACd,KAAA,EAAO,EAAA;AAAA,cACP,MAAA,EAAQ,EAAA;AAAA,cACR,MAAA,EAAQ,CAAA;AAAA,cACR,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,OAAA;AAAA,cAC1B,SAAA,EAAW;AAAA,gBACT,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO;AAAA;AACxC,aACF;AAAA,YACA,OAAA,EAAS,eAAA;AAAA,YACT,IAAA,EAAK,OAAA;AAAA,YAEL,8BAAC,gBAAA,EAAA,EAAiB;AAAA;AAAA,SACpB;AAAA,wBAGF,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI;AAAA,cACF,OAAA,EAAS,mBAAmB,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,cAC9D,YAAA,EAAc,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,cAChD,OAAA,EAAS,MAAA;AAAA,cACT,UAAA,EAAY,QAAA;AAAA,cACZ,cAAA,EAAgB,QAAA;AAAA,cAChB,SAAA,EAAW;AAAA,aACb;AAAA,YAEC,QAAA,EAAA;AAAA,cAAA,CAAC,oCACA,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,WAAQ,IAAA,EAAM,EAAA,EAAI,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,OAAA,EAAS,CAAA;AAAA,gCACtD,GAAA;AAAA,kBAAC,UAAA;AAAA,kBAAA;AAAA,oBACC,OAAA,EAAQ,IAAA;AAAA,oBACR,EAAA,EAAI;AAAA,sBACF,UAAA,EAAY,GAAA;AAAA,sBACZ,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,sBAC3B,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK;AAAA,qBAC5B;AAAA,oBACD,QAAA,EAAA;AAAA;AAAA;AAED,eAAA,EACF,CAAA;AAAA,cAED,gBAAA,oBACC,GAAA;AAAA,gBAAC,GAAA;AAAA,gBAAA;AAAA,kBACC,EAAA,EAAI;AAAA,oBACF,OAAA,EAAS,MAAA;AAAA,oBACT,cAAA,EAAgB,QAAA;AAAA,oBAChB,YAAA,EAAc;AAAA,mBAChB;AAAA,kBAEA,QAAA,kBAAA,GAAA;AAAA,oBAAC,UAAA;AAAA,oBAAA;AAAA,sBACC,IAAA,EAAK,OAAA;AAAA,sBACL,OAAA,EAAS,eAAA;AAAA,sBACT,IAAI,EAAE,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,OAAA,EAAQ;AAAA,sBAExC,8BAAC,eAAA,EAAA,EAAgB;AAAA;AAAA;AACnB;AAAA;AACF;AAAA;AAAA,SAEJ;AAAA,QAEC,CAAC,oCACA,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,GAAA,EAAA,EAAI,EAAA,EAAI,EAAE,OAAA,EAAS,iBAAgB,EAClC,QAAA,kBAAA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAQ,WAAA;AAAA,cACR,SAAA,sBAAY,OAAA,EAAA,EAAQ,CAAA;AAAA,cACpB,EAAA,EAAI;AAAA,gBACF,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAA;AAAA,gBAClC,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,YAAA;AAAA,gBAC7B,SAAA,EAAW;AAAA,kBACT,UAAA,EAAY,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ;AAAA,iBACpC;AAAA,gBACA,YAAA,EAAc,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,gBAC7B,aAAA,EAAe,MAAA;AAAA,gBACf,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,CAAA,EAAG,CAAC,CAAA;AAAA,gBAC3B,UAAA,EAAY;AAAA,eACd;AAAA,cACA,IAAA,EAAK,OAAA;AAAA,cACL,SAAA,EAAS,IAAA;AAAA,cACT,OAAA,EAAS,SAAA;AAAA,cACV,QAAA,EAAA;AAAA;AAAA,WAED,EACF,CAAA;AAAA,0BAEA,GAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,oBAAoB,cAAA,CAAe,kBAAA;AAAA,cACnC,WAAW,cAAA,CAAe,SAAA;AAAA,cAC1B,OAAO,cAAA,CAAe;AAAA;AAAA,WACxB;AAAA,0BAGA,GAAA;AAAA,YAAC,WAAA;AAAA,YAAA;AAAA,cACC,UAAA;AAAA,cACA,cAAA;AAAA,cACA;AAAA;AAAA;AACF,SAAA,EACF,CAAA;AAAA,QAID,CAAC,gBAAA,oBACA,GAAA;AAAA,UAAC,gBAAA;AAAA,UAAA;AAAA,YACC,UAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,QAGD,gBAAA,oBACC,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI;AAAA,cACF,OAAA,EAAS,UAAA;AAAA,cACT,OAAA,EAAS,MAAA;AAAA,cACT,aAAA,EAAe,QAAA;AAAA,cACf,MAAA,EAAQ;AAAA,aACV;AAAA,YAGA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,GAAA,EAAA,EAEC,QAAA,kBAAA,GAAA;AAAA,gBAAC,GAAA;AAAA,gBAAA;AAAA,kBACC,EAAA,EAAI;AAAA,oBACF,OAAA,EAAS,MAAA;AAAA,oBACT,cAAA,EAAgB,QAAA;AAAA,oBAChB,YAAA,EAAc;AAAA,mBAChB;AAAA,kBAEA,QAAA,kBAAA,GAAA;AAAA,oBAAC,UAAA;AAAA,oBAAA;AAAA,sBACC,IAAA,EAAK,OAAA;AAAA,sBACL,OAAA,EAAS,SAAA;AAAA,sBACT,EAAA,EAAI;AAAA,wBACF,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAA;AAAA,wBACvC,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,YAAA;AAAA,wBAC7B,UAAA,EAAY,eAAA;AAAA,wBACZ,SAAA,EAAW;AAAA,0BACT,eAAA,EAAiB,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAA;AAAA,0BACvC,SAAA,EAAW;AAAA;AACb,uBACF;AAAA,sBAEA,8BAAC,OAAA,EAAA,EAAQ;AAAA;AAAA;AACX;AAAA,eACF,EACF,CAAA;AAAA,mCAGC,GAAA,EAAA,EAEC,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,GAAA;AAAA,kBAAA;AAAA,oBACC,EAAA,EAAI;AAAA,sBACF,SAAA,EAAW,CAAA,UAAA,EAAa,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,CAAA;AAAA,sBAC7C,MAAA,EAAQ;AAAA;AACV;AAAA,iBACF;AAAA,gCAGA,GAAA;AAAA,kBAAC,GAAA;AAAA,kBAAA;AAAA,oBACC,EAAA,EAAI;AAAA,sBACF,OAAA,EAAS,MAAA;AAAA,sBACT,cAAA,EAAgB;AAAA,qBAClB;AAAA,oBAEA,QAAA,kBAAA,GAAA;AAAA,sBAAC,UAAA;AAAA,sBAAA;AAAA,wBACC,IAAA,EAAK,QAAA;AAAA,wBACL,KAAA,EAAM,mBAAA;AAAA,wBACN,OAAA,EAAS,eAAA;AAAA,wBACT,IAAI,EAAE,KAAA,EAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,OAAA,EAAQ;AAAA,wBAExC,8BAAC,UAAA,EAAA,EAAW;AAAA;AAAA;AACd;AAAA;AACF,eAAA,EACF;AAAA;AAAA;AAAA;AACF;AAAA;AAAA,GAEJ;AAEJ;;;;"}
1
+ {"version":3,"file":"RightPane.esm.js","sources":["../../../src/components/RightPane/RightPane.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\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 */\nimport { FC, useState } from 'react';\nimport { useTheme } from '@mui/material/styles';\nimport AddIcon from '@mui/icons-material/Add';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport ChevronRightIcon from '@mui/icons-material/ChevronRight';\nimport MemoryIcon from '@mui/icons-material/Memory';\nimport HistoryIcon from '@mui/icons-material/History';\nimport SettingsIcon from '@mui/icons-material/Settings';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\nimport ToggleButton from '@mui/material/ToggleButton';\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup';\nimport { ActiveMcpServers } from './ActiveMcpServers';\nimport { ActiveTools } from './ActiveTools';\nimport { ProviderStatus } from './ProviderStatus';\nimport { ConversationHistory } from './ConversationHistory';\nimport { BotIcon } from '../BotIcon';\nimport { MCPServer, ConversationRecord } from '../../types';\nimport { UseProviderStatusReturn, useAvailableTools } from '../../hooks';\n\ntype TabType = 'status' | 'history';\n\ninterface RightPaneProps {\n sidebarCollapsed: boolean;\n onToggleSidebar: () => void;\n onNewChat: () => void;\n mcpServers: MCPServer[];\n onServerToggle: (serverName: string) => void;\n providerStatus: UseProviderStatusReturn;\n // Conversation history props\n starredConversations: ConversationRecord[];\n recentConversations: ConversationRecord[];\n conversationsLoading: boolean;\n conversationsError?: string;\n searchQuery: string;\n onSearchChange: (query: string) => void;\n onSearchClear: () => void;\n onSelectConversation: (conversation: ConversationRecord) => void;\n onToggleStar: (id: string) => void;\n onDeleteConversation: (id: string) => void;\n selectedConversationId?: string;\n}\n\nexport const RightPane: FC<RightPaneProps> = ({\n sidebarCollapsed,\n onToggleSidebar,\n onNewChat,\n mcpServers,\n onServerToggle,\n providerStatus,\n starredConversations,\n recentConversations,\n conversationsLoading,\n conversationsError,\n searchQuery,\n onSearchChange,\n onSearchClear,\n onSelectConversation,\n onToggleStar,\n onDeleteConversation,\n selectedConversationId,\n}: RightPaneProps) => {\n const theme = useTheme();\n const [activeTab, setActiveTab] = useState<TabType>('status');\n const { availableTools, isLoading: toolsLoading } =\n useAvailableTools(mcpServers);\n\n const handleTabChange = (\n _event: React.MouseEvent<HTMLElement>,\n newTab: TabType | null,\n ) => {\n if (newTab !== null) {\n setActiveTab(newTab);\n }\n };\n\n return (\n <Box\n sx={{\n width: sidebarCollapsed ? 60 : 400,\n backgroundColor: theme.palette.background.paper,\n borderLeft: `1px solid ${theme.palette.divider}`,\n display: 'flex',\n flexDirection: 'column',\n transition: 'width 0.3s ease',\n position: 'absolute',\n top: 0,\n right: 0,\n bottom: 0,\n }}\n >\n {!sidebarCollapsed && (\n <IconButton\n sx={{\n position: 'absolute',\n top: theme.spacing(1),\n left: -20,\n backgroundColor: theme.palette.background.paper,\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: '50%',\n width: 40,\n height: 40,\n zIndex: 2,\n color: theme.palette.text.primary,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n onClick={onToggleSidebar}\n size=\"small\"\n >\n <ChevronRightIcon />\n </IconButton>\n )}\n\n {/* Header */}\n <Box\n sx={{\n padding: sidebarCollapsed ? theme.spacing(1) : theme.spacing(2),\n borderBottom: `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 64,\n }}\n >\n {!sidebarCollapsed && (\n <>\n <BotIcon size={25} color={theme.palette.text.primary} />\n <Typography\n variant=\"h6\"\n sx={{\n fontWeight: 600,\n marginLeft: theme.spacing(1),\n color: theme.palette.text.primary,\n }}\n >\n MCP Chat\n </Typography>\n </>\n )}\n {sidebarCollapsed && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n marginBottom: '8px',\n }}\n >\n <IconButton\n size=\"small\"\n onClick={onToggleSidebar}\n sx={{ color: theme.palette.text.primary }}\n >\n <ChevronLeftIcon />\n </IconButton>\n </Box>\n )}\n </Box>\n\n {!sidebarCollapsed && (\n <>\n {/* New Chat Button */}\n <Box sx={{ padding: '16px 16px 8px' }}>\n <Button\n variant=\"contained\"\n startIcon={<AddIcon />}\n sx={{\n background: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n '&:hover': {\n background: theme.palette.primary.dark,\n },\n borderRadius: theme.spacing(1),\n textTransform: 'none',\n padding: theme.spacing(1, 2),\n fontWeight: 600,\n }}\n size=\"small\"\n fullWidth\n onClick={onNewChat}\n >\n New chat\n </Button>\n </Box>\n\n {/* Tab Buttons */}\n <Box sx={{ padding: '8px 16px' }}>\n <ToggleButtonGroup\n value={activeTab}\n exclusive\n onChange={handleTabChange}\n size=\"small\"\n fullWidth\n sx={{\n '& .MuiToggleButton-root': {\n textTransform: 'none',\n fontWeight: 500,\n padding: theme.spacing(0.75, 2),\n '&.Mui-selected': {\n backgroundColor: theme.palette.action.selected,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n },\n },\n }}\n >\n <ToggleButton value=\"status\">\n <SettingsIcon sx={{ fontSize: 18, mr: 0.5 }} />\n Status\n </ToggleButton>\n <ToggleButton value=\"history\">\n <HistoryIcon sx={{ fontSize: 18, mr: 0.5 }} />\n History\n </ToggleButton>\n </ToggleButtonGroup>\n </Box>\n\n {/* Tab Content */}\n {activeTab === 'status' && (\n <>\n <ProviderStatus\n providerStatusData={providerStatus.providerStatusData}\n isLoading={providerStatus.isLoading}\n error={providerStatus.error}\n />\n\n <ActiveTools\n mcpServers={mcpServers}\n availableTools={availableTools}\n toolsLoading={toolsLoading}\n />\n\n <ActiveMcpServers\n mcpServers={mcpServers}\n onServerToggle={onServerToggle}\n />\n </>\n )}\n\n {activeTab === 'history' && (\n <ConversationHistory\n starredConversations={starredConversations}\n recentConversations={recentConversations}\n loading={conversationsLoading}\n error={conversationsError}\n searchQuery={searchQuery}\n onSearchChange={onSearchChange}\n onSearchClear={onSearchClear}\n onSelectConversation={onSelectConversation}\n onToggleStar={onToggleStar}\n onDelete={onDeleteConversation}\n selectedConversationId={selectedConversationId}\n />\n )}\n </>\n )}\n\n {sidebarCollapsed && (\n <Box\n sx={{\n padding: '16px 8px',\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n }}\n >\n {/* Top section - buttons that stay at top */}\n <Box>\n {/* Add button when collapsed */}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n marginBottom: '16px',\n }}\n >\n <IconButton\n size=\"small\"\n onClick={onNewChat}\n sx={{\n backgroundColor: theme.palette.primary.main,\n color: theme.palette.primary.contrastText,\n transition: 'all 0.2s ease',\n '&:hover': {\n backgroundColor: theme.palette.primary.dark,\n transform: 'scale(1.05)',\n },\n }}\n >\n <AddIcon />\n </IconButton>\n </Box>\n\n {/* History button when collapsed */}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n marginBottom: '8px',\n }}\n >\n <IconButton\n size=\"small\"\n title=\"History\"\n onClick={() => {\n onToggleSidebar();\n setActiveTab('history');\n }}\n sx={{ color: theme.palette.text.secondary }}\n >\n <HistoryIcon />\n </IconButton>\n </Box>\n </Box>\n\n {/* Bottom section - MCP Servers */}\n <Box sx={{ marginTop: 'auto' }}>\n {/* Separator line */}\n <Box\n sx={{\n borderTop: `2px solid ${theme.palette.divider}`,\n margin: '0 8px 16px 8px',\n }}\n />\n\n {/* MCP Servers Section Icon */}\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n <IconButton\n size=\"medium\"\n title=\"MCP Configuration\"\n onClick={() => {\n onToggleSidebar();\n setActiveTab('status');\n }}\n sx={{ color: theme.palette.text.primary }}\n >\n <MemoryIcon />\n </IconButton>\n </Box>\n </Box>\n </Box>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import { useState, useEffect, useCallback, useMemo } from 'react';
2
+ import { useApi, identityApiRef } from '@backstage/core-plugin-api';
3
+ import useAsync from 'react-use/esm/useAsync';
4
+ import { mcpChatApiRef } from '../api/index.esm.js';
5
+
6
+ function isGuestUser(userEntityRef) {
7
+ const guestPattern = /^user:development\/guest$/i;
8
+ return guestPattern.test(userEntityRef);
9
+ }
10
+ function filterConversations(conversations, query) {
11
+ const lowerQuery = query.toLowerCase();
12
+ return conversations.filter((conv) => {
13
+ if (conv.title?.toLowerCase().includes(lowerQuery)) {
14
+ return true;
15
+ }
16
+ return conv.messages.some(
17
+ (m) => m.role === "user" && m.content?.toLowerCase().includes(lowerQuery)
18
+ );
19
+ });
20
+ }
21
+ function useConversations() {
22
+ const mcpChatApi = useApi(mcpChatApiRef);
23
+ const identityApi = useApi(identityApiRef);
24
+ const [refreshKey, setRefreshKey] = useState(0);
25
+ const [localConversations, setLocalConversations] = useState([]);
26
+ const [searchQuery, setSearchQuery] = useState("");
27
+ const {
28
+ value: fetchedConversations,
29
+ loading,
30
+ error
31
+ } = useAsync(async () => {
32
+ try {
33
+ const identity = await identityApi.getBackstageIdentity();
34
+ if (isGuestUser(identity.userEntityRef)) {
35
+ return [];
36
+ }
37
+ const response = await mcpChatApi.getConversations();
38
+ return response.conversations;
39
+ } catch (err) {
40
+ return [];
41
+ }
42
+ }, [mcpChatApi, identityApi, refreshKey]);
43
+ useEffect(() => {
44
+ if (fetchedConversations) {
45
+ setLocalConversations(fetchedConversations);
46
+ }
47
+ }, [fetchedConversations]);
48
+ const clearSearch = useCallback(() => {
49
+ setSearchQuery("");
50
+ }, []);
51
+ const loadConversation = useCallback(
52
+ async (id) => {
53
+ const identity = await identityApi.getBackstageIdentity();
54
+ if (isGuestUser(identity.userEntityRef)) {
55
+ throw new Error("Guest users cannot load conversations");
56
+ }
57
+ return mcpChatApi.getConversationById(id);
58
+ },
59
+ [mcpChatApi, identityApi]
60
+ );
61
+ const refreshConversations = useCallback(() => {
62
+ setRefreshKey((prev) => prev + 1);
63
+ }, []);
64
+ const deleteConversation = useCallback(
65
+ async (id) => {
66
+ const previousConversations = localConversations;
67
+ setLocalConversations((prev) => prev.filter((c) => c.id !== id));
68
+ try {
69
+ await mcpChatApi.deleteConversation(id);
70
+ } catch (err) {
71
+ setLocalConversations(previousConversations);
72
+ throw err;
73
+ }
74
+ },
75
+ [mcpChatApi, localConversations]
76
+ );
77
+ const toggleStar = useCallback(
78
+ async (id) => {
79
+ const previousConversations = localConversations;
80
+ setLocalConversations(
81
+ (prev) => prev.map((c) => c.id === id ? { ...c, isStarred: !c.isStarred } : c)
82
+ );
83
+ try {
84
+ await mcpChatApi.toggleConversationStar(id);
85
+ } catch (err) {
86
+ setLocalConversations(previousConversations);
87
+ throw err;
88
+ }
89
+ },
90
+ [mcpChatApi, localConversations]
91
+ );
92
+ const conversations = useMemo(() => {
93
+ if (searchQuery && searchQuery.length >= 2) {
94
+ return filterConversations(localConversations, searchQuery);
95
+ }
96
+ return localConversations;
97
+ }, [searchQuery, localConversations]);
98
+ const starredConversations = useMemo(
99
+ () => conversations.filter((c) => c.isStarred),
100
+ [conversations]
101
+ );
102
+ const recentConversations = useMemo(
103
+ () => conversations.filter((c) => !c.isStarred),
104
+ [conversations]
105
+ );
106
+ return {
107
+ conversations,
108
+ starredConversations,
109
+ recentConversations,
110
+ loading,
111
+ error: error?.message,
112
+ searchQuery,
113
+ setSearchQuery,
114
+ clearSearch,
115
+ loadConversation,
116
+ refreshConversations,
117
+ deleteConversation,
118
+ toggleStar
119
+ };
120
+ }
121
+
122
+ export { useConversations };
123
+ //# sourceMappingURL=useConversations.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConversations.esm.js","sources":["../../src/hooks/useConversations.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\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 { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useApi, identityApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/esm/useAsync';\nimport { mcpChatApiRef } from '../api';\nimport type { ConversationRecord } from '../types';\n\n/**\n * Check if a user is a guest user based on their userEntityRef.\n * Guest users have userEntityRef like 'user:development/guest'.\n */\nfunction isGuestUser(userEntityRef: string): boolean {\n const guestPattern = /^user:development\\/guest$/i;\n return guestPattern.test(userEntityRef);\n}\n\n/**\n * Filter conversations by search query.\n * Searches in title and user message content (case-insensitive).\n */\nfunction filterConversations(\n conversations: ConversationRecord[],\n query: string,\n): ConversationRecord[] {\n const lowerQuery = query.toLowerCase();\n return conversations.filter(conv => {\n // Check title\n if (conv.title?.toLowerCase().includes(lowerQuery)) {\n return true;\n }\n // Check user messages\n return conv.messages.some(\n m => m.role === 'user' && m.content?.toLowerCase().includes(lowerQuery),\n );\n });\n}\n\n/**\n * Return type for the useConversations hook.\n * @public\n */\nexport interface UseConversationsReturn {\n /** List of conversations (filtered if search is active) */\n conversations: ConversationRecord[];\n /** Starred conversations */\n starredConversations: ConversationRecord[];\n /** Non-starred conversations */\n recentConversations: ConversationRecord[];\n /** Whether conversations are currently loading */\n loading: boolean;\n /** Error message if loading failed */\n error?: string;\n /** Current search query */\n searchQuery: string;\n /** Set the search query */\n setSearchQuery: (query: string) => void;\n /** Clear the search */\n clearSearch: () => void;\n /** Load a specific conversation by ID */\n loadConversation: (id: string) => Promise<ConversationRecord>;\n /** Refresh the conversation list */\n refreshConversations: () => void;\n /** Delete a conversation (with optimistic update) */\n deleteConversation: (id: string) => Promise<void>;\n /** Toggle star status (with optimistic update) */\n toggleStar: (id: string) => Promise<void>;\n}\n\n/**\n * Hook for managing conversation history.\n * Handles fetching conversations, caching, search, and optimistic updates.\n *\n * @returns Conversation data and helper functions\n * @public\n */\nexport function useConversations(): UseConversationsReturn {\n const mcpChatApi = useApi(mcpChatApiRef);\n const identityApi = useApi(identityApiRef);\n const [refreshKey, setRefreshKey] = useState(0);\n const [localConversations, setLocalConversations] = useState<\n ConversationRecord[]\n >([]);\n const [searchQuery, setSearchQuery] = useState('');\n\n const {\n value: fetchedConversations,\n loading,\n error,\n } = useAsync(async () => {\n try {\n // Check if user is a guest - skip API call for guests\n const identity = await identityApi.getBackstageIdentity();\n if (isGuestUser(identity.userEntityRef)) {\n return [];\n }\n\n const response = await mcpChatApi.getConversations();\n return response.conversations;\n } catch (err: any) {\n // Gracefully handle errors by returning empty array\n // Conversation history is a nice-to-have, not critical\n return [];\n }\n }, [mcpChatApi, identityApi, refreshKey]);\n\n // Sync fetched conversations to local state\n useEffect(() => {\n if (fetchedConversations) {\n setLocalConversations(fetchedConversations);\n }\n }, [fetchedConversations]);\n\n const clearSearch = useCallback(() => {\n setSearchQuery('');\n }, []);\n\n const loadConversation = useCallback(\n async (id: string): Promise<ConversationRecord> => {\n // Check if user is a guest\n const identity = await identityApi.getBackstageIdentity();\n if (isGuestUser(identity.userEntityRef)) {\n throw new Error('Guest users cannot load conversations');\n }\n return mcpChatApi.getConversationById(id);\n },\n [mcpChatApi, identityApi],\n );\n\n const refreshConversations = useCallback(() => {\n setRefreshKey(prev => prev + 1);\n }, []);\n\n const deleteConversation = useCallback(\n async (id: string): Promise<void> => {\n // Optimistic update: remove from local state immediately\n const previousConversations = localConversations;\n setLocalConversations(prev => prev.filter(c => c.id !== id));\n\n try {\n await mcpChatApi.deleteConversation(id);\n } catch (err) {\n // Rollback on failure\n setLocalConversations(previousConversations);\n throw err;\n }\n },\n [mcpChatApi, localConversations],\n );\n\n const toggleStar = useCallback(\n async (id: string): Promise<void> => {\n // Optimistic update: toggle star in local state\n const previousConversations = localConversations;\n setLocalConversations(prev =>\n prev.map(c => (c.id === id ? { ...c, isStarred: !c.isStarred } : c)),\n );\n\n try {\n await mcpChatApi.toggleConversationStar(id);\n } catch (err) {\n // Rollback on failure\n setLocalConversations(previousConversations);\n throw err;\n }\n },\n [mcpChatApi, localConversations],\n );\n\n // Determine which conversations to show (with local filtering)\n const conversations = useMemo(() => {\n if (searchQuery && searchQuery.length >= 2) {\n return filterConversations(localConversations, searchQuery);\n }\n return localConversations;\n }, [searchQuery, localConversations]);\n\n // Split into starred and non-starred\n const starredConversations = useMemo(\n () => conversations.filter(c => c.isStarred),\n [conversations],\n );\n\n const recentConversations = useMemo(\n () => conversations.filter(c => !c.isStarred),\n [conversations],\n );\n\n return {\n conversations,\n starredConversations,\n recentConversations,\n loading,\n error: error?.message,\n searchQuery,\n setSearchQuery,\n clearSearch,\n loadConversation,\n refreshConversations,\n deleteConversation,\n toggleStar,\n };\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -26,7 +26,6 @@ declare const MCPChatIcon: IconComponent;
26
26
  */
27
27
  declare enum MCPServerType {
28
28
  STDIO = "stdio",
29
- SSE = "sse",
30
29
  STREAMABLE_HTTP = "streamable-http"
31
30
  }
32
31
  /**
@@ -129,16 +128,55 @@ interface ChatResponse {
129
128
  content: string;
130
129
  toolResponses?: any[];
131
130
  toolsUsed?: string[];
131
+ conversationId?: string;
132
+ }
133
+ /**
134
+ * A stored conversation record from the backend.
135
+ * @public
136
+ */
137
+ interface ConversationRecord {
138
+ /** Unique identifier for the conversation */
139
+ id: string;
140
+ /** User entity ref who owns this conversation */
141
+ userId: string;
142
+ /** Array of chat messages in the conversation */
143
+ messages: ChatMessage[];
144
+ /** Optional array of tool names used in the conversation */
145
+ toolsUsed?: string[];
146
+ /** AI-generated or user-edited conversation title */
147
+ title?: string;
148
+ /** Whether the conversation is starred/favorited */
149
+ isStarred: boolean;
150
+ /** ISO timestamp when the conversation was created */
151
+ createdAt: string;
152
+ /** ISO timestamp when the conversation was last updated */
153
+ updatedAt: string;
154
+ }
155
+ /**
156
+ * Response from the /conversations endpoint.
157
+ * @public
158
+ */
159
+ interface ConversationsResponse {
160
+ /** Array of conversation records */
161
+ conversations: ConversationRecord[];
162
+ /** Total count of conversations returned */
163
+ count: number;
132
164
  }
133
165
 
134
166
  /**
135
167
  * @public
136
168
  */
137
169
  interface McpChatApi {
138
- sendChatMessage(messages: ChatMessage[], enabledTools?: string[], signal?: AbortSignal): Promise<ChatResponse>;
170
+ sendChatMessage(messages: ChatMessage[], enabledTools?: string[], signal?: AbortSignal, conversationId?: string): Promise<ChatResponse>;
139
171
  getMCPServerStatus(): Promise<MCPServerStatusData>;
140
172
  getAvailableTools(): Promise<ToolsResponse>;
141
173
  getProviderStatus(): Promise<ProviderStatusData>;
174
+ getConversations(): Promise<ConversationsResponse>;
175
+ getConversationById(id: string): Promise<ConversationRecord>;
176
+ deleteConversation(id: string): Promise<void>;
177
+ toggleConversationStar(id: string): Promise<{
178
+ isStarred: boolean;
179
+ }>;
142
180
  }
143
181
 
144
182
  /**
@@ -147,4 +185,4 @@ interface McpChatApi {
147
185
  declare const mcpChatApiRef: _backstage_core_plugin_api.ApiRef<McpChatApi>;
148
186
 
149
187
  export { MCPChatIcon, MCPServerType, McpChatPage, mcpChatApiRef, mcpChatPlugin };
150
- export type { ChatMessage, ChatResponse, MCPServer, MCPServerStatusData, McpChatApi, Provider, ProviderConnectionStatus, ProviderStatusData, Tool, ToolsResponse };
188
+ export type { ChatMessage, ChatResponse, ConversationRecord, ConversationsResponse, MCPServer, MCPServerStatusData, McpChatApi, Provider, ProviderConnectionStatus, ProviderStatusData, Tool, ToolsResponse };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-mcp-chat",
3
3
  "description": "A Backstage plugin that provides a chat interface for interacting with the MCP Servers.",
4
- "version": "0.1.2",
4
+ "version": "0.3.0",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.esm.js",
7
7
  "types": "dist/index.d.ts",
@@ -43,16 +43,18 @@
43
43
  "@types/react": "^17.0.0 || ^18.0.0",
44
44
  "react": "^17.0.0 || ^18.0.0",
45
45
  "react-dom": "^17.0.0 || ^18.0.0",
46
- "react-router": "^6.3.0",
46
+ "react-router": "^6.30.2",
47
47
  "react-router-dom": "^6.3.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@backstage/cli": "^0.33.0",
51
51
  "@backstage/dev-utils": "^1.1.11",
52
52
  "@backstage/test-utils": "^1.7.8",
53
+ "@testing-library/dom": "^10.4.1",
53
54
  "@testing-library/jest-dom": "^6.0.0",
54
- "@testing-library/react": "^14.0.0",
55
+ "@testing-library/react": "^16.0.0",
55
56
  "@types/react": "^17.0.0 || ^18.0.0",
57
+ "@types/react-dom": "^19.2.3",
56
58
  "react": "^17.0.0 || ^18.0.0",
57
59
  "react-dom": "^17.0.0 || ^18.0.0",
58
60
  "react-router-dom": "^6.3.0"