Skip to content

Commit 555ef5b

Browse files
feat(lightspeed): support drag and drop in lightspeed (#954)
* support file drag and drop in lightspeed * add unit tests * add drag and drop support for attachments
1 parent 05a002a commit 555ef5b

4 files changed

Lines changed: 77 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-lightspeed': patch
3+
---
4+
5+
Added support for Drag and Drop attachment upload

workspaces/lightspeed/plugins/lightspeed/src/components/LightSpeedChat.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ import {
3131
ChatbotHeaderMain,
3232
ChatbotHeaderMenu,
3333
ChatbotHeaderTitle,
34+
FileDropZone,
3435
MessageBar,
3536
MessageProps,
3637
} from '@patternfly/chatbot';
3738
import ChatbotConversationHistoryNav from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
3839
import { DropdownItem, DropEvent, Title } from '@patternfly/react-core';
3940
import { useQueryClient } from '@tanstack/react-query';
4041

41-
import { TEMP_CONVERSATION_ID } from '../const';
42+
import { supportedFileTypes, TEMP_CONVERSATION_ID } from '../const';
4243
import {
4344
useBackstageUserIdentity,
4445
useConversationMessages,
@@ -232,11 +233,19 @@ export const LightspeedChat = ({
232233
(async () => {
233234
if (conversationId !== TEMP_CONVERSATION_ID) {
234235
setMessages([]);
236+
setFileContents([]);
237+
setUploadError({ message: null });
235238
setConversationId(TEMP_CONVERSATION_ID);
236239
setNewChatCreated(true);
237240
}
238241
})();
239-
}, [conversationId, setConversationId, setMessages]);
242+
}, [
243+
conversationId,
244+
setConversationId,
245+
setMessages,
246+
setUploadError,
247+
setFileContents,
248+
]);
240249

241250
const openDeleteModal = (conversation_id: string) => {
242251
setTargetConversationId(conversation_id);
@@ -324,9 +333,11 @@ export const LightspeedChat = ({
324333
}
325334
return c_id;
326335
});
336+
setFileContents([]);
337+
setUploadError({ message: null });
327338
scrollToBottomRef.current?.scrollToBottom();
328339
},
329-
[setConversationId, scrollToBottomRef],
340+
[setConversationId, setUploadError, setFileContents, scrollToBottomRef],
330341
);
331342

332343
const conversationFound = !!conversations.find(
@@ -424,7 +435,13 @@ export const LightspeedChat = ({
424435
onNewChat={newChatCreated ? undefined : onNewChat}
425436
handleTextInputChange={handleFilter}
426437
drawerContent={
427-
<>
438+
<FileDropZone
439+
onFileDrop={(e, data) => handleAttach(data, e)}
440+
displayMode={ChatbotDisplayMode.embedded}
441+
infoText="Supported file types are: .txt, .yaml, .json and .xml. The maximum file size is 25 MB."
442+
allowedFileTypes={supportedFileTypes}
443+
onAttachRejected={onAttachRejected}
444+
>
428445
{showAlert && uploadError.message && (
429446
<div className={classes.errorContainer}>
430447
<ChatbotAlert
@@ -438,6 +455,7 @@ export const LightspeedChat = ({
438455
</ChatbotAlert>
439456
</div>
440457
)}
458+
441459
<ChatbotContent>
442460
<LightspeedChatBox
443461
userName={userName}
@@ -461,18 +479,13 @@ export const LightspeedChat = ({
461479
inputTestId: 'attachment-input',
462480
},
463481
}}
464-
allowedFileTypes={{
465-
'text/plain': ['.txt'],
466-
'application/json': ['.json'],
467-
'application/yaml': ['.yaml', '.yml'],
468-
'application/xml': ['.xml'],
469-
}}
482+
allowedFileTypes={supportedFileTypes}
470483
onAttachRejected={onAttachRejected}
471484
placeholder="Send a message and optionally upload a JSON, YAML, TXT, or XML file..."
472485
/>
473486
<ChatbotFootnote {...getFootnoteProps(classes.footerPopover)} />
474487
</ChatbotFooter>
475-
</>
488+
</FileDropZone>
476489
}
477490
/>
478491
</Chatbot>

workspaces/lightspeed/plugins/lightspeed/src/components/__tests__/LightspeedChat.test.tsx

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ import { usePermission } from '@backstage/plugin-permission-react';
2424
import { mockApis, TestApiProvider } from '@backstage/test-utils';
2525

2626
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
27-
import { render, screen, waitFor } from '@testing-library/react';
27+
import {
28+
act,
29+
fireEvent,
30+
render,
31+
screen,
32+
waitFor,
33+
} from '@testing-library/react';
2834
import userEvent from '@testing-library/user-event';
2935

3036
import { useConversations } from '../../hooks';
@@ -186,4 +192,38 @@ describe('LightspeedChat', () => {
186192
'text/plain,.txt,application/json,.json,application/yaml,.yaml,.yml,application/xml,.xml',
187193
);
188194
});
195+
196+
it('should show an alert when unsupported file types are dropped', async () => {
197+
render(setupLightspeedChat());
198+
199+
const fileDropzone = screen.getByText('MessageBox')
200+
.parentElement as HTMLElement;
201+
202+
const invalidFile = new File(['dummy'], 'file.pdf', {
203+
type: 'application/pdf',
204+
});
205+
206+
const dataTransfer = {
207+
files: [invalidFile],
208+
items: [
209+
{
210+
kind: 'file',
211+
type: 'application/pdf',
212+
getAsFile: () => invalidFile,
213+
},
214+
],
215+
types: ['Files'],
216+
};
217+
await act(async () => {
218+
fireEvent.drop(fileDropzone, {
219+
dataTransfer,
220+
});
221+
});
222+
223+
expect(
224+
screen.getByText(
225+
'Unsupported file type. Supported types are: .txt, .yaml, .json and .xml.',
226+
),
227+
).toBeInTheDocument();
228+
});
189229
});

workspaces/lightspeed/plugins/lightspeed/src/const.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ const createPrompt = (title: string, message: string) => {
2525
return { title, message };
2626
};
2727

28+
export const supportedFileTypes = {
29+
'text/plain': ['.txt'],
30+
'application/json': ['.json'],
31+
'application/yaml': ['.yaml', '.yml'],
32+
'application/xml': ['.xml'],
33+
};
34+
2835
export const DEFAULT_SAMPLE_PROMPTS: SamplePrompts = [
2936
createPrompt(
3037
'Get Help On Code Readability',

0 commit comments

Comments
 (0)