import ChatbotToggle from '@patternfly/chatbot/dist/dynamic/ChatbotToggle'; import Chatbot from '@patternfly/chatbot/dist/dynamic/Chatbot'; import ChatbotContent from '@patternfly/chatbot/dist/dynamic/ChatbotContent'; import ChatbotWelcomePrompt from '@patternfly/chatbot/dist/dynamic/ChatbotWelcomePrompt'; import ChatbotFooter, { ChatbotFootnote } from '@patternfly/chatbot/dist/dynamic/ChatbotFooter'; import MessageBar from '@patternfly/chatbot/dist/dynamic/MessageBar'; import MessageBox from '@patternfly/chatbot/dist/dynamic/MessageBox'; import Message, { MessageProps } from '@patternfly/chatbot/dist/dynamic/Message'; import FileDropZone from '@patternfly/chatbot/dist/dynamic/FileDropZone'; import SourceDetailsMenuItem from '@patternfly/chatbot/dist/dynamic/SourceDetailsMenuItem'; import ChatbotAlert from '@patternfly/chatbot/dist/dynamic/ChatbotAlert'; import { Divider, DropdownGroup, DropdownItem, DropdownList, DropEvent } from '@patternfly/react-core'; import FileDetailsLabel from '@patternfly/chatbot/dist/dynamic/FileDetailsLabel'; import { BellIcon, CalendarAltIcon, ClipboardIcon, CodeIcon, UploadIcon } from '@patternfly/react-icons'; import { useDropzone } from 'react-dropzone'; import userAvatar from '../Messages/user_avatar.svg'; import patternflyAvatar from '../Messages/patternfly_avatar.jpg'; import '@patternfly/react-core/dist/styles/base.css'; import '@patternfly/chatbot/dist/css/main.css'; import { cloneElement, FunctionComponent, isValidElement, ReactNode, useState, Children } from 'react'; const initialMenuItems = [ } name="auth-operator" type="Pod" /> , }> Alerts }> Events }> Logs }> YAML - Status }> YAML - All contents ]; const messages: MessageProps[] = [ { role: 'user', content: 'Hello, can you give me an example of what you can do?', name: 'User', avatar: userAvatar, avatarProps: { isBordered: true } }, { role: 'bot', content: 'I sure can!', name: 'Bot', avatar: patternflyAvatar } ]; export const AttachmentMenuDemo: FunctionComponent = () => { const [chatbotVisible, setChatbotVisible] = useState(true); const [file, setFile] = useState(); const [isLoadingFile, setIsLoadingFile] = useState(false); const [userFacingMenuItems, setUserFacingMenuItems] = useState([]); const [error, setError] = useState(); const [showAlert, setShowAlert] = useState(false); const [isOpen, setIsOpen] = useState(false); const { open, getInputProps } = useDropzone({ onDropAccepted: (files: File[]) => { setIsLoadingFile(true); setIsOpen(false); // any custom validation you may want if (files.length > 1) { setShowAlert(true); setFile(undefined); setError('Uploaded more than one file.'); return; } // this is 25MB in bytes; size is in bytes if (files[0].size > 25000000) { setShowAlert(true); setFile(undefined); setError('File is larger than 25MB.'); return; } setFile(files[0]); setShowAlert(false); setError(undefined); // this is just for demo purposes, to make the loading state really obvious setTimeout(() => { setIsLoadingFile(false); }, 1000); } }); const handleSend = (message) => alert(message); // Attachments // -------------------------------------------------------------------------- const handleFileDrop = (event: DropEvent, data: File[]) => { setIsOpen(false); setFile(data[0]); setIsLoadingFile(true); setTimeout(() => { setIsLoadingFile(false); }, 1000); }; const onClose = () => { setFile(undefined); }; // Attachmenu menu // -------------------------------------------------------------------------- const uploadMenuItems = [ , { open(); setIsOpen(!isOpen); }} key="upload" value="upload" id="upload" icon={} > Upload from computer ]; const onToggleClick = () => { setUserFacingMenuItems(initialMenuItems.concat(uploadMenuItems)); }; const findMatchingElements = (elements: ReactNode[], targetValue: string) => { let matchingElements = [] as ReactNode[]; elements.forEach((element) => { if (isValidElement(element)) { // Check if the element's value matches the targetValue if (element.props.value && element.props.value.toLowerCase().includes(targetValue.toLowerCase())) { matchingElements.push(cloneElement(element, { key: element.props.value })); } // Recursively check the element's children const children = Children.toArray(element.props.children); matchingElements = matchingElements.concat(findMatchingElements(children, targetValue)); } }); return matchingElements; }; const onTextChange = (textValue: string) => { if (textValue === '') { setUserFacingMenuItems(initialMenuItems.concat(uploadMenuItems)); return; } const newMenuItems = findMatchingElements(initialMenuItems, textValue); // this is necessary because the React nodes we find traversing the recursive search // aren't correctly wrapped in a DropdownList. This leads to problems with the // auth-operator item where it winds up floating in a bad place in the DOM and never // gets removed setUserFacingMenuItems( <> {newMenuItems.length === 0 ? ( No results found ) : ( newMenuItems.map((item) => item) )} {uploadMenuItems.map((item) => item)} ); }; // Main return statement // -------------------------------------------------------------------------- return ( <> {/* this is required for react-dropzone to work in Safari and Firefox */} setChatbotVisible(!chatbotVisible)} /> <> {showAlert && ( { setShowAlert(false); setError(undefined); }} title="File upload failed" > {error} )} {messages.map((message) => ( ))} {file && (
)} { // eslint-disable-next-line no-console console.log('selected', value); }, attachMenuInputPlaceholder: 'Search cluster resources...', onAttachMenuInputChange: onTextChange, onAttachMenuToggleClick: onToggleClick }} />
); };