@red-hat-developer-hub/backstage-plugin-lightspeed 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -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 +48 -21
- 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,32 @@
|
|
|
1
1
|
## @red-hat-developer-hub/backstage-plugin-lightspeed
|
|
2
2
|
|
|
3
|
+
## 0.5.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b3cca2b: Reset localstorage if the conversations are empty
|
|
8
|
+
|
|
9
|
+
## 0.5.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- fe413e3: Functional disclaimer with topic restriction
|
|
14
|
+
- a9e5f32: Updated dependency `@openapitools/openapi-generator-cli` to `2.20.0`.
|
|
15
|
+
Updated dependency `prettier` to `3.5.3`.
|
|
16
|
+
Updated dependency `@redhat-developer/red-hat-developer-hub-theme` to `0.5.1`.
|
|
17
|
+
Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.6.0`.
|
|
18
|
+
Updated dependency `@janus-idp/cli` to `3.5.0`.
|
|
19
|
+
- 3a76aaf: Updated dependency `@patternfly/react-core` to `6.3.0-prerelease.4`.
|
|
20
|
+
- 002f7c9: Updated dependency `@testing-library/user-event` to `14.6.1`.
|
|
21
|
+
- ab6a532: Add configurable sample prompts
|
|
22
|
+
- dc4ff7c: Add file attachment support
|
|
23
|
+
Update functional and legal disclaimers
|
|
24
|
+
Add citation links in the bot response
|
|
25
|
+
Update initial user prompts
|
|
26
|
+
- db3257b: Upgrade PF chatbot
|
|
27
|
+
- Updated dependencies [a9e5f32]
|
|
28
|
+
- @red-hat-developer-hub/backstage-plugin-lightspeed-common@0.3.1
|
|
29
|
+
|
|
3
30
|
## 0.5.1
|
|
4
31
|
|
|
5
32
|
### 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":"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"}
|
|
@@ -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":";;;AA2Ca,MAAA,qBAAA,GACXA,cAAM,CAAA,aAAA,CAAgD,IAAI;AAE5D,MAAM,6BAED,GAAA,CAAC,EAAE,QAAA,EAAe,KAAA;AACrB,EAAA,MAAM,CAAC,kBAAA,EAAoB,qBAAqB,CAAA,GAAIA,eAAM,QAExD,EAAA;AACF,EAAA,MAAM,CAAC,aAAe,EAAA,gBAAgB,IAAIA,cAAM,CAAA,QAAA,CAE9C,EAAE,CAAA;AACJ,EAAA,MAAM,CAAC,eAAiB,EAAA,kBAAkB,CAAI,GAAAA,cAAA,CAAM,SAAiB,CAAC,CAAA;AACtE,EAAA,MAAM,CAAC,SAAW,EAAA,YAAY,CAAI,GAAAA,cAAA,CAAM,SAAkB,KAAK,CAAA;AAC/D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIA,eAAM,QAAsB,CAAA;AAAA,IAChE,OAAS,EAAA;AAAA,GACV,CAAA;AACD,EAAA,MAAM,CAAC,YAAc,EAAA,eAAe,IAAIA,cAAM,CAAA,QAAA,CAAwB,EAAE,CAAA;AACxE,EAAA,MAAM,CAAC,kBAAoB,EAAA,qBAAqB,CAC9C,GAAAA,cAAA,CAAM,SAAkB,KAAK,CAAA;AAC/B,EAAA,MAAM,CAAC,eAAiB,EAAA,kBAAkB,CAAI,GAAAA,cAAA,CAAM,SAAkB,KAAK,CAAA;AAC3E,EAAM,MAAA,gBAAA,GAAmB,CAAC,OAAoB,KAAA;AAC5C,IAAA,MAAM,eAAe,YAAa,CAAA,IAAA;AAAA,MAChC,CAAQ,IAAA,KAAA,IAAA,CAAK,IAAS,KAAA,OAAA,CAAQ,CAAC,CAAE,CAAA;AAAA,KACnC;AACA,IAAA,IAAI,YAAc,EAAA;AAChB,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,cAAA,CAAe,EAAE,IAAA,EAAM,MAAQ,EAAA,OAAA,EAAS,wBAAwB,CAAA;AAChE,MAAA;AAAA;AAGF,IAAiB,gBAAA,CAAA,EAAE,CAAC,OAAQ,CAAA,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;AAE5C,IAAI,IAAA,OAAA,CAAQ,SAAS,CAAG,EAAA;AACtB,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAe,cAAA,CAAA;AAAA,QACb,OAAS,EAAA;AAAA,OACV,CAAA;AACD,MAAA;AAAA;AAEF,IAAA,IAAI,CAAC,mBAAA,CAAoB,OAAQ,CAAA,CAAC,CAAC,CAAG,EAAA;AACpC,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAe,cAAA,CAAA;AAAA,QACb,OACE,EAAA;AAAA,OACH,CAAA;AACD,MAAA;AAAA;AAIF,IAAA,IAAI,OAAQ,CAAA,CAAC,CAAE,CAAA,IAAA,GAAO,IAAU,EAAA;AAC9B,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAe,cAAA,CAAA;AAAA,QACb,OACE,EAAA;AAAA,OACH,CAAA;AACD,MAAA;AAAA;AAGF,IAAA,cAAA,CAAe,OAAQ,CAAA,CAAC,CAAC,CAAA,CACtB,KAAK,CAAQ,IAAA,KAAA;AACZ,MAAA,eAAA,CAAgB,CAAQ,IAAA,KAAA;AAAA,QACtB,GAAG,IAAA;AAAA,QACH;AAAA,UACE,IAAA,EAAM,OAAQ,CAAA,CAAC,CAAE,CAAA,IAAA;AAAA,UACjB,IAAA,EAAM,OAAQ,CAAA,CAAC,CAAE,CAAA,IAAA;AAAA,UACjB,OAAS,EAAA;AAAA;AACX,OACD,CAAA;AACD,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAe,cAAA,CAAA,EAAE,OAAS,EAAA,IAAA,EAAM,CAAA;AAChC,MAAiB,gBAAA,CAAA,EAAE,CAAC,OAAQ,CAAA,CAAC,EAAE,IAAI,GAAG,OAAO,CAAA;AAAA,KAC9C,CAAA,CACA,KAAM,CAAA,CAAC,KAAwB,KAAA;AAC9B,MAAe,cAAA,CAAA;AAAA,QACb,OAAA,EAAS,CAAwB,qBAAA,EAAA,KAAA,CAAM,OAAO,CAAA;AAAA,OAC/C,CAAA;AAAA,KACF,CAAA;AAAA,GACL;AAEA,EAAA,MAAM,UAAa,GAAA;AAAA,IACjB,kBAAA;AAAA,IACA,qBAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACA,EACE,uBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,qBAAsB,CAAA,QAAA;AAAA,IAAtB;AAAA,MACC,KAAO,EAAA;AAAA,QACL,UAAA;AAAA,QACA,YAAA;AAAA,QACA,eAAA;AAAA,QACA,gBAAA;AAAA,QACA,aAAA;AAAA,QACA,SAAA;AAAA,QACA,WAAA;AAAA,QACA,cAAA;AAAA,QACA,kBAAA;AAAA,QACA;AAAA;AACF,KAAA;AAAA,IAEC;AAAA,GACH;AAEJ;AAIO,MAAM,2BAA2B,MAAiC;AACvE,EAAA,MAAM,UAAUA,cAAM,CAAA,UAAA;AAAA,IACpB;AAAA,GACF;AAEA,EAAA,IAAI,YAAY,IAAM,EAAA;AACpB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA;AAGF,EAAO,OAAA,OAAA;AACT;;;;"}
|
|
@@ -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,21 +81,32 @@ 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);
|
|
77
88
|
}
|
|
78
89
|
}, [lastOpenedId, isReady]);
|
|
79
90
|
const queryClient = useQueryClient();
|
|
80
|
-
const {
|
|
91
|
+
const {
|
|
92
|
+
data: conversations = [],
|
|
93
|
+
isLoading,
|
|
94
|
+
isRefetching
|
|
95
|
+
} = useConversations();
|
|
81
96
|
const { mutateAsync: deleteConversation } = useDeleteConversation();
|
|
82
97
|
const { allowed: hasDeleteAccess } = useLightspeedDeletePermission();
|
|
98
|
+
const samplePrompts = useWelcomePrompts();
|
|
83
99
|
React__default.useEffect(() => {
|
|
84
100
|
if (user && lastOpenedId === null && isReady) {
|
|
85
101
|
setConversationId(TEMP_CONVERSATION_ID);
|
|
86
102
|
setNewChatCreated(true);
|
|
87
103
|
}
|
|
88
104
|
}, [user, isReady, lastOpenedId, setConversationId]);
|
|
105
|
+
React__default.useEffect(() => {
|
|
106
|
+
if (!isLoading && !isRefetching && conversations.length === 0 && lastOpenedId) {
|
|
107
|
+
clearLastOpenedId();
|
|
108
|
+
}
|
|
109
|
+
}, [isLoading, isRefetching, conversations, lastOpenedId, clearLastOpenedId]);
|
|
89
110
|
React__default.useEffect(() => {
|
|
90
111
|
if (conversationId) {
|
|
91
112
|
setLastOpenedId(conversationId);
|
|
@@ -100,6 +121,9 @@ const LightspeedChat = ({
|
|
|
100
121
|
queryClient.invalidateQueries({
|
|
101
122
|
queryKey: ["conversations"]
|
|
102
123
|
});
|
|
124
|
+
queryClient.invalidateQueries({
|
|
125
|
+
queryKey: ["conversationMessages", conversationId]
|
|
126
|
+
});
|
|
103
127
|
setNewChatCreated(false);
|
|
104
128
|
};
|
|
105
129
|
const { conversationMessages, handleInputPrompt, scrollToBottomRef } = useConversationMessages(
|
|
@@ -118,16 +142,19 @@ const LightspeedChat = ({
|
|
|
118
142
|
setAnnouncement(
|
|
119
143
|
`Message from User: ${prompt}. Message from Bot is loading.`
|
|
120
144
|
);
|
|
121
|
-
handleInputPrompt(message.toString());
|
|
145
|
+
handleInputPrompt(message.toString(), getAttachments(fileContents));
|
|
122
146
|
setIsSendButtonDisabled(true);
|
|
147
|
+
setFileContents([]);
|
|
123
148
|
};
|
|
124
149
|
const onNewChat = React__default.useCallback(() => {
|
|
125
150
|
(async () => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
151
|
+
if (conversationId !== TEMP_CONVERSATION_ID) {
|
|
152
|
+
setMessages([]);
|
|
153
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
154
|
+
setNewChatCreated(true);
|
|
155
|
+
}
|
|
129
156
|
})();
|
|
130
|
-
}, [setConversationId, setMessages]);
|
|
157
|
+
}, [conversationId, setConversationId, setMessages]);
|
|
131
158
|
const openDeleteModal = (conversation_id) => {
|
|
132
159
|
setTargetConversationId(conversation_id);
|
|
133
160
|
setIsDeleteModalOpen(true);
|
|
@@ -210,24 +237,23 @@ const LightspeedChat = ({
|
|
|
210
237
|
const conversationFound = !!conversations.find(
|
|
211
238
|
(c) => c.conversation_id === conversationId
|
|
212
239
|
);
|
|
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")
|
|
240
|
+
const welcomePrompts = newChatCreated && conversationMessages.length === 0 || !conversationFound && conversationMessages.length === 0 ? samplePrompts?.map((prompt2) => ({
|
|
241
|
+
title: prompt2.title,
|
|
242
|
+
message: prompt2.message,
|
|
243
|
+
onClick: () => {
|
|
244
|
+
sendMessage(prompt2.message);
|
|
223
245
|
}
|
|
224
|
-
|
|
246
|
+
})) : [];
|
|
225
247
|
const handleFilter = React__default.useCallback((value) => {
|
|
226
248
|
setFilterValue(value);
|
|
227
249
|
}, []);
|
|
228
250
|
const onDrawerToggle = React__default.useCallback(() => {
|
|
229
251
|
setIsDrawerOpen((isOpen) => !isOpen);
|
|
230
252
|
}, []);
|
|
253
|
+
const handleAttach = (data, event) => {
|
|
254
|
+
event.preventDefault();
|
|
255
|
+
handleFileUpload(data);
|
|
256
|
+
};
|
|
231
257
|
if (error) {
|
|
232
258
|
return /* @__PURE__ */ React__default.createElement(Box, { padding: 1 }, /* @__PURE__ */ React__default.createElement(ErrorPanel, { error }));
|
|
233
259
|
}
|
|
@@ -283,18 +309,19 @@ const LightspeedChat = ({
|
|
|
283
309
|
ref: scrollToBottomRef,
|
|
284
310
|
welcomePrompts
|
|
285
311
|
}
|
|
286
|
-
)), /* @__PURE__ */ React__default.createElement(ChatbotFooter, { className: classes.footer }, /* @__PURE__ */ React__default.createElement(
|
|
312
|
+
)), /* @__PURE__ */ React__default.createElement(ChatbotFooter, { className: classes.footer }, /* @__PURE__ */ React__default.createElement(FilePreview, null), /* @__PURE__ */ React__default.createElement(
|
|
287
313
|
MessageBar,
|
|
288
314
|
{
|
|
289
315
|
onSendMessage: sendMessage,
|
|
290
316
|
isSendButtonDisabled,
|
|
291
|
-
hasAttachButton:
|
|
317
|
+
hasAttachButton: true,
|
|
318
|
+
handleAttach,
|
|
292
319
|
hasMicrophoneButton: true
|
|
293
320
|
}
|
|
294
|
-
), /* @__PURE__ */ React__default.createElement(ChatbotFootnote, { ...getFootnoteProps() })))
|
|
321
|
+
), /* @__PURE__ */ React__default.createElement(ChatbotFootnote, { ...getFootnoteProps(classes.footerPopover) })))
|
|
295
322
|
}
|
|
296
323
|
)
|
|
297
|
-
));
|
|
324
|
+
), /* @__PURE__ */ React__default.createElement(Attachment, null));
|
|
298
325
|
};
|
|
299
326
|
|
|
300
327
|
export { LightspeedChat };
|