@red-hat-developer-hub/backstage-plugin-lightspeed 1.2.1 → 1.2.3

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 (39) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/alpha.d.ts +0 -6
  3. package/dist/api/LightspeedApiClient.esm.js +20 -6
  4. package/dist/api/LightspeedApiClient.esm.js.map +1 -1
  5. package/dist/components/DeleteModal.esm.js +2 -3
  6. package/dist/components/DeleteModal.esm.js.map +1 -1
  7. package/dist/components/LightSpeedChat.esm.js +1 -11
  8. package/dist/components/LightSpeedChat.esm.js.map +1 -1
  9. package/dist/components/LightspeedChatBox.esm.js +48 -17
  10. package/dist/components/LightspeedChatBox.esm.js.map +1 -1
  11. package/dist/components/LightspeedDrawerProvider.esm.js +39 -26
  12. package/dist/components/LightspeedDrawerProvider.esm.js.map +1 -1
  13. package/dist/components/LightspeedDrawerStateExposer.esm.js +8 -2
  14. package/dist/components/LightspeedDrawerStateExposer.esm.js.map +1 -1
  15. package/dist/components/RenameConversationModal.esm.js +26 -8
  16. package/dist/components/RenameConversationModal.esm.js.map +1 -1
  17. package/dist/components/ToolCallContent.esm.js +25 -54
  18. package/dist/components/ToolCallContent.esm.js.map +1 -1
  19. package/dist/hooks/useDisplayModeSettings.esm.js +57 -0
  20. package/dist/hooks/useDisplayModeSettings.esm.js.map +1 -0
  21. package/dist/translations/de.esm.js +1 -7
  22. package/dist/translations/de.esm.js.map +1 -1
  23. package/dist/translations/es.esm.js +1 -7
  24. package/dist/translations/es.esm.js.map +1 -1
  25. package/dist/translations/fr.esm.js +1 -7
  26. package/dist/translations/fr.esm.js.map +1 -1
  27. package/dist/translations/it.esm.js +6 -7
  28. package/dist/translations/it.esm.js.map +1 -1
  29. package/dist/translations/ja.esm.js +6 -7
  30. package/dist/translations/ja.esm.js.map +1 -1
  31. package/dist/translations/ref.esm.js +1 -7
  32. package/dist/translations/ref.esm.js.map +1 -1
  33. package/dist/utils/lightspeed-chatbox-utils.esm.js +13 -23
  34. package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
  35. package/dist/utils/reasoningParser.esm.js +18 -31
  36. package/dist/utils/reasoningParser.esm.js.map +1 -1
  37. package/dist/utils/toolCallMapper.esm.js +2 -2
  38. package/dist/utils/toolCallMapper.esm.js.map +1 -1
  39. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedChatBox.esm.js","sources":["../../src/components/LightspeedChatBox.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n ChatbotDisplayMode,\n ChatbotWelcomePrompt,\n DeepThinking,\n DeepThinkingProps,\n Message,\n MessageBox,\n MessageBoxHandle,\n MessageProps,\n ToolCall as PatternFlyToolCall,\n WelcomePrompt,\n} from '@patternfly/chatbot';\nimport { Alert } from '@patternfly/react-core';\n\nimport { useAutoScroll } from '../hooks/useAutoScroll';\nimport { useBufferedMessages } from '../hooks/useBufferedMessages';\nimport { useFeedbackActions } from '../hooks/useFeedbackActions';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { ToolCall } from '../types';\nimport { parseReasoning } from '../utils/reasoningParser';\nimport { mapToPatternFlyToolCall } from '../utils/toolCallMapper';\n\nconst useStyles = makeStyles(theme => ({\n prompt: {\n 'justify-content': 'flex-end',\n },\n container: {\n maxWidth: 'unset !important',\n },\n alert: {\n background: 'unset !important',\n },\n promptSuggestions: {\n '& div.pf-chatbot__prompt-suggestions': {\n 'flex-direction': 'column !important',\n },\n },\n\n userMessageText: {\n '& div.pf-chatbot__message--user': {\n '& div.pf-chatbot__message-text': {\n '& p': {\n color: theme.palette.common.white,\n },\n },\n },\n },\n}));\n\n// Extended message type that includes tool calls\ninterface ExtendedMessageProps extends MessageProps {\n toolCalls?: ToolCall[];\n}\n\ntype LightspeedChatBoxProps = {\n userName?: string;\n messages: ExtendedMessageProps[];\n profileLoading: boolean;\n announcement: string | undefined;\n topicRestrictionEnabled: boolean;\n welcomePrompts: WelcomePrompt[];\n conversationId: string;\n isStreaming: boolean;\n displayMode?: ChatbotDisplayMode;\n};\n\nexport interface ScrollContainerHandle {\n scrollToBottom: () => void;\n}\n\nexport const LightspeedChatBox = forwardRef(\n (\n {\n userName,\n messages,\n announcement,\n conversationId,\n profileLoading,\n welcomePrompts,\n isStreaming,\n topicRestrictionEnabled,\n displayMode,\n }: LightspeedChatBoxProps,\n ref: ForwardedRef<ScrollContainerHandle>,\n ) => {\n const classes = useStyles();\n const scrollQueued = useRef(false);\n const containerRef = useRef<MessageBoxHandle>(null);\n const { t } = useTranslation();\n\n const cmessages = useBufferedMessages(messages, 30);\n const { autoScroll, scrollToBottom, scrollToTop } =\n useAutoScroll(containerRef);\n const conversationMessages = useFeedbackActions(\n cmessages,\n conversationId,\n isStreaming,\n );\n\n useImperativeHandle(ref, () => ({\n scrollToBottom: () => {\n if (scrollQueued.current) return;\n scrollQueued.current = true;\n\n requestAnimationFrame(() => {\n scrollToBottom();\n scrollQueued.current = false;\n });\n },\n }));\n\n // Auto-scrolls to the latest message\n useEffect(() => {\n if (!autoScroll || scrollQueued.current) return undefined;\n\n scrollQueued.current = true;\n\n const rafId = requestAnimationFrame(() => {\n const container = containerRef.current;\n if (!container) return;\n\n setTimeout(() => {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'auto',\n });\n }, 0);\n\n scrollQueued.current = false;\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n scrollQueued.current = false;\n };\n\n // eslint-disable-next-line\n }, [autoScroll, cmessages, containerRef]);\n\n const messageBoxClasses = `${classes.container} ${classes.userMessageText}`;\n const isEmbeddedMode = displayMode === ChatbotDisplayMode.embedded;\n\n const getMessageBoxClassName = () => {\n if (!welcomePrompts.length) {\n return messageBoxClasses;\n }\n const baseClasses = `${messageBoxClasses} ${classes.prompt}`;\n if (isEmbeddedMode) {\n return baseClasses;\n }\n return `${baseClasses} ${classes.promptSuggestions}`;\n };\n\n return (\n <MessageBox\n className={getMessageBoxClassName()}\n announcement={announcement}\n ref={containerRef}\n onScrollToTopClick={scrollToTop}\n onScrollToBottomClick={scrollToBottom}\n jumpButtonBottomProps={{ 'aria-label': t('aria.scroll.down') }}\n jumpButtonTopProps={{ 'aria-label': t('aria.scroll.up') }}\n jumpButtonBottomTooltipProps={{ content: t('tooltip.backToBottom') }}\n jumpButtonTopTooltipProps={{ content: t('tooltip.backToTop') }}\n >\n <div>\n <Alert\n title={t('aria.important')}\n variant=\"info\"\n isInline\n className={classes.alert}\n >\n {topicRestrictionEnabled\n ? t('disclaimer.withValidation')\n : t('disclaimer.withoutValidation')}\n </Alert>\n <br />\n </div>\n {welcomePrompts.length ? (\n <ChatbotWelcomePrompt\n title={t('chatbox.welcome.greeting' as any, {\n userName: profileLoading\n ? t('user.loading')\n : (userName ?? t('user.guest')),\n })}\n description={t('chatbox.welcome.description')}\n prompts={welcomePrompts}\n style={{ paddingBottom: '0' }}\n />\n ) : (\n <br />\n )}\n {conversationMessages.map((message, index) => {\n const messageContent = message.content as string;\n const parsedReasoning = parseReasoning(messageContent || '');\n\n // Map first tool call to PatternFly's toolCall prop\n const firstToolCall = message.toolCalls?.[0];\n const toolCallProp = firstToolCall\n ? mapToPatternFlyToolCall(firstToolCall, t)\n : undefined;\n\n // Handle additional tool calls (if any) via extraContent\n const additionalToolCalls = message.toolCalls?.slice(1);\n\n const extraContentParts: {\n beforeMainContent?: React.ReactNode;\n afterMainContent?: React.ReactNode;\n } = {};\n\n let deepThinking: DeepThinkingProps | undefined = undefined;\n\n if (\n parsedReasoning.isReasoningInProgress ||\n parsedReasoning.hasReasoning\n ) {\n const reasoningContent =\n parsedReasoning.reasoning ||\n (() => {\n const reasoningMatch = messageContent.match(/<think>(.*?)$/s);\n return reasoningMatch ? reasoningMatch[1].trim() : '';\n })();\n\n if (reasoningContent) {\n deepThinking = {\n cardBodyProps: {\n id: `deep-thinking-${index}`,\n style: { whiteSpace: 'pre-line' },\n },\n toggleContent: t('reasoning.thinking'),\n body: reasoningContent,\n expandableSectionProps: {},\n };\n extraContentParts.beforeMainContent = (\n <DeepThinking {...deepThinking} />\n );\n }\n }\n\n if (additionalToolCalls && additionalToolCalls.length > 0) {\n extraContentParts.afterMainContent = (\n <>\n {additionalToolCalls.map(tc => {\n const tcProps = mapToPatternFlyToolCall(tc, t);\n return (\n <div\n key={`tool-${tc.id}-${tc.toolName}`}\n style={{ marginTop: '8px' }}\n >\n <PatternFlyToolCall {...tcProps} />\n </div>\n );\n })}\n </>\n );\n }\n\n const extraContent =\n extraContentParts.beforeMainContent ||\n extraContentParts.afterMainContent\n ? extraContentParts\n : undefined;\n\n const finalMessage =\n parsedReasoning.hasReasoning ||\n parsedReasoning.isReasoningInProgress\n ? { ...message, content: parsedReasoning.mainContent }\n : message;\n\n return (\n <Message\n key={`${message.role}-${index}`}\n toolCall={toolCallProp}\n extraContent={extraContent}\n {...finalMessage}\n />\n );\n })}\n </MessageBox>\n );\n },\n);\n"],"names":["PatternFlyToolCall"],"mappings":"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"}
1
+ {"version":3,"file":"LightspeedChatBox.esm.js","sources":["../../src/components/LightspeedChatBox.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ForwardedRef,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n ChatbotDisplayMode,\n ChatbotWelcomePrompt,\n DeepThinking,\n DeepThinkingProps,\n Message,\n MessageBox,\n MessageBoxHandle,\n MessageProps,\n ToolCall as PatternFlyToolCall,\n WelcomePrompt,\n} from '@patternfly/chatbot';\nimport { Alert } from '@patternfly/react-core';\n\nimport { useAutoScroll } from '../hooks/useAutoScroll';\nimport { useBufferedMessages } from '../hooks/useBufferedMessages';\nimport { useFeedbackActions } from '../hooks/useFeedbackActions';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { ToolCall } from '../types';\nimport { parseReasoning } from '../utils/reasoningParser';\nimport { mapToPatternFlyToolCall } from '../utils/toolCallMapper';\n\nconst useStyles = makeStyles(theme => ({\n prompt: {\n 'justify-content': 'flex-end',\n },\n container: {\n maxWidth: 'unset !important',\n },\n alert: {\n background: 'unset !important',\n },\n promptSuggestions: {\n '& div.pf-chatbot__prompt-suggestions': {\n 'flex-direction': 'column !important',\n },\n },\n\n userMessageText: {\n '& div.pf-chatbot__message--user': {\n '& div.pf-chatbot__message-text': {\n '& p': {\n color: theme.palette.common.white,\n },\n },\n },\n },\n deepThinking: {\n animation: '$deepThinking 1.6s ease-in-out infinite',\n },\n\n '@keyframes deepThinking': {\n '0%': {\n opacity: 0.65,\n },\n '50%': {\n opacity: 1,\n },\n '100%': {\n opacity: 0.65,\n },\n },\n}));\n\n// Extended message type that includes tool calls\ninterface ExtendedMessageProps extends MessageProps {\n toolCalls?: ToolCall[];\n}\n\ntype LightspeedChatBoxProps = {\n userName?: string;\n messages: ExtendedMessageProps[];\n profileLoading: boolean;\n announcement: string | undefined;\n topicRestrictionEnabled: boolean;\n welcomePrompts: WelcomePrompt[];\n conversationId: string;\n isStreaming: boolean;\n displayMode?: ChatbotDisplayMode;\n};\n\nexport interface ScrollContainerHandle {\n scrollToBottom: () => void;\n}\n\nexport const LightspeedChatBox = forwardRef(\n (\n {\n userName,\n messages,\n announcement,\n conversationId,\n profileLoading,\n welcomePrompts,\n isStreaming,\n topicRestrictionEnabled,\n displayMode,\n }: LightspeedChatBoxProps,\n ref: ForwardedRef<ScrollContainerHandle>,\n ) => {\n const classes = useStyles();\n const scrollQueued = useRef(false);\n const containerRef = useRef<MessageBoxHandle>(null);\n const { t } = useTranslation();\n\n const cmessages = useBufferedMessages(messages, 30);\n const { autoScroll, scrollToBottom, scrollToTop } =\n useAutoScroll(containerRef);\n const conversationMessages = useFeedbackActions(\n cmessages,\n conversationId,\n isStreaming,\n );\n\n useImperativeHandle(ref, () => ({\n scrollToBottom: () => {\n if (scrollQueued.current) return;\n scrollQueued.current = true;\n\n requestAnimationFrame(() => {\n scrollToBottom();\n scrollQueued.current = false;\n });\n },\n }));\n\n // Auto-scrolls to the latest message\n useEffect(() => {\n if (!autoScroll || scrollQueued.current) return undefined;\n\n scrollQueued.current = true;\n\n const rafId = requestAnimationFrame(() => {\n const container = containerRef.current;\n if (!container) return;\n\n setTimeout(() => {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'auto',\n });\n }, 0);\n\n scrollQueued.current = false;\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n scrollQueued.current = false;\n };\n\n // eslint-disable-next-line\n }, [autoScroll, cmessages, containerRef]);\n\n const messageBoxClasses = `${classes.container} ${classes.userMessageText}`;\n const isEmbeddedMode = displayMode === ChatbotDisplayMode.embedded;\n\n const getMessageBoxClassName = () => {\n if (!welcomePrompts.length) {\n return messageBoxClasses;\n }\n const baseClasses = `${messageBoxClasses} ${classes.prompt}`;\n if (isEmbeddedMode) {\n return baseClasses;\n }\n return `${baseClasses} ${classes.promptSuggestions}`;\n };\n\n return (\n <MessageBox\n className={getMessageBoxClassName()}\n announcement={announcement}\n ref={containerRef}\n onScrollToTopClick={scrollToTop}\n onScrollToBottomClick={scrollToBottom}\n jumpButtonBottomProps={{ 'aria-label': t('aria.scroll.down') }}\n jumpButtonTopProps={{ 'aria-label': t('aria.scroll.up') }}\n jumpButtonBottomTooltipProps={{ content: t('tooltip.backToBottom') }}\n jumpButtonTopTooltipProps={{ content: t('tooltip.backToTop') }}\n >\n <div>\n <Alert\n title={t('aria.important')}\n variant=\"info\"\n isInline\n className={classes.alert}\n >\n {topicRestrictionEnabled\n ? t('disclaimer.withValidation')\n : t('disclaimer.withoutValidation')}\n </Alert>\n <br />\n </div>\n {welcomePrompts.length ? (\n <ChatbotWelcomePrompt\n title={t('chatbox.welcome.greeting' as any, {\n userName: profileLoading\n ? t('user.loading')\n : (userName ?? t('user.guest')),\n })}\n description={t('chatbox.welcome.description')}\n prompts={welcomePrompts}\n style={{ paddingBottom: '0' }}\n />\n ) : (\n <br />\n )}\n {conversationMessages.map((message, index) => {\n const messageContent = message.content as string;\n const parsedReasoning = parseReasoning(messageContent || '');\n\n // Map first tool call to PatternFly's toolCall prop\n const firstToolCall = message.toolCalls?.[0];\n const toolCallProp = firstToolCall\n ? mapToPatternFlyToolCall(firstToolCall, t, message.role)\n : undefined;\n\n // Handle additional tool calls (if any) via extraContent\n const additionalToolCalls = message.toolCalls?.slice(1);\n\n const extraContentParts: {\n beforeMainContent?: React.ReactNode;\n afterMainContent?: React.ReactNode;\n } = {};\n\n let deepThinking: DeepThinkingProps | undefined = undefined;\n\n if (\n parsedReasoning.isReasoningInProgress ||\n parsedReasoning.hasReasoning\n ) {\n const reasoningContent = parsedReasoning.reasoning;\n\n if (reasoningContent) {\n deepThinking = {\n cardBodyProps: {\n id: `deep-thinking-${index}`,\n style: { whiteSpace: 'pre-line' },\n className: parsedReasoning.isReasoningInProgress\n ? classes.deepThinking\n : undefined,\n },\n toggleContent: t('reasoning.thinking'),\n body: reasoningContent,\n isDefaultExpanded: false,\n };\n }\n }\n\n const allToolCalls: React.ReactNode[] = [];\n\n // Add first tool call if it exists\n if (toolCallProp && firstToolCall) {\n allToolCalls.push(\n <div\n key={`tool-${firstToolCall.id}-${firstToolCall.toolName}`}\n style={{ marginTop: '8px' }}\n >\n <PatternFlyToolCall {...toolCallProp} />\n </div>,\n );\n }\n\n // Add additional tool calls\n if (additionalToolCalls && additionalToolCalls.length > 0) {\n additionalToolCalls.forEach(tc => {\n const tcProps = mapToPatternFlyToolCall(tc, t, message.role);\n allToolCalls.push(\n <div\n key={`tool-${tc.id}-${tc.toolName}`}\n style={{ marginTop: '8px' }}\n >\n <PatternFlyToolCall {...tcProps} />\n </div>,\n );\n });\n }\n\n // Show Thinking first, then tool calls\n if (deepThinking || allToolCalls.length > 0) {\n extraContentParts.beforeMainContent = (\n <>\n {deepThinking && <DeepThinking {...deepThinking} />}\n {allToolCalls.length > 0 && (\n <div style={{ marginTop: deepThinking ? '8px' : '0' }}>\n {allToolCalls}\n </div>\n )}\n </>\n );\n }\n\n const extraContent =\n extraContentParts.beforeMainContent ||\n extraContentParts.afterMainContent\n ? extraContentParts\n : undefined;\n\n const finalMessage =\n parsedReasoning.hasReasoning ||\n parsedReasoning.isReasoningInProgress\n ? { ...message, content: parsedReasoning.mainContent }\n : message;\n\n return (\n <Message\n key={`${message.role}-${index}`}\n extraContent={extraContent}\n {...finalMessage}\n />\n );\n })}\n </MessageBox>\n );\n },\n);\n"],"names":["PatternFlyToolCall"],"mappings":"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"}
@@ -3,6 +3,16 @@ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
3
  import { useNavigate, useLocation, useMatch } from 'react-router-dom';
4
4
  import { makeStyles } from '@mui/styles';
5
5
  import { ChatbotDisplayMode, ChatbotModal } from '@patternfly/chatbot';
6
+ import '@backstage/core-plugin-api';
7
+ import '@tanstack/react-query';
8
+ import '../api/api.esm.js';
9
+ import { useBackstageUserIdentity } from '../hooks/useBackstageUserIdentity.esm.js';
10
+ import '@mui/icons-material/PushPin';
11
+ import '@backstage/plugin-permission-react';
12
+ import '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
13
+ import { useDisplayModeSettings } from '../hooks/useDisplayModeSettings.esm.js';
14
+ import '@backstage/core-plugin-api/alpha';
15
+ import '../translations/ref.esm.js';
6
16
  import { LightspeedChatContainer } from './LightspeedChatContainer.esm.js';
7
17
  import { LightspeedDrawerContext } from './LightspeedDrawerContext.esm.js';
8
18
 
@@ -17,9 +27,12 @@ const LightspeedDrawerProvider = ({ children }) => {
17
27
  const classes = useStyles();
18
28
  const navigate = useNavigate();
19
29
  const location = useLocation();
20
- const [displayModeState, setDisplayModeState] = useState(
21
- ChatbotDisplayMode.default
22
- );
30
+ const user = useBackstageUserIdentity();
31
+ const {
32
+ displayMode: persistedDisplayMode,
33
+ setDisplayMode: setPersistedDisplayMode
34
+ } = useDisplayModeSettings(user, ChatbotDisplayMode.default);
35
+ const [displayModeState, setDisplayModeState] = useState(persistedDisplayMode);
23
36
  const [isOpen, setIsOpen] = useState(false);
24
37
  const [drawerWidth, setDrawerWidth] = useState(400);
25
38
  const [currentConversationIdState, setCurrentConversationIdState] = useState(undefined);
@@ -40,39 +53,38 @@ const LightspeedDrawerProvider = ({ children }) => {
40
53
  navigate(-1);
41
54
  }, [navigate]);
42
55
  useEffect(() => {
56
+ if (conversationId) {
57
+ setCurrentConversationIdState(conversationId);
58
+ } else {
59
+ setCurrentConversationIdState(undefined);
60
+ }
43
61
  if (isLightspeedRoute) {
44
- if (conversationId) {
45
- setCurrentConversationIdState(conversationId);
46
- } else {
47
- setCurrentConversationIdState(undefined);
48
- }
49
- setDisplayModeState((prev) => {
50
- if (prev === ChatbotDisplayMode.docked) {
51
- return prev;
52
- }
53
- return ChatbotDisplayMode.embedded;
54
- });
62
+ setDisplayModeState(ChatbotDisplayMode.embedded);
55
63
  setIsOpen(true);
56
64
  } else {
57
- setDisplayModeState((prev) => {
58
- if (prev === ChatbotDisplayMode.embedded) {
59
- return ChatbotDisplayMode.default;
60
- }
61
- return prev;
62
- });
65
+ if (persistedDisplayMode === ChatbotDisplayMode.embedded) {
66
+ setDisplayModeState(ChatbotDisplayMode.default);
67
+ } else {
68
+ setDisplayModeState(persistedDisplayMode);
69
+ }
63
70
  }
64
- }, [conversationId, isLightspeedRoute]);
71
+ }, [conversationId, isLightspeedRoute, persistedDisplayMode]);
65
72
  const openChatbot = useCallback(() => {
66
73
  openedViaFABRef.current = true;
67
- setDisplayModeState(ChatbotDisplayMode.default);
74
+ const modeToUse = persistedDisplayMode || ChatbotDisplayMode.default;
75
+ setDisplayModeState(modeToUse);
76
+ if (modeToUse === ChatbotDisplayMode.embedded) {
77
+ const convId = currentConversationIdState;
78
+ const path = convId ? `/lightspeed/conversation/${convId}` : "/lightspeed";
79
+ navigate(path);
80
+ }
68
81
  setIsOpen(true);
69
- }, []);
82
+ }, [persistedDisplayMode, currentConversationIdState, navigate]);
70
83
  const closeChatbot = useCallback(() => {
71
84
  if (displayModeState === ChatbotDisplayMode.embedded && isLightspeedRoute) {
72
85
  navigateBackOrGoToCatalog();
73
86
  }
74
87
  setIsOpen(false);
75
- setDisplayModeState(ChatbotDisplayMode.default);
76
88
  }, [displayModeState, isLightspeedRoute, navigateBackOrGoToCatalog]);
77
89
  const toggleChatbot = useCallback(() => {
78
90
  if (isOpen) {
@@ -102,7 +114,7 @@ const LightspeedDrawerProvider = ({ children }) => {
102
114
  if (mode === displayModeState) {
103
115
  return;
104
116
  }
105
- setDisplayModeState(mode);
117
+ setPersistedDisplayMode(mode);
106
118
  if (mode === ChatbotDisplayMode.embedded) {
107
119
  const convId = conversationIdParam ?? currentConversationIdState;
108
120
  const path = convId ? `/lightspeed/conversation/${convId}` : "/lightspeed";
@@ -120,7 +132,8 @@ const LightspeedDrawerProvider = ({ children }) => {
120
132
  isLightspeedRoute,
121
133
  currentConversationIdState,
122
134
  displayModeState,
123
- navigateBackOrGoToCatalog
135
+ navigateBackOrGoToCatalog,
136
+ setPersistedDisplayMode
124
137
  ]
125
138
  );
126
139
  const shouldRenderOverlayModal = isOpen && displayModeState === ChatbotDisplayMode.default && !isLightspeedRoute;
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedDrawerProvider.esm.js","sources":["../../src/components/LightspeedDrawerProvider.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PropsWithChildren,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useLocation, useMatch, useNavigate } from 'react-router-dom';\n\nimport { makeStyles } from '@mui/styles';\nimport { ChatbotDisplayMode, ChatbotModal } from '@patternfly/chatbot';\n\nimport { FileContent } from '../types';\nimport { LightspeedChatContainer } from './LightspeedChatContainer';\nimport { LightspeedDrawerContext } from './LightspeedDrawerContext';\n\nconst useStyles = makeStyles(theme => ({\n chatbotModal: {\n boxShadow:\n '0 14px 20px -7px rgba(0, 0, 0, 0.22), 0 32px 50px 6px rgba(0, 0, 0, 0.16), 0 12px 60px 12px rgba(0, 0, 0, 0.14) !important',\n bottom: `calc(${theme?.spacing?.(2) ?? '16px'} + 5em)`,\n right: `calc(${theme?.spacing?.(2) ?? '16px'} + 1.5em)`,\n },\n}));\n\n/**\n * @public\n */\nexport const LightspeedDrawerProvider = ({ children }: PropsWithChildren) => {\n const classes = useStyles();\n const navigate = useNavigate();\n const location = useLocation();\n\n const [displayModeState, setDisplayModeState] = useState<ChatbotDisplayMode>(\n ChatbotDisplayMode.default,\n );\n const [isOpen, setIsOpen] = useState<boolean>(false);\n const [drawerWidth, setDrawerWidth] = useState<number>(400);\n const [currentConversationIdState, setCurrentConversationIdState] = useState<\n string | undefined\n >(undefined);\n const [draftMessage, setDraftMessageState] = useState<string>('');\n const [draftFileContents, setDraftFileContentsState] = useState<\n FileContent[]\n >([]);\n const openedViaFABRef = useRef<boolean>(false);\n\n const isLightspeedRoute = location.pathname.startsWith('/lightspeed');\n\n const conversationMatch = useMatch(\n '/lightspeed/conversation/:conversationId',\n );\n\n const conversationId = conversationMatch?.params?.conversationId;\n\n const navigateBackOrGoToCatalog = useCallback(() => {\n // go to catalog page, if the user opens the lightspeed route via a new tab\n if (!openedViaFABRef.current) {\n navigate('/catalog');\n openedViaFABRef.current = true;\n return;\n }\n navigate(-1);\n }, [navigate]);\n\n useEffect(() => {\n if (isLightspeedRoute) {\n if (conversationId) {\n setCurrentConversationIdState(conversationId);\n } else {\n setCurrentConversationIdState(undefined);\n }\n // Update this to fullscreen only when it is not already in the docked mode\n setDisplayModeState(prev => {\n if (prev === ChatbotDisplayMode.docked) {\n return prev; // Don't override docked mode\n }\n return ChatbotDisplayMode.embedded;\n });\n setIsOpen(true);\n } else {\n // When leaving lightspeed route, update this only when the current mode is fullscreen\n setDisplayModeState(prev => {\n if (prev === ChatbotDisplayMode.embedded) {\n return ChatbotDisplayMode.default;\n }\n return prev;\n });\n }\n }, [conversationId, isLightspeedRoute]);\n\n // Open chatbot in overlay mode\n const openChatbot = useCallback(() => {\n openedViaFABRef.current = true;\n setDisplayModeState(ChatbotDisplayMode.default);\n setIsOpen(true);\n }, []);\n\n // Close chatbot\n const closeChatbot = useCallback(() => {\n // If in embedded mode on the lightspeed route, navigate back\n if (displayModeState === ChatbotDisplayMode.embedded && isLightspeedRoute) {\n navigateBackOrGoToCatalog();\n }\n setIsOpen(false);\n setDisplayModeState(ChatbotDisplayMode.default);\n }, [displayModeState, isLightspeedRoute, navigateBackOrGoToCatalog]);\n\n const toggleChatbot = useCallback(() => {\n if (isOpen) {\n closeChatbot();\n } else {\n openChatbot();\n }\n }, [isOpen, openChatbot, closeChatbot]);\n\n const setCurrentConversationId = useCallback(\n (id: string | undefined) => {\n setCurrentConversationIdState(id);\n\n // Update route if in embedded mode\n if (\n displayModeState === ChatbotDisplayMode.embedded &&\n isLightspeedRoute\n ) {\n const path = id ? `/lightspeed/conversation/${id}` : '/lightspeed';\n navigate(path, { replace: true });\n }\n },\n [displayModeState, isLightspeedRoute, navigate],\n );\n\n const setDraftMessage = useCallback((message: string) => {\n setDraftMessageState(message);\n }, []);\n\n const setDraftFileContents = useCallback((files: FileContent[]) => {\n setDraftFileContentsState(files);\n }, []);\n\n // Set display mode with route handling for embedded/fullscreen\n const setDisplayMode = useCallback(\n (mode: ChatbotDisplayMode, conversationIdParam?: string) => {\n if (mode === displayModeState) {\n return;\n }\n\n setDisplayModeState(mode);\n\n // Navigate to fullscreen route with conversation ID if available\n if (mode === ChatbotDisplayMode.embedded) {\n const convId = conversationIdParam ?? currentConversationIdState;\n const path = convId\n ? `/lightspeed/conversation/${convId}`\n : '/lightspeed';\n navigate(path);\n setIsOpen(true);\n } else {\n if (isLightspeedRoute) {\n navigateBackOrGoToCatalog();\n }\n setIsOpen(true);\n }\n },\n [\n navigate,\n isLightspeedRoute,\n currentConversationIdState,\n displayModeState,\n navigateBackOrGoToCatalog,\n ],\n );\n\n // Only render ChatbotModal for overlay mode\n // Docked mode is handled by ApplicationDrawer in Root\n // Embedded mode is handled by LightspeedPage route\n const shouldRenderOverlayModal =\n isOpen &&\n displayModeState === ChatbotDisplayMode.default &&\n !isLightspeedRoute;\n\n const contextValue = useMemo(\n () => ({\n isChatbotActive: isOpen,\n toggleChatbot,\n displayMode: displayModeState,\n setDisplayMode,\n drawerWidth,\n setDrawerWidth,\n currentConversationId: currentConversationIdState,\n setCurrentConversationId,\n draftMessage,\n setDraftMessage,\n draftFileContents,\n setDraftFileContents,\n }),\n [\n isOpen,\n toggleChatbot,\n displayModeState,\n setDisplayMode,\n drawerWidth,\n setDrawerWidth,\n currentConversationIdState,\n setCurrentConversationId,\n draftMessage,\n setDraftMessage,\n draftFileContents,\n setDraftFileContents,\n ],\n );\n\n return (\n <LightspeedDrawerContext.Provider value={contextValue}>\n {children}\n {shouldRenderOverlayModal && (\n <ChatbotModal\n isOpen\n displayMode={displayModeState}\n onClose={closeChatbot}\n ouiaId=\"LightspeedChatbotModal\"\n aria-labelledby=\"lightspeed-chatpopup-modal\"\n className={classes.chatbotModal}\n >\n <LightspeedChatContainer />\n </ChatbotModal>\n )}\n </LightspeedDrawerContext.Provider>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LightspeedDrawerProvider.esm.js","sources":["../../src/components/LightspeedDrawerProvider.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n PropsWithChildren,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useLocation, useMatch, useNavigate } from 'react-router-dom';\n\nimport { makeStyles } from '@mui/styles';\nimport { ChatbotDisplayMode, ChatbotModal } from '@patternfly/chatbot';\n\nimport { useBackstageUserIdentity, useDisplayModeSettings } from '../hooks';\nimport { FileContent } from '../types';\nimport { LightspeedChatContainer } from './LightspeedChatContainer';\nimport { LightspeedDrawerContext } from './LightspeedDrawerContext';\n\nconst useStyles = makeStyles(theme => ({\n chatbotModal: {\n boxShadow:\n '0 14px 20px -7px rgba(0, 0, 0, 0.22), 0 32px 50px 6px rgba(0, 0, 0, 0.16), 0 12px 60px 12px rgba(0, 0, 0, 0.14) !important',\n bottom: `calc(${theme?.spacing?.(2) ?? '16px'} + 5em)`,\n right: `calc(${theme?.spacing?.(2) ?? '16px'} + 1.5em)`,\n },\n}));\n\n/**\n * @public\n */\nexport const LightspeedDrawerProvider = ({ children }: PropsWithChildren) => {\n const classes = useStyles();\n const navigate = useNavigate();\n const location = useLocation();\n const user = useBackstageUserIdentity();\n const {\n displayMode: persistedDisplayMode,\n setDisplayMode: setPersistedDisplayMode,\n } = useDisplayModeSettings(user, ChatbotDisplayMode.default);\n\n const [displayModeState, setDisplayModeState] =\n useState<ChatbotDisplayMode>(persistedDisplayMode);\n const [isOpen, setIsOpen] = useState<boolean>(false);\n const [drawerWidth, setDrawerWidth] = useState<number>(400);\n const [currentConversationIdState, setCurrentConversationIdState] = useState<\n string | undefined\n >(undefined);\n const [draftMessage, setDraftMessageState] = useState<string>('');\n const [draftFileContents, setDraftFileContentsState] = useState<\n FileContent[]\n >([]);\n const openedViaFABRef = useRef<boolean>(false);\n\n const isLightspeedRoute = location.pathname.startsWith('/lightspeed');\n\n const conversationMatch = useMatch(\n '/lightspeed/conversation/:conversationId',\n );\n\n const conversationId = conversationMatch?.params?.conversationId;\n\n const navigateBackOrGoToCatalog = useCallback(() => {\n // go to catalog page, if the user opens the lightspeed route via a new tab\n if (!openedViaFABRef.current) {\n navigate('/catalog');\n openedViaFABRef.current = true;\n return;\n }\n navigate(-1);\n }, [navigate]);\n\n useEffect(() => {\n if (conversationId) {\n setCurrentConversationIdState(conversationId);\n } else {\n setCurrentConversationIdState(undefined);\n }\n\n if (isLightspeedRoute) {\n setDisplayModeState(ChatbotDisplayMode.embedded);\n setIsOpen(true);\n } else {\n // When leaving lightspeed route, restore the persisted display mode\n // If persisted mode is embedded, reset to default\n if (persistedDisplayMode === ChatbotDisplayMode.embedded) {\n setDisplayModeState(ChatbotDisplayMode.default);\n } else {\n setDisplayModeState(persistedDisplayMode);\n }\n }\n }, [conversationId, isLightspeedRoute, persistedDisplayMode]);\n\n // Open chatbot using the persisted display mode preference\n const openChatbot = useCallback(() => {\n openedViaFABRef.current = true;\n\n const modeToUse = persistedDisplayMode || ChatbotDisplayMode.default;\n setDisplayModeState(modeToUse);\n\n if (modeToUse === ChatbotDisplayMode.embedded) {\n const convId = currentConversationIdState;\n const path = convId\n ? `/lightspeed/conversation/${convId}`\n : '/lightspeed';\n navigate(path);\n }\n\n setIsOpen(true);\n }, [persistedDisplayMode, currentConversationIdState, navigate]);\n\n const closeChatbot = useCallback(() => {\n // If in embedded mode on the lightspeed route, navigate back\n if (displayModeState === ChatbotDisplayMode.embedded && isLightspeedRoute) {\n navigateBackOrGoToCatalog();\n }\n setIsOpen(false);\n }, [displayModeState, isLightspeedRoute, navigateBackOrGoToCatalog]);\n\n const toggleChatbot = useCallback(() => {\n if (isOpen) {\n closeChatbot();\n } else {\n openChatbot();\n }\n }, [isOpen, openChatbot, closeChatbot]);\n\n const setCurrentConversationId = useCallback(\n (id: string | undefined) => {\n setCurrentConversationIdState(id);\n\n if (\n displayModeState === ChatbotDisplayMode.embedded &&\n isLightspeedRoute\n ) {\n const path = id ? `/lightspeed/conversation/${id}` : '/lightspeed';\n navigate(path, { replace: true });\n }\n },\n [displayModeState, isLightspeedRoute, navigate],\n );\n\n const setDraftMessage = useCallback((message: string) => {\n setDraftMessageState(message);\n }, []);\n\n const setDraftFileContents = useCallback((files: FileContent[]) => {\n setDraftFileContentsState(files);\n }, []);\n\n // Set display mode with route handling for embedded/fullscreen\n const setDisplayMode = useCallback(\n (mode: ChatbotDisplayMode, conversationIdParam?: string) => {\n if (mode === displayModeState) {\n return;\n }\n\n setPersistedDisplayMode(mode);\n\n // Navigate to fullscreen route with conversation ID if available\n if (mode === ChatbotDisplayMode.embedded) {\n const convId = conversationIdParam ?? currentConversationIdState;\n const path = convId\n ? `/lightspeed/conversation/${convId}`\n : '/lightspeed';\n navigate(path);\n setIsOpen(true);\n } else {\n if (isLightspeedRoute) {\n navigateBackOrGoToCatalog();\n }\n setIsOpen(true);\n }\n },\n [\n navigate,\n isLightspeedRoute,\n currentConversationIdState,\n displayModeState,\n navigateBackOrGoToCatalog,\n setPersistedDisplayMode,\n ],\n );\n\n // Only render ChatbotModal for overlay mode\n // Docked mode is handled by ApplicationDrawer in Root\n // Embedded mode is handled by LightspeedPage route\n const shouldRenderOverlayModal =\n isOpen &&\n displayModeState === ChatbotDisplayMode.default &&\n !isLightspeedRoute;\n\n const contextValue = useMemo(\n () => ({\n isChatbotActive: isOpen,\n toggleChatbot,\n displayMode: displayModeState,\n setDisplayMode,\n drawerWidth,\n setDrawerWidth,\n currentConversationId: currentConversationIdState,\n setCurrentConversationId,\n draftMessage,\n setDraftMessage,\n draftFileContents,\n setDraftFileContents,\n }),\n [\n isOpen,\n toggleChatbot,\n displayModeState,\n setDisplayMode,\n drawerWidth,\n setDrawerWidth,\n currentConversationIdState,\n setCurrentConversationId,\n draftMessage,\n setDraftMessage,\n draftFileContents,\n setDraftFileContents,\n ],\n );\n\n return (\n <LightspeedDrawerContext.Provider value={contextValue}>\n {children}\n {shouldRenderOverlayModal && (\n <ChatbotModal\n isOpen\n displayMode={displayModeState}\n onClose={closeChatbot}\n ouiaId=\"LightspeedChatbotModal\"\n aria-labelledby=\"lightspeed-chatpopup-modal\"\n className={classes.chatbotModal}\n >\n <LightspeedChatContainer />\n </ChatbotModal>\n )}\n </LightspeedDrawerContext.Provider>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -5,8 +5,14 @@ import { useLightspeedDrawerContext } from '../hooks/useLightspeedDrawerContext.
5
5
  const LightspeedDrawerStateExposer = ({
6
6
  onStateChange
7
7
  }) => {
8
- const { displayMode, drawerWidth, setDrawerWidth, toggleChatbot } = useLightspeedDrawerContext();
9
- const isDrawerOpen = displayMode === ChatbotDisplayMode.docked;
8
+ const {
9
+ displayMode,
10
+ drawerWidth,
11
+ setDrawerWidth,
12
+ toggleChatbot,
13
+ isChatbotActive
14
+ } = useLightspeedDrawerContext();
15
+ const isDrawerOpen = displayMode === ChatbotDisplayMode.docked && isChatbotActive;
10
16
  const toggleChatbotRef = useRef(toggleChatbot);
11
17
  toggleChatbotRef.current = toggleChatbot;
12
18
  const closeDrawer = useCallback(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedDrawerStateExposer.esm.js","sources":["../../src/components/LightspeedDrawerStateExposer.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport { ChatbotDisplayMode } from '@patternfly/chatbot';\n\nimport { useLightspeedDrawerContext } from '../hooks/useLightspeedDrawerContext';\n\n/**\n * @public\n * Partial Lightspeed drawer state exposed to the ApplicationDrawer\n */\nexport type DrawerState = {\n id: string;\n isDrawerOpen: boolean;\n drawerWidth: number;\n setDrawerWidth: (width: number) => void;\n closeDrawer: () => void;\n};\n\n/**\n * @public\n * Props for drawer state exposer components\n */\nexport type DrawerStateExposerProps = {\n /**\n * Callback called whenever the drawer state changes\n */\n onStateChange: (state: DrawerState) => void;\n};\n\n/**\n * @public\n * This exposes LightspeedDrawer's partial context to the ApplicationDrawer\n *\n * It reads the LightspeedDrawerContext and calls the onStateChange callback with the\n * partial state (id, isDrawerOpen, drawerWidth, setDrawerWidth).\n \n */\nexport const LightspeedDrawerStateExposer = ({\n onStateChange,\n}: DrawerStateExposerProps) => {\n const { displayMode, drawerWidth, setDrawerWidth, toggleChatbot } =\n useLightspeedDrawerContext();\n\n const isDrawerOpen = displayMode === ChatbotDisplayMode.docked;\n\n const toggleChatbotRef = useRef(toggleChatbot);\n toggleChatbotRef.current = toggleChatbot;\n\n const closeDrawer = useCallback(() => {\n toggleChatbotRef.current();\n }, []);\n\n useEffect(() => {\n onStateChange({\n id: 'lightspeed',\n isDrawerOpen,\n drawerWidth,\n setDrawerWidth,\n closeDrawer,\n });\n }, [isDrawerOpen, drawerWidth, setDrawerWidth, closeDrawer, onStateChange]);\n\n return null;\n};\n"],"names":[],"mappings":";;;;AAqDO,MAAM,+BAA+B,CAAC;AAAA,EAC3C;AACF,CAA+B,KAAA;AAC7B,EAAA,MAAM,EAAE,WAAa,EAAA,WAAA,EAAa,cAAgB,EAAA,aAAA,KAChD,0BAA2B,EAAA;AAE7B,EAAM,MAAA,YAAA,GAAe,gBAAgB,kBAAmB,CAAA,MAAA;AAExD,EAAM,MAAA,gBAAA,GAAmB,OAAO,aAAa,CAAA;AAC7C,EAAA,gBAAA,CAAiB,OAAU,GAAA,aAAA;AAE3B,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,OAAQ,EAAA;AAAA,GAC3B,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAc,aAAA,CAAA;AAAA,MACZ,EAAI,EAAA,YAAA;AAAA,MACJ,YAAA;AAAA,MACA,WAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,KACA,CAAC,YAAA,EAAc,aAAa,cAAgB,EAAA,WAAA,EAAa,aAAa,CAAC,CAAA;AAE1E,EAAO,OAAA,IAAA;AACT;;;;"}
1
+ {"version":3,"file":"LightspeedDrawerStateExposer.esm.js","sources":["../../src/components/LightspeedDrawerStateExposer.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport { ChatbotDisplayMode } from '@patternfly/chatbot';\n\nimport { useLightspeedDrawerContext } from '../hooks/useLightspeedDrawerContext';\n\n/**\n * @public\n * Partial Lightspeed drawer state exposed to the ApplicationDrawer\n */\nexport type DrawerState = {\n id: string;\n isDrawerOpen: boolean;\n drawerWidth: number;\n setDrawerWidth: (width: number) => void;\n closeDrawer: () => void;\n};\n\n/**\n * @public\n * Props for drawer state exposer components\n */\nexport type DrawerStateExposerProps = {\n /**\n * Callback called whenever the drawer state changes\n */\n onStateChange: (state: DrawerState) => void;\n};\n\n/**\n * @public\n * This exposes LightspeedDrawer's partial context to the ApplicationDrawer\n *\n * It reads the LightspeedDrawerContext and calls the onStateChange callback with the\n * partial state (id, isDrawerOpen, drawerWidth, setDrawerWidth).\n \n */\nexport const LightspeedDrawerStateExposer = ({\n onStateChange,\n}: DrawerStateExposerProps) => {\n const {\n displayMode,\n drawerWidth,\n setDrawerWidth,\n toggleChatbot,\n isChatbotActive,\n } = useLightspeedDrawerContext();\n\n const isDrawerOpen =\n displayMode === ChatbotDisplayMode.docked && isChatbotActive;\n\n const toggleChatbotRef = useRef(toggleChatbot);\n toggleChatbotRef.current = toggleChatbot;\n\n const closeDrawer = useCallback(() => {\n toggleChatbotRef.current();\n }, []);\n\n useEffect(() => {\n onStateChange({\n id: 'lightspeed',\n isDrawerOpen,\n drawerWidth,\n setDrawerWidth,\n closeDrawer,\n });\n }, [isDrawerOpen, drawerWidth, setDrawerWidth, closeDrawer, onStateChange]);\n\n return null;\n};\n"],"names":[],"mappings":";;;;AAqDO,MAAM,+BAA+B,CAAC;AAAA,EAC3C;AACF,CAA+B,KAAA;AAC7B,EAAM,MAAA;AAAA,IACJ,WAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,MACE,0BAA2B,EAAA;AAE/B,EAAM,MAAA,YAAA,GACJ,WAAgB,KAAA,kBAAA,CAAmB,MAAU,IAAA,eAAA;AAE/C,EAAM,MAAA,gBAAA,GAAmB,OAAO,aAAa,CAAA;AAC7C,EAAA,gBAAA,CAAiB,OAAU,GAAA,aAAA;AAE3B,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,gBAAA,CAAiB,OAAQ,EAAA;AAAA,GAC3B,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAc,aAAA,CAAA;AAAA,MACZ,EAAI,EAAA,YAAA;AAAA,MACJ,YAAA;AAAA,MACA,WAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,KACA,CAAC,YAAA,EAAc,aAAa,cAAgB,EAAA,WAAA,EAAa,aAAa,CAAC,CAAA;AAE1E,EAAO,OAAA,IAAA;AACT;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useState } from 'react';
2
+ import { useState, useEffect } from 'react';
3
3
  import { TextField } from '@material-ui/core';
4
4
  import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';
5
5
  import CloseIcon from '@mui/icons-material/Close';
@@ -12,6 +12,7 @@ import DialogContent from '@mui/material/DialogContent';
12
12
  import DialogTitle from '@mui/material/DialogTitle';
13
13
  import IconButton from '@mui/material/IconButton';
14
14
  import Typography from '@mui/material/Typography';
15
+ import { useConversations } from '../hooks/useConversations.esm.js';
15
16
  import { useRenameConversation } from '../hooks/useRenameConversation.esm.js';
16
17
  import { useTranslation } from '../hooks/useTranslation.esm.js';
17
18
 
@@ -26,19 +27,37 @@ const RenameConversationModal = ({
26
27
  isError,
27
28
  error
28
29
  } = useRenameConversation();
30
+ const { data: conversations } = useConversations();
29
31
  const [chatName, setChatName] = useState("");
32
+ const [originalChatName, setOriginalChatName] = useState("");
33
+ useEffect(() => {
34
+ if (isOpen && conversations) {
35
+ const conversation = conversations.find(
36
+ (c) => c.conversation_id === conversationId
37
+ );
38
+ if (conversation) {
39
+ setChatName(conversation.topic_summary);
40
+ setOriginalChatName(conversation.topic_summary);
41
+ } else {
42
+ setChatName("");
43
+ setOriginalChatName("");
44
+ }
45
+ }
46
+ }, [isOpen, conversationId, conversations]);
30
47
  const handleChatNameChange = (event) => {
31
48
  setChatName(event.target.value);
32
49
  };
33
- const handleRename = () => {
34
- (async () => {
50
+ const handleRename = async () => {
51
+ try {
35
52
  await renameConversation({
36
53
  conversation_id: conversationId,
37
54
  newName: chatName,
38
55
  invalidateCache: false
39
56
  });
40
57
  onClose();
41
- })();
58
+ } catch (e) {
59
+ console.warn(e);
60
+ }
42
61
  };
43
62
  return /* @__PURE__ */ jsxs(
44
63
  Dialog,
@@ -89,6 +108,7 @@ const RenameConversationModal = ({
89
108
  style: { marginTop: "10px" },
90
109
  variant: "outlined",
91
110
  InputProps: {
111
+ autoFocus: true,
92
112
  endAdornment: /* @__PURE__ */ jsx(
93
113
  IconButton,
94
114
  {
@@ -101,9 +121,7 @@ const RenameConversationModal = ({
101
121
  }
102
122
  }
103
123
  ) }),
104
- isError && /* @__PURE__ */ jsx(Box, { maxWidth: "650px", marginLeft: "20px", children: /* @__PURE__ */ jsx(Alert, { severity: "error", children: t("conversation.action.error", {
105
- error: String(error)
106
- }) }) }),
124
+ isError && /* @__PURE__ */ jsx(Box, { maxWidth: "650px", marginLeft: "20px", marginRight: "20px", children: /* @__PURE__ */ jsx(Alert, { severity: "error", children: String(error) }) }),
107
125
  /* @__PURE__ */ jsxs(DialogActions, { style: { justifyContent: "left", padding: "20px" }, children: [
108
126
  /* @__PURE__ */ jsx(
109
127
  Button,
@@ -112,7 +130,7 @@ const RenameConversationModal = ({
112
130
  sx: {
113
131
  textTransform: "none"
114
132
  },
115
- disabled: chatName.trim() === "",
133
+ disabled: chatName.trim() === "" || chatName.trim() === originalChatName.trim(),
116
134
  onClick: handleRename,
117
135
  children: t("conversation.rename.confirm.action")
118
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RenameConversationModal.esm.js","sources":["../../src/components/RenameConversationModal.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState } from 'react';\n\nimport { TextField } from '@material-ui/core';\nimport CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\n\nimport { useRenameConversation } from '../hooks/useRenameConversation';\nimport { useTranslation } from '../hooks/useTranslation';\n\nexport const RenameConversationModal = ({\n isOpen,\n onClose,\n conversationId,\n}: {\n isOpen: boolean;\n onClose: () => void;\n conversationId: string;\n}) => {\n const { t } = useTranslation();\n const {\n mutateAsync: renameConversation,\n isError,\n error,\n } = useRenameConversation();\n const [chatName, setChatName] = useState<string>('');\n\n const handleChatNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setChatName(event.target.value);\n };\n\n const handleRename = () => {\n (async () => {\n await renameConversation({\n conversation_id: conversationId,\n newName: chatName,\n invalidateCache: false,\n });\n onClose();\n })();\n };\n\n return (\n <Dialog\n open={isOpen}\n onClose={onClose}\n aria-labelledby=\"rename-modal\"\n aria-describedby=\"rename-modal-confirmation\"\n fullWidth\n >\n <DialogTitle sx={{ p: '16px 20px', fontStyle: 'inherit' }}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n }}\n >\n <Typography component=\"span\" sx={{ fontWeight: 'bold' }}>\n {t('conversation.rename.confirm.title')}\n </Typography>\n\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n title={t('common.close')}\n size=\"large\"\n sx={{\n position: 'absolute',\n right: 1,\n top: 1,\n color: 'grey.700',\n }}\n >\n <CloseIcon />\n </IconButton>\n </Box>\n </DialogTitle>\n <DialogContent id=\"rename-modal-body-input\">\n <TextField\n id=\"outlined-chat-name-input\"\n label={t('conversation.rename.placeholder')}\n onChange={handleChatNameChange}\n fullWidth\n value={chatName}\n style={{ marginTop: '10px' }}\n variant=\"outlined\"\n InputProps={{\n endAdornment: (\n <IconButton\n aria-label=\"clear-input\"\n onClick={() => setChatName('')}\n edge=\"end\"\n >\n <CancelOutlinedIcon />\n </IconButton>\n ),\n }}\n />\n </DialogContent>\n {isError && (\n <Box maxWidth=\"650px\" marginLeft=\"20px\">\n <Alert severity=\"error\">\n {t('conversation.action.error' as any, {\n error: String(error),\n })}\n </Alert>\n </Box>\n )}\n <DialogActions style={{ justifyContent: 'left', padding: '20px' }}>\n <Button\n variant=\"contained\"\n sx={{\n textTransform: 'none',\n }}\n disabled={chatName.trim() === ''}\n onClick={handleRename}\n >\n {t('conversation.rename.confirm.action')}\n </Button>\n <Button\n key=\"cancel\"\n variant=\"outlined\"\n sx={{\n textTransform: 'none',\n }}\n onClick={onClose}\n >\n {t('common.cancel')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RenameConversationModal.esm.js","sources":["../../src/components/RenameConversationModal.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useState } from 'react';\n\nimport { TextField } from '@material-ui/core';\nimport CancelOutlinedIcon from '@mui/icons-material/CancelOutlined';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Alert from '@mui/material/Alert';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Dialog from '@mui/material/Dialog';\nimport DialogActions from '@mui/material/DialogActions';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport IconButton from '@mui/material/IconButton';\nimport Typography from '@mui/material/Typography';\n\nimport { useConversations } from '../hooks/useConversations';\nimport { useRenameConversation } from '../hooks/useRenameConversation';\nimport { useTranslation } from '../hooks/useTranslation';\n\nexport const RenameConversationModal = ({\n isOpen,\n onClose,\n conversationId,\n}: {\n isOpen: boolean;\n onClose: () => void;\n conversationId: string;\n}) => {\n const { t } = useTranslation();\n const {\n mutateAsync: renameConversation,\n isError,\n error,\n } = useRenameConversation();\n const { data: conversations } = useConversations();\n const [chatName, setChatName] = useState<string>('');\n const [originalChatName, setOriginalChatName] = useState<string>('');\n\n useEffect(() => {\n if (isOpen && conversations) {\n const conversation = conversations.find(\n c => c.conversation_id === conversationId,\n );\n if (conversation) {\n setChatName(conversation.topic_summary);\n setOriginalChatName(conversation.topic_summary);\n } else {\n setChatName('');\n setOriginalChatName('');\n }\n }\n }, [isOpen, conversationId, conversations]);\n\n const handleChatNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setChatName(event.target.value);\n };\n\n const handleRename = async () => {\n try {\n await renameConversation({\n conversation_id: conversationId,\n newName: chatName,\n invalidateCache: false,\n });\n onClose();\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(e);\n }\n };\n\n return (\n <Dialog\n open={isOpen}\n onClose={onClose}\n aria-labelledby=\"rename-modal\"\n aria-describedby=\"rename-modal-confirmation\"\n fullWidth\n >\n <DialogTitle sx={{ p: '16px 20px', fontStyle: 'inherit' }}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n }}\n >\n <Typography component=\"span\" sx={{ fontWeight: 'bold' }}>\n {t('conversation.rename.confirm.title')}\n </Typography>\n\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n title={t('common.close')}\n size=\"large\"\n sx={{\n position: 'absolute',\n right: 1,\n top: 1,\n color: 'grey.700',\n }}\n >\n <CloseIcon />\n </IconButton>\n </Box>\n </DialogTitle>\n <DialogContent id=\"rename-modal-body-input\">\n <TextField\n id=\"outlined-chat-name-input\"\n label={t('conversation.rename.placeholder')}\n onChange={handleChatNameChange}\n fullWidth\n value={chatName}\n style={{ marginTop: '10px' }}\n variant=\"outlined\"\n InputProps={{\n autoFocus: true,\n endAdornment: (\n <IconButton\n aria-label=\"clear-input\"\n onClick={() => setChatName('')}\n edge=\"end\"\n >\n <CancelOutlinedIcon />\n </IconButton>\n ),\n }}\n />\n </DialogContent>\n {isError && (\n <Box maxWidth=\"650px\" marginLeft=\"20px\" marginRight=\"20px\">\n <Alert severity=\"error\">{String(error)}</Alert>\n </Box>\n )}\n <DialogActions style={{ justifyContent: 'left', padding: '20px' }}>\n <Button\n variant=\"contained\"\n sx={{\n textTransform: 'none',\n }}\n disabled={\n chatName.trim() === '' ||\n chatName.trim() === originalChatName.trim()\n }\n onClick={handleRename}\n >\n {t('conversation.rename.confirm.action')}\n </Button>\n <Button\n key=\"cancel\"\n variant=\"outlined\"\n sx={{\n textTransform: 'none',\n }}\n onClick={onClose}\n >\n {t('common.cancel')}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAmCO,MAAM,0BAA0B,CAAC;AAAA,EACtC,MAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAIM,KAAA;AACJ,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAC7B,EAAM,MAAA;AAAA,IACJ,WAAa,EAAA,kBAAA;AAAA,IACb,OAAA;AAAA,IACA;AAAA,MACE,qBAAsB,EAAA;AAC1B,EAAA,MAAM,EAAE,IAAA,EAAM,aAAc,EAAA,GAAI,gBAAiB,EAAA;AACjD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAiB,EAAE,CAAA;AACnD,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAI,SAAiB,EAAE,CAAA;AAEnE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,UAAU,aAAe,EAAA;AAC3B,MAAA,MAAM,eAAe,aAAc,CAAA,IAAA;AAAA,QACjC,CAAA,CAAA,KAAK,EAAE,eAAoB,KAAA;AAAA,OAC7B;AACA,MAAA,IAAI,YAAc,EAAA;AAChB,QAAA,WAAA,CAAY,aAAa,aAAa,CAAA;AACtC,QAAA,mBAAA,CAAoB,aAAa,aAAa,CAAA;AAAA,OACzC,MAAA;AACL,QAAA,WAAA,CAAY,EAAE,CAAA;AACd,QAAA,mBAAA,CAAoB,EAAE,CAAA;AAAA;AACxB;AACF,GACC,EAAA,CAAC,MAAQ,EAAA,cAAA,EAAgB,aAAa,CAAC,CAAA;AAE1C,EAAM,MAAA,oBAAA,GAAuB,CAAC,KAA+C,KAAA;AAC3E,IAAY,WAAA,CAAA,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,GAChC;AAEA,EAAA,MAAM,eAAe,YAAY;AAC/B,IAAI,IAAA;AACF,MAAA,MAAM,kBAAmB,CAAA;AAAA,QACvB,eAAiB,EAAA,cAAA;AAAA,QACjB,OAAS,EAAA,QAAA;AAAA,QACT,eAAiB,EAAA;AAAA,OAClB,CAAA;AACD,MAAQ,OAAA,EAAA;AAAA,aACD,CAAG,EAAA;AAEV,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA;AAChB,GACF;AAEA,EACE,uBAAA,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAM,EAAA,MAAA;AAAA,MACN,OAAA;AAAA,MACA,iBAAgB,EAAA,cAAA;AAAA,MAChB,kBAAiB,EAAA,2BAAA;AAAA,MACjB,SAAS,EAAA,IAAA;AAAA,MAET,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,eAAY,EAAI,EAAA,EAAE,GAAG,WAAa,EAAA,SAAA,EAAW,WAC5C,EAAA,QAAA,kBAAA,IAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,EAAI,EAAA;AAAA,cACF,OAAS,EAAA,MAAA;AAAA,cACT,UAAY,EAAA,QAAA;AAAA,cACZ,GAAK,EAAA;AAAA,aACP;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAC,GAAA,CAAA,UAAA,EAAA,EAAW,SAAU,EAAA,MAAA,EAAO,EAAI,EAAA,EAAE,YAAY,MAAO,EAAA,EACnD,QAAE,EAAA,CAAA,CAAA,mCAAmC,CACxC,EAAA,CAAA;AAAA,8BAEA,GAAA;AAAA,gBAAC,UAAA;AAAA,gBAAA;AAAA,kBACC,YAAW,EAAA,OAAA;AAAA,kBACX,OAAS,EAAA,OAAA;AAAA,kBACT,KAAA,EAAO,EAAE,cAAc,CAAA;AAAA,kBACvB,IAAK,EAAA,OAAA;AAAA,kBACL,EAAI,EAAA;AAAA,oBACF,QAAU,EAAA,UAAA;AAAA,oBACV,KAAO,EAAA,CAAA;AAAA,oBACP,GAAK,EAAA,CAAA;AAAA,oBACL,KAAO,EAAA;AAAA,mBACT;AAAA,kBAEA,8BAAC,SAAU,EAAA,EAAA;AAAA;AAAA;AACb;AAAA;AAAA,SAEJ,EAAA,CAAA;AAAA,wBACA,GAAA,CAAC,aAAc,EAAA,EAAA,EAAA,EAAG,yBAChB,EAAA,QAAA,kBAAA,GAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YACC,EAAG,EAAA,0BAAA;AAAA,YACH,KAAA,EAAO,EAAE,iCAAiC,CAAA;AAAA,YAC1C,QAAU,EAAA,oBAAA;AAAA,YACV,SAAS,EAAA,IAAA;AAAA,YACT,KAAO,EAAA,QAAA;AAAA,YACP,KAAA,EAAO,EAAE,SAAA,EAAW,MAAO,EAAA;AAAA,YAC3B,OAAQ,EAAA,UAAA;AAAA,YACR,UAAY,EAAA;AAAA,cACV,SAAW,EAAA,IAAA;AAAA,cACX,YACE,kBAAA,GAAA;AAAA,gBAAC,UAAA;AAAA,gBAAA;AAAA,kBACC,YAAW,EAAA,aAAA;AAAA,kBACX,OAAA,EAAS,MAAM,WAAA,CAAY,EAAE,CAAA;AAAA,kBAC7B,IAAK,EAAA,KAAA;AAAA,kBAEL,8BAAC,kBAAmB,EAAA,EAAA;AAAA;AAAA;AACtB;AAEJ;AAAA,SAEJ,EAAA,CAAA;AAAA,QACC,2BACE,GAAA,CAAA,GAAA,EAAA,EAAI,QAAS,EAAA,OAAA,EAAQ,YAAW,MAAO,EAAA,WAAA,EAAY,MAClD,EAAA,QAAA,kBAAA,GAAA,CAAC,SAAM,QAAS,EAAA,OAAA,EAAS,QAAO,EAAA,MAAA,CAAA,KAAK,GAAE,CACzC,EAAA,CAAA;AAAA,wBAEF,IAAA,CAAC,iBAAc,KAAO,EAAA,EAAE,gBAAgB,MAAQ,EAAA,OAAA,EAAS,QACvD,EAAA,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,OAAQ,EAAA,WAAA;AAAA,cACR,EAAI,EAAA;AAAA,gBACF,aAAe,EAAA;AAAA,eACjB;AAAA,cACA,QAAA,EACE,SAAS,IAAK,EAAA,KAAM,MACpB,QAAS,CAAA,IAAA,EAAW,KAAA,gBAAA,CAAiB,IAAK,EAAA;AAAA,cAE5C,OAAS,EAAA,YAAA;AAAA,cAER,YAAE,oCAAoC;AAAA;AAAA,WACzC;AAAA,0BACA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cAEC,OAAQ,EAAA,UAAA;AAAA,cACR,EAAI,EAAA;AAAA,gBACF,aAAe,EAAA;AAAA,eACjB;AAAA,cACA,OAAS,EAAA,OAAA;AAAA,cAER,YAAE,eAAe;AAAA,aAAA;AAAA,YAPd;AAAA;AAQN,SACF,EAAA;AAAA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -1,17 +1,14 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useState } from 'react';
3
- import { Flex, FlexItem, Content, ContentVariants, DescriptionList, DescriptionListGroup, DescriptionListTerm, DescriptionListDescription, Label, Tooltip, Button } from '@patternfly/react-core';
4
- import { WrenchIcon, CopyIcon } from '@patternfly/react-icons';
2
+ import { Message } from '@patternfly/chatbot';
3
+ import { Flex, FlexItem, Content, ContentVariants, DescriptionList, DescriptionListGroup, DescriptionListTerm, DescriptionListDescription, Label } from '@patternfly/react-core';
4
+ import { WrenchIcon } from '@patternfly/react-icons';
5
5
  import { useTranslation } from '../hooks/useTranslation.esm.js';
6
6
 
7
- const ToolCallContent = ({ toolCall }) => {
7
+ const ToolCallContent = ({
8
+ toolCall,
9
+ role = "bot"
10
+ }) => {
8
11
  const { t } = useTranslation();
9
- const [isExpanded, setIsExpanded] = useState(false);
10
- const handleCopy = async () => {
11
- if (toolCall.response) {
12
- await globalThis.navigator.clipboard.writeText(toolCall.response);
13
- }
14
- };
15
12
  const formatExecutionTime = (seconds) => {
16
13
  if (seconds === undefined) return "";
17
14
  if (seconds < 1) return `${Math.round(seconds * 1e3)}ms`;
@@ -134,65 +131,39 @@ const ToolCallContent = ({ toolCall }) => {
134
131
  "--pf-v6-c-description-list__group--RowGap": "var(--pf-t--global--spacer--xs)"
135
132
  },
136
133
  children: [
137
- /* @__PURE__ */ jsxs(
134
+ /* @__PURE__ */ jsx(
138
135
  Flex,
139
136
  {
140
137
  alignItems: { default: "alignItemsCenter" },
141
138
  justifyContent: { default: "justifyContentSpaceBetween" },
142
- children: [
143
- /* @__PURE__ */ jsx(FlexItem, { flex: { default: "flex_1" }, children: /* @__PURE__ */ jsxs("strong", { children: [
144
- " ",
145
- t("toolCall.response")
146
- ] }) }),
147
- /* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(Tooltip, { content: t("toolCall.copyResponse"), children: /* @__PURE__ */ jsx(
148
- Button,
149
- {
150
- variant: "plain",
151
- "aria-label": t("toolCall.copyResponse"),
152
- onClick: handleCopy,
153
- icon: /* @__PURE__ */ jsx(CopyIcon, {})
154
- }
155
- ) }) })
156
- ]
139
+ children: /* @__PURE__ */ jsx(FlexItem, { flex: { default: "flex_1" }, children: /* @__PURE__ */ jsxs("strong", { children: [
140
+ " ",
141
+ t("toolCall.response")
142
+ ] }) })
157
143
  }
158
144
  ),
159
145
  /* @__PURE__ */ jsx(
160
146
  DescriptionListDescription,
161
147
  {
162
148
  style: { marginInlineStart: 0 },
163
- children: /* @__PURE__ */ jsxs(
149
+ children: /* @__PURE__ */ jsx(
164
150
  Flex,
165
151
  {
166
152
  direction: { default: "column" },
167
153
  spaceItems: { default: "spaceItemsXs" },
168
- children: [
169
- /* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(
170
- "div",
171
- {
172
- style: {
173
- fontFamily: "Red Hat Mono, Monaco, Consolas, monospace",
174
- fontSize: "0.875rem",
175
- whiteSpace: "pre-wrap",
176
- wordBreak: "break-word",
177
- padding: "var(--pf-t--global--spacer--sm)",
178
- borderRadius: "var(--pf-t--global--border--radius--small)",
179
- maxHeight: isExpanded ? "300px" : "105px",
180
- overflowY: "auto",
181
- transition: "max-height 0.3s ease"
182
- },
183
- children: toolCall.response
184
- }
185
- ) }),
186
- toolCall.response.length > 300 && /* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(
187
- Button,
188
- {
189
- variant: "link",
190
- isInline: true,
191
- onClick: () => setIsExpanded(!isExpanded),
192
- children: isExpanded ? t("toolCall.showLess") : t("toolCall.showMore")
154
+ children: /* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(
155
+ Message,
156
+ {
157
+ content: toolCall.response,
158
+ role,
159
+ codeBlockProps: {
160
+ isExpandable: true,
161
+ expandableSectionProps: {
162
+ truncateMaxLines: 1
163
+ }
193
164
  }
194
- ) })
195
- ]
165
+ }
166
+ ) })
196
167
  }
197
168
  )
198
169
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCallContent.esm.js","sources":["../../src/components/ToolCallContent.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useState } from 'react';\n\nimport {\n Button,\n Content,\n ContentVariants,\n DescriptionList,\n DescriptionListDescription,\n DescriptionListGroup,\n DescriptionListTerm,\n Flex,\n FlexItem,\n Label,\n Tooltip,\n} from '@patternfly/react-core';\nimport { CopyIcon, WrenchIcon } from '@patternfly/react-icons';\n\nimport { useTranslation } from '../hooks/useTranslation';\nimport { ToolCall } from '../types';\n\ninterface ToolCallContentProps {\n toolCall: ToolCall;\n}\n\n/**\n * Lightweight component for rendering tool call expandable content.\n * Used inside PatternFly's ToolCall component's expandableContent prop.\n */\nexport const ToolCallContent = ({ toolCall }: ToolCallContentProps) => {\n const { t } = useTranslation();\n const [isExpanded, setIsExpanded] = useState(false);\n\n const handleCopy = async () => {\n if (toolCall.response) {\n await globalThis.navigator.clipboard.writeText(toolCall.response);\n }\n };\n\n const formatExecutionTime = (seconds?: number): string => {\n if (seconds === undefined) return '';\n if (seconds < 1) return `${Math.round(seconds * 1000)}ms`;\n return `${seconds.toFixed(2)}s`;\n };\n\n const getParameterKeys = (): string[] => {\n if (!toolCall.arguments) return [];\n return Object.keys(toolCall.arguments).filter(\n key => toolCall.arguments[key] !== '' && toolCall.arguments[key] !== null,\n );\n };\n\n const getThinkingTime = (): number => {\n if (toolCall.startTime && toolCall.endTime) {\n return Math.round((toolCall.endTime - toolCall.startTime) / 1000);\n }\n return 0;\n };\n\n const thinkingTime = getThinkingTime();\n const parameterKeys = getParameterKeys();\n\n return (\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsSm' }}\n >\n {/* Thinking Time */}\n {thinkingTime > 0 && (\n <FlexItem>\n <Content component={ContentVariants.small}>\n {t('toolCall.thinking' as any, {\n seconds: String(thinkingTime),\n })}\n </Content>\n </FlexItem>\n )}\n\n {/* Summary */}\n <FlexItem>\n <Content component={ContentVariants.p}>{t('toolCall.summary')}</Content>\n </FlexItem>\n\n {/* Tool Header with MCP Server */}\n <FlexItem>\n <div\n style={{\n border: '1px solid var(--pf-t--global--border--color--default)',\n borderRadius: 'var(--pf-t--global--border--radius--small)',\n padding: 'var(--pf-t--global--spacer--md)',\n }}\n >\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsSm' }}\n >\n <FlexItem\n style={{\n borderBottom:\n '1px solid var(--pf-t--global--border--color--default)',\n paddingBottom: 'var(--pf-t--global--spacer--sm)',\n }}\n >\n <Content\n component={ContentVariants.p}\n style={{ marginBlockEnd: 0 }}\n >\n <WrenchIcon\n style={{\n color: 'var(--pf-t--global--icon--color--brand--default)',\n marginRight: '0.5em',\n }}\n />\n <strong>{t('toolCall.mcpServer')}</strong>\n </Content>\n {toolCall.executionTime !== undefined && (\n <Content component={ContentVariants.small}>\n {t('toolCall.executionTime')}\n {formatExecutionTime(toolCall.executionTime)}\n </Content>\n )}\n </FlexItem>\n\n {/* Description List for Parameters and Response */}\n <FlexItem>\n <DescriptionList\n style={\n {\n '--pf-v6-c-description-list--RowGap':\n 'var(--pf-t--global--spacer--md)',\n } as any\n }\n aria-label=\"Tool response\"\n >\n {/* Parameters Section */}\n {parameterKeys.length > 0 && (\n <DescriptionListGroup\n style={\n {\n '--pf-v6-c-description-list__group--RowGap':\n 'var(--pf-t--global--spacer--xs)',\n } as any\n }\n >\n <DescriptionListTerm>\n {t('toolCall.parameters' as any, {\n defaultValue: 'Parameters',\n }) || 'Parameters'}\n </DescriptionListTerm>\n <DescriptionListDescription\n style={{ marginInlineStart: 0 }}\n >\n <Flex direction={{ default: 'column' }}>\n {toolCall.description && (\n <FlexItem>\n <Content component={ContentVariants.small}>\n {toolCall.description}\n </Content>\n </FlexItem>\n )}\n <FlexItem>\n <Flex\n gap={{ default: 'gapSm' }}\n flexWrap={{ default: 'wrap' }}\n >\n {parameterKeys.map(key => (\n <FlexItem key={key}>\n <Label variant=\"outline\" color=\"blue\">\n {key}\n </Label>\n </FlexItem>\n ))}\n </Flex>\n </FlexItem>\n </Flex>\n </DescriptionListDescription>\n </DescriptionListGroup>\n )}\n\n {/* Response Section */}\n {toolCall.response && (\n <DescriptionListGroup\n style={\n {\n '--pf-v6-c-description-list__group--RowGap':\n 'var(--pf-t--global--spacer--xs)',\n } as any\n }\n >\n {/* <DescriptionListTerm> */}\n <Flex\n alignItems={{ default: 'alignItemsCenter' }}\n justifyContent={{ default: 'justifyContentSpaceBetween' }}\n >\n <FlexItem flex={{ default: 'flex_1' }}>\n <strong> {t('toolCall.response')}</strong>\n </FlexItem>\n <FlexItem>\n <Tooltip content={t('toolCall.copyResponse')}>\n <Button\n variant=\"plain\"\n aria-label={t('toolCall.copyResponse')}\n onClick={handleCopy}\n icon={<CopyIcon />}\n />\n </Tooltip>\n </FlexItem>\n </Flex>\n {/* </DescriptionListTerm> */}\n <DescriptionListDescription\n style={{ marginInlineStart: 0 }}\n >\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsXs' }}\n >\n <FlexItem>\n <div\n style={{\n fontFamily:\n 'Red Hat Mono, Monaco, Consolas, monospace',\n fontSize: '0.875rem',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n padding: 'var(--pf-t--global--spacer--sm)',\n borderRadius:\n 'var(--pf-t--global--border--radius--small)',\n maxHeight: isExpanded ? '300px' : '105px',\n overflowY: 'auto',\n transition: 'max-height 0.3s ease',\n }}\n >\n {toolCall.response}\n </div>\n </FlexItem>\n {toolCall.response.length > 300 && (\n <FlexItem>\n <Button\n variant=\"link\"\n isInline\n onClick={() => setIsExpanded(!isExpanded)}\n >\n {isExpanded\n ? t('toolCall.showLess')\n : t('toolCall.showMore')}\n </Button>\n </FlexItem>\n )}\n </Flex>\n </DescriptionListDescription>\n </DescriptionListGroup>\n )}\n </DescriptionList>\n </FlexItem>\n </Flex>\n </div>\n </FlexItem>\n </Flex>\n );\n};\n\nexport default ToolCallContent;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolCallContent.esm.js","sources":["../../src/components/ToolCallContent.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Message } from '@patternfly/chatbot';\nimport {\n Content,\n ContentVariants,\n DescriptionList,\n DescriptionListDescription,\n DescriptionListGroup,\n DescriptionListTerm,\n Flex,\n FlexItem,\n Label,\n} from '@patternfly/react-core';\nimport { WrenchIcon } from '@patternfly/react-icons';\n\nimport { useTranslation } from '../hooks/useTranslation';\nimport { ToolCall } from '../types';\n\ninterface ToolCallContentProps {\n toolCall: ToolCall;\n role?: 'user' | 'bot';\n}\n\n/**\n * Lightweight component for rendering tool call expandable content.\n * Used inside PatternFly's ToolCall component's expandableContent prop.\n */\nexport const ToolCallContent = ({\n toolCall,\n role = 'bot',\n}: ToolCallContentProps) => {\n const { t } = useTranslation();\n\n const formatExecutionTime = (seconds?: number): string => {\n if (seconds === undefined) return '';\n if (seconds < 1) return `${Math.round(seconds * 1000)}ms`;\n return `${seconds.toFixed(2)}s`;\n };\n\n const getParameterKeys = (): string[] => {\n if (!toolCall.arguments) return [];\n return Object.keys(toolCall.arguments).filter(\n key => toolCall.arguments[key] !== '' && toolCall.arguments[key] !== null,\n );\n };\n\n const getThinkingTime = (): number => {\n if (toolCall.startTime && toolCall.endTime) {\n return Math.round((toolCall.endTime - toolCall.startTime) / 1000);\n }\n return 0;\n };\n\n const thinkingTime = getThinkingTime();\n const parameterKeys = getParameterKeys();\n\n return (\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsSm' }}\n >\n {/* Thinking Time */}\n {thinkingTime > 0 && (\n <FlexItem>\n <Content component={ContentVariants.small}>\n {t('toolCall.thinking' as any, {\n seconds: String(thinkingTime),\n })}\n </Content>\n </FlexItem>\n )}\n\n {/* Summary */}\n <FlexItem>\n <Content component={ContentVariants.p}>{t('toolCall.summary')}</Content>\n </FlexItem>\n\n {/* Tool Header with MCP Server */}\n <FlexItem>\n <div\n style={{\n border: '1px solid var(--pf-t--global--border--color--default)',\n borderRadius: 'var(--pf-t--global--border--radius--small)',\n padding: 'var(--pf-t--global--spacer--md)',\n }}\n >\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsSm' }}\n >\n <FlexItem\n style={{\n borderBottom:\n '1px solid var(--pf-t--global--border--color--default)',\n paddingBottom: 'var(--pf-t--global--spacer--sm)',\n }}\n >\n <Content\n component={ContentVariants.p}\n style={{ marginBlockEnd: 0 }}\n >\n <WrenchIcon\n style={{\n color: 'var(--pf-t--global--icon--color--brand--default)',\n marginRight: '0.5em',\n }}\n />\n <strong>{t('toolCall.mcpServer')}</strong>\n </Content>\n {toolCall.executionTime !== undefined && (\n <Content component={ContentVariants.small}>\n {t('toolCall.executionTime')}\n {formatExecutionTime(toolCall.executionTime)}\n </Content>\n )}\n </FlexItem>\n\n {/* Description List for Parameters and Response */}\n <FlexItem>\n <DescriptionList\n style={\n {\n '--pf-v6-c-description-list--RowGap':\n 'var(--pf-t--global--spacer--md)',\n } as any\n }\n aria-label=\"Tool response\"\n >\n {/* Parameters Section */}\n {parameterKeys.length > 0 && (\n <DescriptionListGroup\n style={\n {\n '--pf-v6-c-description-list__group--RowGap':\n 'var(--pf-t--global--spacer--xs)',\n } as any\n }\n >\n <DescriptionListTerm>\n {t('toolCall.parameters' as any, {\n defaultValue: 'Parameters',\n }) || 'Parameters'}\n </DescriptionListTerm>\n <DescriptionListDescription\n style={{ marginInlineStart: 0 }}\n >\n <Flex direction={{ default: 'column' }}>\n {toolCall.description && (\n <FlexItem>\n <Content component={ContentVariants.small}>\n {toolCall.description}\n </Content>\n </FlexItem>\n )}\n <FlexItem>\n <Flex\n gap={{ default: 'gapSm' }}\n flexWrap={{ default: 'wrap' }}\n >\n {parameterKeys.map(key => (\n <FlexItem key={key}>\n <Label variant=\"outline\" color=\"blue\">\n {key}\n </Label>\n </FlexItem>\n ))}\n </Flex>\n </FlexItem>\n </Flex>\n </DescriptionListDescription>\n </DescriptionListGroup>\n )}\n\n {/* Response Section */}\n {toolCall.response && (\n <DescriptionListGroup\n style={\n {\n '--pf-v6-c-description-list__group--RowGap':\n 'var(--pf-t--global--spacer--xs)',\n } as any\n }\n >\n {/* <DescriptionListTerm> */}\n <Flex\n alignItems={{ default: 'alignItemsCenter' }}\n justifyContent={{ default: 'justifyContentSpaceBetween' }}\n >\n <FlexItem flex={{ default: 'flex_1' }}>\n <strong> {t('toolCall.response')}</strong>\n </FlexItem>\n </Flex>\n {/* </DescriptionListTerm> */}\n <DescriptionListDescription\n style={{ marginInlineStart: 0 }}\n >\n <Flex\n direction={{ default: 'column' }}\n spaceItems={{ default: 'spaceItemsXs' }}\n >\n <FlexItem>\n <Message\n content={toolCall.response}\n role={role}\n codeBlockProps={{\n isExpandable: true,\n expandableSectionProps: {\n truncateMaxLines: 1,\n },\n }}\n />\n </FlexItem>\n </Flex>\n </DescriptionListDescription>\n </DescriptionListGroup>\n )}\n </DescriptionList>\n </FlexItem>\n </Flex>\n </div>\n </FlexItem>\n </Flex>\n );\n};\n\nexport default ToolCallContent;\n"],"names":[],"mappings":"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"}