@red-hat-developer-hub/backstage-plugin-lightspeed 0.5.4 → 0.5.6

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 (36) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +3 -3
  3. package/dist/api/LightspeedApiClient.esm.js +34 -0
  4. package/dist/api/LightspeedApiClient.esm.js.map +1 -1
  5. package/dist/api/api.esm.js.map +1 -1
  6. package/dist/components/LightSpeedChat.esm.js +5 -2
  7. package/dist/components/LightSpeedChat.esm.js.map +1 -1
  8. package/dist/components/LightspeedChatBox.esm.js +10 -2
  9. package/dist/components/LightspeedChatBox.esm.js.map +1 -1
  10. package/dist/components/LightspeedPage.esm.js +9 -2
  11. package/dist/components/LightspeedPage.esm.js.map +1 -1
  12. package/dist/components/PermissionRequiredState.esm.js +1 -1
  13. package/dist/components/PermissionRequiredState.esm.js.map +1 -1
  14. package/dist/const.esm.js +4 -4
  15. package/dist/const.esm.js.map +1 -1
  16. package/dist/hooks/useCaptureFeedback.esm.js +21 -0
  17. package/dist/hooks/useCaptureFeedback.esm.js.map +1 -0
  18. package/dist/hooks/useConversationMessages.esm.js +10 -11
  19. package/dist/hooks/useConversationMessages.esm.js.map +1 -1
  20. package/dist/hooks/useFeedbackActions.esm.js +246 -0
  21. package/dist/hooks/useFeedbackActions.esm.js.map +1 -0
  22. package/dist/hooks/useFeedbackState.esm.js +93 -0
  23. package/dist/hooks/useFeedbackState.esm.js.map +1 -0
  24. package/dist/hooks/useFeedbackStatus.esm.js +14 -0
  25. package/dist/hooks/useFeedbackStatus.esm.js.map +1 -0
  26. package/dist/hooks/useLightspeedDeletePermission.esm.js +2 -2
  27. package/dist/hooks/useLightspeedDeletePermission.esm.js.map +1 -1
  28. package/dist/hooks/useLightspeedViewPermission.esm.js +7 -7
  29. package/dist/hooks/useLightspeedViewPermission.esm.js.map +1 -1
  30. package/dist/images/bot-avatar.svg +15 -0
  31. package/dist/images/user-avatar.svg +4 -0
  32. package/dist/types.esm.js.map +1 -1
  33. package/dist/utils/lightspeed-chatbox-utils.esm.js +7 -8
  34. package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
  35. package/package.json +4 -4
  36. package/dist/images/logo.svg +0 -1
@@ -3,7 +3,8 @@ import { useApi } from '@backstage/core-plugin-api';
3
3
  import { useQuery } from '@tanstack/react-query';
4
4
  import { lightspeedApiRef } from '../api/api.esm.js';
5
5
  import { TEMP_CONVERSATION_ID } from '../const.esm.js';
6
- import logo from '../images/logo.svg';
6
+ import botAvatar from '../images/bot-avatar.svg';
7
+ import userAvatar from '../images/user-avatar.svg';
7
8
  import { getMessageData, createUserMessage, createBotMessage, transformDocumentsToSources, getTimestamp } from '../utils/lightspeed-chatbox-utils.esm.js';
8
9
  import { useCreateConversationMessage } from './useCreateCoversationMessage.esm.js';
9
10
 
@@ -18,8 +19,7 @@ const useFetchConversationMessages = (currentConversation) => {
18
19
  retry: false
19
20
  });
20
21
  };
21
- const defaultAvatar = "https://img.freepik.com/premium-photo/graphic-designer-digital-avatar-generative-ai_934475-9292.jpg";
22
- const useConversationMessages = (conversationId, userName, selectedModel, avatar = defaultAvatar, onComplete, onStart) => {
22
+ const useConversationMessages = (conversationId, userName, selectedModel, avatar = userAvatar, onComplete, onStart) => {
23
23
  const { mutateAsync: createMessage } = useCreateConversationMessage();
24
24
  const scrollToBottomRef = React__default.useRef(null);
25
25
  const [currentConversation, setCurrentConversation] = React__default.useState(conversationId);
@@ -68,7 +68,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
68
68
  timestamp: userTimestamp
69
69
  }),
70
70
  createBotMessage({
71
- avatar: logo,
71
+ avatar: botAvatar,
72
72
  isLoading: false,
73
73
  name: model ?? selectedModel,
74
74
  content: botMessage,
@@ -104,7 +104,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
104
104
  timestamp: getTimestamp(Date.now()) ?? ""
105
105
  }),
106
106
  createBotMessage({
107
- avatar: logo,
107
+ avatar: botAvatar,
108
108
  isLoading: true,
109
109
  name: selectedModel,
110
110
  content: "",
@@ -196,12 +196,11 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
196
196
  }) : { ...conversation[lastMessageIndex] };
197
197
  if (documents.length) {
198
198
  lastMessage.sources = {
199
- sources: documents.map(
200
- (doc) => ({
201
- title: doc.doc_title,
202
- link: doc.doc_url
203
- })
204
- )
199
+ sources: documents.map((doc) => ({
200
+ title: doc.doc_title,
201
+ link: doc.doc_url,
202
+ body: doc.doc_description
203
+ }))
205
204
  };
206
205
  }
207
206
  const updatedConversation = [
@@ -1 +1 @@
1
- {"version":3,"file":"useConversationMessages.esm.js","sources":["../../src/hooks/useConversationMessages.ts"],"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 React from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\nimport { ScrollContainerHandle } from '../components/LightspeedChatBox';\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport logo from '../images/logo.svg';\nimport { Attachment } from '../types';\nimport {\n createBotMessage,\n createUserMessage,\n getMessageData,\n getTimestamp,\n transformDocumentsToSources,\n} from '../utils/lightspeed-chatbox-utils';\nimport { useCreateConversationMessage } from './useCreateCoversationMessage';\n\n// Fetch all conversation messages\nexport const useFetchConversationMessages = (currentConversation: string) => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['conversationMessages', currentConversation],\n queryFn: currentConversation\n ? async () => {\n const response =\n await lightspeedApi.getConversationMessages(currentConversation);\n\n return response;\n }\n : undefined,\n retry: false,\n });\n};\n\ntype Conversations = { [_key: string]: MessageProps[] };\n\nconst defaultAvatar =\n 'https://img.freepik.com/premium-photo/graphic-designer-digital-avatar-generative-ai_934475-9292.jpg';\n/**\n * Fetches all the messages for given conversation_id\n * @param conversationId\n * @param userName\n * @param selectedModel\n * @param avatar\n *\n */\nexport const useConversationMessages = (\n conversationId: string,\n userName: string | undefined,\n selectedModel: string,\n avatar: string = defaultAvatar,\n onComplete?: (message: string) => void,\n onStart?: (conversation_id: string) => void,\n) => {\n const { mutateAsync: createMessage } = useCreateConversationMessage();\n const scrollToBottomRef = React.useRef<ScrollContainerHandle>(null);\n\n const [currentConversation, setCurrentConversation] =\n React.useState(conversationId);\n const [conversations, setConversations] = React.useState<Conversations>({\n [currentConversation]: [],\n });\n const streamingConversations = React.useRef<Conversations>({\n [currentConversation]: [],\n });\n\n React.useEffect(() => {\n if (currentConversation !== conversationId) {\n setCurrentConversation(conversationId);\n setConversations(prev => {\n if (prev[conversationId]) return prev;\n\n return {\n ...prev,\n [conversationId]: [],\n };\n });\n }\n }, [currentConversation, conversationId]);\n\n const { data: conversationsData = [], ...queryProps } =\n useFetchConversationMessages(currentConversation);\n\n React.useEffect(() => {\n if (\n !Array.isArray(conversationsData) ||\n (conversationsData.length === 0 &&\n conversationId !== TEMP_CONVERSATION_ID)\n )\n return;\n\n const newConvoIndex: number[] = [];\n\n if (conversations) {\n const _conversations: { [key: string]: any[] } = {\n [currentConversation]: [],\n };\n\n let index = 0;\n for (let i = 0; i < conversationsData.length; i += 2) {\n const userMessage = conversationsData[i];\n const aiMessage = conversationsData[i + 1];\n\n const { content: humanMessage, timestamp: userTimestamp } =\n getMessageData(userMessage);\n const {\n model,\n content: botMessage,\n timestamp: botTimestamp,\n referencedDocuments,\n } = getMessageData(aiMessage);\n\n _conversations[currentConversation].push(\n ...[\n createUserMessage({\n avatar,\n name: userName,\n content: humanMessage,\n timestamp: userTimestamp,\n }),\n createBotMessage({\n avatar: logo,\n isLoading: false,\n name: model ?? selectedModel,\n content: botMessage,\n timestamp: botTimestamp,\n sources: transformDocumentsToSources(referencedDocuments),\n }),\n ],\n );\n\n newConvoIndex.push(index);\n index++;\n }\n\n if (streamingConversations.current[currentConversation]) {\n _conversations[currentConversation].push(\n ...streamingConversations.current[currentConversation],\n );\n }\n\n setConversations(_conversations);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n conversationsData,\n userName,\n avatar,\n currentConversation,\n selectedModel,\n streamingConversations,\n ]);\n\n const handleInputPrompt = React.useCallback(\n async (prompt: string, attachments: Attachment[] = []) => {\n let newConversationId = '';\n\n const conversationTuple = [\n createUserMessage({\n avatar,\n name: userName,\n content: prompt,\n timestamp: getTimestamp(Date.now()) ?? '',\n }),\n createBotMessage({\n avatar: logo,\n isLoading: true,\n name: selectedModel,\n content: '',\n timestamp: '',\n }),\n ];\n\n streamingConversations.current = {\n ...streamingConversations.current,\n [currentConversation]: conversationTuple,\n };\n\n setConversations((prevConv: Conversations) => {\n return {\n ...prevConv,\n [currentConversation]: [\n ...(prevConv?.[currentConversation] ?? []),\n ...conversationTuple,\n ],\n };\n });\n\n setTimeout(() => {\n scrollToBottomRef.current?.scrollToBottom();\n }, 0);\n const finalMessages: string[] = [];\n let buffer = '';\n\n try {\n const reader = await createMessage({\n prompt,\n selectedModel,\n currentConversation,\n attachments,\n });\n\n const decoder = new TextDecoder('utf-8');\n const keepGoing = true;\n\n while (keepGoing) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process all complete messages separated by double newlines\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const lines = part\n .split('\\n')\n .filter(line => line.startsWith('data:'));\n\n const jsonString = lines\n .map(line => line.trim().slice(5).trim())\n .join('');\n try {\n const { event, data } = JSON.parse(jsonString);\n if (event === 'start') {\n if (currentConversation === TEMP_CONVERSATION_ID) {\n // If the conversation is temp, we need to set the new conversation id\n newConversationId = data?.conversation_id;\n }\n }\n\n if (event === 'token') {\n const content = data?.token || '';\n\n finalMessages.push(content);\n\n // Store streaming message\n const [humanMessage, aiMessage] =\n streamingConversations.current[currentConversation];\n streamingConversations.current[currentConversation] = [\n humanMessage,\n { ...aiMessage, content: aiMessage.content + content },\n ];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += content;\n lastMessage.name =\n data?.response_metadata?.model || selectedModel;\n lastMessage.timestamp = getTimestamp(\n data?.response_metadata?.created_at || Date.now(),\n );\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n\n if (event === 'end') {\n const documents = data?.referenced_documents || [];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n if (documents.length) {\n lastMessage.sources = {\n sources: documents.map(\n (doc: { doc_title: string; doc_url: string }) => ({\n title: doc.doc_title,\n link: doc.doc_url,\n }),\n ),\n };\n }\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Error parsing JSON:', error);\n if (typeof onComplete === 'function') {\n onComplete('Invalid JSON received');\n }\n }\n }\n }\n } catch (e) {\n setConversations(prevConversations => {\n const conversation = prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += e;\n lastMessage.error = {\n title: e.message,\n };\n lastMessage.timestamp = getTimestamp(Date.now());\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n finalMessages.push(`${e}`);\n\n return {\n ...prevConversations,\n [newConversationId.length > 0\n ? newConversationId\n : currentConversation]: updatedConversation,\n };\n });\n }\n // reset current streaming\n streamingConversations.current[currentConversation] = [];\n if (typeof onComplete === 'function') {\n onComplete(finalMessages.join(''));\n }\n // Swap temp conversation messages with new conversation\n\n if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {\n setConversations(prevConversations => {\n return {\n ...prevConversations,\n [newConversationId]: prevConversations[TEMP_CONVERSATION_ID],\n };\n });\n\n onStart?.(newConversationId);\n\n setConversations(prev => {\n const { temp, ...rest } = prev;\n return rest;\n });\n }\n },\n\n [\n avatar,\n userName,\n onComplete,\n onStart,\n selectedModel,\n createMessage,\n currentConversation,\n ],\n );\n\n return {\n conversationMessages: conversations[currentConversation] ?? [],\n handleInputPrompt,\n conversations,\n scrollToBottomRef,\n ...queryProps,\n };\n};\n"],"names":["React"],"mappings":";;;;;;;;;AAsCa,MAAA,4BAAA,GAA+B,CAAC,mBAAgC,KAAA;AAC3E,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,OAAO,QAAS,CAAA;AAAA,IACd,QAAA,EAAU,CAAC,sBAAA,EAAwB,mBAAmB,CAAA;AAAA,IACtD,OAAA,EAAS,sBACL,YAAY;AACV,MAAA,MAAM,QACJ,GAAA,MAAM,aAAc,CAAA,uBAAA,CAAwB,mBAAmB,CAAA;AAEjE,MAAO,OAAA,QAAA;AAAA,KAET,GAAA,SAAA;AAAA,IACJ,KAAO,EAAA;AAAA,GACR,CAAA;AACH;AAIA,MAAM,aACJ,GAAA,qGAAA;AASW,MAAA,uBAAA,GAA0B,CACrC,cACA,EAAA,QAAA,EACA,eACA,MAAiB,GAAA,aAAA,EACjB,YACA,OACG,KAAA;AACH,EAAA,MAAM,EAAE,WAAA,EAAa,aAAc,EAAA,GAAI,4BAA6B,EAAA;AACpE,EAAM,MAAA,iBAAA,GAAoBA,cAAM,CAAA,MAAA,CAA8B,IAAI,CAAA;AAElE,EAAA,MAAM,CAAC,mBAAqB,EAAA,sBAAsB,CAChD,GAAAA,cAAA,CAAM,SAAS,cAAc,CAAA;AAC/B,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIA,eAAM,QAAwB,CAAA;AAAA,IACtE,CAAC,mBAAmB,GAAG;AAAC,GACzB,CAAA;AACD,EAAM,MAAA,sBAAA,GAAyBA,eAAM,MAAsB,CAAA;AAAA,IACzD,CAAC,mBAAmB,GAAG;AAAC,GACzB,CAAA;AAED,EAAAA,cAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,wBAAwB,cAAgB,EAAA;AAC1C,MAAA,sBAAA,CAAuB,cAAc,CAAA;AACrC,MAAA,gBAAA,CAAiB,CAAQ,IAAA,KAAA;AACvB,QAAI,IAAA,IAAA,CAAK,cAAc,CAAA,EAAU,OAAA,IAAA;AAEjC,QAAO,OAAA;AAAA,UACL,GAAG,IAAA;AAAA,UACH,CAAC,cAAc,GAAG;AAAC,SACrB;AAAA,OACD,CAAA;AAAA;AACH,GACC,EAAA,CAAC,mBAAqB,EAAA,cAAc,CAAC,CAAA;AAExC,EAAM,MAAA,EAAE,MAAM,iBAAoB,GAAA,IAAI,GAAG,UAAA,EACvC,GAAA,4BAAA,CAA6B,mBAAmB,CAAA;AAElD,EAAAA,cAAA,CAAM,UAAU,MAAM;AACpB,IACE,IAAA,CAAC,MAAM,OAAQ,CAAA,iBAAiB,KAC/B,iBAAkB,CAAA,MAAA,KAAW,KAC5B,cAAmB,KAAA,oBAAA;AAErB,MAAA;AAIF,IAAA,IAAI,aAAe,EAAA;AACjB,MAAA,MAAM,cAA2C,GAAA;AAAA,QAC/C,CAAC,mBAAmB,GAAG;AAAC,OAC1B;AAGA,MAAA,KAAA,IAAS,IAAI,CAAG,EAAA,CAAA,GAAI,iBAAkB,CAAA,MAAA,EAAQ,KAAK,CAAG,EAAA;AACpD,QAAM,MAAA,WAAA,GAAc,kBAAkB,CAAC,CAAA;AACvC,QAAM,MAAA,SAAA,GAAY,iBAAkB,CAAA,CAAA,GAAI,CAAC,CAAA;AAEzC,QAAA,MAAM,EAAE,OAAS,EAAA,YAAA,EAAc,WAAW,aAAc,EAAA,GACtD,eAAe,WAAW,CAAA;AAC5B,QAAM,MAAA;AAAA,UACJ,KAAA;AAAA,UACA,OAAS,EAAA,UAAA;AAAA,UACT,SAAW,EAAA,YAAA;AAAA,UACX;AAAA,SACF,GAAI,eAAe,SAAS,CAAA;AAE5B,QAAA,cAAA,CAAe,mBAAmB,CAAE,CAAA,IAAA;AAAA,UAClC,GAAG;AAAA,YACD,iBAAkB,CAAA;AAAA,cAChB,MAAA;AAAA,cACA,IAAM,EAAA,QAAA;AAAA,cACN,OAAS,EAAA,YAAA;AAAA,cACT,SAAW,EAAA;AAAA,aACZ,CAAA;AAAA,YACD,gBAAiB,CAAA;AAAA,cACf,MAAQ,EAAA,IAAA;AAAA,cACR,SAAW,EAAA,KAAA;AAAA,cACX,MAAM,KAAS,IAAA,aAAA;AAAA,cACf,OAAS,EAAA,UAAA;AAAA,cACT,SAAW,EAAA,YAAA;AAAA,cACX,OAAA,EAAS,4BAA4B,mBAAmB;AAAA,aACzD;AAAA;AACH,SACF;AAGA;AAGF,MAAI,IAAA,sBAAA,CAAuB,OAAQ,CAAA,mBAAmB,CAAG,EAAA;AACvD,QAAA,cAAA,CAAe,mBAAmB,CAAE,CAAA,IAAA;AAAA,UAClC,GAAG,sBAAuB,CAAA,OAAA,CAAQ,mBAAmB;AAAA,SACvD;AAAA;AAGF,MAAA,gBAAA,CAAiB,cAAc,CAAA;AAAA;AACjC,GAEC,EAAA;AAAA,IACD,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,mBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,oBAAoBA,cAAM,CAAA,WAAA;AAAA,IAC9B,OAAO,MAAA,EAAgB,WAA4B,GAAA,EAAO,KAAA;AACxD,MAAA,IAAI,iBAAoB,GAAA,EAAA;AAExB,MAAA,MAAM,iBAAoB,GAAA;AAAA,QACxB,iBAAkB,CAAA;AAAA,UAChB,MAAA;AAAA,UACA,IAAM,EAAA,QAAA;AAAA,UACN,OAAS,EAAA,MAAA;AAAA,UACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK,CAAK,IAAA;AAAA,SACxC,CAAA;AAAA,QACD,gBAAiB,CAAA;AAAA,UACf,MAAQ,EAAA,IAAA;AAAA,UACR,SAAW,EAAA,IAAA;AAAA,UACX,IAAM,EAAA,aAAA;AAAA,UACN,OAAS,EAAA,EAAA;AAAA,UACT,SAAW,EAAA;AAAA,SACZ;AAAA,OACH;AAEA,MAAA,sBAAA,CAAuB,OAAU,GAAA;AAAA,QAC/B,GAAG,sBAAuB,CAAA,OAAA;AAAA,QAC1B,CAAC,mBAAmB,GAAG;AAAA,OACzB;AAEA,MAAA,gBAAA,CAAiB,CAAC,QAA4B,KAAA;AAC5C,QAAO,OAAA;AAAA,UACL,GAAG,QAAA;AAAA,UACH,CAAC,mBAAmB,GAAG;AAAA,YACrB,GAAI,QAAA,GAAW,mBAAmB,CAAA,IAAK,EAAC;AAAA,YACxC,GAAG;AAAA;AACL,SACF;AAAA,OACD,CAAA;AAED,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,iBAAA,CAAkB,SAAS,cAAe,EAAA;AAAA,SACzC,CAAC,CAAA;AACJ,MAAA,MAAM,gBAA0B,EAAC;AACjC,MAAA,IAAI,MAAS,GAAA,EAAA;AAEb,MAAI,IAAA;AACF,QAAM,MAAA,MAAA,GAAS,MAAM,aAAc,CAAA;AAAA,UACjC,MAAA;AAAA,UACA,aAAA;AAAA,UACA,mBAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAM,MAAA,OAAA,GAAU,IAAI,WAAA,CAAY,OAAO,CAAA;AACvC,QAAA,MAAM,SAAY,GAAA,IAAA;AAElB,QAAA,OAAO,SAAW,EAAA;AAChB,UAAA,MAAM,EAAE,KAAO,EAAA,IAAA,EAAS,GAAA,MAAM,OAAO,IAAK,EAAA;AAC1C,UAAA,IAAI,IAAM,EAAA;AAEV,UAAA,MAAA,IAAU,QAAQ,MAAO,CAAA,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AAGhD,UAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,KAAA,CAAM,MAAM,CAAA;AACjC,UAAA,MAAA,GAAS,MAAM,GAAI,EAAA;AAEnB,UAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,YAAM,MAAA,KAAA,GAAQ,IACX,CAAA,KAAA,CAAM,IAAI,CAAA,CACV,OAAO,CAAQ,IAAA,KAAA,IAAA,CAAK,UAAW,CAAA,OAAO,CAAC,CAAA;AAE1C,YAAA,MAAM,UAAa,GAAA,KAAA,CAChB,GAAI,CAAA,CAAA,IAAA,KAAQ,KAAK,IAAK,EAAA,CAAE,KAAM,CAAA,CAAC,CAAE,CAAA,IAAA,EAAM,CAAA,CACvC,KAAK,EAAE,CAAA;AACV,YAAI,IAAA;AACF,cAAA,MAAM,EAAE,KAAO,EAAA,IAAA,EAAS,GAAA,IAAA,CAAK,MAAM,UAAU,CAAA;AAC7C,cAAA,IAAI,UAAU,OAAS,EAAA;AACrB,gBAAA,IAAI,wBAAwB,oBAAsB,EAAA;AAEhD,kBAAA,iBAAA,GAAoB,IAAM,EAAA,eAAA;AAAA;AAC5B;AAGF,cAAA,IAAI,UAAU,OAAS,EAAA;AACrB,gBAAM,MAAA,OAAA,GAAU,MAAM,KAAS,IAAA,EAAA;AAE/B,gBAAA,aAAA,CAAc,KAAK,OAAO,CAAA;AAG1B,gBAAA,MAAM,CAAC,YAAc,EAAA,SAAS,CAC5B,GAAA,sBAAA,CAAuB,QAAQ,mBAAmB,CAAA;AACpD,gBAAuB,sBAAA,CAAA,OAAA,CAAQ,mBAAmB,CAAI,GAAA;AAAA,kBACpD,YAAA;AAAA,kBACA,EAAE,GAAG,SAAA,EAAW,OAAS,EAAA,SAAA,CAAU,UAAU,OAAQ;AAAA,iBACvD;AAEA,gBAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,kBAAA,MAAM,YACJ,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAE7C,kBAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,kBAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,oBACf,OAAS,EAAA,EAAA;AAAA,oBACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,mBACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,kBAAA,WAAA,CAAY,SAAY,GAAA,KAAA;AACxB,kBAAA,WAAA,CAAY,OAAW,IAAA,OAAA;AACvB,kBAAY,WAAA,CAAA,IAAA,GACV,IAAM,EAAA,iBAAA,EAAmB,KAAS,IAAA,aAAA;AACpC,kBAAA,WAAA,CAAY,SAAY,GAAA,YAAA;AAAA,oBACtB,IAAM,EAAA,iBAAA,EAAmB,UAAc,IAAA,IAAA,CAAK,GAAI;AAAA,mBAClD;AAEA,kBAAA,MAAM,mBAAsB,GAAA;AAAA,oBAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,oBACzC;AAAA,mBACF;AAEA,kBAAO,OAAA;AAAA,oBACL,GAAG,iBAAA;AAAA,oBACH,CAAC,mBAAmB,GAAG;AAAA,mBACzB;AAAA,iBACD,CAAA;AAAA;AAGH,cAAA,IAAI,UAAU,KAAO,EAAA;AACnB,gBAAM,MAAA,SAAA,GAAY,IAAM,EAAA,oBAAA,IAAwB,EAAC;AAEjD,gBAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,kBAAA,MAAM,YACJ,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAE7C,kBAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,kBAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,oBACf,OAAS,EAAA,EAAA;AAAA,oBACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,mBACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,kBAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,oBAAA,WAAA,CAAY,OAAU,GAAA;AAAA,sBACpB,SAAS,SAAU,CAAA,GAAA;AAAA,wBACjB,CAAC,GAAiD,MAAA;AAAA,0BAChD,OAAO,GAAI,CAAA,SAAA;AAAA,0BACX,MAAM,GAAI,CAAA;AAAA,yBACZ;AAAA;AACF,qBACF;AAAA;AAGF,kBAAA,MAAM,mBAAsB,GAAA;AAAA,oBAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,oBACzC;AAAA,mBACF;AAEA,kBAAO,OAAA;AAAA,oBACL,GAAG,iBAAA;AAAA,oBACH,CAAC,mBAAmB,GAAG;AAAA,mBACzB;AAAA,iBACD,CAAA;AAAA;AACH,qBACO,KAAO,EAAA;AAEd,cAAQ,OAAA,CAAA,IAAA,CAAK,uBAAuB,KAAK,CAAA;AACzC,cAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,gBAAA,UAAA,CAAW,uBAAuB,CAAA;AAAA;AACpC;AACF;AACF;AACF,eACO,CAAG,EAAA;AACV,QAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,UAAA,MAAM,YAAe,GAAA,iBAAA,CAAkB,mBAAmB,CAAA,IAAK,EAAC;AAEhE,UAAM,MAAA,gBAAA,GAAmB,aAAa,MAAS,GAAA,CAAA;AAC/C,UAAA,MAAM,WACJ,GAAA,YAAA,CAAa,MAAW,KAAA,CAAA,GACpB,gBAAiB,CAAA;AAAA,YACf,OAAS,EAAA,EAAA;AAAA,YACT,SAAW,EAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK;AAAA,WACnC,CACD,GAAA,EAAE,GAAG,YAAA,CAAa,gBAAgB,CAAE,EAAA;AAE1C,UAAA,WAAA,CAAY,SAAY,GAAA,KAAA;AACxB,UAAA,WAAA,CAAY,OAAW,IAAA,CAAA;AACvB,UAAA,WAAA,CAAY,KAAQ,GAAA;AAAA,YAClB,OAAO,CAAE,CAAA;AAAA,WACX;AACA,UAAA,WAAA,CAAY,SAAY,GAAA,YAAA,CAAa,IAAK,CAAA,GAAA,EAAK,CAAA;AAE/C,UAAA,MAAM,mBAAsB,GAAA;AAAA,YAC1B,GAAG,YAAA,CAAa,KAAM,CAAA,CAAA,EAAG,gBAAgB,CAAA;AAAA,YACzC;AAAA,WACF;AAEA,UAAc,aAAA,CAAA,IAAA,CAAK,CAAG,EAAA,CAAC,CAAE,CAAA,CAAA;AAEzB,UAAO,OAAA;AAAA,YACL,GAAG,iBAAA;AAAA,YACH,CAAC,iBAAkB,CAAA,MAAA,GAAS,CACxB,GAAA,iBAAA,GACA,mBAAmB,GAAG;AAAA,WAC5B;AAAA,SACD,CAAA;AAAA;AAGH,MAAuB,sBAAA,CAAA,OAAA,CAAQ,mBAAmB,CAAA,GAAI,EAAC;AACvD,MAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,QAAW,UAAA,CAAA,aAAA,CAAc,IAAK,CAAA,EAAE,CAAC,CAAA;AAAA;AAInC,MAAI,IAAA,mBAAA,KAAwB,wBAAwB,iBAAmB,EAAA;AACrE,QAAA,gBAAA,CAAiB,CAAqB,iBAAA,KAAA;AACpC,UAAO,OAAA;AAAA,YACL,GAAG,iBAAA;AAAA,YACH,CAAC,iBAAiB,GAAG,iBAAA,CAAkB,oBAAoB;AAAA,WAC7D;AAAA,SACD,CAAA;AAED,QAAA,OAAA,GAAU,iBAAiB,CAAA;AAE3B,QAAA,gBAAA,CAAiB,CAAQ,IAAA,KAAA;AACvB,UAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAS,GAAA,IAAA;AAC1B,UAAO,OAAA,IAAA;AAAA,SACR,CAAA;AAAA;AACH,KACF;AAAA,IAEA;AAAA,MACE,MAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAA;AAAA,MACA,OAAA;AAAA,MACA,aAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAO,OAAA;AAAA,IACL,oBAAsB,EAAA,aAAA,CAAc,mBAAmB,CAAA,IAAK,EAAC;AAAA,IAC7D,iBAAA;AAAA,IACA,aAAA;AAAA,IACA,iBAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;;;;"}
1
+ {"version":3,"file":"useConversationMessages.esm.js","sources":["../../src/hooks/useConversationMessages.ts"],"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 React from 'react';\n\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport { useQuery } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\nimport { ScrollContainerHandle } from '../components/LightspeedChatBox';\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport botAvatar from '../images/bot-avatar.svg';\nimport userAvatar from '../images/user-avatar.svg';\nimport { Attachment, ReferencedDocument } from '../types';\nimport {\n createBotMessage,\n createUserMessage,\n getMessageData,\n getTimestamp,\n transformDocumentsToSources,\n} from '../utils/lightspeed-chatbox-utils';\nimport { useCreateConversationMessage } from './useCreateCoversationMessage';\n\n// Fetch all conversation messages\nexport const useFetchConversationMessages = (currentConversation: string) => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['conversationMessages', currentConversation],\n queryFn: currentConversation\n ? async () => {\n const response =\n await lightspeedApi.getConversationMessages(currentConversation);\n\n return response;\n }\n : undefined,\n retry: false,\n });\n};\n\ntype Conversations = { [_key: string]: MessageProps[] };\n\n/**\n * Fetches all the messages for given conversation_id\n * @param conversationId\n * @param userName\n * @param selectedModel\n * @param avatar\n *\n */\nexport const useConversationMessages = (\n conversationId: string,\n userName: string | undefined,\n selectedModel: string,\n avatar: string = userAvatar,\n onComplete?: (message: string) => void,\n onStart?: (conversation_id: string) => void,\n) => {\n const { mutateAsync: createMessage } = useCreateConversationMessage();\n const scrollToBottomRef = React.useRef<ScrollContainerHandle>(null);\n\n const [currentConversation, setCurrentConversation] =\n React.useState(conversationId);\n const [conversations, setConversations] = React.useState<Conversations>({\n [currentConversation]: [],\n });\n const streamingConversations = React.useRef<Conversations>({\n [currentConversation]: [],\n });\n\n React.useEffect(() => {\n if (currentConversation !== conversationId) {\n setCurrentConversation(conversationId);\n setConversations(prev => {\n if (prev[conversationId]) return prev;\n\n return {\n ...prev,\n [conversationId]: [],\n };\n });\n }\n }, [currentConversation, conversationId]);\n\n const { data: conversationsData = [], ...queryProps } =\n useFetchConversationMessages(currentConversation);\n\n React.useEffect(() => {\n if (\n !Array.isArray(conversationsData) ||\n (conversationsData.length === 0 &&\n conversationId !== TEMP_CONVERSATION_ID)\n )\n return;\n\n const newConvoIndex: number[] = [];\n\n if (conversations) {\n const _conversations: { [key: string]: any[] } = {\n [currentConversation]: [],\n };\n\n let index = 0;\n for (let i = 0; i < conversationsData.length; i += 2) {\n const userMessage = conversationsData[i];\n const aiMessage = conversationsData[i + 1];\n\n const { content: humanMessage, timestamp: userTimestamp } =\n getMessageData(userMessage);\n const {\n model,\n content: botMessage,\n timestamp: botTimestamp,\n referencedDocuments,\n } = getMessageData(aiMessage);\n\n _conversations[currentConversation].push(\n ...[\n createUserMessage({\n avatar,\n name: userName,\n content: humanMessage,\n timestamp: userTimestamp,\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: false,\n name: model ?? selectedModel,\n content: botMessage,\n timestamp: botTimestamp,\n sources: transformDocumentsToSources(referencedDocuments),\n }),\n ],\n );\n\n newConvoIndex.push(index);\n index++;\n }\n\n if (streamingConversations.current[currentConversation]) {\n _conversations[currentConversation].push(\n ...streamingConversations.current[currentConversation],\n );\n }\n\n setConversations(_conversations);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n conversationsData,\n userName,\n avatar,\n currentConversation,\n selectedModel,\n streamingConversations,\n ]);\n\n const handleInputPrompt = React.useCallback(\n async (prompt: string, attachments: Attachment[] = []) => {\n let newConversationId = '';\n\n const conversationTuple = [\n createUserMessage({\n avatar,\n name: userName,\n content: prompt,\n timestamp: getTimestamp(Date.now()) ?? '',\n }),\n createBotMessage({\n avatar: botAvatar,\n isLoading: true,\n name: selectedModel,\n content: '',\n timestamp: '',\n }),\n ];\n\n streamingConversations.current = {\n ...streamingConversations.current,\n [currentConversation]: conversationTuple,\n };\n\n setConversations((prevConv: Conversations) => {\n return {\n ...prevConv,\n [currentConversation]: [\n ...(prevConv?.[currentConversation] ?? []),\n ...conversationTuple,\n ],\n };\n });\n\n setTimeout(() => {\n scrollToBottomRef.current?.scrollToBottom();\n }, 0);\n const finalMessages: string[] = [];\n let buffer = '';\n\n try {\n const reader = await createMessage({\n prompt,\n selectedModel,\n currentConversation,\n attachments,\n });\n\n const decoder = new TextDecoder('utf-8');\n const keepGoing = true;\n\n while (keepGoing) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process all complete messages separated by double newlines\n const parts = buffer.split('\\n\\n');\n buffer = parts.pop()!;\n\n for (const part of parts) {\n const lines = part\n .split('\\n')\n .filter(line => line.startsWith('data:'));\n\n const jsonString = lines\n .map(line => line.trim().slice(5).trim())\n .join('');\n try {\n const { event, data } = JSON.parse(jsonString);\n if (event === 'start') {\n if (currentConversation === TEMP_CONVERSATION_ID) {\n // If the conversation is temp, we need to set the new conversation id\n newConversationId = data?.conversation_id;\n }\n }\n\n if (event === 'token') {\n const content = data?.token || '';\n\n finalMessages.push(content);\n\n // Store streaming message\n const [humanMessage, aiMessage] =\n streamingConversations.current[currentConversation];\n streamingConversations.current[currentConversation] = [\n humanMessage,\n { ...aiMessage, content: aiMessage.content + content },\n ];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += content;\n lastMessage.name =\n data?.response_metadata?.model || selectedModel;\n lastMessage.timestamp = getTimestamp(\n data?.response_metadata?.created_at || Date.now(),\n );\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n\n if (event === 'end') {\n const documents = data?.referenced_documents || [];\n\n setConversations(prevConversations => {\n const conversation =\n prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n if (documents.length) {\n lastMessage.sources = {\n sources: documents.map((doc: ReferencedDocument) => ({\n title: doc.doc_title,\n link: doc.doc_url,\n body: doc.doc_description,\n })),\n };\n }\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n return {\n ...prevConversations,\n [currentConversation]: updatedConversation,\n };\n });\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn('Error parsing JSON:', error);\n if (typeof onComplete === 'function') {\n onComplete('Invalid JSON received');\n }\n }\n }\n }\n } catch (e) {\n setConversations(prevConversations => {\n const conversation = prevConversations[currentConversation] ?? [];\n\n const lastMessageIndex = conversation.length - 1;\n const lastMessage =\n conversation.length === 0\n ? createBotMessage({\n content: '',\n timestamp: getTimestamp(Date.now()),\n })\n : { ...conversation[lastMessageIndex] };\n\n lastMessage.isLoading = false;\n lastMessage.content += e;\n lastMessage.error = {\n title: e.message,\n };\n lastMessage.timestamp = getTimestamp(Date.now());\n\n const updatedConversation = [\n ...conversation.slice(0, lastMessageIndex),\n lastMessage,\n ];\n\n finalMessages.push(`${e}`);\n\n return {\n ...prevConversations,\n [newConversationId.length > 0\n ? newConversationId\n : currentConversation]: updatedConversation,\n };\n });\n }\n // reset current streaming\n streamingConversations.current[currentConversation] = [];\n if (typeof onComplete === 'function') {\n onComplete(finalMessages.join(''));\n }\n // Swap temp conversation messages with new conversation\n\n if (currentConversation === TEMP_CONVERSATION_ID && newConversationId) {\n setConversations(prevConversations => {\n return {\n ...prevConversations,\n [newConversationId]: prevConversations[TEMP_CONVERSATION_ID],\n };\n });\n\n onStart?.(newConversationId);\n\n setConversations(prev => {\n const { temp, ...rest } = prev;\n return rest;\n });\n }\n },\n\n [\n avatar,\n userName,\n onComplete,\n onStart,\n selectedModel,\n createMessage,\n currentConversation,\n ],\n );\n\n return {\n conversationMessages: conversations[currentConversation] ?? [],\n handleInputPrompt,\n conversations,\n scrollToBottomRef,\n ...queryProps,\n };\n};\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,246 @@
1
+ import { useRef, useCallback, useEffect, useMemo } from 'react';
2
+ import { useCaptureFeedback } from './useCaptureFeedback.esm.js';
3
+ import { useFeedbackState } from './useFeedbackState.esm.js';
4
+ import { useFeedbackStatus } from './useFeedbackStatus.esm.js';
5
+
6
+ const quickResponses = {
7
+ positive: [
8
+ { id: "1", content: "Helpful information" },
9
+ { id: "2", content: "Easy to understand" },
10
+ { id: "3", content: "Resolved my issue" }
11
+ ],
12
+ negative: [
13
+ { id: "1", content: `Didn\u2019t answer my question` },
14
+ { id: "2", content: "Hard to understand" },
15
+ { id: "3", content: "Not Helpful" }
16
+ ]
17
+ };
18
+ const useFeedbackActions = (messages, conversationId, isStreaming) => {
19
+ const copyButtonRef = useRef(null);
20
+ const speakingButtonRef = useRef(null);
21
+ const currentSpeakingIdRef = useRef(null);
22
+ const { data: feedbackEnabled } = useFeedbackStatus();
23
+ const { state, ...dispatch } = useFeedbackState();
24
+ const { mutateAsync: captureFeedback } = useCaptureFeedback();
25
+ const getFeedbackForm = useCallback(
26
+ (messageId, sentiment) => ({
27
+ key: `feedback-${sentiment}`,
28
+ id: `feedback-${sentiment}-${messageId}`,
29
+ hasTextArea: true,
30
+ quickResponses: quickResponses[sentiment],
31
+ onSubmit: (quickResponse = "0", additionalFeedback) => {
32
+ const quickIndex = Number(quickResponse) - 1;
33
+ const quickText = quickResponse !== "0" ? quickResponses[sentiment]?.[quickIndex]?.content : undefined;
34
+ let user_feedback = "";
35
+ if (quickText && additionalFeedback) {
36
+ user_feedback = `${quickText}
37
+ Additional feedback: ${additionalFeedback}`;
38
+ } else if (quickText) {
39
+ user_feedback = quickText;
40
+ } else if (additionalFeedback) {
41
+ user_feedback = additionalFeedback;
42
+ }
43
+ const botAnswerId = Number(messageId.split("-").pop());
44
+ const userQuestionId = botAnswerId - 1;
45
+ const payload = {
46
+ conversation_id: conversationId,
47
+ user_feedback,
48
+ sentiment: sentiment === "positive" ? 1 : -1,
49
+ user_question: messages[userQuestionId].content || "",
50
+ llm_response: messages[botAnswerId].content || ""
51
+ };
52
+ captureFeedback(payload).then(() => {
53
+ dispatch.hideFeedbackForm(messageId, sentiment);
54
+ dispatch.showCompletionForm(messageId, sentiment);
55
+ dispatch.updateButtonState(messageId, {
56
+ sentiment,
57
+ feedbackSubmitted: true
58
+ });
59
+ setTimeout(() => {
60
+ dispatch.hideCompletionForm(messageId, sentiment);
61
+ }, 1e3);
62
+ });
63
+ },
64
+ // eslint-disable-next-line no-console
65
+ onClose: () => {
66
+ dispatch.hideFeedbackForm(messageId, sentiment);
67
+ dispatch.resetButtonState(messageId);
68
+ dispatch.updateButtonState(messageId, { sentiment: undefined });
69
+ },
70
+ focusOnLoad: true
71
+ }),
72
+ [captureFeedback, conversationId, dispatch, messages]
73
+ );
74
+ const feedbackForms = useCallback(
75
+ (messageId) => ({
76
+ positive: getFeedbackForm(messageId, "positive"),
77
+ negative: getFeedbackForm(messageId, "negative")
78
+ }),
79
+ [getFeedbackForm]
80
+ );
81
+ const getUserFeedbackComplete = useCallback(
82
+ (messageId, sentiment) => {
83
+ const isVisible = state[messageId]?.completionForm?.[sentiment];
84
+ if (!isVisible) return undefined;
85
+ return {
86
+ id: `feebback-completion-${sentiment}-${messageId}`,
87
+ onClose: () => {
88
+ dispatch.hideCompletionForm(messageId, sentiment);
89
+ dispatch.resetButtonState(messageId);
90
+ }
91
+ };
92
+ },
93
+ [state, dispatch]
94
+ );
95
+ const scrollToFeedbackForm = useCallback(
96
+ (messageId, sentiment) => {
97
+ setTimeout(() => {
98
+ const el = document.getElementById(
99
+ `feedback-${sentiment}-${messageId}`
100
+ );
101
+ if (el) {
102
+ el.scrollIntoView({ behavior: "auto", block: "start" });
103
+ el.focus();
104
+ }
105
+ }, 0);
106
+ },
107
+ []
108
+ );
109
+ const speakMessage = useCallback(
110
+ (messageId, content) => {
111
+ if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {
112
+ window.speechSynthesis.cancel();
113
+ if (currentSpeakingIdRef.current && currentSpeakingIdRef.current !== messageId) {
114
+ dispatch.updateButtonState(currentSpeakingIdRef.current, {
115
+ isSpeaking: false
116
+ });
117
+ }
118
+ }
119
+ currentSpeakingIdRef.current = messageId;
120
+ const utterance = new SpeechSynthesisUtterance(content);
121
+ utterance.onstart = () => {
122
+ dispatch.updateButtonState(messageId, { isSpeaking: true });
123
+ };
124
+ utterance.onend = () => {
125
+ dispatch.updateButtonState(messageId, { isSpeaking: false });
126
+ currentSpeakingIdRef.current = null;
127
+ };
128
+ utterance.onerror = () => {
129
+ dispatch.updateButtonState(messageId, { isSpeaking: false });
130
+ currentSpeakingIdRef.current = null;
131
+ };
132
+ window.speechSynthesis.speak(utterance);
133
+ },
134
+ [dispatch]
135
+ );
136
+ const cancelSpeaking = useCallback(
137
+ (messageId) => {
138
+ window.speechSynthesis.cancel();
139
+ currentSpeakingIdRef.current = null;
140
+ if (messageId) {
141
+ dispatch.updateButtonState(messageId, { isSpeaking: false });
142
+ } else {
143
+ Object.keys(state).forEach((id) => {
144
+ if (state[id].buttonState?.isSpeaking) {
145
+ dispatch.updateButtonState(id, { isSpeaking: false });
146
+ }
147
+ });
148
+ }
149
+ setTimeout(() => {
150
+ const el = document.getElementById(`listen-${messageId}`);
151
+ if (el) {
152
+ el.blur();
153
+ }
154
+ }, 10);
155
+ },
156
+ [state, dispatch]
157
+ );
158
+ useEffect(() => {
159
+ return () => {
160
+ cancelSpeaking();
161
+ };
162
+ }, [conversationId]);
163
+ return useMemo(() => {
164
+ return feedbackEnabled ? messages.map((message, index) => {
165
+ if (message.role === "user" || isStreaming && messages.length - 1 === index)
166
+ return message;
167
+ const messageId = `${conversationId}-${message.role}-${index}`;
168
+ const { sentiment, copied, isSpeaking } = state[messageId]?.buttonState || {};
169
+ const showFeedbackForm = state[messageId]?.feedbackForm?.[sentiment];
170
+ const userFeedbackForm = showFeedbackForm && feedbackForms(messageId)[sentiment];
171
+ const userFeedbackComplete = getUserFeedbackComplete(
172
+ messageId,
173
+ sentiment
174
+ );
175
+ const createSentimentAction = (selected) => ({
176
+ isClicked: sentiment === selected,
177
+ onClick: () => {
178
+ if (sentiment !== selected) {
179
+ dispatch.toggleFeedbackForm(messageId, selected);
180
+ dispatch.updateButtonState(messageId, { sentiment: selected });
181
+ scrollToFeedbackForm(messageId, sentiment);
182
+ }
183
+ },
184
+ "aria-expanded": sentiment === selected,
185
+ "aria-controls": showFeedbackForm ? `feedback-${sentiment}-${messageId}` : `feebback-completion-${sentiment}-${messageId}`
186
+ });
187
+ const copyAction = {
188
+ isClicked: copied,
189
+ ref: copyButtonRef,
190
+ tooltipContent: copied ? "Copied" : null,
191
+ onClick: async () => {
192
+ await window.navigator.clipboard.writeText(
193
+ message.content
194
+ );
195
+ dispatch.updateButtonState(messageId, {
196
+ copied: true
197
+ });
198
+ setTimeout(() => {
199
+ dispatch.updateButtonState(messageId, { copied: false });
200
+ copyButtonRef?.current?.blur();
201
+ }, 1e3);
202
+ }
203
+ };
204
+ const listenAction = {
205
+ isClicked: isSpeaking,
206
+ ref: speakingButtonRef,
207
+ id: `listen-${messageId}`,
208
+ onClick: () => {
209
+ const isCurrentlySpeaking = state[messageId]?.buttonState?.isSpeaking;
210
+ if (isCurrentlySpeaking) {
211
+ cancelSpeaking(messageId);
212
+ } else {
213
+ cancelSpeaking();
214
+ speakMessage(messageId, message.content);
215
+ }
216
+ }
217
+ };
218
+ return {
219
+ ...message,
220
+ userFeedbackForm,
221
+ userFeedbackComplete,
222
+ actions: {
223
+ positive: createSentimentAction("positive"),
224
+ negative: createSentimentAction("negative"),
225
+ copy: copyAction,
226
+ listen: listenAction
227
+ }
228
+ };
229
+ }) : messages;
230
+ }, [
231
+ conversationId,
232
+ messages,
233
+ state,
234
+ dispatch,
235
+ isStreaming,
236
+ speakMessage,
237
+ feedbackForms,
238
+ cancelSpeaking,
239
+ feedbackEnabled,
240
+ getUserFeedbackComplete,
241
+ scrollToFeedbackForm
242
+ ]);
243
+ };
244
+
245
+ export { useFeedbackActions };
246
+ //# sourceMappingURL=useFeedbackActions.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFeedbackActions.esm.js","sources":["../../src/hooks/useFeedbackActions.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 */\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { MessageProps } from '@patternfly/chatbot';\nimport QuickResponse from '@patternfly/chatbot/dist/cjs/Message/QuickResponse/QuickResponse';\nimport { UserFeedbackProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedback';\nimport { UserFeedbackCompleteProps } from '@patternfly/chatbot/dist/cjs/Message/UserFeedback/UserFeedbackComplete';\n\nimport { useCaptureFeedback } from '../hooks/useCaptureFeedback';\nimport { CaptureFeedback } from '../types';\nimport { Sentiment, useFeedbackState } from './useFeedbackState';\nimport { useFeedbackStatus } from './useFeedbackStatus';\n\nconst quickResponses: { [key in Sentiment]: QuickResponse[] } = {\n positive: [\n { id: '1', content: 'Helpful information' },\n { id: '2', content: 'Easy to understand' },\n { id: '3', content: 'Resolved my issue' },\n ],\n negative: [\n { id: '1', content: `Didn’t answer my question` },\n { id: '2', content: 'Hard to understand' },\n { id: '3', content: 'Not Helpful' },\n ],\n};\n\nexport const useFeedbackActions = <T extends MessageProps>(\n messages: T[],\n conversationId: string,\n isStreaming: boolean,\n): T[] => {\n const copyButtonRef = useRef<HTMLButtonElement>(null);\n const speakingButtonRef = useRef<HTMLButtonElement>(null);\n const currentSpeakingIdRef = useRef<string | null>(null);\n\n const { data: feedbackEnabled } = useFeedbackStatus();\n const { state, ...dispatch } = useFeedbackState();\n const { mutateAsync: captureFeedback } = useCaptureFeedback();\n\n const getFeedbackForm = useCallback(\n (messageId: string, sentiment: 'positive' | 'negative') => ({\n key: `feedback-${sentiment}`,\n id: `feedback-${sentiment}-${messageId}`,\n hasTextArea: true,\n quickResponses: quickResponses[sentiment],\n onSubmit: (\n quickResponse: string | undefined = '0',\n additionalFeedback: string | undefined,\n ) => {\n const quickIndex = Number(quickResponse) - 1;\n const quickText =\n quickResponse !== '0'\n ? quickResponses[sentiment]?.[quickIndex]?.content\n : undefined;\n\n let user_feedback = '';\n\n if (quickText && additionalFeedback) {\n user_feedback = `${quickText}\\nAdditional feedback: ${additionalFeedback}`;\n } else if (quickText) {\n user_feedback = quickText;\n } else if (additionalFeedback) {\n user_feedback = additionalFeedback;\n }\n\n const botAnswerId = Number(messageId.split('-').pop());\n const userQuestionId = botAnswerId - 1;\n\n const payload: CaptureFeedback = {\n conversation_id: conversationId,\n user_feedback,\n sentiment: sentiment === 'positive' ? 1 : -1,\n user_question: messages[userQuestionId].content || '',\n llm_response: messages[botAnswerId].content || '',\n };\n\n captureFeedback(payload).then(() => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.showCompletionForm(messageId, sentiment);\n dispatch.updateButtonState(messageId, {\n sentiment: sentiment,\n feedbackSubmitted: true,\n });\n\n setTimeout(() => {\n dispatch.hideCompletionForm(messageId, sentiment);\n }, 1000);\n });\n },\n\n // eslint-disable-next-line no-console\n onClose: () => {\n dispatch.hideFeedbackForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n dispatch.updateButtonState(messageId, { sentiment: undefined });\n },\n focusOnLoad: true,\n }),\n [captureFeedback, conversationId, dispatch, messages],\n );\n\n const feedbackForms = useCallback(\n (messageId: string): { [key in Sentiment]: UserFeedbackProps } => ({\n positive: getFeedbackForm(messageId, 'positive'),\n negative: getFeedbackForm(messageId, 'negative'),\n }),\n [getFeedbackForm],\n );\n\n const getUserFeedbackComplete = useCallback(\n (\n messageId: string,\n sentiment: Sentiment,\n ): UserFeedbackCompleteProps | undefined => {\n const isVisible = state[messageId]?.completionForm?.[sentiment];\n if (!isVisible) return undefined;\n\n return {\n id: `feebback-completion-${sentiment}-${messageId}`,\n onClose: () => {\n dispatch.hideCompletionForm(messageId, sentiment);\n dispatch.resetButtonState(messageId);\n },\n };\n },\n [state, dispatch],\n );\n\n const scrollToFeedbackForm = useCallback(\n (messageId: string, sentiment: Sentiment) => {\n setTimeout(() => {\n const el = document.getElementById(\n `feedback-${sentiment}-${messageId}`,\n );\n if (el) {\n el.scrollIntoView({ behavior: 'auto', block: 'start' });\n el.focus();\n }\n }, 0);\n },\n [],\n );\n\n const speakMessage = useCallback(\n (messageId: string, content: string) => {\n if (window.speechSynthesis.speaking || window.speechSynthesis.pending) {\n window.speechSynthesis.cancel();\n\n if (\n currentSpeakingIdRef.current &&\n currentSpeakingIdRef.current !== messageId\n ) {\n dispatch.updateButtonState(currentSpeakingIdRef.current, {\n isSpeaking: false,\n });\n }\n }\n\n // Track the current SpeakingId\n currentSpeakingIdRef.current = messageId;\n\n const utterance = new SpeechSynthesisUtterance(content);\n\n utterance.onstart = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: true });\n };\n\n utterance.onend = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n utterance.onerror = () => {\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n currentSpeakingIdRef.current = null;\n };\n\n window.speechSynthesis.speak(utterance);\n },\n [dispatch],\n );\n\n const cancelSpeaking = useCallback(\n (messageId?: string) => {\n window.speechSynthesis.cancel();\n\n currentSpeakingIdRef.current = null;\n\n if (messageId) {\n // Cancel just this one message\n dispatch.updateButtonState(messageId, { isSpeaking: false });\n } else {\n // Cancel all messages\n Object.keys(state).forEach(id => {\n if (state[id].buttonState?.isSpeaking) {\n dispatch.updateButtonState(id, { isSpeaking: false });\n }\n });\n }\n setTimeout(() => {\n const el = document.getElementById(`listen-${messageId}`);\n if (el) {\n el.blur();\n }\n }, 10);\n },\n [state, dispatch],\n );\n\n useEffect(() => {\n return () => {\n // Stop any ongoing speech when component unmounts\n cancelSpeaking();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [conversationId]);\n\n return useMemo(() => {\n return feedbackEnabled\n ? messages.map((message, index) => {\n if (\n message.role === 'user' ||\n (isStreaming && messages.length - 1 === index)\n )\n return message;\n\n const messageId = `${conversationId}-${message.role}-${index}`;\n const { sentiment, copied, isSpeaking } =\n state[messageId]?.buttonState || {};\n const showFeedbackForm = state[messageId]?.feedbackForm?.[sentiment];\n const userFeedbackForm =\n showFeedbackForm && feedbackForms(messageId)[sentiment];\n\n const userFeedbackComplete = getUserFeedbackComplete(\n messageId,\n sentiment,\n );\n\n const createSentimentAction = (selected: Sentiment) => ({\n isClicked: sentiment === selected,\n onClick: () => {\n if (sentiment !== selected) {\n dispatch.toggleFeedbackForm(messageId, selected);\n dispatch.updateButtonState(messageId, { sentiment: selected });\n scrollToFeedbackForm(messageId, sentiment);\n }\n },\n 'aria-expanded': sentiment === selected,\n 'aria-controls': showFeedbackForm\n ? `feedback-${sentiment}-${messageId}`\n : `feebback-completion-${sentiment}-${messageId}`,\n });\n\n const copyAction = {\n isClicked: copied,\n ref: copyButtonRef,\n tooltipContent: copied ? 'Copied' : null,\n onClick: async () => {\n await window.navigator.clipboard.writeText(\n message.content as string,\n );\n dispatch.updateButtonState(messageId, {\n copied: true,\n });\n\n setTimeout(() => {\n dispatch.updateButtonState(messageId, { copied: false });\n copyButtonRef?.current?.blur();\n }, 1000);\n },\n };\n\n const listenAction = {\n isClicked: isSpeaking,\n ref: speakingButtonRef,\n id: `listen-${messageId}`,\n onClick: () => {\n const isCurrentlySpeaking =\n state[messageId]?.buttonState?.isSpeaking;\n\n if (isCurrentlySpeaking) {\n // Stop if it's already speaking this message\n cancelSpeaking(messageId);\n } else {\n cancelSpeaking();\n speakMessage(messageId, message.content as string);\n }\n },\n };\n\n return {\n ...message,\n userFeedbackForm,\n userFeedbackComplete,\n actions: {\n positive: createSentimentAction('positive'),\n negative: createSentimentAction('negative'),\n copy: copyAction,\n listen: listenAction,\n },\n };\n })\n : messages;\n }, [\n conversationId,\n messages,\n state,\n dispatch,\n isStreaming,\n speakMessage,\n feedbackForms,\n cancelSpeaking,\n feedbackEnabled,\n getUserFeedbackComplete,\n scrollToFeedbackForm,\n ]);\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { useReducer } from 'react';
2
+
3
+ function reducer(state, action) {
4
+ const entry = state[action.messageId] ?? {
5
+ feedbackForm: { positive: false, negative: false },
6
+ completionForm: { positive: false, negative: false },
7
+ buttonState: {}
8
+ };
9
+ switch (action.type) {
10
+ case "SHOW_FEEDBACK_FORM":
11
+ return {
12
+ ...state,
13
+ [action.messageId]: {
14
+ ...entry,
15
+ feedbackForm: { ...entry.feedbackForm, [action.sentiment]: true }
16
+ }
17
+ };
18
+ case "HIDE_FEEDBACK_FORM":
19
+ return {
20
+ ...state,
21
+ [action.messageId]: {
22
+ ...entry,
23
+ feedbackForm: { ...entry.feedbackForm, [action.sentiment]: false }
24
+ }
25
+ };
26
+ case "SHOW_COMPLETION_FORM":
27
+ return {
28
+ ...state,
29
+ [action.messageId]: {
30
+ ...entry,
31
+ completionForm: { ...entry.completionForm, [action.sentiment]: true }
32
+ }
33
+ };
34
+ case "HIDE_COMPLETION_FORM":
35
+ return {
36
+ ...state,
37
+ [action.messageId]: {
38
+ ...entry,
39
+ completionForm: {
40
+ ...entry.completionForm,
41
+ [action.sentiment]: false
42
+ }
43
+ }
44
+ };
45
+ case "UPDATE_BUTTON_STATE":
46
+ return {
47
+ ...state,
48
+ [action.messageId]: {
49
+ ...entry,
50
+ buttonState: { ...entry.buttonState, ...action.payload }
51
+ }
52
+ };
53
+ case "RESET_BUTTON_STATE": {
54
+ const { [action.messageId]: _, ...rest } = state;
55
+ return rest;
56
+ }
57
+ default:
58
+ return state;
59
+ }
60
+ }
61
+ function useFeedbackState() {
62
+ const [state, dispatch] = useReducer(reducer, {});
63
+ const showFeedbackForm = (messageId, sentiment) => dispatch({ type: "SHOW_FEEDBACK_FORM", messageId, sentiment });
64
+ const hideFeedbackForm = (messageId, sentiment) => dispatch({ type: "HIDE_FEEDBACK_FORM", messageId, sentiment });
65
+ const showCompletionForm = (messageId, sentiment) => dispatch({ type: "SHOW_COMPLETION_FORM", messageId, sentiment });
66
+ const hideCompletionForm = (messageId, sentiment) => dispatch({ type: "HIDE_COMPLETION_FORM", messageId, sentiment });
67
+ const updateButtonState = (messageId, payload) => dispatch({ type: "UPDATE_BUTTON_STATE", messageId, payload });
68
+ const resetButtonState = (messageId) => dispatch({ type: "RESET_BUTTON_STATE", messageId });
69
+ const getFeedbackState = (messageId) => state[messageId] ?? {
70
+ feedbackForm: { positive: false, negative: false },
71
+ completionForm: { positive: false, negative: false },
72
+ buttonState: { sentiment: "positive", copied: false }
73
+ };
74
+ const toggleFeedbackForm = (messageId, sentimentToShow) => {
75
+ const opposite = sentimentToShow === "positive" ? "negative" : "positive";
76
+ hideFeedbackForm(messageId, opposite);
77
+ showFeedbackForm(messageId, sentimentToShow);
78
+ };
79
+ return {
80
+ state,
81
+ getFeedbackState,
82
+ showFeedbackForm,
83
+ hideFeedbackForm,
84
+ toggleFeedbackForm,
85
+ showCompletionForm,
86
+ hideCompletionForm,
87
+ updateButtonState,
88
+ resetButtonState
89
+ };
90
+ }
91
+
92
+ export { useFeedbackState };
93
+ //# sourceMappingURL=useFeedbackState.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFeedbackState.esm.js","sources":["../../src/hooks/useFeedbackState.ts"],"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 */\nimport { useReducer } from 'react';\n\nexport type Sentiment = 'positive' | 'negative';\n\ntype FeedbackButtonState = {\n sentiment: Sentiment;\n copied: boolean;\n isSpeaking: boolean;\n feedbackSubmitted?: boolean;\n};\n\ntype MessageState = {\n feedbackForm: Record<Sentiment, boolean>;\n completionForm: Record<Sentiment, boolean>;\n buttonState: FeedbackButtonState;\n};\n\ntype State = Record<string, MessageState>;\n\ntype Action =\n | { type: 'SHOW_FEEDBACK_FORM'; messageId: string; sentiment: Sentiment }\n | { type: 'HIDE_FEEDBACK_FORM'; messageId: string; sentiment: Sentiment }\n | { type: 'SHOW_COMPLETION_FORM'; messageId: string; sentiment: Sentiment }\n | { type: 'HIDE_COMPLETION_FORM'; messageId: string; sentiment: Sentiment }\n | { type: 'RESET_BUTTON_STATE'; messageId: string }\n | {\n type: 'UPDATE_BUTTON_STATE';\n messageId: string;\n payload: Partial<FeedbackButtonState>;\n };\n\nfunction reducer(state: State, action: Action): State {\n const entry = state[action.messageId] ?? {\n feedbackForm: { positive: false, negative: false },\n completionForm: { positive: false, negative: false },\n buttonState: {},\n };\n\n switch (action.type) {\n case 'SHOW_FEEDBACK_FORM':\n return {\n ...state,\n [action.messageId]: {\n ...entry,\n feedbackForm: { ...entry.feedbackForm, [action.sentiment]: true },\n },\n };\n case 'HIDE_FEEDBACK_FORM':\n return {\n ...state,\n [action.messageId]: {\n ...entry,\n feedbackForm: { ...entry.feedbackForm, [action.sentiment]: false },\n },\n };\n case 'SHOW_COMPLETION_FORM':\n return {\n ...state,\n [action.messageId]: {\n ...entry,\n completionForm: { ...entry.completionForm, [action.sentiment]: true },\n },\n };\n case 'HIDE_COMPLETION_FORM':\n return {\n ...state,\n [action.messageId]: {\n ...entry,\n completionForm: {\n ...entry.completionForm,\n [action.sentiment]: false,\n },\n },\n };\n case 'UPDATE_BUTTON_STATE':\n return {\n ...state,\n [action.messageId]: {\n ...entry,\n buttonState: { ...entry.buttonState, ...action.payload },\n },\n };\n case 'RESET_BUTTON_STATE': {\n const { [action.messageId]: _, ...rest } = state;\n return rest;\n }\n default:\n return state;\n }\n}\n\nexport function useFeedbackState() {\n const [state, dispatch] = useReducer(reducer, {});\n\n const showFeedbackForm = (messageId: string, sentiment: Sentiment) =>\n dispatch({ type: 'SHOW_FEEDBACK_FORM', messageId, sentiment });\n\n const hideFeedbackForm = (messageId: string, sentiment: Sentiment) =>\n dispatch({ type: 'HIDE_FEEDBACK_FORM', messageId, sentiment });\n\n const showCompletionForm = (messageId: string, sentiment: Sentiment) =>\n dispatch({ type: 'SHOW_COMPLETION_FORM', messageId, sentiment });\n\n const hideCompletionForm = (messageId: string, sentiment: Sentiment) =>\n dispatch({ type: 'HIDE_COMPLETION_FORM', messageId, sentiment });\n\n const updateButtonState = (\n messageId: string,\n payload: Partial<FeedbackButtonState>,\n ) => dispatch({ type: 'UPDATE_BUTTON_STATE', messageId, payload });\n\n const resetButtonState = (messageId: string) =>\n dispatch({ type: 'RESET_BUTTON_STATE', messageId });\n\n const getFeedbackState = (messageId: string) =>\n state[messageId] ?? {\n feedbackForm: { positive: false, negative: false },\n completionForm: { positive: false, negative: false },\n buttonState: { sentiment: 'positive', copied: false },\n };\n\n const toggleFeedbackForm = (\n messageId: string,\n sentimentToShow: Sentiment,\n ) => {\n const opposite: Sentiment =\n sentimentToShow === 'positive' ? 'negative' : 'positive';\n\n hideFeedbackForm(messageId, opposite);\n showFeedbackForm(messageId, sentimentToShow);\n };\n\n return {\n state,\n getFeedbackState,\n showFeedbackForm,\n hideFeedbackForm,\n toggleFeedbackForm,\n showCompletionForm,\n hideCompletionForm,\n updateButtonState,\n resetButtonState,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { useApi } from '@backstage/core-plugin-api';
2
+ import { useQuery } from '@tanstack/react-query';
3
+ import { lightspeedApiRef } from '../api/api.esm.js';
4
+
5
+ const useFeedbackStatus = () => {
6
+ const lightspeedApi = useApi(lightspeedApiRef);
7
+ return useQuery({
8
+ queryKey: ["feedbackStatus"],
9
+ queryFn: async () => await lightspeedApi.getFeedbackStatus()
10
+ });
11
+ };
12
+
13
+ export { useFeedbackStatus };
14
+ //# sourceMappingURL=useFeedbackStatus.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFeedbackStatus.esm.js","sources":["../../src/hooks/useFeedbackStatus.ts"],"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 */\nimport { useApi } from '@backstage/core-plugin-api';\n\nimport { useQuery } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\n\n// Fetch feedback status\nexport const useFeedbackStatus = () => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['feedbackStatus'],\n queryFn: async () => await lightspeedApi.getFeedbackStatus(),\n });\n};\n"],"names":[],"mappings":";;;;AAsBO,MAAM,oBAAoB,MAAM;AACrC,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,OAAO,QAAS,CAAA;AAAA,IACd,QAAA,EAAU,CAAC,gBAAgB,CAAA;AAAA,IAC3B,OAAS,EAAA,YAAY,MAAM,aAAA,CAAc,iBAAkB;AAAA,GAC5D,CAAA;AACH;;;;"}
@@ -1,9 +1,9 @@
1
1
  import { usePermission } from '@backstage/plugin-permission-react';
2
- import { lightspeedConversationsDeletePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
2
+ import { lightspeedChatDeletePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
3
3
 
4
4
  const useLightspeedDeletePermission = () => {
5
5
  const lightspeedDeletePermissionResult = usePermission({
6
- permission: lightspeedConversationsDeletePermission
6
+ permission: lightspeedChatDeletePermission
7
7
  });
8
8
  return lightspeedDeletePermissionResult;
9
9
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useLightspeedDeletePermission.esm.js","sources":["../../src/hooks/useLightspeedDeletePermission.ts"],"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 { usePermission } from '@backstage/plugin-permission-react';\n\nimport { lightspeedConversationsDeletePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';\n\nexport const useLightspeedDeletePermission = () => {\n const lightspeedDeletePermissionResult = usePermission({\n permission: lightspeedConversationsDeletePermission,\n });\n\n return lightspeedDeletePermissionResult;\n};\n"],"names":[],"mappings":";;;AAoBO,MAAM,gCAAgC,MAAM;AACjD,EAAA,MAAM,mCAAmC,aAAc,CAAA;AAAA,IACrD,UAAY,EAAA;AAAA,GACb,CAAA;AAED,EAAO,OAAA,gCAAA;AACT;;;;"}
1
+ {"version":3,"file":"useLightspeedDeletePermission.esm.js","sources":["../../src/hooks/useLightspeedDeletePermission.ts"],"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 { usePermission } from '@backstage/plugin-permission-react';\n\nimport { lightspeedChatDeletePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';\n\nexport const useLightspeedDeletePermission = () => {\n const lightspeedDeletePermissionResult = usePermission({\n permission: lightspeedChatDeletePermission,\n });\n\n return lightspeedDeletePermissionResult;\n};\n"],"names":[],"mappings":";;;AAoBO,MAAM,gCAAgC,MAAM;AACjD,EAAA,MAAM,mCAAmC,aAAc,CAAA;AAAA,IACrD,UAAY,EAAA;AAAA,GACb,CAAA;AAED,EAAO,OAAA,gCAAA;AACT;;;;"}
@@ -1,16 +1,16 @@
1
1
  import { usePermission } from '@backstage/plugin-permission-react';
2
- import { lightspeedConversationsReadPermission, lightspeedConversationsCreatePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
2
+ import { lightspeedChatReadPermission, lightspeedChatCreatePermission } from '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
3
3
 
4
4
  const useLightspeedViewPermission = () => {
5
- const canReadConversations = usePermission({
6
- permission: lightspeedConversationsReadPermission
5
+ const canReadChats = usePermission({
6
+ permission: lightspeedChatReadPermission
7
7
  });
8
- const canCreateConversations = usePermission({
9
- permission: lightspeedConversationsCreatePermission
8
+ const canCreateChats = usePermission({
9
+ permission: lightspeedChatCreatePermission
10
10
  });
11
11
  return {
12
- loading: canReadConversations.loading || canCreateConversations.loading,
13
- allowed: canReadConversations.allowed && canCreateConversations.allowed
12
+ loading: canReadChats.loading || canCreateChats.loading,
13
+ allowed: canReadChats.allowed && canCreateChats.allowed
14
14
  };
15
15
  };
16
16