@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.
@@ -0,0 +1,218 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { useTheme } from '@mui/material/styles';
3
+ import Box from '@mui/material/Box';
4
+ import Typography from '@mui/material/Typography';
5
+ import List from '@mui/material/List';
6
+ import Divider from '@mui/material/Divider';
7
+ import CircularProgress from '@mui/material/CircularProgress';
8
+ import ChatIcon from '@mui/icons-material/Chat';
9
+ import StarIcon from '@mui/icons-material/Star';
10
+ import SearchOffIcon from '@mui/icons-material/SearchOff';
11
+ import { ConversationSearchBar } from './ConversationSearchBar.esm.js';
12
+ import { ConversationItem } from './ConversationItem.esm.js';
13
+
14
+ const ConversationHistory = ({
15
+ starredConversations,
16
+ recentConversations,
17
+ loading,
18
+ error,
19
+ searchQuery,
20
+ onSearchChange,
21
+ onSearchClear,
22
+ onSelectConversation,
23
+ onToggleStar,
24
+ onDelete,
25
+ selectedConversationId
26
+ }) => {
27
+ const theme = useTheme();
28
+ const hasConversations = starredConversations.length > 0 || recentConversations.length > 0;
29
+ const isSearchActive = searchQuery.length >= 2;
30
+ const noSearchResults = isSearchActive && !hasConversations;
31
+ return /* @__PURE__ */ jsxs(
32
+ Box,
33
+ {
34
+ sx: {
35
+ flex: 1,
36
+ display: "flex",
37
+ flexDirection: "column",
38
+ overflow: "hidden"
39
+ },
40
+ children: [
41
+ /* @__PURE__ */ jsx(
42
+ ConversationSearchBar,
43
+ {
44
+ value: searchQuery,
45
+ onChange: onSearchChange,
46
+ onClear: onSearchClear
47
+ }
48
+ ),
49
+ /* @__PURE__ */ jsxs(
50
+ Box,
51
+ {
52
+ sx: {
53
+ flex: 1,
54
+ overflowY: "auto",
55
+ padding: theme.spacing(0, 1, 1)
56
+ },
57
+ children: [
58
+ loading && !hasConversations && /* @__PURE__ */ jsx(
59
+ Box,
60
+ {
61
+ sx: {
62
+ display: "flex",
63
+ justifyContent: "center",
64
+ padding: theme.spacing(4)
65
+ },
66
+ children: /* @__PURE__ */ jsx(CircularProgress, { size: 24 })
67
+ }
68
+ ),
69
+ !loading && error && !hasConversations && /* @__PURE__ */ jsx(
70
+ Typography,
71
+ {
72
+ variant: "body2",
73
+ color: "error",
74
+ sx: {
75
+ padding: theme.spacing(2),
76
+ textAlign: "center"
77
+ },
78
+ children: error
79
+ }
80
+ ),
81
+ noSearchResults && /* @__PURE__ */ jsxs(
82
+ Box,
83
+ {
84
+ sx: {
85
+ display: "flex",
86
+ flexDirection: "column",
87
+ alignItems: "center",
88
+ padding: theme.spacing(4),
89
+ color: theme.palette.text.secondary
90
+ },
91
+ children: [
92
+ /* @__PURE__ */ jsx(
93
+ SearchOffIcon,
94
+ {
95
+ sx: { fontSize: 48, marginBottom: 2, opacity: 0.5 }
96
+ }
97
+ ),
98
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "No conversations found" }),
99
+ /* @__PURE__ */ jsx(
100
+ Typography,
101
+ {
102
+ variant: "caption",
103
+ color: "text.secondary",
104
+ sx: { marginTop: 1 },
105
+ children: "Try a different search term"
106
+ }
107
+ )
108
+ ]
109
+ }
110
+ ),
111
+ !hasConversations && !loading && !error && !isSearchActive && /* @__PURE__ */ jsxs(
112
+ Box,
113
+ {
114
+ sx: {
115
+ display: "flex",
116
+ flexDirection: "column",
117
+ alignItems: "center",
118
+ padding: theme.spacing(4),
119
+ color: theme.palette.text.secondary
120
+ },
121
+ children: [
122
+ /* @__PURE__ */ jsx(ChatIcon, { sx: { fontSize: 48, marginBottom: 2, opacity: 0.5 } }),
123
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "text.secondary", children: "No conversations yet" }),
124
+ /* @__PURE__ */ jsx(
125
+ Typography,
126
+ {
127
+ variant: "caption",
128
+ color: "text.secondary",
129
+ sx: { marginTop: 1 },
130
+ children: "Start a new chat to see your history here"
131
+ }
132
+ )
133
+ ]
134
+ }
135
+ ),
136
+ starredConversations.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
137
+ /* @__PURE__ */ jsxs(
138
+ Box,
139
+ {
140
+ sx: {
141
+ display: "flex",
142
+ alignItems: "center",
143
+ gap: 0.5,
144
+ padding: theme.spacing(1, 0.5),
145
+ color: theme.palette.text.secondary
146
+ },
147
+ children: [
148
+ /* @__PURE__ */ jsx(StarIcon, { sx: { fontSize: 14 } }),
149
+ /* @__PURE__ */ jsx(
150
+ Typography,
151
+ {
152
+ variant: "caption",
153
+ sx: { fontWeight: 600, textTransform: "uppercase" },
154
+ children: "Starred"
155
+ }
156
+ )
157
+ ]
158
+ }
159
+ ),
160
+ /* @__PURE__ */ jsx(List, { dense: true, sx: { padding: 0 }, children: starredConversations.map((conversation) => /* @__PURE__ */ jsx(
161
+ ConversationItem,
162
+ {
163
+ conversation,
164
+ isSelected: selectedConversationId === conversation.id,
165
+ onSelect: () => onSelectConversation(conversation),
166
+ onToggleStar: () => onToggleStar(conversation.id),
167
+ onDelete: () => onDelete(conversation.id)
168
+ },
169
+ conversation.id
170
+ )) })
171
+ ] }),
172
+ starredConversations.length > 0 && recentConversations.length > 0 && /* @__PURE__ */ jsx(Divider, { sx: { my: 1 } }),
173
+ recentConversations.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
174
+ starredConversations.length > 0 && /* @__PURE__ */ jsxs(
175
+ Box,
176
+ {
177
+ sx: {
178
+ display: "flex",
179
+ alignItems: "center",
180
+ gap: 0.5,
181
+ padding: theme.spacing(1, 0.5),
182
+ color: theme.palette.text.secondary
183
+ },
184
+ children: [
185
+ /* @__PURE__ */ jsx(ChatIcon, { sx: { fontSize: 14 } }),
186
+ /* @__PURE__ */ jsx(
187
+ Typography,
188
+ {
189
+ variant: "caption",
190
+ sx: { fontWeight: 600, textTransform: "uppercase" },
191
+ children: "Recent"
192
+ }
193
+ )
194
+ ]
195
+ }
196
+ ),
197
+ /* @__PURE__ */ jsx(List, { dense: true, sx: { padding: 0 }, children: recentConversations.map((conversation) => /* @__PURE__ */ jsx(
198
+ ConversationItem,
199
+ {
200
+ conversation,
201
+ isSelected: selectedConversationId === conversation.id,
202
+ onSelect: () => onSelectConversation(conversation),
203
+ onToggleStar: () => onToggleStar(conversation.id),
204
+ onDelete: () => onDelete(conversation.id)
205
+ },
206
+ conversation.id
207
+ )) })
208
+ ] })
209
+ ]
210
+ }
211
+ )
212
+ ]
213
+ }
214
+ );
215
+ };
216
+
217
+ export { ConversationHistory };
218
+ //# sourceMappingURL=ConversationHistory.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationHistory.esm.js","sources":["../../../src/components/RightPane/ConversationHistory.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 Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport List from '@mui/material/List';\nimport Divider from '@mui/material/Divider';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport ChatIcon from '@mui/icons-material/Chat';\nimport StarIcon from '@mui/icons-material/Star';\nimport SearchOffIcon from '@mui/icons-material/SearchOff';\nimport { ConversationSearchBar } from './ConversationSearchBar';\nimport { ConversationItem } from './ConversationItem';\nimport type { ConversationRecord } from '../../types';\n\ninterface ConversationHistoryProps {\n /** Starred conversations */\n starredConversations: ConversationRecord[];\n /** Non-starred (recent) conversations */\n recentConversations: ConversationRecord[];\n /** Whether conversations are loading */\n loading: boolean;\n /** Error message if loading failed */\n error?: string;\n /** Current search query */\n searchQuery: string;\n /** Callback to set search query */\n onSearchChange: (query: string) => void;\n /** Callback to clear search */\n onSearchClear: () => void;\n /** Callback when a conversation is selected */\n onSelectConversation: (conversation: ConversationRecord) => void;\n /** Callback to toggle star status */\n onToggleStar: (id: string) => void;\n /** Callback to delete a conversation */\n onDelete: (id: string) => void;\n /** Currently selected conversation ID */\n selectedConversationId?: string;\n}\n\n/**\n * Displays a list of conversation history items with search, star, and delete functionality.\n * Shows starred conversations at the top, followed by recent conversations.\n */\nexport const ConversationHistory: FC<ConversationHistoryProps> = ({\n starredConversations,\n recentConversations,\n loading,\n error,\n searchQuery,\n onSearchChange,\n onSearchClear,\n onSelectConversation,\n onToggleStar,\n onDelete,\n selectedConversationId,\n}) => {\n const theme = useTheme();\n\n const hasConversations =\n starredConversations.length > 0 || recentConversations.length > 0;\n const isSearchActive = searchQuery.length >= 2;\n const noSearchResults = isSearchActive && !hasConversations;\n\n return (\n <Box\n sx={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n >\n {/* Search bar */}\n <ConversationSearchBar\n value={searchQuery}\n onChange={onSearchChange}\n onClear={onSearchClear}\n />\n\n {/* Scrollable content */}\n <Box\n sx={{\n flex: 1,\n overflowY: 'auto',\n padding: theme.spacing(0, 1, 1),\n }}\n >\n {/* Loading state */}\n {loading && !hasConversations && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'center',\n padding: theme.spacing(4),\n }}\n >\n <CircularProgress size={24} />\n </Box>\n )}\n\n {/* Error state */}\n {!loading && error && !hasConversations && (\n <Typography\n variant=\"body2\"\n color=\"error\"\n sx={{\n padding: theme.spacing(2),\n textAlign: 'center',\n }}\n >\n {error}\n </Typography>\n )}\n\n {/* No search results */}\n {noSearchResults && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n padding: theme.spacing(4),\n color: theme.palette.text.secondary,\n }}\n >\n <SearchOffIcon\n sx={{ fontSize: 48, marginBottom: 2, opacity: 0.5 }}\n />\n <Typography variant=\"body2\" color=\"text.secondary\">\n No conversations found\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ marginTop: 1 }}\n >\n Try a different search term\n </Typography>\n </Box>\n )}\n\n {/* Empty state (no search active) */}\n {!hasConversations && !loading && !error && !isSearchActive && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n padding: theme.spacing(4),\n color: theme.palette.text.secondary,\n }}\n >\n <ChatIcon sx={{ fontSize: 48, marginBottom: 2, opacity: 0.5 }} />\n <Typography variant=\"body2\" color=\"text.secondary\">\n No conversations yet\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ marginTop: 1 }}\n >\n Start a new chat to see your history here\n </Typography>\n </Box>\n )}\n\n {/* Starred conversations section */}\n {starredConversations.length > 0 && (\n <>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n padding: theme.spacing(1, 0.5),\n color: theme.palette.text.secondary,\n }}\n >\n <StarIcon sx={{ fontSize: 14 }} />\n <Typography\n variant=\"caption\"\n sx={{ fontWeight: 600, textTransform: 'uppercase' }}\n >\n Starred\n </Typography>\n </Box>\n <List dense sx={{ padding: 0 }}>\n {starredConversations.map(conversation => (\n <ConversationItem\n key={conversation.id}\n conversation={conversation}\n isSelected={selectedConversationId === conversation.id}\n onSelect={() => onSelectConversation(conversation)}\n onToggleStar={() => onToggleStar(conversation.id)}\n onDelete={() => onDelete(conversation.id)}\n />\n ))}\n </List>\n </>\n )}\n\n {/* Divider between starred and recent */}\n {starredConversations.length > 0 && recentConversations.length > 0 && (\n <Divider sx={{ my: 1 }} />\n )}\n\n {/* Recent conversations section */}\n {recentConversations.length > 0 && (\n <>\n {starredConversations.length > 0 && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n padding: theme.spacing(1, 0.5),\n color: theme.palette.text.secondary,\n }}\n >\n <ChatIcon sx={{ fontSize: 14 }} />\n <Typography\n variant=\"caption\"\n sx={{ fontWeight: 600, textTransform: 'uppercase' }}\n >\n Recent\n </Typography>\n </Box>\n )}\n <List dense sx={{ padding: 0 }}>\n {recentConversations.map(conversation => (\n <ConversationItem\n key={conversation.id}\n conversation={conversation}\n isSelected={selectedConversationId === conversation.id}\n onSelect={() => onSelectConversation(conversation)}\n onToggleStar={() => onToggleStar(conversation.id)}\n onDelete={() => onDelete(conversation.id)}\n />\n ))}\n </List>\n </>\n )}\n </Box>\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useCallback } from 'react';
3
+ import { useTheme } from '@mui/material/styles';
4
+ import Box from '@mui/material/Box';
5
+ import Typography from '@mui/material/Typography';
6
+ import ListItem from '@mui/material/ListItem';
7
+ import ListItemButton from '@mui/material/ListItemButton';
8
+ import IconButton from '@mui/material/IconButton';
9
+ import Popover from '@mui/material/Popover';
10
+ import Button from '@mui/material/Button';
11
+ import StarIcon from '@mui/icons-material/Star';
12
+ import StarBorderIcon from '@mui/icons-material/StarBorder';
13
+ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
14
+
15
+ const ConversationItem = ({
16
+ conversation,
17
+ isSelected,
18
+ onSelect,
19
+ onToggleStar,
20
+ onDelete
21
+ }) => {
22
+ const theme = useTheme();
23
+ const [deleteAnchor, setDeleteAnchor] = useState(null);
24
+ const [isHovered, setIsHovered] = useState(false);
25
+ const getDisplayTitle = () => {
26
+ if (conversation.title) {
27
+ return conversation.title;
28
+ }
29
+ const firstUserMessage = conversation.messages.find((m) => m.role === "user");
30
+ const content = firstUserMessage?.content || "Empty conversation";
31
+ return content.length > 40 ? `${content.substring(0, 40)}...` : content;
32
+ };
33
+ const formatDate = (dateString) => {
34
+ const date = new Date(dateString);
35
+ const now = /* @__PURE__ */ new Date();
36
+ const diffDays = Math.floor(
37
+ (now.getTime() - date.getTime()) / (1e3 * 60 * 60 * 24)
38
+ );
39
+ if (diffDays === 0) {
40
+ return "Today";
41
+ } else if (diffDays === 1) {
42
+ return "Yesterday";
43
+ } else if (diffDays < 7) {
44
+ return `${diffDays} days ago`;
45
+ }
46
+ return date.toLocaleDateString();
47
+ };
48
+ const handleDeleteClick = useCallback(
49
+ (event) => {
50
+ event.stopPropagation();
51
+ setDeleteAnchor(event.currentTarget);
52
+ },
53
+ []
54
+ );
55
+ const handleDeleteClose = useCallback(() => {
56
+ setDeleteAnchor(null);
57
+ }, []);
58
+ const handleDeleteConfirm = useCallback(() => {
59
+ setDeleteAnchor(null);
60
+ onDelete();
61
+ }, [onDelete]);
62
+ const handleStarClick = useCallback(
63
+ (event) => {
64
+ event.stopPropagation();
65
+ onToggleStar();
66
+ },
67
+ [onToggleStar]
68
+ );
69
+ const showActions = isHovered || isSelected || Boolean(deleteAnchor);
70
+ return /* @__PURE__ */ jsxs(
71
+ ListItem,
72
+ {
73
+ disablePadding: true,
74
+ sx: { mb: 0.5 },
75
+ onMouseEnter: () => setIsHovered(true),
76
+ onMouseLeave: () => setIsHovered(false),
77
+ children: [
78
+ /* @__PURE__ */ jsxs(
79
+ ListItemButton,
80
+ {
81
+ selected: isSelected,
82
+ onClick: onSelect,
83
+ sx: {
84
+ borderRadius: 1,
85
+ padding: theme.spacing(1, 1.5),
86
+ position: "relative",
87
+ "&.Mui-selected": {
88
+ backgroundColor: theme.palette.action.selected,
89
+ "&:hover": {
90
+ backgroundColor: theme.palette.action.hover
91
+ }
92
+ },
93
+ "&:hover": {
94
+ backgroundColor: theme.palette.action.hover
95
+ }
96
+ },
97
+ children: [
98
+ /* @__PURE__ */ jsxs(Box, { sx: { flex: 1, minWidth: 0, pr: showActions ? 6 : 0 }, children: [
99
+ /* @__PURE__ */ jsx(
100
+ Typography,
101
+ {
102
+ variant: "body2",
103
+ sx: {
104
+ fontWeight: isSelected ? 600 : 400,
105
+ overflow: "hidden",
106
+ textOverflow: "ellipsis",
107
+ whiteSpace: "nowrap",
108
+ color: theme.palette.text.primary
109
+ },
110
+ children: getDisplayTitle()
111
+ }
112
+ ),
113
+ /* @__PURE__ */ jsxs(
114
+ Box,
115
+ {
116
+ sx: {
117
+ display: "flex",
118
+ justifyContent: "space-between",
119
+ alignItems: "center",
120
+ marginTop: 0.5
121
+ },
122
+ children: [
123
+ /* @__PURE__ */ jsx(
124
+ Typography,
125
+ {
126
+ variant: "caption",
127
+ color: "text.secondary",
128
+ sx: { fontSize: "0.7rem" },
129
+ children: formatDate(conversation.updatedAt)
130
+ }
131
+ ),
132
+ conversation.toolsUsed && conversation.toolsUsed.length > 0 && /* @__PURE__ */ jsxs(
133
+ Typography,
134
+ {
135
+ variant: "caption",
136
+ color: "text.secondary",
137
+ sx: { fontSize: "0.65rem" },
138
+ children: [
139
+ conversation.toolsUsed.length,
140
+ " tool",
141
+ conversation.toolsUsed.length > 1 ? "s" : ""
142
+ ]
143
+ }
144
+ )
145
+ ]
146
+ }
147
+ )
148
+ ] }),
149
+ showActions && /* @__PURE__ */ jsxs(
150
+ Box,
151
+ {
152
+ sx: {
153
+ position: "absolute",
154
+ right: theme.spacing(1),
155
+ top: "50%",
156
+ transform: "translateY(-50%)",
157
+ display: "flex",
158
+ gap: 0.5,
159
+ backgroundColor: isSelected ? theme.palette.action.selected : theme.palette.background.paper,
160
+ borderRadius: 1,
161
+ padding: "2px"
162
+ },
163
+ onClick: (e) => e.stopPropagation(),
164
+ children: [
165
+ /* @__PURE__ */ jsx(
166
+ IconButton,
167
+ {
168
+ size: "small",
169
+ onClick: handleStarClick,
170
+ sx: {
171
+ padding: 0.5,
172
+ color: conversation.isStarred ? theme.palette.warning.main : theme.palette.text.secondary,
173
+ "&:hover": {
174
+ color: theme.palette.warning.main
175
+ }
176
+ },
177
+ "aria-label": conversation.isStarred ? "Remove from favorites" : "Add to favorites",
178
+ children: conversation.isStarred ? /* @__PURE__ */ jsx(StarIcon, { sx: { fontSize: 18 } }) : /* @__PURE__ */ jsx(StarBorderIcon, { sx: { fontSize: 18 } })
179
+ }
180
+ ),
181
+ /* @__PURE__ */ jsx(
182
+ IconButton,
183
+ {
184
+ size: "small",
185
+ onClick: handleDeleteClick,
186
+ sx: {
187
+ padding: 0.5,
188
+ color: theme.palette.text.secondary,
189
+ "&:hover": {
190
+ color: theme.palette.error.main
191
+ }
192
+ },
193
+ "aria-label": "Delete conversation",
194
+ children: /* @__PURE__ */ jsx(DeleteOutlineIcon, { sx: { fontSize: 18 } })
195
+ }
196
+ )
197
+ ]
198
+ }
199
+ )
200
+ ]
201
+ }
202
+ ),
203
+ /* @__PURE__ */ jsx(
204
+ Popover,
205
+ {
206
+ open: Boolean(deleteAnchor),
207
+ anchorEl: deleteAnchor,
208
+ onClose: handleDeleteClose,
209
+ anchorOrigin: {
210
+ vertical: "bottom",
211
+ horizontal: "center"
212
+ },
213
+ transformOrigin: {
214
+ vertical: "top",
215
+ horizontal: "center"
216
+ },
217
+ children: /* @__PURE__ */ jsxs(Box, { sx: { p: 2, maxWidth: 250 }, children: [
218
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { mb: 1.5 }, children: "Delete this conversation? This action cannot be undone." }),
219
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", gap: 1, justifyContent: "flex-end" }, children: [
220
+ /* @__PURE__ */ jsx(Button, { size: "small", onClick: handleDeleteClose, children: "Cancel" }),
221
+ /* @__PURE__ */ jsx(
222
+ Button,
223
+ {
224
+ size: "small",
225
+ color: "error",
226
+ variant: "contained",
227
+ onClick: handleDeleteConfirm,
228
+ children: "Delete"
229
+ }
230
+ )
231
+ ] })
232
+ ] })
233
+ }
234
+ )
235
+ ]
236
+ }
237
+ );
238
+ };
239
+
240
+ export { ConversationItem };
241
+ //# sourceMappingURL=ConversationItem.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationItem.esm.js","sources":["../../../src/components/RightPane/ConversationItem.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 */\n\nimport { FC, useState, useCallback } from 'react';\nimport { useTheme } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport ListItem from '@mui/material/ListItem';\nimport ListItemButton from '@mui/material/ListItemButton';\nimport IconButton from '@mui/material/IconButton';\nimport Popover from '@mui/material/Popover';\nimport Button from '@mui/material/Button';\nimport StarIcon from '@mui/icons-material/Star';\nimport StarBorderIcon from '@mui/icons-material/StarBorder';\nimport DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';\nimport type { ConversationRecord } from '../../types';\n\ninterface ConversationItemProps {\n /** The conversation to display */\n conversation: ConversationRecord;\n /** Whether this conversation is currently selected */\n isSelected: boolean;\n /** Called when the conversation is clicked */\n onSelect: () => void;\n /** Called when the star button is clicked */\n onToggleStar: () => void;\n /** Called when delete is confirmed */\n onDelete: () => void;\n}\n\n/**\n * Single conversation item in the history list.\n * Displays title, date, and action buttons (star, delete).\n */\nexport const ConversationItem: FC<ConversationItemProps> = ({\n conversation,\n isSelected,\n onSelect,\n onToggleStar,\n onDelete,\n}) => {\n const theme = useTheme();\n const [deleteAnchor, setDeleteAnchor] = useState<HTMLElement | null>(null);\n const [isHovered, setIsHovered] = useState(false);\n\n // Get display title - use title if available, fallback to first user message\n const getDisplayTitle = (): string => {\n if (conversation.title) {\n return conversation.title;\n }\n const firstUserMessage = conversation.messages.find(m => m.role === 'user');\n const content = firstUserMessage?.content || 'Empty conversation';\n return content.length > 40 ? `${content.substring(0, 40)}...` : content;\n };\n\n // Format date to relative or absolute\n const formatDate = (dateString: string): string => {\n const date = new Date(dateString);\n const now = new Date();\n const diffDays = Math.floor(\n (now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n if (diffDays === 0) {\n return 'Today';\n } else if (diffDays === 1) {\n return 'Yesterday';\n } else if (diffDays < 7) {\n return `${diffDays} days ago`;\n }\n return date.toLocaleDateString();\n };\n\n const handleDeleteClick = useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n event.stopPropagation();\n setDeleteAnchor(event.currentTarget);\n },\n [],\n );\n\n const handleDeleteClose = useCallback(() => {\n setDeleteAnchor(null);\n }, []);\n\n const handleDeleteConfirm = useCallback(() => {\n setDeleteAnchor(null);\n onDelete();\n }, [onDelete]);\n\n const handleStarClick = useCallback(\n (event: React.MouseEvent) => {\n event.stopPropagation();\n onToggleStar();\n },\n [onToggleStar],\n );\n\n const showActions = isHovered || isSelected || Boolean(deleteAnchor);\n\n return (\n <ListItem\n disablePadding\n sx={{ mb: 0.5 }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <ListItemButton\n selected={isSelected}\n onClick={onSelect}\n sx={{\n borderRadius: 1,\n padding: theme.spacing(1, 1.5),\n position: 'relative',\n '&.Mui-selected': {\n backgroundColor: theme.palette.action.selected,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n },\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n {/* Content */}\n <Box sx={{ flex: 1, minWidth: 0, pr: showActions ? 6 : 0 }}>\n <Typography\n variant=\"body2\"\n sx={{\n fontWeight: isSelected ? 600 : 400,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n color: theme.palette.text.primary,\n }}\n >\n {getDisplayTitle()}\n </Typography>\n\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginTop: 0.5,\n }}\n >\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: '0.7rem' }}\n >\n {formatDate(conversation.updatedAt)}\n </Typography>\n {conversation.toolsUsed && conversation.toolsUsed.length > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: '0.65rem' }}\n >\n {conversation.toolsUsed.length} tool\n {conversation.toolsUsed.length > 1 ? 's' : ''}\n </Typography>\n )}\n </Box>\n </Box>\n\n {/* Action buttons - shown on hover or selection */}\n {showActions && (\n <Box\n sx={{\n position: 'absolute',\n right: theme.spacing(1),\n top: '50%',\n transform: 'translateY(-50%)',\n display: 'flex',\n gap: 0.5,\n backgroundColor: isSelected\n ? theme.palette.action.selected\n : theme.palette.background.paper,\n borderRadius: 1,\n padding: '2px',\n }}\n onClick={e => e.stopPropagation()}\n >\n <IconButton\n size=\"small\"\n onClick={handleStarClick}\n sx={{\n padding: 0.5,\n color: conversation.isStarred\n ? theme.palette.warning.main\n : theme.palette.text.secondary,\n '&:hover': {\n color: theme.palette.warning.main,\n },\n }}\n aria-label={\n conversation.isStarred\n ? 'Remove from favorites'\n : 'Add to favorites'\n }\n >\n {conversation.isStarred ? (\n <StarIcon sx={{ fontSize: 18 }} />\n ) : (\n <StarBorderIcon sx={{ fontSize: 18 }} />\n )}\n </IconButton>\n\n <IconButton\n size=\"small\"\n onClick={handleDeleteClick}\n sx={{\n padding: 0.5,\n color: theme.palette.text.secondary,\n '&:hover': {\n color: theme.palette.error.main,\n },\n }}\n aria-label=\"Delete conversation\"\n >\n <DeleteOutlineIcon sx={{ fontSize: 18 }} />\n </IconButton>\n </Box>\n )}\n </ListItemButton>\n\n {/* Delete confirmation popover */}\n <Popover\n open={Boolean(deleteAnchor)}\n anchorEl={deleteAnchor}\n onClose={handleDeleteClose}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'center',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'center',\n }}\n >\n <Box sx={{ p: 2, maxWidth: 250 }}>\n <Typography variant=\"body2\" sx={{ mb: 1.5 }}>\n Delete this conversation? This action cannot be undone.\n </Typography>\n <Box sx={{ display: 'flex', gap: 1, justifyContent: 'flex-end' }}>\n <Button size=\"small\" onClick={handleDeleteClose}>\n Cancel\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n variant=\"contained\"\n onClick={handleDeleteConfirm}\n >\n Delete\n </Button>\n </Box>\n </Box>\n </Popover>\n </ListItem>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect, useCallback } from 'react';
3
+ import { useTheme } from '@mui/material/styles';
4
+ import Box from '@mui/material/Box';
5
+ import TextField from '@mui/material/TextField';
6
+ import InputAdornment from '@mui/material/InputAdornment';
7
+ import IconButton from '@mui/material/IconButton';
8
+ import SearchIcon from '@mui/icons-material/Search';
9
+ import ClearIcon from '@mui/icons-material/Clear';
10
+
11
+ const DEBOUNCE_DELAY = 300;
12
+ const ConversationSearchBar = ({
13
+ value,
14
+ onChange,
15
+ onClear,
16
+ placeholder = "Search conversations..."
17
+ }) => {
18
+ const theme = useTheme();
19
+ const [localValue, setLocalValue] = useState(value);
20
+ useEffect(() => {
21
+ setLocalValue(value);
22
+ }, [value]);
23
+ useEffect(() => {
24
+ const timer = setTimeout(() => {
25
+ if (localValue !== value) {
26
+ onChange(localValue);
27
+ }
28
+ }, DEBOUNCE_DELAY);
29
+ return () => clearTimeout(timer);
30
+ }, [localValue, value, onChange]);
31
+ const handleChange = useCallback(
32
+ (event) => {
33
+ setLocalValue(event.target.value);
34
+ },
35
+ []
36
+ );
37
+ const handleClear = useCallback(() => {
38
+ setLocalValue("");
39
+ onClear();
40
+ }, [onClear]);
41
+ const handleKeyDown = useCallback(
42
+ (event) => {
43
+ if (event.key === "Escape") {
44
+ handleClear();
45
+ }
46
+ },
47
+ [handleClear]
48
+ );
49
+ return /* @__PURE__ */ jsx(Box, { sx: { padding: theme.spacing(1, 1.5) }, children: /* @__PURE__ */ jsx(
50
+ TextField,
51
+ {
52
+ fullWidth: true,
53
+ size: "small",
54
+ placeholder,
55
+ value: localValue,
56
+ onChange: handleChange,
57
+ onKeyDown: handleKeyDown,
58
+ InputProps: {
59
+ startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx(
60
+ SearchIcon,
61
+ {
62
+ sx: {
63
+ color: theme.palette.text.secondary,
64
+ fontSize: 20
65
+ }
66
+ }
67
+ ) }),
68
+ endAdornment: localValue ? /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
69
+ IconButton,
70
+ {
71
+ size: "small",
72
+ onClick: handleClear,
73
+ sx: { padding: 0.5 },
74
+ "aria-label": "Clear search",
75
+ children: /* @__PURE__ */ jsx(ClearIcon, { sx: { fontSize: 18 } })
76
+ }
77
+ ) }) : null
78
+ },
79
+ sx: {
80
+ "& .MuiOutlinedInput-root": {
81
+ borderRadius: 2,
82
+ backgroundColor: theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "rgba(0, 0, 0, 0.03)",
83
+ "& fieldset": {
84
+ borderColor: "transparent"
85
+ },
86
+ "&:hover fieldset": {
87
+ borderColor: theme.palette.divider
88
+ },
89
+ "&.Mui-focused fieldset": {
90
+ borderColor: theme.palette.primary.main,
91
+ borderWidth: 1
92
+ }
93
+ },
94
+ "& .MuiOutlinedInput-input": {
95
+ padding: theme.spacing(1, 0),
96
+ fontSize: "0.875rem"
97
+ }
98
+ }
99
+ }
100
+ ) });
101
+ };
102
+
103
+ export { ConversationSearchBar };
104
+ //# sourceMappingURL=ConversationSearchBar.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConversationSearchBar.esm.js","sources":["../../../src/components/RightPane/ConversationSearchBar.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 */\n\nimport { FC, useState, useEffect, useCallback } from 'react';\nimport { useTheme } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\nimport TextField from '@mui/material/TextField';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport IconButton from '@mui/material/IconButton';\nimport SearchIcon from '@mui/icons-material/Search';\nimport ClearIcon from '@mui/icons-material/Clear';\n\n/** Debounce delay in milliseconds */\nconst DEBOUNCE_DELAY = 300;\n\ninterface ConversationSearchBarProps {\n /** Current search value */\n value: string;\n /** Called when search value changes (debounced) */\n onChange: (value: string) => void;\n /** Called when search is cleared */\n onClear: () => void;\n /** Placeholder text */\n placeholder?: string;\n}\n\n/**\n * Search bar component for filtering conversations.\n * Includes debouncing for smooth filtering.\n */\nexport const ConversationSearchBar: FC<ConversationSearchBarProps> = ({\n value,\n onChange,\n onClear,\n placeholder = 'Search conversations...',\n}) => {\n const theme = useTheme();\n const [localValue, setLocalValue] = useState(value);\n\n // Sync local value with prop value\n useEffect(() => {\n setLocalValue(value);\n }, [value]);\n\n // Debounced onChange handler\n useEffect(() => {\n const timer = setTimeout(() => {\n if (localValue !== value) {\n onChange(localValue);\n }\n }, DEBOUNCE_DELAY);\n\n return () => clearTimeout(timer);\n }, [localValue, value, onChange]);\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n setLocalValue(event.target.value);\n },\n [],\n );\n\n const handleClear = useCallback(() => {\n setLocalValue('');\n onClear();\n }, [onClear]);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') {\n handleClear();\n }\n },\n [handleClear],\n );\n\n return (\n <Box sx={{ padding: theme.spacing(1, 1.5) }}>\n <TextField\n fullWidth\n size=\"small\"\n placeholder={placeholder}\n value={localValue}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon\n sx={{\n color: theme.palette.text.secondary,\n fontSize: 20,\n }}\n />\n </InputAdornment>\n ),\n endAdornment: localValue ? (\n <InputAdornment position=\"end\">\n <IconButton\n size=\"small\"\n onClick={handleClear}\n sx={{ padding: 0.5 }}\n aria-label=\"Clear search\"\n >\n <ClearIcon sx={{ fontSize: 18 }} />\n </IconButton>\n </InputAdornment>\n ) : null,\n }}\n sx={{\n '& .MuiOutlinedInput-root': {\n borderRadius: 2,\n backgroundColor:\n theme.palette.mode === 'dark'\n ? 'rgba(255, 255, 255, 0.05)'\n : 'rgba(0, 0, 0, 0.03)',\n '& fieldset': {\n borderColor: 'transparent',\n },\n '&:hover fieldset': {\n borderColor: theme.palette.divider,\n },\n '&.Mui-focused fieldset': {\n borderColor: theme.palette.primary.main,\n borderWidth: 1,\n },\n },\n '& .MuiOutlinedInput-input': {\n padding: theme.spacing(1, 0),\n fontSize: '0.875rem',\n },\n }}\n />\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}