@red-hat-developer-hub/backstage-plugin-lightspeed 0.5.1 → 0.5.2
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.
- package/CHANGELOG.md +21 -0
- package/README.md +15 -0
- package/config.d.ts +21 -0
- package/dist/api/LightspeedApiClient.esm.js +3 -2
- package/dist/api/LightspeedApiClient.esm.js.map +1 -1
- package/dist/api/api.esm.js.map +1 -1
- package/dist/components/Attachment.esm.js +98 -0
- package/dist/components/Attachment.esm.js.map +1 -0
- package/dist/components/AttachmentContext.esm.js +105 -0
- package/dist/components/AttachmentContext.esm.js.map +1 -0
- package/dist/components/FilePreview.esm.js +59 -0
- package/dist/components/FilePreview.esm.js.map +1 -0
- package/dist/components/LightSpeedChat.esm.js +38 -20
- package/dist/components/LightSpeedChat.esm.js.map +1 -1
- package/dist/components/LightspeedChatBox.esm.js +24 -4
- package/dist/components/LightspeedChatBox.esm.js.map +1 -1
- package/dist/components/LightspeedPage.esm.js +3 -2
- package/dist/components/LightspeedPage.esm.js.map +1 -1
- package/dist/const.esm.js +58 -1
- package/dist/const.esm.js.map +1 -1
- package/dist/hooks/useConversationMessages.esm.js +32 -2
- package/dist/hooks/useConversationMessages.esm.js.map +1 -1
- package/dist/hooks/useCreateCoversationMessage.esm.js +4 -2
- package/dist/hooks/useCreateCoversationMessage.esm.js.map +1 -1
- package/dist/hooks/useWelcomePrompts.esm.js +20 -0
- package/dist/hooks/useWelcomePrompts.esm.js.map +1 -0
- package/dist/types.esm.js +9 -0
- package/dist/types.esm.js.map +1 -0
- package/dist/utils/attachment-utils.esm.js +23 -0
- package/dist/utils/attachment-utils.esm.js.map +1 -0
- package/dist/utils/lightspeed-chatbox-utils.esm.js +9 -4
- package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
- package/dist/utils/prompt-utils.esm.js +17 -0
- package/dist/utils/prompt-utils.esm.js.map +1 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
## @red-hat-developer-hub/backstage-plugin-lightspeed
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fe413e3: Functional disclaimer with topic restriction
|
|
8
|
+
- a9e5f32: Updated dependency `@openapitools/openapi-generator-cli` to `2.20.0`.
|
|
9
|
+
Updated dependency `prettier` to `3.5.3`.
|
|
10
|
+
Updated dependency `@redhat-developer/red-hat-developer-hub-theme` to `0.5.1`.
|
|
11
|
+
Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.6.0`.
|
|
12
|
+
Updated dependency `@janus-idp/cli` to `3.5.0`.
|
|
13
|
+
- 3a76aaf: Updated dependency `@patternfly/react-core` to `6.3.0-prerelease.4`.
|
|
14
|
+
- 002f7c9: Updated dependency `@testing-library/user-event` to `14.6.1`.
|
|
15
|
+
- ab6a532: Add configurable sample prompts
|
|
16
|
+
- dc4ff7c: Add file attachment support
|
|
17
|
+
Update functional and legal disclaimers
|
|
18
|
+
Add citation links in the bot response
|
|
19
|
+
Update initial user prompts
|
|
20
|
+
- db3257b: Upgrade PF chatbot
|
|
21
|
+
- Updated dependencies [a9e5f32]
|
|
22
|
+
- @red-hat-developer-hub/backstage-plugin-lightspeed-common@0.3.1
|
|
23
|
+
|
|
3
24
|
## 0.5.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -122,6 +122,21 @@ lightspeed:
|
|
|
122
122
|
- id: <server_id>
|
|
123
123
|
url: <server_URL>
|
|
124
124
|
token: <api_key>
|
|
125
|
+
questionValidation: true # Optional - To disable question (prompt) validation set it to false.
|
|
126
|
+
prompts: # optional
|
|
127
|
+
- title: <prompt_title>
|
|
128
|
+
- message: <prompt_message>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`questionValidation` is default to be enabled with topic restriction on RHDH related topics.
|
|
132
|
+
If you want to disable the validation, set the value to be `false`.
|
|
133
|
+
|
|
134
|
+
Example configuration to disable `questionValidation`:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
lightspeed:
|
|
138
|
+
questionValidation: false
|
|
139
|
+
servers: ... ...
|
|
125
140
|
```
|
|
126
141
|
|
|
127
142
|
---
|
package/config.d.ts
CHANGED
|
@@ -38,5 +38,26 @@ export interface Config {
|
|
|
38
38
|
*/
|
|
39
39
|
url: string;
|
|
40
40
|
}>;
|
|
41
|
+
/**
|
|
42
|
+
* query restriction validation (Enabled by default).
|
|
43
|
+
* @visibility frontend
|
|
44
|
+
*/
|
|
45
|
+
questionValidation?: boolean;
|
|
46
|
+
prompts?: Array</**
|
|
47
|
+
* @visibility frontend
|
|
48
|
+
*/
|
|
49
|
+
{
|
|
50
|
+
/**
|
|
51
|
+
* The title of the prompt.
|
|
52
|
+
* Displayed as the heading of the prompt.
|
|
53
|
+
* @visibility frontend
|
|
54
|
+
*/
|
|
55
|
+
title: string;
|
|
56
|
+
/**
|
|
57
|
+
* The main question or message shown in the prompt.
|
|
58
|
+
* @visibility frontend
|
|
59
|
+
*/
|
|
60
|
+
message: string;
|
|
61
|
+
}>;
|
|
41
62
|
};
|
|
42
63
|
}
|
|
@@ -13,7 +13,7 @@ class LightspeedApiClient {
|
|
|
13
13
|
getServerUrl() {
|
|
14
14
|
return `${this.configApi.getConfigArray("lightspeed.servers")[0].getOptionalString("url")}`;
|
|
15
15
|
}
|
|
16
|
-
async createMessage(prompt, selectedModel, conversation_id) {
|
|
16
|
+
async createMessage(prompt, selectedModel, conversation_id, attachments) {
|
|
17
17
|
const baseUrl = await this.getBaseUrl();
|
|
18
18
|
const response = await this.fetchApi.fetch(`${baseUrl}/v1/query`, {
|
|
19
19
|
method: "POST",
|
|
@@ -25,7 +25,8 @@ class LightspeedApiClient {
|
|
|
25
25
|
model: selectedModel,
|
|
26
26
|
provider: this.configApi.getConfigArray("lightspeed.servers")[0].getOptionalString("id"),
|
|
27
27
|
// Currently supports a single llm server
|
|
28
|
-
query: prompt
|
|
28
|
+
query: prompt,
|
|
29
|
+
attachments
|
|
29
30
|
})
|
|
30
31
|
});
|
|
31
32
|
if (!response.body) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LightspeedApiClient.esm.js","sources":["../../src/api/LightspeedApiClient.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 { ConfigApi, FetchApi } from '@backstage/core-plugin-api';\n\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport { LightspeedAPI } from './api';\n\nexport type Options = {\n configApi: ConfigApi;\n fetchApi: FetchApi;\n};\n\nexport class LightspeedApiClient implements LightspeedAPI {\n private readonly configApi: ConfigApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: Options) {\n this.configApi = options.configApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getBaseUrl() {\n return `${this.configApi.getString('backend.baseUrl')}/api/lightspeed`;\n }\n\n getServerUrl() {\n // Currently supports a single llm server\n return `${this.configApi\n .getConfigArray('lightspeed.servers')[0]\n .getOptionalString('url')}`;\n }\n\n async createMessage(\n prompt: string,\n selectedModel: string,\n conversation_id: string,\n ) {\n const baseUrl = await this.getBaseUrl();\n\n const response = await this.fetchApi.fetch(`${baseUrl}/v1/query`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n conversation_id:\n conversation_id === TEMP_CONVERSATION_ID\n ? undefined\n : conversation_id,\n model: selectedModel,\n provider: this.configApi\n .getConfigArray('lightspeed.servers')[0]\n .getOptionalString('id'), // Currently supports a single llm server\n query: prompt,\n }),\n });\n\n if (!response.body) {\n throw new Error('Readable stream is not supported or there is no body.');\n }\n\n if (!response.ok) {\n const body = await response.body.getReader();\n const reader = body.read();\n const decoder = new TextDecoder('utf-8');\n const text = await reader.then(({ done, value }) => {\n if (done) {\n return '';\n }\n return decoder.decode(value);\n });\n const errorMessage = JSON.parse(text);\n if (errorMessage?.error) {\n throw new Error(`failed to create message: ${errorMessage.error}`);\n }\n }\n return response.body.getReader();\n }\n\n private async fetcher(url: string) {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n throw new Error(\n `failed to fetch data, status ${response.status}: ${response.statusText}`,\n );\n }\n return response;\n }\n\n async getAllModels() {\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(`${baseUrl}/v1/models`);\n\n if (!result.ok) {\n throw new Error(\n `failed to get models, status ${result.status}: ${result.statusText}`,\n );\n }\n\n const response = await result.json();\n return response?.data ? response.data : [];\n }\n\n async getConversationMessages(conversation_id: string) {\n if (conversation_id === TEMP_CONVERSATION_ID) {\n return [];\n }\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(\n `${baseUrl}/conversations/${encodeURIComponent(conversation_id)}`,\n );\n if (!result.ok) {\n throw new Error(\n `failed to get conversation messages, status ${result.status}: ${result.statusText}`,\n );\n }\n const response = await result.json();\n return response.chat_history ?? [];\n }\n\n async getConversations() {\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(`${baseUrl}/conversations`);\n\n if (!result.ok) {\n throw new Error(\n `failed to get conversation, status ${result.status}: ${result.statusText}`,\n );\n }\n\n const response = await result.json();\n return response.conversations ?? [];\n }\n\n async deleteConversation(conversation_id: string) {\n const baseUrl = await this.getBaseUrl();\n\n const response = await this.fetchApi.fetch(\n `${baseUrl}/conversations/${encodeURIComponent(conversation_id)}`,\n {\n method: 'DELETE',\n headers: {},\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `failed to delete conversation, status ${response.status}: ${response.statusText}`,\n );\n }\n return { success: true };\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"LightspeedApiClient.esm.js","sources":["../../src/api/LightspeedApiClient.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 { ConfigApi, FetchApi } from '@backstage/core-plugin-api';\n\nimport { TEMP_CONVERSATION_ID } from '../const';\nimport { Attachment } from '../types';\nimport { LightspeedAPI } from './api';\n\nexport type Options = {\n configApi: ConfigApi;\n fetchApi: FetchApi;\n};\n\nexport class LightspeedApiClient implements LightspeedAPI {\n private readonly configApi: ConfigApi;\n private readonly fetchApi: FetchApi;\n\n constructor(options: Options) {\n this.configApi = options.configApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getBaseUrl() {\n return `${this.configApi.getString('backend.baseUrl')}/api/lightspeed`;\n }\n\n getServerUrl() {\n // Currently supports a single llm server\n return `${this.configApi\n .getConfigArray('lightspeed.servers')[0]\n .getOptionalString('url')}`;\n }\n\n async createMessage(\n prompt: string,\n selectedModel: string,\n conversation_id: string,\n attachments: Attachment[],\n ) {\n const baseUrl = await this.getBaseUrl();\n\n const response = await this.fetchApi.fetch(`${baseUrl}/v1/query`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n conversation_id:\n conversation_id === TEMP_CONVERSATION_ID\n ? undefined\n : conversation_id,\n model: selectedModel,\n provider: this.configApi\n .getConfigArray('lightspeed.servers')[0]\n .getOptionalString('id'), // Currently supports a single llm server\n query: prompt,\n attachments,\n }),\n });\n\n if (!response.body) {\n throw new Error('Readable stream is not supported or there is no body.');\n }\n\n if (!response.ok) {\n const body = await response.body.getReader();\n const reader = body.read();\n const decoder = new TextDecoder('utf-8');\n const text = await reader.then(({ done, value }) => {\n if (done) {\n return '';\n }\n return decoder.decode(value);\n });\n const errorMessage = JSON.parse(text);\n if (errorMessage?.error) {\n throw new Error(`failed to create message: ${errorMessage.error}`);\n }\n }\n return response.body.getReader();\n }\n\n private async fetcher(url: string) {\n const response = await this.fetchApi.fetch(url, {\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n throw new Error(\n `failed to fetch data, status ${response.status}: ${response.statusText}`,\n );\n }\n return response;\n }\n\n async getAllModels() {\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(`${baseUrl}/v1/models`);\n\n if (!result.ok) {\n throw new Error(\n `failed to get models, status ${result.status}: ${result.statusText}`,\n );\n }\n\n const response = await result.json();\n return response?.data ? response.data : [];\n }\n\n async getConversationMessages(conversation_id: string) {\n if (conversation_id === TEMP_CONVERSATION_ID) {\n return [];\n }\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(\n `${baseUrl}/conversations/${encodeURIComponent(conversation_id)}`,\n );\n if (!result.ok) {\n throw new Error(\n `failed to get conversation messages, status ${result.status}: ${result.statusText}`,\n );\n }\n const response = await result.json();\n return response.chat_history ?? [];\n }\n\n async getConversations() {\n const baseUrl = await this.getBaseUrl();\n const result = await this.fetcher(`${baseUrl}/conversations`);\n\n if (!result.ok) {\n throw new Error(\n `failed to get conversation, status ${result.status}: ${result.statusText}`,\n );\n }\n\n const response = await result.json();\n return response.conversations ?? [];\n }\n\n async deleteConversation(conversation_id: string) {\n const baseUrl = await this.getBaseUrl();\n\n const response = await this.fetchApi.fetch(\n `${baseUrl}/conversations/${encodeURIComponent(conversation_id)}`,\n {\n method: 'DELETE',\n headers: {},\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `failed to delete conversation, status ${response.status}: ${response.statusText}`,\n );\n }\n return { success: true };\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/api/api.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.esm.js","sources":["../../src/api/api.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 { createApiRef } from '@backstage/core-plugin-api';\n\nimport OpenAI from 'openai';\n\nimport { BaseMessage, ConversationList } from '../types';\n\nexport type LightspeedAPI = {\n getAllModels: () => Promise<OpenAI.Models.Model[]>;\n getConversationMessages: (conversation_id: string) => Promise<BaseMessage[]>;\n createMessage: (\n prompt: string,\n selectedModel: string,\n conversation_id: string,\n ) => Promise<ReadableStreamDefaultReader>;\n deleteConversation: (\n conversation_id: string,\n ) => Promise<{ success: boolean }>;\n getConversations: () => Promise<ConversationList>;\n};\n\nexport const lightspeedApiRef = createApiRef<LightspeedAPI>({\n id: 'plugin.lightspeed.service',\n});\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"api.esm.js","sources":["../../src/api/api.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 { createApiRef } from '@backstage/core-plugin-api';\n\nimport OpenAI from 'openai';\n\nimport { Attachment, BaseMessage, ConversationList } from '../types';\n\nexport type LightspeedAPI = {\n getAllModels: () => Promise<OpenAI.Models.Model[]>;\n getConversationMessages: (conversation_id: string) => Promise<BaseMessage[]>;\n createMessage: (\n prompt: string,\n selectedModel: string,\n conversation_id: string,\n attachments: Attachment[],\n ) => Promise<ReadableStreamDefaultReader>;\n deleteConversation: (\n conversation_id: string,\n ) => Promise<{ success: boolean }>;\n getConversations: () => Promise<ConversationList>;\n};\n\nexport const lightspeedApiRef = createApiRef<LightspeedAPI>({\n id: 'plugin.lightspeed.service',\n});\n"],"names":[],"mappings":";;AAqCO,MAAM,mBAAmB,YAA4B,CAAA;AAAA,EAC1D,EAAI,EAAA;AACN,CAAC;;;;"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { makeStyles } from '@material-ui/core';
|
|
3
|
+
import { PreviewAttachment, ChatbotDisplayMode, AttachmentEdit } from '@patternfly/chatbot';
|
|
4
|
+
import { useFileAttachmentContext } from './AttachmentContext.esm.js';
|
|
5
|
+
|
|
6
|
+
const useStyles = makeStyles(() => ({
|
|
7
|
+
modalFooter: {
|
|
8
|
+
"&>button": {
|
|
9
|
+
width: "12% !important"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}));
|
|
13
|
+
const Attachment = () => {
|
|
14
|
+
const {
|
|
15
|
+
currentFileContent,
|
|
16
|
+
setFileContents,
|
|
17
|
+
modalState,
|
|
18
|
+
setCurrentFileContent
|
|
19
|
+
} = useFileAttachmentContext();
|
|
20
|
+
const classes = useStyles();
|
|
21
|
+
if (!currentFileContent) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const {
|
|
25
|
+
previewModalKey,
|
|
26
|
+
isPreviewModalOpen,
|
|
27
|
+
isEditModalOpen,
|
|
28
|
+
setPreviewModalKey,
|
|
29
|
+
setIsEditModalOpen,
|
|
30
|
+
setIsPreviewModalOpen
|
|
31
|
+
} = modalState;
|
|
32
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
|
|
33
|
+
PreviewAttachment,
|
|
34
|
+
{
|
|
35
|
+
key: previewModalKey,
|
|
36
|
+
code: currentFileContent?.content,
|
|
37
|
+
fileName: currentFileContent?.name,
|
|
38
|
+
isModalOpen: isPreviewModalOpen,
|
|
39
|
+
secondaryActionButtonText: "Close",
|
|
40
|
+
modalFooterClassName: classes.modalFooter,
|
|
41
|
+
onEdit: () => {
|
|
42
|
+
setIsPreviewModalOpen(false);
|
|
43
|
+
setIsEditModalOpen(true);
|
|
44
|
+
},
|
|
45
|
+
onDismiss: () => {
|
|
46
|
+
setCurrentFileContent(undefined);
|
|
47
|
+
setIsPreviewModalOpen(false);
|
|
48
|
+
},
|
|
49
|
+
handleModalToggle: () => setIsPreviewModalOpen(false),
|
|
50
|
+
displayMode: ChatbotDisplayMode.fullscreen
|
|
51
|
+
}
|
|
52
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
53
|
+
AttachmentEdit,
|
|
54
|
+
{
|
|
55
|
+
key: currentFileContent?.content,
|
|
56
|
+
code: currentFileContent?.content,
|
|
57
|
+
fileName: currentFileContent?.name,
|
|
58
|
+
isModalOpen: isEditModalOpen,
|
|
59
|
+
modalFooterClassName: classes.modalFooter,
|
|
60
|
+
onSave: (_, content) => {
|
|
61
|
+
setCurrentFileContent({
|
|
62
|
+
...currentFileContent,
|
|
63
|
+
content
|
|
64
|
+
});
|
|
65
|
+
setFileContents((prev) => {
|
|
66
|
+
const existingIndex = prev.findIndex(
|
|
67
|
+
(f) => f.name === currentFileContent?.name
|
|
68
|
+
);
|
|
69
|
+
if (existingIndex !== -1) {
|
|
70
|
+
const updated = [...prev];
|
|
71
|
+
updated[existingIndex] = {
|
|
72
|
+
...updated[existingIndex],
|
|
73
|
+
content
|
|
74
|
+
};
|
|
75
|
+
return updated;
|
|
76
|
+
}
|
|
77
|
+
return [
|
|
78
|
+
...prev,
|
|
79
|
+
{
|
|
80
|
+
name: currentFileContent?.name,
|
|
81
|
+
type: currentFileContent?.type,
|
|
82
|
+
content
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
});
|
|
86
|
+
setPreviewModalKey((prev) => prev + 1);
|
|
87
|
+
setIsEditModalOpen(false);
|
|
88
|
+
setIsPreviewModalOpen(true);
|
|
89
|
+
},
|
|
90
|
+
onCancel: () => setCurrentFileContent(undefined),
|
|
91
|
+
handleModalToggle: () => setIsEditModalOpen(false),
|
|
92
|
+
displayMode: ChatbotDisplayMode.fullscreen
|
|
93
|
+
}
|
|
94
|
+
));
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export { Attachment as default };
|
|
98
|
+
//# sourceMappingURL=Attachment.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Attachment.esm.js","sources":["../../src/components/Attachment.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 React from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n AttachmentEdit,\n ChatbotDisplayMode,\n PreviewAttachment,\n} from '@patternfly/chatbot';\n\nimport { useFileAttachmentContext } from './AttachmentContext';\n\nconst useStyles = makeStyles(() => ({\n modalFooter: {\n '&>button': {\n width: '12% !important',\n },\n },\n}));\nconst Attachment = () => {\n const {\n currentFileContent,\n setFileContents,\n modalState,\n setCurrentFileContent,\n } = useFileAttachmentContext();\n const classes = useStyles();\n\n if (!currentFileContent) {\n return null;\n }\n const {\n previewModalKey,\n isPreviewModalOpen,\n isEditModalOpen,\n setPreviewModalKey,\n setIsEditModalOpen,\n setIsPreviewModalOpen,\n } = modalState;\n\n return (\n <>\n <PreviewAttachment\n key={previewModalKey}\n code={currentFileContent?.content}\n fileName={currentFileContent?.name}\n isModalOpen={isPreviewModalOpen}\n secondaryActionButtonText=\"Close\"\n modalFooterClassName={classes.modalFooter}\n onEdit={() => {\n setIsPreviewModalOpen(false);\n setIsEditModalOpen(true);\n }}\n onDismiss={() => {\n setCurrentFileContent(undefined);\n setIsPreviewModalOpen(false);\n }}\n handleModalToggle={() => setIsPreviewModalOpen(false)}\n displayMode={ChatbotDisplayMode.fullscreen}\n />\n <AttachmentEdit\n key={currentFileContent?.content}\n code={currentFileContent?.content}\n fileName={currentFileContent?.name}\n isModalOpen={isEditModalOpen}\n modalFooterClassName={classes.modalFooter}\n onSave={(_, content) => {\n setCurrentFileContent({\n ...currentFileContent,\n content,\n });\n setFileContents(prev => {\n const existingIndex = prev.findIndex(\n f => f.name === currentFileContent?.name,\n );\n\n if (existingIndex !== -1) {\n // Update the existing file's content\n const updated = [...prev];\n updated[existingIndex] = {\n ...updated[existingIndex],\n content: content as string,\n };\n return updated;\n }\n\n // File doesn't exist, add a new one\n return [\n ...prev,\n {\n name: currentFileContent?.name,\n type: currentFileContent?.type,\n content: content as string,\n },\n ];\n });\n\n setPreviewModalKey(prev => prev + 1);\n setIsEditModalOpen(false);\n setIsPreviewModalOpen(true);\n }}\n onCancel={() => setCurrentFileContent(undefined)}\n handleModalToggle={() => setIsEditModalOpen(false)}\n displayMode={ChatbotDisplayMode.fullscreen}\n />\n </>\n );\n};\n\nexport default Attachment;\n"],"names":["React"],"mappings":";;;;;AA0BA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,WAAa,EAAA;AAAA,IACX,UAAY,EAAA;AAAA,MACV,KAAO,EAAA;AAAA;AACT;AAEJ,CAAE,CAAA,CAAA;AACF,MAAM,aAAa,MAAM;AACvB,EAAM,MAAA;AAAA,IACJ,kBAAA;AAAA,IACA,eAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,MACE,wBAAyB,EAAA;AAC7B,EAAA,MAAM,UAAU,SAAU,EAAA;AAE1B,EAAA,IAAI,CAAC,kBAAoB,EAAA;AACvB,IAAO,OAAA,IAAA;AAAA;AAET,EAAM,MAAA;AAAA,IACJ,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA,GACE,GAAA,UAAA;AAEJ,EAAA,uBAEIA,cAAA,CAAA,aAAA,CAAAA,cAAA,CAAA,QAAA,EAAA,IAAA,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,GAAK,EAAA,eAAA;AAAA,MACL,MAAM,kBAAoB,EAAA,OAAA;AAAA,MAC1B,UAAU,kBAAoB,EAAA,IAAA;AAAA,MAC9B,WAAa,EAAA,kBAAA;AAAA,MACb,yBAA0B,EAAA,OAAA;AAAA,MAC1B,sBAAsB,OAAQ,CAAA,WAAA;AAAA,MAC9B,QAAQ,MAAM;AACZ,QAAA,qBAAA,CAAsB,KAAK,CAAA;AAC3B,QAAA,kBAAA,CAAmB,IAAI,CAAA;AAAA,OACzB;AAAA,MACA,WAAW,MAAM;AACf,QAAA,qBAAA,CAAsB,SAAS,CAAA;AAC/B,QAAA,qBAAA,CAAsB,KAAK,CAAA;AAAA,OAC7B;AAAA,MACA,iBAAA,EAAmB,MAAM,qBAAA,CAAsB,KAAK,CAAA;AAAA,MACpD,aAAa,kBAAmB,CAAA;AAAA;AAAA,GAElC,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,KAAK,kBAAoB,EAAA,OAAA;AAAA,MACzB,MAAM,kBAAoB,EAAA,OAAA;AAAA,MAC1B,UAAU,kBAAoB,EAAA,IAAA;AAAA,MAC9B,WAAa,EAAA,eAAA;AAAA,MACb,sBAAsB,OAAQ,CAAA,WAAA;AAAA,MAC9B,MAAA,EAAQ,CAAC,CAAA,EAAG,OAAY,KAAA;AACtB,QAAsB,qBAAA,CAAA;AAAA,UACpB,GAAG,kBAAA;AAAA,UACH;AAAA,SACD,CAAA;AACD,QAAA,eAAA,CAAgB,CAAQ,IAAA,KAAA;AACtB,UAAA,MAAM,gBAAgB,IAAK,CAAA,SAAA;AAAA,YACzB,CAAA,CAAA,KAAK,CAAE,CAAA,IAAA,KAAS,kBAAoB,EAAA;AAAA,WACtC;AAEA,UAAA,IAAI,kBAAkB,EAAI,EAAA;AAExB,YAAM,MAAA,OAAA,GAAU,CAAC,GAAG,IAAI,CAAA;AACxB,YAAA,OAAA,CAAQ,aAAa,CAAI,GAAA;AAAA,cACvB,GAAG,QAAQ,aAAa,CAAA;AAAA,cACxB;AAAA,aACF;AACA,YAAO,OAAA,OAAA;AAAA;AAIT,UAAO,OAAA;AAAA,YACL,GAAG,IAAA;AAAA,YACH;AAAA,cACE,MAAM,kBAAoB,EAAA,IAAA;AAAA,cAC1B,MAAM,kBAAoB,EAAA,IAAA;AAAA,cAC1B;AAAA;AACF,WACF;AAAA,SACD,CAAA;AAED,QAAmB,kBAAA,CAAA,CAAA,IAAA,KAAQ,OAAO,CAAC,CAAA;AACnC,QAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,QAAA,qBAAA,CAAsB,IAAI,CAAA;AAAA,OAC5B;AAAA,MACA,QAAA,EAAU,MAAM,qBAAA,CAAsB,SAAS,CAAA;AAAA,MAC/C,iBAAA,EAAmB,MAAM,kBAAA,CAAmB,KAAK,CAAA;AAAA,MACjD,aAAa,kBAAmB,CAAA;AAAA;AAAA,GAEpC,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { isSupportedFileType, readFileAsText } from '../utils/attachment-utils.esm.js';
|
|
3
|
+
|
|
4
|
+
const FileAttachmentContext = React__default.createContext(null);
|
|
5
|
+
const FileAttachmentContextProvider = ({ children }) => {
|
|
6
|
+
const [currentFileContent, setCurrentFileContent] = React__default.useState();
|
|
7
|
+
const [isLoadingFile, setIsLoadingFile] = React__default.useState({});
|
|
8
|
+
const [previewModalKey, setPreviewModalKey] = React__default.useState(0);
|
|
9
|
+
const [showAlert, setShowAlert] = React__default.useState(false);
|
|
10
|
+
const [uploadError, setUploadError] = React__default.useState({
|
|
11
|
+
message: null
|
|
12
|
+
});
|
|
13
|
+
const [fileContents, setFileContents] = React__default.useState([]);
|
|
14
|
+
const [isPreviewModalOpen, setIsPreviewModalOpen] = React__default.useState(false);
|
|
15
|
+
const [isEditModalOpen, setIsEditModalOpen] = React__default.useState(false);
|
|
16
|
+
const handleFileUpload = (fileArr) => {
|
|
17
|
+
const existingFile = fileContents.find(
|
|
18
|
+
(file) => file.name === fileArr[0].name
|
|
19
|
+
);
|
|
20
|
+
if (existingFile) {
|
|
21
|
+
setShowAlert(true);
|
|
22
|
+
setUploadError({ type: "info", message: "File already exists." });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
setIsLoadingFile({ [fileArr[0].name]: true });
|
|
26
|
+
if (fileArr.length > 1) {
|
|
27
|
+
setShowAlert(true);
|
|
28
|
+
setUploadError({
|
|
29
|
+
message: "Uploaded more than one file."
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!isSupportedFileType(fileArr[0])) {
|
|
34
|
+
setShowAlert(true);
|
|
35
|
+
setUploadError({
|
|
36
|
+
message: "Unsupported file type. Supported types are: .txt, .yaml, .json."
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (fileArr[0].size > 25e6) {
|
|
41
|
+
setShowAlert(true);
|
|
42
|
+
setUploadError({
|
|
43
|
+
message: "Your file size is too large. Please ensure that your file is less than 25 MB."
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
readFileAsText(fileArr[0]).then((data) => {
|
|
48
|
+
setFileContents((prev) => [
|
|
49
|
+
...prev,
|
|
50
|
+
{
|
|
51
|
+
name: fileArr[0].name,
|
|
52
|
+
type: fileArr[0].type,
|
|
53
|
+
content: data
|
|
54
|
+
}
|
|
55
|
+
]);
|
|
56
|
+
setShowAlert(false);
|
|
57
|
+
setUploadError({ message: null });
|
|
58
|
+
setIsLoadingFile({ [fileArr[0].name]: false });
|
|
59
|
+
}).catch((error) => {
|
|
60
|
+
setUploadError({
|
|
61
|
+
message: `Failed to read file: ${error.message}`
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const modalState = {
|
|
66
|
+
isPreviewModalOpen,
|
|
67
|
+
setIsPreviewModalOpen,
|
|
68
|
+
isEditModalOpen,
|
|
69
|
+
setIsEditModalOpen,
|
|
70
|
+
previewModalKey,
|
|
71
|
+
setPreviewModalKey
|
|
72
|
+
};
|
|
73
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
74
|
+
FileAttachmentContext.Provider,
|
|
75
|
+
{
|
|
76
|
+
value: {
|
|
77
|
+
modalState,
|
|
78
|
+
fileContents,
|
|
79
|
+
setFileContents,
|
|
80
|
+
handleFileUpload,
|
|
81
|
+
isLoadingFile,
|
|
82
|
+
showAlert,
|
|
83
|
+
uploadError,
|
|
84
|
+
setUploadError,
|
|
85
|
+
currentFileContent,
|
|
86
|
+
setCurrentFileContent
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
children
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
const useFileAttachmentContext = () => {
|
|
93
|
+
const context = React__default.useContext(
|
|
94
|
+
FileAttachmentContext
|
|
95
|
+
);
|
|
96
|
+
if (context === null) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"useFileAttachmentContext must be within a FileAttachmentContextProvider"
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export { FileAttachmentContext, FileAttachmentContextProvider as default, useFileAttachmentContext };
|
|
105
|
+
//# sourceMappingURL=AttachmentContext.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentContext.esm.js","sources":["../../src/components/AttachmentContext.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 React from 'react';\n\nimport { FileContent } from '../types';\nimport { isSupportedFileType, readFileAsText } from '../utils/attachment-utils';\n\ntype UploadError = { type?: 'info' | 'danger'; message: string | null };\ninterface FileAttachmentContextType {\n showAlert: boolean;\n uploadError: UploadError;\n fileContents: FileContent[];\n isLoadingFile: Record<string, boolean>;\n handleFileUpload: (files: File[]) => void;\n setFileContents: React.Dispatch<React.SetStateAction<FileContent[]>>;\n setUploadError: React.Dispatch<React.SetStateAction<UploadError>>;\n currentFileContent?: FileContent;\n setCurrentFileContent: React.Dispatch<\n React.SetStateAction<FileContent | undefined>\n >;\n modalState: {\n previewModalKey: number;\n setPreviewModalKey: React.Dispatch<React.SetStateAction<number>>;\n isPreviewModalOpen: boolean;\n setIsPreviewModalOpen: React.Dispatch<React.SetStateAction<boolean>>;\n isEditModalOpen: boolean;\n setIsEditModalOpen: React.Dispatch<React.SetStateAction<boolean>>;\n };\n}\n\nexport const FileAttachmentContext =\n React.createContext<FileAttachmentContextType | null>(null);\n\nconst FileAttachmentContextProvider: React.FC<{\n children: React.ReactNode;\n}> = ({ children }) => {\n const [currentFileContent, setCurrentFileContent] = React.useState<\n FileContent | undefined\n >();\n const [isLoadingFile, setIsLoadingFile] = React.useState<\n Record<string, boolean>\n >({});\n const [previewModalKey, setPreviewModalKey] = React.useState<number>(0);\n const [showAlert, setShowAlert] = React.useState<boolean>(false);\n const [uploadError, setUploadError] = React.useState<UploadError>({\n message: null,\n });\n const [fileContents, setFileContents] = React.useState<FileContent[]>([]);\n const [isPreviewModalOpen, setIsPreviewModalOpen] =\n React.useState<boolean>(false);\n const [isEditModalOpen, setIsEditModalOpen] = React.useState<boolean>(false);\n const handleFileUpload = (fileArr: File[]) => {\n const existingFile = fileContents.find(\n file => file.name === fileArr[0].name,\n );\n if (existingFile) {\n setShowAlert(true);\n setUploadError({ type: 'info', message: 'File already exists.' });\n return;\n }\n\n setIsLoadingFile({ [fileArr[0].name]: true });\n\n if (fileArr.length > 1) {\n setShowAlert(true);\n setUploadError({\n message: 'Uploaded more than one file.',\n });\n return;\n }\n if (!isSupportedFileType(fileArr[0])) {\n setShowAlert(true);\n setUploadError({\n message:\n 'Unsupported file type. Supported types are: .txt, .yaml, .json.',\n });\n return;\n }\n\n // this is 25MB in bytes; size is in bytes\n if (fileArr[0].size > 25000000) {\n setShowAlert(true);\n setUploadError({\n message:\n 'Your file size is too large. Please ensure that your file is less than 25 MB.',\n });\n return;\n }\n\n readFileAsText(fileArr[0])\n .then(data => {\n setFileContents(prev => [\n ...prev,\n {\n name: fileArr[0].name,\n type: fileArr[0].type,\n content: data as string,\n },\n ]);\n setShowAlert(false);\n setUploadError({ message: null });\n setIsLoadingFile({ [fileArr[0].name]: false });\n })\n .catch((error: DOMException) => {\n setUploadError({\n message: `Failed to read file: ${error.message}`,\n });\n });\n };\n\n const modalState = {\n isPreviewModalOpen,\n setIsPreviewModalOpen,\n isEditModalOpen,\n setIsEditModalOpen,\n previewModalKey,\n setPreviewModalKey,\n };\n return (\n <FileAttachmentContext.Provider\n value={{\n modalState,\n fileContents,\n setFileContents,\n handleFileUpload,\n isLoadingFile,\n showAlert,\n uploadError,\n setUploadError,\n currentFileContent,\n setCurrentFileContent,\n }}\n >\n {children}\n </FileAttachmentContext.Provider>\n );\n};\n\nexport default FileAttachmentContextProvider;\n\nexport const useFileAttachmentContext = (): FileAttachmentContextType => {\n const context = React.useContext<FileAttachmentContextType | null>(\n FileAttachmentContext,\n );\n\n if (context === null) {\n throw new Error(\n 'useFileAttachmentContext must be within a FileAttachmentContextProvider',\n );\n }\n\n return context;\n};\n"],"names":["React"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { Divider } from '@material-ui/core';
|
|
3
|
+
import { FileDetailsLabel, ChatbotAlert } from '@patternfly/chatbot';
|
|
4
|
+
import { useFileAttachmentContext } from './AttachmentContext.esm.js';
|
|
5
|
+
|
|
6
|
+
const FilePreview = () => {
|
|
7
|
+
const {
|
|
8
|
+
showAlert,
|
|
9
|
+
fileContents,
|
|
10
|
+
isLoadingFile,
|
|
11
|
+
uploadError,
|
|
12
|
+
modalState,
|
|
13
|
+
setFileContents,
|
|
14
|
+
setUploadError,
|
|
15
|
+
setCurrentFileContent
|
|
16
|
+
} = useFileAttachmentContext();
|
|
17
|
+
const { setIsEditModalOpen, setIsPreviewModalOpen, setPreviewModalKey } = modalState;
|
|
18
|
+
const onAttachmentClick = (_, name) => {
|
|
19
|
+
const file = fileContents?.find((f) => f.name === name);
|
|
20
|
+
setCurrentFileContent({
|
|
21
|
+
name,
|
|
22
|
+
type: file?.type ?? "text/plain",
|
|
23
|
+
content: file?.content ?? ""
|
|
24
|
+
});
|
|
25
|
+
setPreviewModalKey((prev) => prev + 1);
|
|
26
|
+
setIsEditModalOpen(false);
|
|
27
|
+
setIsPreviewModalOpen(true);
|
|
28
|
+
};
|
|
29
|
+
const removeFile = (indexToRemove) => {
|
|
30
|
+
setFileContents(
|
|
31
|
+
(prevContents) => prevContents.filter((_, index) => index !== indexToRemove)
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, fileContents.length > 0 && /* @__PURE__ */ React__default.createElement(Divider, null), fileContents && /* @__PURE__ */ React__default.createElement("div", { style: { display: "flex", gap: "10px" } }, fileContents.map((file, index) => /* @__PURE__ */ React__default.createElement(
|
|
35
|
+
FileDetailsLabel,
|
|
36
|
+
{
|
|
37
|
+
key: index,
|
|
38
|
+
fileName: file.name,
|
|
39
|
+
isLoading: isLoadingFile[file.name],
|
|
40
|
+
onClick: onAttachmentClick,
|
|
41
|
+
onClose: () => {
|
|
42
|
+
removeFile(index);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
))), showAlert && uploadError.message && /* @__PURE__ */ React__default.createElement(
|
|
46
|
+
ChatbotAlert,
|
|
47
|
+
{
|
|
48
|
+
component: "h4",
|
|
49
|
+
title: "File upload failed",
|
|
50
|
+
variant: uploadError.type ?? "danger",
|
|
51
|
+
isInline: true,
|
|
52
|
+
onClose: () => setUploadError({ message: null })
|
|
53
|
+
},
|
|
54
|
+
uploadError.message
|
|
55
|
+
));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { FilePreview as default };
|
|
59
|
+
//# sourceMappingURL=FilePreview.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilePreview.esm.js","sources":["../../src/components/FilePreview.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 React from 'react';\n\nimport { Divider } from '@material-ui/core';\nimport { ChatbotAlert, FileDetailsLabel } from '@patternfly/chatbot';\n\nimport { useFileAttachmentContext } from './AttachmentContext';\n\nconst FilePreview = () => {\n const {\n showAlert,\n fileContents,\n isLoadingFile,\n uploadError,\n modalState,\n setFileContents,\n setUploadError,\n setCurrentFileContent,\n } = useFileAttachmentContext();\n\n const { setIsEditModalOpen, setIsPreviewModalOpen, setPreviewModalKey } =\n modalState;\n\n const onAttachmentClick = (_: React.MouseEvent, name: string) => {\n const file = fileContents?.find(f => f.name === name);\n setCurrentFileContent({\n name,\n type: file?.type ?? 'text/plain',\n content: file?.content ?? '',\n });\n setPreviewModalKey(prev => prev + 1); // update key to re-render content\n setIsEditModalOpen(false);\n setIsPreviewModalOpen(true);\n };\n\n const removeFile = (indexToRemove: number) => {\n setFileContents(prevContents =>\n prevContents.filter((_, index) => index !== indexToRemove),\n );\n };\n\n return (\n <>\n {fileContents.length > 0 && <Divider />}\n {fileContents && (\n <div style={{ display: 'flex', gap: '10px' }}>\n {fileContents.map((file, index) => (\n <FileDetailsLabel\n key={index}\n fileName={file.name}\n isLoading={isLoadingFile[file.name]}\n onClick={onAttachmentClick}\n onClose={() => {\n removeFile(index);\n }}\n />\n ))}\n </div>\n )}\n {showAlert && uploadError.message && (\n <ChatbotAlert\n component=\"h4\"\n title=\"File upload failed\"\n variant={uploadError.type ?? 'danger'}\n isInline\n onClose={() => setUploadError({ message: null })}\n >\n {uploadError.message}\n </ChatbotAlert>\n )}\n </>\n );\n};\n\nexport default FilePreview;\n"],"names":["React"],"mappings":";;;;;AAsBA,MAAM,cAAc,MAAM;AACxB,EAAM,MAAA;AAAA,IACJ,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,MACE,wBAAyB,EAAA;AAE7B,EAAA,MAAM,EAAE,kBAAA,EAAoB,qBAAuB,EAAA,kBAAA,EACjD,GAAA,UAAA;AAEF,EAAM,MAAA,iBAAA,GAAoB,CAAC,CAAA,EAAqB,IAAiB,KAAA;AAC/D,IAAA,MAAM,OAAO,YAAc,EAAA,IAAA,CAAK,CAAK,CAAA,KAAA,CAAA,CAAE,SAAS,IAAI,CAAA;AACpD,IAAsB,qBAAA,CAAA;AAAA,MACpB,IAAA;AAAA,MACA,IAAA,EAAM,MAAM,IAAQ,IAAA,YAAA;AAAA,MACpB,OAAA,EAAS,MAAM,OAAW,IAAA;AAAA,KAC3B,CAAA;AACD,IAAmB,kBAAA,CAAA,CAAA,IAAA,KAAQ,OAAO,CAAC,CAAA;AACnC,IAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,IAAA,qBAAA,CAAsB,IAAI,CAAA;AAAA,GAC5B;AAEA,EAAM,MAAA,UAAA,GAAa,CAAC,aAA0B,KAAA;AAC5C,IAAA,eAAA;AAAA,MAAgB,kBACd,YAAa,CAAA,MAAA,CAAO,CAAC,CAAG,EAAA,KAAA,KAAU,UAAU,aAAa;AAAA,KAC3D;AAAA,GACF;AAEA,EACE,uBAAAA,cAAA,CAAA,aAAA,CAAAA,cAAA,CAAA,QAAA,EAAA,IAAA,EACG,aAAa,MAAS,GAAA,CAAA,iDAAM,OAAQ,EAAA,IAAA,CAAA,EACpC,gCACEA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,OAAO,EAAE,OAAA,EAAS,QAAQ,GAAK,EAAA,MAAA,MACjC,YAAa,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,KACvB,qBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,GAAK,EAAA,KAAA;AAAA,MACL,UAAU,IAAK,CAAA,IAAA;AAAA,MACf,SAAA,EAAW,aAAc,CAAA,IAAA,CAAK,IAAI,CAAA;AAAA,MAClC,OAAS,EAAA,iBAAA;AAAA,MACT,SAAS,MAAM;AACb,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA;AAClB;AAAA,GAEH,CACH,CAED,EAAA,SAAA,IAAa,YAAY,OACxB,oBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,SAAU,EAAA,IAAA;AAAA,MACV,KAAM,EAAA,oBAAA;AAAA,MACN,OAAA,EAAS,YAAY,IAAQ,IAAA,QAAA;AAAA,MAC7B,QAAQ,EAAA,IAAA;AAAA,MACR,SAAS,MAAM,cAAA,CAAe,EAAE,OAAA,EAAS,MAAM;AAAA,KAAA;AAAA,IAE9C,WAAY,CAAA;AAAA,GAGnB,CAAA;AAEJ;;;;"}
|
|
@@ -17,8 +17,13 @@ import { useLastOpenedConversation } from '../hooks/useLastOpenedConversation.es
|
|
|
17
17
|
import { useLightspeedDeletePermission } from '../hooks/useLightspeedDeletePermission.esm.js';
|
|
18
18
|
import '@backstage/plugin-permission-react';
|
|
19
19
|
import '@red-hat-developer-hub/backstage-plugin-lightspeed-common';
|
|
20
|
+
import { useWelcomePrompts } from '../hooks/useWelcomePrompts.esm.js';
|
|
21
|
+
import { getAttachments } from '../utils/attachment-utils.esm.js';
|
|
20
22
|
import { getCategorizeMessages, getFootnoteProps } from '../utils/lightspeed-chatbox-utils.esm.js';
|
|
23
|
+
import Attachment from './Attachment.esm.js';
|
|
24
|
+
import { useFileAttachmentContext } from './AttachmentContext.esm.js';
|
|
21
25
|
import { DeleteModal } from './DeleteModal.esm.js';
|
|
26
|
+
import FilePreview from './FilePreview.esm.js';
|
|
22
27
|
import { LightspeedChatBox } from './LightspeedChatBox.esm.js';
|
|
23
28
|
import { LightspeedChatBoxHeader } from './LightspeedChatBoxHeader.esm.js';
|
|
24
29
|
|
|
@@ -48,6 +53,11 @@ const useStyles = makeStyles((theme) => ({
|
|
|
48
53
|
width: "95% !important",
|
|
49
54
|
maxWidth: "unset !important"
|
|
50
55
|
}
|
|
56
|
+
},
|
|
57
|
+
footerPopover: {
|
|
58
|
+
"& img": {
|
|
59
|
+
maxWidth: "100%"
|
|
60
|
+
}
|
|
51
61
|
}
|
|
52
62
|
}));
|
|
53
63
|
const LightspeedChat = ({
|
|
@@ -71,6 +81,7 @@ const LightspeedChat = ({
|
|
|
71
81
|
const [targetConversationId, setTargetConversationId] = React__default.useState("");
|
|
72
82
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = React__default.useState(false);
|
|
73
83
|
const { isReady, lastOpenedId, setLastOpenedId, clearLastOpenedId } = useLastOpenedConversation(user);
|
|
84
|
+
const { fileContents, setFileContents, handleFileUpload } = useFileAttachmentContext();
|
|
74
85
|
React__default.useEffect(() => {
|
|
75
86
|
if (isReady && lastOpenedId !== null) {
|
|
76
87
|
setConversationId(lastOpenedId);
|
|
@@ -80,6 +91,7 @@ const LightspeedChat = ({
|
|
|
80
91
|
const { data: conversations = [] } = useConversations();
|
|
81
92
|
const { mutateAsync: deleteConversation } = useDeleteConversation();
|
|
82
93
|
const { allowed: hasDeleteAccess } = useLightspeedDeletePermission();
|
|
94
|
+
const samplePrompts = useWelcomePrompts();
|
|
83
95
|
React__default.useEffect(() => {
|
|
84
96
|
if (user && lastOpenedId === null && isReady) {
|
|
85
97
|
setConversationId(TEMP_CONVERSATION_ID);
|
|
@@ -100,6 +112,9 @@ const LightspeedChat = ({
|
|
|
100
112
|
queryClient.invalidateQueries({
|
|
101
113
|
queryKey: ["conversations"]
|
|
102
114
|
});
|
|
115
|
+
queryClient.invalidateQueries({
|
|
116
|
+
queryKey: ["conversationMessages", conversationId]
|
|
117
|
+
});
|
|
103
118
|
setNewChatCreated(false);
|
|
104
119
|
};
|
|
105
120
|
const { conversationMessages, handleInputPrompt, scrollToBottomRef } = useConversationMessages(
|
|
@@ -118,16 +133,19 @@ const LightspeedChat = ({
|
|
|
118
133
|
setAnnouncement(
|
|
119
134
|
`Message from User: ${prompt}. Message from Bot is loading.`
|
|
120
135
|
);
|
|
121
|
-
handleInputPrompt(message.toString());
|
|
136
|
+
handleInputPrompt(message.toString(), getAttachments(fileContents));
|
|
122
137
|
setIsSendButtonDisabled(true);
|
|
138
|
+
setFileContents([]);
|
|
123
139
|
};
|
|
124
140
|
const onNewChat = React__default.useCallback(() => {
|
|
125
141
|
(async () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
142
|
+
if (conversationId !== TEMP_CONVERSATION_ID) {
|
|
143
|
+
setMessages([]);
|
|
144
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
145
|
+
setNewChatCreated(true);
|
|
146
|
+
}
|
|
129
147
|
})();
|
|
130
|
-
}, [setConversationId, setMessages]);
|
|
148
|
+
}, [conversationId, setConversationId, setMessages]);
|
|
131
149
|
const openDeleteModal = (conversation_id) => {
|
|
132
150
|
setTargetConversationId(conversation_id);
|
|
133
151
|
setIsDeleteModalOpen(true);
|
|
@@ -210,24 +228,23 @@ const LightspeedChat = ({
|
|
|
210
228
|
const conversationFound = !!conversations.find(
|
|
211
229
|
(c) => c.conversation_id === conversationId
|
|
212
230
|
);
|
|
213
|
-
const welcomePrompts = newChatCreated && conversationMessages.length === 0 || !conversationFound && conversationMessages.length === 0 ?
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
title: "Topic 2",
|
|
221
|
-
message: "Helpful prompt for Topic 2",
|
|
222
|
-
onClick: () => sendMessage("Helpful prompt for Topic 2")
|
|
231
|
+
const welcomePrompts = newChatCreated && conversationMessages.length === 0 || !conversationFound && conversationMessages.length === 0 ? samplePrompts?.map((prompt2) => ({
|
|
232
|
+
title: prompt2.title,
|
|
233
|
+
message: prompt2.message,
|
|
234
|
+
onClick: () => {
|
|
235
|
+
sendMessage(prompt2.message);
|
|
223
236
|
}
|
|
224
|
-
|
|
237
|
+
})) : [];
|
|
225
238
|
const handleFilter = React__default.useCallback((value) => {
|
|
226
239
|
setFilterValue(value);
|
|
227
240
|
}, []);
|
|
228
241
|
const onDrawerToggle = React__default.useCallback(() => {
|
|
229
242
|
setIsDrawerOpen((isOpen) => !isOpen);
|
|
230
243
|
}, []);
|
|
244
|
+
const handleAttach = (data, event) => {
|
|
245
|
+
event.preventDefault();
|
|
246
|
+
handleFileUpload(data);
|
|
247
|
+
};
|
|
231
248
|
if (error) {
|
|
232
249
|
return /* @__PURE__ */ React__default.createElement(Box, { padding: 1 }, /* @__PURE__ */ React__default.createElement(ErrorPanel, { error }));
|
|
233
250
|
}
|
|
@@ -283,18 +300,19 @@ const LightspeedChat = ({
|
|
|
283
300
|
ref: scrollToBottomRef,
|
|
284
301
|
welcomePrompts
|
|
285
302
|
}
|
|
286
|
-
)), /* @__PURE__ */ React__default.createElement(ChatbotFooter, { className: classes.footer }, /* @__PURE__ */ React__default.createElement(
|
|
303
|
+
)), /* @__PURE__ */ React__default.createElement(ChatbotFooter, { className: classes.footer }, /* @__PURE__ */ React__default.createElement(FilePreview, null), /* @__PURE__ */ React__default.createElement(
|
|
287
304
|
MessageBar,
|
|
288
305
|
{
|
|
289
306
|
onSendMessage: sendMessage,
|
|
290
307
|
isSendButtonDisabled,
|
|
291
|
-
hasAttachButton:
|
|
308
|
+
hasAttachButton: true,
|
|
309
|
+
handleAttach,
|
|
292
310
|
hasMicrophoneButton: true
|
|
293
311
|
}
|
|
294
|
-
), /* @__PURE__ */ React__default.createElement(ChatbotFootnote, { ...getFootnoteProps() })))
|
|
312
|
+
), /* @__PURE__ */ React__default.createElement(ChatbotFootnote, { ...getFootnoteProps(classes.footerPopover) })))
|
|
295
313
|
}
|
|
296
314
|
)
|
|
297
|
-
));
|
|
315
|
+
), /* @__PURE__ */ React__default.createElement(Attachment, null));
|
|
298
316
|
};
|
|
299
317
|
|
|
300
318
|
export { LightspeedChat };
|