From d5b6511974bb98b136079a039bb8b6e97d2364bd Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 20 Apr 2023 14:49:43 +0100 Subject: [PATCH] add api dialog --- packages/ui/package.json | 1 + packages/ui/src/assets/images/cURL.svg | 1 + packages/ui/src/assets/images/javascript.svg | 1 + packages/ui/src/assets/images/python.svg | 1 + packages/ui/src/themes/palette.js | 2 - .../src/ui-component/dialog/APICodeDialog.js | 163 ++++++++++++++++++ packages/ui/src/views/canvas/CanvasHeader.js | 34 +++- 7 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 packages/ui/src/assets/images/cURL.svg create mode 100644 packages/ui/src/assets/images/javascript.svg create mode 100644 packages/ui/src/assets/images/python.svg create mode 100644 packages/ui/src/ui-component/dialog/APICodeDialog.js diff --git a/packages/ui/package.json b/packages/ui/package.json index dfbac8427..fe6a709e6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -25,6 +25,7 @@ "prismjs": "^1.28.0", "prop-types": "^15.7.2", "react": "^18.2.0", + "react-code-blocks": "^0.0.9-0", "react-datepicker": "^4.8.0", "react-device-detect": "^1.17.0", "react-dom": "^18.2.0", diff --git a/packages/ui/src/assets/images/cURL.svg b/packages/ui/src/assets/images/cURL.svg new file mode 100644 index 000000000..7f3644ae2 --- /dev/null +++ b/packages/ui/src/assets/images/cURL.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/ui/src/assets/images/javascript.svg b/packages/ui/src/assets/images/javascript.svg new file mode 100644 index 000000000..e7f9f2a30 --- /dev/null +++ b/packages/ui/src/assets/images/javascript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/ui/src/assets/images/python.svg b/packages/ui/src/assets/images/python.svg new file mode 100644 index 000000000..9cbbf9478 --- /dev/null +++ b/packages/ui/src/assets/images/python.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/ui/src/themes/palette.js b/packages/ui/src/themes/palette.js index 97abbe89d..a4a5104dd 100644 --- a/packages/ui/src/themes/palette.js +++ b/packages/ui/src/themes/palette.js @@ -80,8 +80,6 @@ export default function themePalette(theme) { main: theme.customization.isDarkMode ? theme.colors?.darkPrimary800 : theme.colors?.grey50 }, canvasHeader: { - executionLight: theme.colors?.successLight, - executionDark: theme.colors?.successDark, deployLight: theme.colors?.primaryLight, deployDark: theme.colors?.primaryDark, saveLight: theme.colors?.secondaryLight, diff --git a/packages/ui/src/ui-component/dialog/APICodeDialog.js b/packages/ui/src/ui-component/dialog/APICodeDialog.js new file mode 100644 index 000000000..e23e91b26 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/APICodeDialog.js @@ -0,0 +1,163 @@ +import { createPortal } from 'react-dom' +import { useState } from 'react' +import PropTypes from 'prop-types' + +import { Tabs, Tab, Dialog, DialogContent, DialogTitle, Box } from '@mui/material' +import { CopyBlock, atomOneDark } from 'react-code-blocks' +import { baseURL } from 'store/constant' +import pythonSVG from 'assets/images/python.svg' +import javascriptSVG from 'assets/images/javascript.svg' +import cURLSVG from 'assets/images/cURL.svg' + +function TabPanel(props) { + const { children, value, index, ...other } = props + return ( + + ) +} + +TabPanel.propTypes = { + children: PropTypes.node, + index: PropTypes.number.isRequired, + value: PropTypes.number.isRequired +} + +function a11yProps(index) { + return { + id: `attachment-tab-${index}`, + 'aria-controls': `attachment-tabpanel-${index}` + } +} + +const APICodeDialog = ({ show, dialogProps, onCancel }) => { + const portalElement = document.getElementById('portal') + const codes = ['Python', 'JavaScript', 'cURL'] + const [value, setValue] = useState(0) + + const handleChange = (event, newValue) => { + setValue(newValue) + } + + const getCode = (codeLang) => { + if (codeLang === 'Python') { + return `import requests + +API_URL = "${baseURL}/api/v1/prediction/${dialogProps.chatflowid}" + +def query(payload): + response = requests.post(API_URL, json=payload) + return response.json() + +output = query({ + "question": "Hey, how are you?", +}) +` + } else if (codeLang === 'JavaScript') { + return `async function query(data) { + const response = await fetch( + "${baseURL}/api/v1/prediction/${dialogProps.chatflowid}", + { + method: "POST", + body: { + "question": "Hey, how are you?" + }, + } + ); + const result = await response.json(); + return result; +} +` + } else if (codeLang === 'cURL') { + return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\ + -X POST \\ + -d '{"question": "Hey, how are you?"}'` + } + return '' + } + + const getLang = (codeLang) => { + if (codeLang === 'Python') { + return 'python' + } else if (codeLang === 'JavaScript') { + return 'javascript' + } else if (codeLang === 'cURL') { + return 'bash' + } + return 'python' + } + + const getSVG = (codeLang) => { + if (codeLang === 'Python') { + return pythonSVG + } else if (codeLang === 'JavaScript') { + return javascriptSVG + } else if (codeLang === 'cURL') { + return cURLSVG + } + return pythonSVG + } + + const component = show ? ( + + + {dialogProps.title} + + + + {codes.map((codeLang, index) => ( + + } + iconPosition='left' + key={index} + label={codeLang} + {...a11yProps(index)} + > + ))} + +
+ {codes.map((codeLang, index) => ( + + + + ))} +
+
+ ) : null + + return createPortal(component, portalElement) +} + +APICodeDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func +} + +export default APICodeDialog diff --git a/packages/ui/src/views/canvas/CanvasHeader.js b/packages/ui/src/views/canvas/CanvasHeader.js index 9a5654e83..266deb70a 100644 --- a/packages/ui/src/views/canvas/CanvasHeader.js +++ b/packages/ui/src/views/canvas/CanvasHeader.js @@ -8,11 +8,12 @@ import { useTheme } from '@mui/material/styles' import { Avatar, Box, ButtonBase, Typography, Stack, TextField } from '@mui/material' // icons -import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck, IconX } from '@tabler/icons' +import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck, IconX, IconWorldWww } from '@tabler/icons' // project imports import Settings from 'views/settings' import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog' +import APICodeDialog from 'ui-component/dialog/APICodeDialog' // API import chatflowsApi from 'api/chatflows' @@ -35,6 +36,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl const [flowName, setFlowName] = useState('') const [isSettingsOpen, setSettingsOpen] = useState(false) const [flowDialogOpen, setFlowDialogOpen] = useState(false) + const [apiDialogOpen, setAPIDialogOpen] = useState(false) + const [apiDialogProps, setAPIDialogProps] = useState({}) const updateChatflowApi = useApi(chatflowsApi.updateChatflow) const canvas = useSelector((state) => state.canvas) @@ -76,6 +79,14 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl } } + const onAPIDialogClick = () => { + setAPIDialogProps({ + title: 'Use this chatflow with API', + chatflowid: chatflow.id + }) + setAPIDialogOpen(true) + } + const onSaveChatflowClick = () => { if (chatflow.id) handleSaveFlow(chatflow.name) else setFlowDialogOpen(true) @@ -219,6 +230,26 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl )} + + + + + setFlowDialogOpen(false)} onConfirm={onConfirmSaveName} /> + setAPIDialogOpen(false)} /> ) }