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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/CHANGELOG.md +681 -0
  2. package/README.md +378 -0
  3. package/config.d.ts +70 -0
  4. package/dist/alpha.d.ts +285 -0
  5. package/dist/alpha.esm.js +3 -0
  6. package/dist/alpha.esm.js.map +1 -0
  7. package/dist/api/LightspeedApiClient.esm.js +234 -0
  8. package/dist/api/LightspeedApiClient.esm.js.map +1 -0
  9. package/dist/api/NotebooksApiClient.esm.js +179 -0
  10. package/dist/api/NotebooksApiClient.esm.js.map +1 -0
  11. package/dist/api/api.esm.js +8 -0
  12. package/dist/api/api.esm.js.map +1 -0
  13. package/dist/api/notebooksApi.esm.js +10 -0
  14. package/dist/api/notebooksApi.esm.js.map +1 -0
  15. package/dist/components/Attachment.esm.js +108 -0
  16. package/dist/components/Attachment.esm.js.map +1 -0
  17. package/dist/components/AttachmentContext.esm.js +125 -0
  18. package/dist/components/AttachmentContext.esm.js.map +1 -0
  19. package/dist/components/CollapsedHistoryStrip.esm.js +87 -0
  20. package/dist/components/CollapsedHistoryStrip.esm.js.map +1 -0
  21. package/dist/components/DeleteModal.esm.js +92 -0
  22. package/dist/components/DeleteModal.esm.js.map +1 -0
  23. package/dist/components/FilePreview.esm.js +49 -0
  24. package/dist/components/FilePreview.esm.js.map +1 -0
  25. package/dist/components/LightSpeedChat.esm.js +1898 -0
  26. package/dist/components/LightSpeedChat.esm.js.map +1 -0
  27. package/dist/components/LightspeedChatBox.esm.js +252 -0
  28. package/dist/components/LightspeedChatBox.esm.js.map +1 -0
  29. package/dist/components/LightspeedChatBoxHeader.esm.js +210 -0
  30. package/dist/components/LightspeedChatBoxHeader.esm.js.map +1 -0
  31. package/dist/components/LightspeedChatContainer.esm.js +162 -0
  32. package/dist/components/LightspeedChatContainer.esm.js.map +1 -0
  33. package/dist/components/LightspeedChatModelsState.esm.js +198 -0
  34. package/dist/components/LightspeedChatModelsState.esm.js.map +1 -0
  35. package/dist/components/LightspeedDrawerContext.esm.js +15 -0
  36. package/dist/components/LightspeedDrawerContext.esm.js.map +1 -0
  37. package/dist/components/LightspeedDrawerProvider.esm.js +44 -0
  38. package/dist/components/LightspeedDrawerProvider.esm.js.map +1 -0
  39. package/dist/components/LightspeedDrawerStateExposer.esm.js +34 -0
  40. package/dist/components/LightspeedDrawerStateExposer.esm.js.map +1 -0
  41. package/dist/components/LightspeedFAB.esm.js +6 -0
  42. package/dist/components/LightspeedFAB.esm.js.map +1 -0
  43. package/dist/components/LightspeedFABContent.esm.js +65 -0
  44. package/dist/components/LightspeedFABContent.esm.js.map +1 -0
  45. package/dist/components/LightspeedIcon.esm.js +46 -0
  46. package/dist/components/LightspeedIcon.esm.js.map +1 -0
  47. package/dist/components/LightspeedPage.esm.js +31 -0
  48. package/dist/components/LightspeedPage.esm.js.map +1 -0
  49. package/dist/components/McpServersSettings.esm.js +953 -0
  50. package/dist/components/McpServersSettings.esm.js.map +1 -0
  51. package/dist/components/McpSettingsIcon.esm.js +18 -0
  52. package/dist/components/McpSettingsIcon.esm.js.map +1 -0
  53. package/dist/components/MessageBarModelSelector.esm.js +92 -0
  54. package/dist/components/MessageBarModelSelector.esm.js.map +1 -0
  55. package/dist/components/PermissionRequiredIcon.esm.js +18 -0
  56. package/dist/components/PermissionRequiredIcon.esm.js.map +1 -0
  57. package/dist/components/PermissionRequiredState.esm.js +88 -0
  58. package/dist/components/PermissionRequiredState.esm.js.map +1 -0
  59. package/dist/components/RenameConversationModal.esm.js +157 -0
  60. package/dist/components/RenameConversationModal.esm.js.map +1 -0
  61. package/dist/components/Router.esm.js +35 -0
  62. package/dist/components/Router.esm.js.map +1 -0
  63. package/dist/components/SourcesChipModal.esm.js +124 -0
  64. package/dist/components/SourcesChipModal.esm.js.map +1 -0
  65. package/dist/components/ToolCallContent.esm.js +208 -0
  66. package/dist/components/ToolCallContent.esm.js.map +1 -0
  67. package/dist/components/Trans.esm.js +33 -0
  68. package/dist/components/Trans.esm.js.map +1 -0
  69. package/dist/components/notebooks/AddDocumentModal.esm.js +271 -0
  70. package/dist/components/notebooks/AddDocumentModal.esm.js.map +1 -0
  71. package/dist/components/notebooks/DeleteDocumentModal.esm.js +131 -0
  72. package/dist/components/notebooks/DeleteDocumentModal.esm.js.map +1 -0
  73. package/dist/components/notebooks/DeleteNotebookModal.esm.js +143 -0
  74. package/dist/components/notebooks/DeleteNotebookModal.esm.js.map +1 -0
  75. package/dist/components/notebooks/DocumentSidebar.esm.js +235 -0
  76. package/dist/components/notebooks/DocumentSidebar.esm.js.map +1 -0
  77. package/dist/components/notebooks/FileListItem.esm.js +94 -0
  78. package/dist/components/notebooks/FileListItem.esm.js.map +1 -0
  79. package/dist/components/notebooks/FileTypeIcon.esm.js +59 -0
  80. package/dist/components/notebooks/FileTypeIcon.esm.js.map +1 -0
  81. package/dist/components/notebooks/NotebookCard.esm.js +118 -0
  82. package/dist/components/notebooks/NotebookCard.esm.js.map +1 -0
  83. package/dist/components/notebooks/NotebookView.esm.js +681 -0
  84. package/dist/components/notebooks/NotebookView.esm.js.map +1 -0
  85. package/dist/components/notebooks/NotebooksTab.esm.js +71 -0
  86. package/dist/components/notebooks/NotebooksTab.esm.js.map +1 -0
  87. package/dist/components/notebooks/OverwriteConfirmModal.esm.js +142 -0
  88. package/dist/components/notebooks/OverwriteConfirmModal.esm.js.map +1 -0
  89. package/dist/components/notebooks/RenameNotebookModal.esm.js +187 -0
  90. package/dist/components/notebooks/RenameNotebookModal.esm.js.map +1 -0
  91. package/dist/components/notebooks/SidebarCollapseIcon.esm.js +50 -0
  92. package/dist/components/notebooks/SidebarCollapseIcon.esm.js.map +1 -0
  93. package/dist/components/notebooks/UploadResourceScreen.esm.js +79 -0
  94. package/dist/components/notebooks/UploadResourceScreen.esm.js.map +1 -0
  95. package/dist/const.esm.js +74 -0
  96. package/dist/const.esm.js.map +1 -0
  97. package/dist/dev.d.ts +2 -0
  98. package/dist/dev.esm.js +48 -0
  99. package/dist/dev.esm.js.map +1 -0
  100. package/dist/hooks/notebooks/useCreateNotebook.esm.js +19 -0
  101. package/dist/hooks/notebooks/useCreateNotebook.esm.js.map +1 -0
  102. package/dist/hooks/notebooks/useCreateNotebookMessage.esm.js +24 -0
  103. package/dist/hooks/notebooks/useCreateNotebookMessage.esm.js.map +1 -0
  104. package/dist/hooks/notebooks/useDeleteNotebook.esm.js +19 -0
  105. package/dist/hooks/notebooks/useDeleteNotebook.esm.js.map +1 -0
  106. package/dist/hooks/notebooks/useDocumentStatusPolling.esm.js +40 -0
  107. package/dist/hooks/notebooks/useDocumentStatusPolling.esm.js.map +1 -0
  108. package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js +15 -0
  109. package/dist/hooks/notebooks/useLightspeedNotebooksPermission.esm.js.map +1 -0
  110. package/dist/hooks/notebooks/useNotebookDocuments.esm.js +18 -0
  111. package/dist/hooks/notebooks/useNotebookDocuments.esm.js.map +1 -0
  112. package/dist/hooks/notebooks/useNotebookSession.esm.js +18 -0
  113. package/dist/hooks/notebooks/useNotebookSession.esm.js.map +1 -0
  114. package/dist/hooks/notebooks/useNotebookSessions.esm.js +18 -0
  115. package/dist/hooks/notebooks/useNotebookSessions.esm.js.map +1 -0
  116. package/dist/hooks/notebooks/useRenameNotebook.esm.js +19 -0
  117. package/dist/hooks/notebooks/useRenameNotebook.esm.js.map +1 -0
  118. package/dist/hooks/notebooks/useUploadDocument.esm.js +28 -0
  119. package/dist/hooks/notebooks/useUploadDocument.esm.js.map +1 -0
  120. package/dist/hooks/toolCallsCacheStore.esm.js +61 -0
  121. package/dist/hooks/toolCallsCacheStore.esm.js.map +1 -0
  122. package/dist/hooks/useAllModels.esm.js +20 -0
  123. package/dist/hooks/useAllModels.esm.js.map +1 -0
  124. package/dist/hooks/useAutoScroll.esm.js +78 -0
  125. package/dist/hooks/useAutoScroll.esm.js.map +1 -0
  126. package/dist/hooks/useBackstageUserIdentity.esm.js +14 -0
  127. package/dist/hooks/useBackstageUserIdentity.esm.js.map +1 -0
  128. package/dist/hooks/useBufferedMessages.esm.js +27 -0
  129. package/dist/hooks/useBufferedMessages.esm.js.map +1 -0
  130. package/dist/hooks/useCaptureFeedback.esm.js +21 -0
  131. package/dist/hooks/useCaptureFeedback.esm.js.map +1 -0
  132. package/dist/hooks/useConversationMessages.esm.js +544 -0
  133. package/dist/hooks/useConversationMessages.esm.js.map +1 -0
  134. package/dist/hooks/useConversations.esm.js +25 -0
  135. package/dist/hooks/useConversations.esm.js.map +1 -0
  136. package/dist/hooks/useCreateCoversationMessage.esm.js +33 -0
  137. package/dist/hooks/useCreateCoversationMessage.esm.js.map +1 -0
  138. package/dist/hooks/useDeleteConversation.esm.js +39 -0
  139. package/dist/hooks/useDeleteConversation.esm.js.map +1 -0
  140. package/dist/hooks/useDisplayModeSettings.esm.js +57 -0
  141. package/dist/hooks/useDisplayModeSettings.esm.js.map +1 -0
  142. package/dist/hooks/useFeedbackActions.esm.js +275 -0
  143. package/dist/hooks/useFeedbackActions.esm.js.map +1 -0
  144. package/dist/hooks/useFeedbackState.esm.js +93 -0
  145. package/dist/hooks/useFeedbackState.esm.js.map +1 -0
  146. package/dist/hooks/useFeedbackStatus.esm.js +14 -0
  147. package/dist/hooks/useFeedbackStatus.esm.js.map +1 -0
  148. package/dist/hooks/useIsMobile.esm.js +14 -0
  149. package/dist/hooks/useIsMobile.esm.js.map +1 -0
  150. package/dist/hooks/useLastOpenedConversation.esm.js +51 -0
  151. package/dist/hooks/useLastOpenedConversation.esm.js.map +1 -0
  152. package/dist/hooks/useLightspeedDeletePermission.esm.js +12 -0
  153. package/dist/hooks/useLightspeedDeletePermission.esm.js.map +1 -0
  154. package/dist/hooks/useLightspeedDrawerContext.esm.js +15 -0
  155. package/dist/hooks/useLightspeedDrawerContext.esm.js.map +1 -0
  156. package/dist/hooks/useLightspeedProviderState.esm.js +277 -0
  157. package/dist/hooks/useLightspeedProviderState.esm.js.map +1 -0
  158. package/dist/hooks/useLightspeedUpdatePermission.esm.js +12 -0
  159. package/dist/hooks/useLightspeedUpdatePermission.esm.js.map +1 -0
  160. package/dist/hooks/useLightspeedViewPermission.esm.js +18 -0
  161. package/dist/hooks/useLightspeedViewPermission.esm.js.map +1 -0
  162. package/dist/hooks/useNotebookConversationIds.esm.js +19 -0
  163. package/dist/hooks/useNotebookConversationIds.esm.js.map +1 -0
  164. package/dist/hooks/useNotebookWelcomePrompts.esm.js +14 -0
  165. package/dist/hooks/useNotebookWelcomePrompts.esm.js.map +1 -0
  166. package/dist/hooks/usePinnedChatsSettings.esm.js +118 -0
  167. package/dist/hooks/usePinnedChatsSettings.esm.js.map +1 -0
  168. package/dist/hooks/useQuestionValidation.esm.js +16 -0
  169. package/dist/hooks/useQuestionValidation.esm.js.map +1 -0
  170. package/dist/hooks/useRenameConversation.esm.js +44 -0
  171. package/dist/hooks/useRenameConversation.esm.js.map +1 -0
  172. package/dist/hooks/useSortSettings.esm.js +60 -0
  173. package/dist/hooks/useSortSettings.esm.js.map +1 -0
  174. package/dist/hooks/useStopConversation.esm.js +18 -0
  175. package/dist/hooks/useStopConversation.esm.js.map +1 -0
  176. package/dist/hooks/useTranslation.esm.js +7 -0
  177. package/dist/hooks/useTranslation.esm.js.map +1 -0
  178. package/dist/hooks/useWelcomePrompts.esm.js +36 -0
  179. package/dist/hooks/useWelcomePrompts.esm.js.map +1 -0
  180. package/dist/images/bot-avatar-dark.svg +4 -0
  181. package/dist/images/bot-avatar.svg +4 -0
  182. package/dist/images/permission-required.svg +319 -0
  183. package/dist/images/user-avatar.svg +4 -0
  184. package/dist/index.d.ts +113 -0
  185. package/dist/index.esm.js +137 -0
  186. package/dist/index.esm.js.map +1 -0
  187. package/dist/intelligent-assistant-fab-module.d.ts +4 -0
  188. package/dist/intelligent-assistant-fab-module.esm.js +2 -0
  189. package/dist/intelligent-assistant-fab-module.esm.js.map +1 -0
  190. package/dist/intelligent-assistant-translations-module.d.ts +4 -0
  191. package/dist/intelligent-assistant-translations-module.esm.js +2 -0
  192. package/dist/intelligent-assistant-translations-module.esm.js.map +1 -0
  193. package/dist/legacy.d.ts +75 -0
  194. package/dist/legacy.esm.js +13 -0
  195. package/dist/legacy.esm.js.map +1 -0
  196. package/dist/plugin.esm.js +84 -0
  197. package/dist/plugin.esm.js.map +1 -0
  198. package/dist/routes.esm.js +23 -0
  199. package/dist/routes.esm.js.map +1 -0
  200. package/dist/translations/de.esm.js +278 -0
  201. package/dist/translations/de.esm.js.map +1 -0
  202. package/dist/translations/es.esm.js +278 -0
  203. package/dist/translations/es.esm.js.map +1 -0
  204. package/dist/translations/fr.esm.js +278 -0
  205. package/dist/translations/fr.esm.js.map +1 -0
  206. package/dist/translations/index.esm.js +16 -0
  207. package/dist/translations/index.esm.js.map +1 -0
  208. package/dist/translations/it.esm.js +278 -0
  209. package/dist/translations/it.esm.js.map +1 -0
  210. package/dist/translations/ja.esm.js +278 -0
  211. package/dist/translations/ja.esm.js.map +1 -0
  212. package/dist/translations/ref.esm.js +315 -0
  213. package/dist/translations/ref.esm.js.map +1 -0
  214. package/dist/types.esm.js +9 -0
  215. package/dist/types.esm.js.map +1 -0
  216. package/dist/utils/attachment-utils.esm.js +30 -0
  217. package/dist/utils/attachment-utils.esm.js.map +1 -0
  218. package/dist/utils/formatToolResponseForMarkdown.esm.js +98 -0
  219. package/dist/utils/formatToolResponseForMarkdown.esm.js.map +1 -0
  220. package/dist/utils/generateClassName.esm.js +12 -0
  221. package/dist/utils/generateClassName.esm.js.map +1 -0
  222. package/dist/utils/lightspeed-chatbox-utils.esm.js +232 -0
  223. package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -0
  224. package/dist/utils/notebook-upload-utils.esm.js +48 -0
  225. package/dist/utils/notebook-upload-utils.esm.js.map +1 -0
  226. package/dist/utils/notebooks-utils.esm.js +25 -0
  227. package/dist/utils/notebooks-utils.esm.js.map +1 -0
  228. package/dist/utils/prompt-utils.esm.js +17 -0
  229. package/dist/utils/prompt-utils.esm.js.map +1 -0
  230. package/dist/utils/queryClient.esm.js +6 -0
  231. package/dist/utils/queryClient.esm.js.map +1 -0
  232. package/dist/utils/reasoningParser.esm.js +33 -0
  233. package/dist/utils/reasoningParser.esm.js.map +1 -0
  234. package/dist/utils/toolCallMapper.esm.js +15 -0
  235. package/dist/utils/toolCallMapper.esm.js.map +1 -0
  236. package/dist/utils/user-utils.esm.js +7 -0
  237. package/dist/utils/user-utils.esm.js.map +1 -0
  238. package/package.json +182 -0
@@ -0,0 +1,118 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useApi, storageApiRef } from '@backstage/core-plugin-api';
3
+ import { isGuestUser } from '../utils/user-utils.esm.js';
4
+
5
+ const BUCKET_NAME = "lightspeed";
6
+ const PINNED_ENABLED_KEY = "pinnedChatsEnabled";
7
+ const PINNED_CHATS_KEY = "pinnedChats";
8
+ const usePinnedChatsSettings = (user) => {
9
+ const storageApi = useApi(storageApiRef);
10
+ const bucket = storageApi.forBucket(BUCKET_NAME);
11
+ const [isPinningChatsEnabled, setIsPinningChatsEnabled] = useState(true);
12
+ const [pinnedChats, setPinnedChats] = useState([]);
13
+ const shouldPersist = !isGuestUser(user);
14
+ useEffect(() => {
15
+ if (!user) {
16
+ setIsPinningChatsEnabled(true);
17
+ setPinnedChats([]);
18
+ return void 0;
19
+ }
20
+ if (isGuestUser(user)) {
21
+ setIsPinningChatsEnabled(true);
22
+ setPinnedChats([]);
23
+ return void 0;
24
+ }
25
+ try {
26
+ const enabledSnapshot = bucket.snapshot(PINNED_ENABLED_KEY);
27
+ const chatsSnapshot = bucket.snapshot(PINNED_CHATS_KEY);
28
+ setIsPinningChatsEnabled(enabledSnapshot.value ?? true);
29
+ setPinnedChats(chatsSnapshot.value ?? []);
30
+ } catch (error) {
31
+ console.error("Error reading pinned chats settings from storage:", error);
32
+ }
33
+ const enabledSubscription = bucket.observe$(PINNED_ENABLED_KEY).subscribe({
34
+ next: (snapshot) => {
35
+ setIsPinningChatsEnabled(snapshot.value ?? true);
36
+ },
37
+ error: (error) => {
38
+ console.error("Error observing pinnedChatsEnabled:", error);
39
+ }
40
+ });
41
+ const chatsSubscription = bucket.observe$(PINNED_CHATS_KEY).subscribe({
42
+ next: (snapshot) => {
43
+ setPinnedChats(snapshot.value ?? []);
44
+ },
45
+ error: (error) => {
46
+ console.error("Error observing pinnedChats:", error);
47
+ }
48
+ });
49
+ return () => {
50
+ enabledSubscription.unsubscribe();
51
+ chatsSubscription.unsubscribe();
52
+ };
53
+ }, [bucket, user]);
54
+ const handlePinningChatsToggle = useCallback(
55
+ (enabled) => {
56
+ if (!user) return;
57
+ setIsPinningChatsEnabled(enabled);
58
+ if (!enabled) {
59
+ setPinnedChats([]);
60
+ }
61
+ if (shouldPersist) {
62
+ try {
63
+ bucket.set(PINNED_ENABLED_KEY, enabled);
64
+ if (!enabled) {
65
+ bucket.set(PINNED_CHATS_KEY, []);
66
+ }
67
+ } catch (error) {
68
+ console.error("Error saving pinning toggle state:", error);
69
+ }
70
+ }
71
+ },
72
+ [bucket, user, shouldPersist]
73
+ );
74
+ const pinChat = useCallback(
75
+ (convId) => {
76
+ if (!user) return;
77
+ setPinnedChats((prev) => {
78
+ const updated = [...prev, convId];
79
+ if (shouldPersist) {
80
+ try {
81
+ bucket.set(PINNED_CHATS_KEY, updated);
82
+ } catch (error) {
83
+ console.error("Error saving pinned chat:", error);
84
+ }
85
+ }
86
+ return updated;
87
+ });
88
+ },
89
+ [bucket, user, shouldPersist]
90
+ );
91
+ const unpinChat = useCallback(
92
+ (convId) => {
93
+ if (!user) return;
94
+ setPinnedChats((prev) => {
95
+ const updated = prev.filter((id) => id !== convId);
96
+ if (shouldPersist) {
97
+ try {
98
+ bucket.set(PINNED_CHATS_KEY, updated);
99
+ } catch (error) {
100
+ console.error("Error saving unpinned chat:", error);
101
+ }
102
+ }
103
+ return updated;
104
+ });
105
+ },
106
+ [bucket, user, shouldPersist]
107
+ );
108
+ return {
109
+ isPinningChatsEnabled,
110
+ pinnedChats,
111
+ handlePinningChatsToggle,
112
+ pinChat,
113
+ unpinChat
114
+ };
115
+ };
116
+
117
+ export { usePinnedChatsSettings };
118
+ //# sourceMappingURL=usePinnedChatsSettings.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePinnedChatsSettings.esm.js","sources":["../../src/hooks/usePinnedChatsSettings.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 { useCallback, useEffect, useState } from 'react';\n\nimport { storageApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { isGuestUser } from '../utils/user-utils';\n\nconst BUCKET_NAME = 'lightspeed';\nconst PINNED_ENABLED_KEY = 'pinnedChatsEnabled';\nconst PINNED_CHATS_KEY = 'pinnedChats';\n\ntype UsePinnedChatsSettingsReturn = {\n isPinningChatsEnabled: boolean;\n pinnedChats: string[];\n handlePinningChatsToggle: (enabled: boolean) => void;\n pinChat: (convId: string) => void;\n unpinChat: (convId: string) => void;\n};\n\n/**\n * Hook to manage pinned chats settings with persistence using Backstage StorageApi.\n * Settings are automatically scoped per-user by the StorageApi backend when using\n * database persistence. For guest users, settings are only kept in local state\n * and not persisted.\n *\n * @param user - The user entity ref (e.g., \"user:default/john\")\n * @returns Object containing pinned chats state and management functions\n */\nexport const usePinnedChatsSettings = (\n user: string | undefined,\n): UsePinnedChatsSettingsReturn => {\n const storageApi = useApi(storageApiRef);\n const bucket = storageApi.forBucket(BUCKET_NAME);\n\n const [isPinningChatsEnabled, setIsPinningChatsEnabled] = useState(true);\n const [pinnedChats, setPinnedChats] = useState<string[]>([]);\n\n // Determine if we should persist settings (not for guest users)\n const shouldPersist = !isGuestUser(user);\n\n // Initialize from storage and subscribe to changes\n useEffect(() => {\n if (!user) {\n setIsPinningChatsEnabled(true);\n setPinnedChats([]);\n return undefined;\n }\n\n // For guest users, use default values without loading from storage\n if (isGuestUser(user)) {\n setIsPinningChatsEnabled(true);\n setPinnedChats([]);\n return undefined;\n }\n\n // Load initial values from snapshot (works for browser mode)\n try {\n const enabledSnapshot = bucket.snapshot<boolean>(PINNED_ENABLED_KEY);\n const chatsSnapshot = bucket.snapshot<string[]>(PINNED_CHATS_KEY);\n\n setIsPinningChatsEnabled(enabledSnapshot.value ?? true);\n setPinnedChats(chatsSnapshot.value ?? []);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error reading pinned chats settings from storage:', error);\n }\n\n // Subscribe to changes (needed for database mode cross-tab sync)\n const enabledSubscription = bucket\n .observe$<boolean>(PINNED_ENABLED_KEY)\n .subscribe({\n next: snapshot => {\n setIsPinningChatsEnabled(snapshot.value ?? true);\n },\n error: error => {\n // eslint-disable-next-line no-console\n console.error('Error observing pinnedChatsEnabled:', error);\n },\n });\n\n const chatsSubscription = bucket\n .observe$<string[]>(PINNED_CHATS_KEY)\n .subscribe({\n next: snapshot => {\n setPinnedChats(snapshot.value ?? []);\n },\n error: error => {\n // eslint-disable-next-line no-console\n console.error('Error observing pinnedChats:', error);\n },\n });\n\n return () => {\n enabledSubscription.unsubscribe();\n chatsSubscription.unsubscribe();\n };\n }, [bucket, user]);\n\n // Toggle pinning feature on/off\n const handlePinningChatsToggle = useCallback(\n (enabled: boolean) => {\n if (!user) return;\n\n setIsPinningChatsEnabled(enabled);\n\n // Clear pinned chats when disabling\n if (!enabled) {\n setPinnedChats([]);\n }\n\n // Only persist for non-guest users\n if (shouldPersist) {\n try {\n bucket.set(PINNED_ENABLED_KEY, enabled);\n\n // Clear pinned chats in storage when disabling\n if (!enabled) {\n bucket.set(PINNED_CHATS_KEY, []);\n }\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error saving pinning toggle state:', error);\n }\n }\n },\n [bucket, user, shouldPersist],\n );\n\n // Pin a chat\n const pinChat = useCallback(\n (convId: string) => {\n if (!user) return;\n\n setPinnedChats(prev => {\n const updated = [...prev, convId];\n\n // Only persist for non-guest users\n if (shouldPersist) {\n try {\n bucket.set(PINNED_CHATS_KEY, updated);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error saving pinned chat:', error);\n }\n }\n\n return updated;\n });\n },\n [bucket, user, shouldPersist],\n );\n\n // Unpin a chat\n const unpinChat = useCallback(\n (convId: string) => {\n if (!user) return;\n\n setPinnedChats(prev => {\n const updated = prev.filter(id => id !== convId);\n\n // Only persist for non-guest users\n if (shouldPersist) {\n try {\n bucket.set(PINNED_CHATS_KEY, updated);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error saving unpinned chat:', error);\n }\n }\n\n return updated;\n });\n },\n [bucket, user, shouldPersist],\n );\n\n return {\n isPinningChatsEnabled,\n pinnedChats,\n handlePinningChatsToggle,\n pinChat,\n unpinChat,\n };\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
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 useTopicRestrictionStatus = () => {
6
+ const lightspeedApi = useApi(lightspeedApiRef);
7
+ return useQuery({
8
+ queryKey: ["topicRestrictionStatus"],
9
+ queryFn: async () => {
10
+ return await lightspeedApi.isTopicRestrictionEnabled();
11
+ }
12
+ });
13
+ };
14
+
15
+ export { useTopicRestrictionStatus };
16
+ //# sourceMappingURL=useQuestionValidation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQuestionValidation.esm.js","sources":["../../src/hooks/useQuestionValidation.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 { useApi } from '@backstage/core-plugin-api';\n\nimport { useQuery, type UseQueryResult } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\n\nexport const useTopicRestrictionStatus = (): UseQueryResult<boolean, Error> => {\n const lightspeedApi = useApi(lightspeedApiRef);\n return useQuery({\n queryKey: ['topicRestrictionStatus'],\n queryFn: async () => {\n return await lightspeedApi.isTopicRestrictionEnabled();\n },\n });\n};\n"],"names":[],"mappings":";;;;AAsBO,MAAM,4BAA4B,MAAsC;AAC7E,EAAA,MAAM,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,OAAO,QAAA,CAAS;AAAA,IACd,QAAA,EAAU,CAAC,wBAAwB,CAAA;AAAA,IACnC,SAAS,YAAY;AACnB,MAAA,OAAO,MAAM,cAAc,yBAAA,EAA0B;AAAA,IACvD;AAAA,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,44 @@
1
+ import { useApi } from '@backstage/core-plugin-api';
2
+ import { useQueryClient, useMutation } from '@tanstack/react-query';
3
+ import { lightspeedApiRef } from '../api/api.esm.js';
4
+
5
+ const useRenameConversation = () => {
6
+ const lightspeedApi = useApi(lightspeedApiRef);
7
+ const queryClient = useQueryClient();
8
+ return useMutation({
9
+ mutationFn: async (props) => {
10
+ await lightspeedApi.renameConversation(
11
+ props.conversation_id,
12
+ props.newName
13
+ );
14
+ },
15
+ onMutate: async (props) => {
16
+ await queryClient.cancelQueries({ queryKey: ["conversations"] });
17
+ const previousConversations = queryClient.getQueryData([
18
+ "conversations"
19
+ ]);
20
+ queryClient.setQueryData(
21
+ ["conversations"],
22
+ (old) => old.map(
23
+ (c) => c.conversation_id === props.conversation_id ? { ...c, topic_summary: props.newName } : c
24
+ )
25
+ );
26
+ return { previousConversations };
27
+ },
28
+ onSuccess: (_, props) => {
29
+ if (props.invalidateCache) {
30
+ queryClient.invalidateQueries({ queryKey: ["conversations"] });
31
+ }
32
+ },
33
+ onError: (_, __, context) => {
34
+ queryClient.setQueryData(
35
+ ["conversations"],
36
+ context?.previousConversations
37
+ );
38
+ return { success: false };
39
+ }
40
+ });
41
+ };
42
+
43
+ export { useRenameConversation };
44
+ //# sourceMappingURL=useRenameConversation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenameConversation.esm.js","sources":["../../src/hooks/useRenameConversation.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 { useApi } from '@backstage/core-plugin-api';\n\nimport {\n useMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\nimport { ConversationList } from '../types';\n\ntype RenameVariables = {\n conversation_id: string;\n newName: string;\n invalidateCache?: boolean;\n};\n\ntype RenameContext = {\n previousConversations?: ConversationList;\n};\n\nexport const useRenameConversation = (): UseMutationResult<\n void,\n Error,\n RenameVariables,\n RenameContext\n> => {\n const lightspeedApi = useApi(lightspeedApiRef);\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async (props: {\n conversation_id: string;\n newName: string;\n invalidateCache?: boolean;\n }) => {\n await lightspeedApi.renameConversation(\n props.conversation_id,\n props.newName,\n );\n },\n onMutate: async props => {\n await queryClient.cancelQueries({ queryKey: ['conversations'] });\n\n const previousConversations = queryClient.getQueryData<ConversationList>([\n 'conversations',\n ]);\n\n queryClient.setQueryData(['conversations'], (old: ConversationList) =>\n old.map(c =>\n c.conversation_id === props.conversation_id\n ? { ...c, topic_summary: props.newName }\n : c,\n ),\n );\n\n return { previousConversations };\n },\n onSuccess: (_, props) => {\n if (props.invalidateCache) {\n queryClient.invalidateQueries({ queryKey: ['conversations'] });\n }\n },\n onError: (_, __, context) => {\n queryClient.setQueryData(\n ['conversations'],\n context?.previousConversations,\n );\n return { success: false };\n },\n });\n};\n"],"names":[],"mappings":";;;;AAqCO,MAAM,wBAAwB,MAKhC;AACH,EAAA,MAAM,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,MAAM,cAAc,cAAA,EAAe;AAEnC,EAAA,OAAO,WAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,KAAA,KAIb;AACJ,MAAA,MAAM,aAAA,CAAc,kBAAA;AAAA,QAClB,KAAA,CAAM,eAAA;AAAA,QACN,KAAA,CAAM;AAAA,OACR;AAAA,IACF,CAAA;AAAA,IACA,QAAA,EAAU,OAAM,KAAA,KAAS;AACvB,MAAA,MAAM,YAAY,aAAA,CAAc,EAAE,UAAU,CAAC,eAAe,GAAG,CAAA;AAE/D,MAAA,MAAM,qBAAA,GAAwB,YAAY,YAAA,CAA+B;AAAA,QACvE;AAAA,OACD,CAAA;AAED,MAAA,WAAA,CAAY,YAAA;AAAA,QAAa,CAAC,eAAe,CAAA;AAAA,QAAG,CAAC,QAC3C,GAAA,CAAI,GAAA;AAAA,UAAI,CAAA,CAAA,KACN,CAAA,CAAE,eAAA,KAAoB,KAAA,CAAM,eAAA,GACxB,EAAE,GAAG,CAAA,EAAG,aAAA,EAAe,KAAA,CAAM,OAAA,EAAQ,GACrC;AAAA;AACN,OACF;AAEA,MAAA,OAAO,EAAE,qBAAA,EAAsB;AAAA,IACjC,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,EAAG,KAAA,KAAU;AACvB,MAAA,IAAI,MAAM,eAAA,EAAiB;AACzB,QAAA,WAAA,CAAY,kBAAkB,EAAE,QAAA,EAAU,CAAC,eAAe,GAAG,CAAA;AAAA,MAC/D;AAAA,IACF,CAAA;AAAA,IACA,OAAA,EAAS,CAAC,CAAA,EAAG,EAAA,EAAI,OAAA,KAAY;AAC3B,MAAA,WAAA,CAAY,YAAA;AAAA,QACV,CAAC,eAAe,CAAA;AAAA,QAChB,OAAA,EAAS;AAAA,OACX;AACA,MAAA,OAAO,EAAE,SAAS,KAAA,EAAM;AAAA,IAC1B;AAAA,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,60 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useApi, storageApiRef } from '@backstage/core-plugin-api';
3
+ import { isGuestUser } from '../utils/user-utils.esm.js';
4
+
5
+ const BUCKET_NAME = "lightspeed";
6
+ const SORT_ORDER_KEY = "sortOrder";
7
+ const useSortSettings = (user) => {
8
+ const storageApi = useApi(storageApiRef);
9
+ const bucket = storageApi.forBucket(BUCKET_NAME);
10
+ const [selectedSort, setSelectedSort] = useState("newest");
11
+ const shouldPersist = !isGuestUser(user);
12
+ useEffect(() => {
13
+ if (!user) {
14
+ setSelectedSort("newest");
15
+ return void 0;
16
+ }
17
+ if (isGuestUser(user)) {
18
+ setSelectedSort("newest");
19
+ return void 0;
20
+ }
21
+ try {
22
+ const sortSnapshot = bucket.snapshot(SORT_ORDER_KEY);
23
+ setSelectedSort(sortSnapshot.value ?? "newest");
24
+ } catch (error) {
25
+ console.error("Error reading sort order from storage:", error);
26
+ }
27
+ const sortSubscription = bucket.observe$(SORT_ORDER_KEY).subscribe({
28
+ next: (snapshot) => {
29
+ setSelectedSort(snapshot.value ?? "newest");
30
+ },
31
+ error: (error) => {
32
+ console.error("Error observing sortOrder:", error);
33
+ }
34
+ });
35
+ return () => {
36
+ sortSubscription.unsubscribe();
37
+ };
38
+ }, [bucket, user]);
39
+ const handleSortChange = useCallback(
40
+ (sortOption) => {
41
+ if (!user) return;
42
+ setSelectedSort(sortOption);
43
+ if (shouldPersist) {
44
+ try {
45
+ bucket.set(SORT_ORDER_KEY, sortOption);
46
+ } catch (error) {
47
+ console.error("Error saving sort order:", error);
48
+ }
49
+ }
50
+ },
51
+ [bucket, user, shouldPersist]
52
+ );
53
+ return {
54
+ selectedSort,
55
+ handleSortChange
56
+ };
57
+ };
58
+
59
+ export { useSortSettings };
60
+ //# sourceMappingURL=useSortSettings.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSortSettings.esm.js","sources":["../../src/hooks/useSortSettings.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 { useCallback, useEffect, useState } from 'react';\n\nimport { storageApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { SortOption } from '../utils/lightspeed-chatbox-utils';\nimport { isGuestUser } from '../utils/user-utils';\n\nconst BUCKET_NAME = 'lightspeed';\nconst SORT_ORDER_KEY = 'sortOrder';\n\ntype UseSortSettingsReturn = {\n selectedSort: SortOption;\n handleSortChange: (sortOption: SortOption) => void;\n};\n\n/**\n * Hook to manage sort order settings with persistence using Backstage StorageApi.\n * Settings are automatically scoped per-user by the StorageApi backend when using\n * database persistence. For guest users, settings are only kept in local state\n * and not persisted.\n *\n * @param user - The user entity ref (e.g., \"user:default/john\")\n * @returns Object containing sort state and management function\n */\nexport const useSortSettings = (\n user: string | undefined,\n): UseSortSettingsReturn => {\n const storageApi = useApi(storageApiRef);\n const bucket = storageApi.forBucket(BUCKET_NAME);\n\n const [selectedSort, setSelectedSort] = useState<SortOption>('newest');\n\n // Determine if we should persist settings (not for guest users)\n const shouldPersist = !isGuestUser(user);\n\n // Initialize from storage and subscribe to changes\n useEffect(() => {\n if (!user) {\n setSelectedSort('newest');\n return undefined;\n }\n\n // For guest users, use default values without loading from storage\n if (isGuestUser(user)) {\n setSelectedSort('newest');\n return undefined;\n }\n\n // Load initial value from snapshot (works for browser mode)\n try {\n const sortSnapshot = bucket.snapshot<SortOption>(SORT_ORDER_KEY);\n setSelectedSort(sortSnapshot.value ?? 'newest');\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error reading sort order from storage:', error);\n }\n\n // Subscribe to changes (needed for database mode cross-tab sync)\n const sortSubscription = bucket\n .observe$<SortOption>(SORT_ORDER_KEY)\n .subscribe({\n next: snapshot => {\n setSelectedSort(snapshot.value ?? 'newest');\n },\n error: error => {\n // eslint-disable-next-line no-console\n console.error('Error observing sortOrder:', error);\n },\n });\n\n return () => {\n sortSubscription.unsubscribe();\n };\n }, [bucket, user]);\n\n // Change sort order\n const handleSortChange = useCallback(\n (sortOption: SortOption) => {\n if (!user) return;\n\n setSelectedSort(sortOption);\n\n // Only persist for non-guest users\n if (shouldPersist) {\n try {\n bucket.set(SORT_ORDER_KEY, sortOption);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error saving sort order:', error);\n }\n }\n },\n [bucket, user, shouldPersist],\n );\n\n return {\n selectedSort,\n handleSortChange,\n };\n};\n"],"names":[],"mappings":";;;;AAsBA,MAAM,WAAA,GAAc,YAAA;AACpB,MAAM,cAAA,GAAiB,WAAA;AAgBhB,MAAM,eAAA,GAAkB,CAC7B,IAAA,KAC0B;AAC1B,EAAA,MAAM,UAAA,GAAa,OAAO,aAAa,CAAA;AACvC,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,SAAA,CAAU,WAAW,CAAA;AAE/C,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAqB,QAAQ,CAAA;AAGrE,EAAA,MAAM,aAAA,GAAgB,CAAC,WAAA,CAAY,IAAI,CAAA;AAGvC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,eAAA,CAAgB,QAAQ,CAAA;AACxB,MAAA,OAAO,MAAA;AAAA,IACT;AAGA,IAAA,IAAI,WAAA,CAAY,IAAI,CAAA,EAAG;AACrB,MAAA,eAAA,CAAgB,QAAQ,CAAA;AACxB,MAAA,OAAO,MAAA;AAAA,IACT;AAGA,IAAA,IAAI;AACF,MAAA,MAAM,YAAA,GAAe,MAAA,CAAO,QAAA,CAAqB,cAAc,CAAA;AAC/D,MAAA,eAAA,CAAgB,YAAA,CAAa,SAAS,QAAQ,CAAA;AAAA,IAChD,SAAS,KAAA,EAAO;AAEd,MAAA,OAAA,CAAQ,KAAA,CAAM,0CAA0C,KAAK,CAAA;AAAA,IAC/D;AAGA,IAAA,MAAM,gBAAA,GAAmB,MAAA,CACtB,QAAA,CAAqB,cAAc,EACnC,SAAA,CAAU;AAAA,MACT,MAAM,CAAA,QAAA,KAAY;AAChB,QAAA,eAAA,CAAgB,QAAA,CAAS,SAAS,QAAQ,CAAA;AAAA,MAC5C,CAAA;AAAA,MACA,OAAO,CAAA,KAAA,KAAS;AAEd,QAAA,OAAA,CAAQ,KAAA,CAAM,8BAA8B,KAAK,CAAA;AAAA,MACnD;AAAA,KACD,CAAA;AAEH,IAAA,OAAO,MAAM;AACX,MAAA,gBAAA,CAAiB,WAAA,EAAY;AAAA,IAC/B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,IAAI,CAAC,CAAA;AAGjB,EAAA,MAAM,gBAAA,GAAmB,WAAA;AAAA,IACvB,CAAC,UAAA,KAA2B;AAC1B,MAAA,IAAI,CAAC,IAAA,EAAM;AAEX,MAAA,eAAA,CAAgB,UAAU,CAAA;AAG1B,MAAA,IAAI,aAAA,EAAe;AACjB,QAAA,IAAI;AACF,UAAA,MAAA,CAAO,GAAA,CAAI,gBAAgB,UAAU,CAAA;AAAA,QACvC,SAAS,KAAA,EAAO;AAEd,UAAA,OAAA,CAAQ,KAAA,CAAM,4BAA4B,KAAK,CAAA;AAAA,QACjD;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,IAAA,EAAM,aAAa;AAAA,GAC9B;AAEA,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,18 @@
1
+ import { useApi } from '@backstage/core-plugin-api';
2
+ import { useMutation } from '@tanstack/react-query';
3
+ import { lightspeedApiRef } from '../api/api.esm.js';
4
+
5
+ const useStopConversation = () => {
6
+ const lightspeedApi = useApi(lightspeedApiRef);
7
+ return useMutation({
8
+ mutationFn: async (requestId) => {
9
+ return await lightspeedApi.stopMessage(requestId);
10
+ },
11
+ onError: (error) => {
12
+ console.warn(error);
13
+ }
14
+ });
15
+ };
16
+
17
+ export { useStopConversation };
18
+ //# sourceMappingURL=useStopConversation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStopConversation.esm.js","sources":["../../src/hooks/useStopConversation.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 { useApi } from '@backstage/core-plugin-api';\n\nimport { useMutation, type UseMutationResult } from '@tanstack/react-query';\n\nimport { lightspeedApiRef } from '../api/api';\n\nexport const useStopConversation = (): UseMutationResult<\n { success: boolean },\n Error,\n string\n> => {\n const lightspeedApi = useApi(lightspeedApiRef);\n\n return useMutation({\n mutationFn: async (requestId: string) => {\n return await lightspeedApi.stopMessage(requestId);\n },\n onError: error => {\n // eslint-disable-next-line no-console\n console.warn(error);\n },\n });\n};\n"],"names":[],"mappings":";;;;AAsBO,MAAM,sBAAsB,MAI9B;AACH,EAAA,MAAM,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAE7C,EAAA,OAAO,WAAA,CAAY;AAAA,IACjB,UAAA,EAAY,OAAO,SAAA,KAAsB;AACvC,MAAA,OAAO,MAAM,aAAA,CAAc,WAAA,CAAY,SAAS,CAAA;AAAA,IAClD,CAAA;AAAA,IACA,SAAS,CAAA,KAAA,KAAS;AAEhB,MAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,IACpB;AAAA,GACD,CAAA;AACH;;;;"}
@@ -0,0 +1,7 @@
1
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
2
+ import { intelligentAssistantTranslationRef } from '../translations/ref.esm.js';
3
+
4
+ const useTranslation = () => useTranslationRef(intelligentAssistantTranslationRef);
5
+
6
+ export { useTranslation };
7
+ //# sourceMappingURL=useTranslation.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslation.esm.js","sources":["../../src/hooks/useTranslation.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 {\n TranslationFunction,\n useTranslationRef,\n} from '@backstage/core-plugin-api/alpha';\n\nimport { intelligentAssistantTranslationRef } from '../translations/ref';\n\nexport const useTranslation = (): {\n t: TranslationFunction<typeof intelligentAssistantTranslationRef.T>;\n} => useTranslationRef(intelligentAssistantTranslationRef);\n"],"names":[],"mappings":";;;AAuBO,MAAM,cAAA,GAAiB,MAEzB,iBAAA,CAAkB,kCAAkC;;;;"}
@@ -0,0 +1,36 @@
1
+ import { useMemo } from 'react';
2
+ import { useApi, configApiRef } from '@backstage/core-plugin-api';
3
+ import { RHDH_SAMPLE_PROMPTS, DEFAULT_SAMPLE_PROMPTS } from '../const.esm.js';
4
+ import { getRandomSamplePrompts } from '../utils/prompt-utils.esm.js';
5
+ import { useTopicRestrictionStatus } from './useQuestionValidation.esm.js';
6
+ import { useTranslation } from './useTranslation.esm.js';
7
+
8
+ const useWelcomePrompts = () => {
9
+ const configApi = useApi(configApiRef);
10
+ const { t } = useTranslation();
11
+ const { data: questionValidationEnabled } = useTopicRestrictionStatus();
12
+ return useMemo(() => {
13
+ const translatePrompts = (prompts) => {
14
+ return prompts.map((prompt) => {
15
+ if ("titleKey" in prompt && "messageKey" in prompt) {
16
+ return {
17
+ title: t(prompt.titleKey, { defaultValue: prompt.titleKey }),
18
+ message: t(prompt.messageKey, {
19
+ defaultValue: prompt.messageKey
20
+ })
21
+ };
22
+ }
23
+ return prompt;
24
+ });
25
+ };
26
+ const DEFAULT_PROMPTS = questionValidationEnabled ? translatePrompts(RHDH_SAMPLE_PROMPTS) : translatePrompts([...DEFAULT_SAMPLE_PROMPTS, ...RHDH_SAMPLE_PROMPTS]);
27
+ const userConfiguredPrompts = (configApi?.getOptionalConfigArray("intelligent-assistant.prompts") ?? []).map((config) => ({
28
+ title: config.getString("title") ?? "",
29
+ message: config.getString("message") ?? ""
30
+ }));
31
+ return getRandomSamplePrompts(userConfiguredPrompts, DEFAULT_PROMPTS);
32
+ }, [configApi, t, questionValidationEnabled]);
33
+ };
34
+
35
+ export { useWelcomePrompts };
36
+ //# sourceMappingURL=useWelcomePrompts.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWelcomePrompts.esm.js","sources":["../../src/hooks/useWelcomePrompts.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 { useMemo } from 'react';\n\nimport { ConfigApi, configApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { DEFAULT_SAMPLE_PROMPTS, RHDH_SAMPLE_PROMPTS } from '../const';\nimport { SamplePrompt, SamplePrompts } from '../types';\nimport { getRandomSamplePrompts } from '../utils/prompt-utils';\nimport { useTopicRestrictionStatus } from './useQuestionValidation';\nimport { useTranslation } from './useTranslation';\n\nexport const useWelcomePrompts = (): SamplePrompts => {\n const configApi: ConfigApi = useApi(configApiRef);\n const { t } = useTranslation();\n const { data: questionValidationEnabled } = useTopicRestrictionStatus();\n\n return useMemo(() => {\n // Transform translation keys to actual prompts\n const translatePrompts = (prompts: SamplePrompts): SamplePrompts => {\n return prompts.map((prompt: SamplePrompt) => {\n if ('titleKey' in prompt && 'messageKey' in prompt) {\n return {\n title: t(prompt.titleKey as any, { defaultValue: prompt.titleKey }),\n message: t(prompt.messageKey as any, {\n defaultValue: prompt.messageKey,\n }),\n };\n }\n return prompt as { title: string; message: string };\n });\n };\n\n const DEFAULT_PROMPTS = questionValidationEnabled\n ? translatePrompts(RHDH_SAMPLE_PROMPTS)\n : translatePrompts([...DEFAULT_SAMPLE_PROMPTS, ...RHDH_SAMPLE_PROMPTS]);\n\n const userConfiguredPrompts: SamplePrompts = (\n configApi?.getOptionalConfigArray('intelligent-assistant.prompts') ?? []\n ).map(config => ({\n title: config.getString('title') ?? '',\n message: config.getString('message') ?? '',\n }));\n return getRandomSamplePrompts(userConfiguredPrompts, DEFAULT_PROMPTS);\n }, [configApi, t, questionValidationEnabled]);\n};\n"],"names":[],"mappings":";;;;;;;AA0BO,MAAM,oBAAoB,MAAqB;AACpD,EAAA,MAAM,SAAA,GAAuB,OAAO,YAAY,CAAA;AAChD,EAAA,MAAM,EAAE,CAAA,EAAE,GAAI,cAAA,EAAe;AAC7B,EAAA,MAAM,EAAE,IAAA,EAAM,yBAAA,EAA0B,GAAI,yBAAA,EAA0B;AAEtE,EAAA,OAAO,QAAQ,MAAM;AAEnB,IAAA,MAAM,gBAAA,GAAmB,CAAC,OAAA,KAA0C;AAClE,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAyB;AAC3C,QAAA,IAAI,UAAA,IAAc,MAAA,IAAU,YAAA,IAAgB,MAAA,EAAQ;AAClD,UAAA,OAAO;AAAA,YACL,KAAA,EAAO,EAAE,MAAA,CAAO,QAAA,EAAiB,EAAE,YAAA,EAAc,MAAA,CAAO,UAAU,CAAA;AAAA,YAClE,OAAA,EAAS,CAAA,CAAE,MAAA,CAAO,UAAA,EAAmB;AAAA,cACnC,cAAc,MAAA,CAAO;AAAA,aACtB;AAAA,WACH;AAAA,QACF;AACA,QAAA,OAAO,MAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB,yBAAA,GACpB,gBAAA,CAAiB,mBAAmB,CAAA,GACpC,gBAAA,CAAiB,CAAC,GAAG,sBAAA,EAAwB,GAAG,mBAAmB,CAAC,CAAA;AAExE,IAAA,MAAM,qBAAA,GAAA,CACJ,WAAW,sBAAA,CAAuB,+BAA+B,KAAK,EAAC,EACvE,IAAI,CAAA,MAAA,MAAW;AAAA,MACf,KAAA,EAAO,MAAA,CAAO,SAAA,CAAU,OAAO,CAAA,IAAK,EAAA;AAAA,MACpC,OAAA,EAAS,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA,IAAK;AAAA,KAC1C,CAAE,CAAA;AACF,IAAA,OAAO,sBAAA,CAAuB,uBAAuB,eAAe,CAAA;AAAA,EACtE,CAAA,EAAG,CAAC,SAAA,EAAW,CAAA,EAAG,yBAAyB,CAAC,CAAA;AAC9C;;;;"}
@@ -0,0 +1,4 @@
1
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="24" cy="24" r="24" fill="#29233B"/>
3
+ <path d="M36 17H25V14H26.75C27.4395 14 28 13.4395 28 12.75V8.25C28 7.56055 27.4395 7 26.75 7H21.25C20.5605 7 20 7.56055 20 8.25V12.75C20 13.4395 20.5605 14 21.25 14H23V17H12C10.3457 17 9 18.3457 9 20V32C9 33.6543 10.3457 35 12 35H36C37.6543 35 39 33.6543 39 32V20C39 18.3457 37.6543 17 36 17ZM22 9H26V12H22V9ZM37 32C37 32.5518 36.5518 33 36 33H12C11.4487 33 11 32.5518 11 32V20C11 19.4487 11.4487 19 12 19H36C36.5518 19 37 19.4487 37 20V32ZM16.75 23V25C16.75 25.4141 16.4141 25.75 16 25.75H14C13.5859 25.75 13.25 25.4141 13.25 25V23C13.25 22.5859 13.5859 22.25 14 22.25H16C16.4141 22.25 16.75 22.5859 16.75 23ZM34.75 23V25C34.75 25.4141 34.4141 25.75 34 25.75H32C31.5859 25.75 31.25 25.4141 31.25 25V23C31.25 22.5859 31.5859 22.25 32 22.25H34C34.4141 22.25 34.75 22.5859 34.75 23ZM27.6992 27.4746C27.9902 27.8613 27.9121 28.4092 27.5254 28.6992C26.502 29.4688 25.2832 29.875 24 29.875C22.7168 29.875 21.4976 29.4688 20.4741 28.6992C20.0874 28.4092 20.0098 27.8613 20.2998 27.4746C20.5903 27.0869 21.1396 27.0088 21.5249 27.3008C22.9614 28.3789 25.0371 28.3789 26.4746 27.3008C26.8613 27.0078 27.4102 27.0879 27.6992 27.4746Z" fill="#B2A3D6"/>
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="24" cy="24" r="24" fill="#F2F0FC"/>
3
+ <path d="M36 17H25V14H26.75C27.4395 14 28 13.4395 28 12.75V8.25C28 7.56055 27.4395 7 26.75 7H21.25C20.5605 7 20 7.56055 20 8.25V12.75C20 13.4395 20.5605 14 21.25 14H23V17H12C10.3457 17 9 18.3457 9 20V32C9 33.6543 10.3457 35 12 35H36C37.6543 35 39 33.6543 39 32V20C39 18.3457 37.6543 17 36 17ZM22 9H26V12H22V9ZM37 32C37 32.5518 36.5518 33 36 33H12C11.4487 33 11 32.5518 11 32V20C11 19.4487 11.4487 19 12 19H36C36.5518 19 37 19.4487 37 20V32ZM16.75 23V25C16.75 25.4141 16.4141 25.75 16 25.75H14C13.5859 25.75 13.25 25.4141 13.25 25V23C13.25 22.5859 13.5859 22.25 14 22.25H16C16.4141 22.25 16.75 22.5859 16.75 23ZM34.75 23V25C34.75 25.4141 34.4141 25.75 34 25.75H32C31.5859 25.75 31.25 25.4141 31.25 25V23C31.25 22.5859 31.5859 22.25 32 22.25H34C34.4141 22.25 34.75 22.5859 34.75 23ZM27.6992 27.4746C27.9902 27.8613 27.9121 28.4092 27.5254 28.6992C26.502 29.4688 25.2832 29.875 24 29.875C22.7168 29.875 21.4976 29.4688 20.4741 28.6992C20.0874 28.4092 20.0098 27.8613 20.2998 27.4746C20.5903 27.0869 21.1396 27.0088 21.5249 27.3008C22.9614 28.3789 25.0371 28.3789 26.4746 27.3008C26.8613 27.0078 27.4102 27.0879 27.6992 27.4746Z" fill="#6753AC"/>
4
+ </svg>