From 78677d9ee51b4427fd793b4b0233125d99698e0d Mon Sep 17 00:00:00 2001 From: Ilango Date: Tue, 20 Feb 2024 15:23:15 +0530 Subject: [PATCH] Add dialog for controlling chat feedback settings --- packages/ui/src/menu-items/settings.js | 20 ++- .../ui-component/dialog/ChatFeedbackDialog.js | 137 ++++++++++++++++++ packages/ui/src/ui-component/switch/Switch.js | 17 ++- packages/ui/src/views/canvas/CanvasHeader.js | 15 ++ 4 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js diff --git a/packages/ui/src/menu-items/settings.js b/packages/ui/src/menu-items/settings.js index 1e0f58dd..5003392c 100644 --- a/packages/ui/src/menu-items/settings.js +++ b/packages/ui/src/menu-items/settings.js @@ -1,8 +1,17 @@ // assets -import { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconSearch, IconMessage, IconPictureInPictureOff } from '@tabler/icons' +import { + IconTrash, + IconFileUpload, + IconFileExport, + IconCopy, + IconSearch, + IconMessage, + IconPictureInPictureOff, + IconThumbUp +} from '@tabler/icons' // constant -const icons = { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconSearch, IconMessage, IconPictureInPictureOff } +const icons = { IconTrash, IconFileUpload, IconFileExport, IconCopy, IconSearch, IconMessage, IconPictureInPictureOff, IconThumbUp } // ==============================|| SETTINGS MENU ITEMS ||============================== // @@ -25,6 +34,13 @@ const settings = { url: '', icon: icons.IconMessage }, + { + id: 'chatFeedback', + title: 'Chat Feedback', + type: 'item', + url: '', + icon: icons.IconThumbUp + }, { id: 'duplicateChatflow', title: 'Duplicate Chatflow', diff --git a/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js new file mode 100644 index 00000000..a88c6f35 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/ChatFeedbackDialog.js @@ -0,0 +1,137 @@ +import { createPortal } from 'react-dom' +import { useDispatch } from 'react-redux' +import { useState, useEffect } from 'react' +import PropTypes from 'prop-types' +import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' + +// material-ui +import { Button, Dialog, DialogContent, DialogTitle, DialogActions, Box } from '@mui/material' +import { IconX } from '@tabler/icons' + +// Project import +import { StyledButton } from 'ui-component/button/StyledButton' +import { SwitchInput } from 'ui-component/switch/Switch' + +// store +import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions' +import useNotifier from 'utils/useNotifier' + +// API +import chatflowsApi from 'api/chatflows' + +const ChatFeedbackDialog = ({ show, dialogProps, onCancel, onConfirm }) => { + const portalElement = document.getElementById('portal') + const dispatch = useDispatch() + + useNotifier() + + const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) + const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) + + const [chatFeedbackStatus, setChatFeedbackStatus] = useState(false) + const [chatbotConfig, setChatbotConfig] = useState({}) + + const handleChange = (value) => { + setChatFeedbackStatus(value) + } + + const onSave = async () => { + try { + let value = { + chatFeedback: { + status: chatFeedbackStatus + } + } + chatbotConfig.chatFeedback = value.chatFeedback + const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { + chatbotConfig: JSON.stringify(chatbotConfig) + }) + if (saveResp.data) { + enqueueSnackbar({ + message: 'Chat Feedback Settings Saved', + options: { + key: new Date().getTime() + Math.random(), + variant: 'success', + action: (key) => ( + + ) + } + }) + dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) + } + onConfirm() + } catch (error) { + const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` + enqueueSnackbar({ + message: `Failed to save Chat Feedback Settings: ${errorData}`, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } + + useEffect(() => { + if (dialogProps.chatflow && dialogProps.chatflow.chatbotConfig) { + let chatbotConfig = JSON.parse(dialogProps.chatflow.chatbotConfig) + setChatbotConfig(chatbotConfig || {}) + if (chatbotConfig.chatFeedback) { + setChatFeedbackStatus(chatbotConfig.chatFeedback.status) + } + } + + return () => {} + }, [dialogProps]) + + useEffect(() => { + if (show) dispatch({ type: SHOW_CANVAS_DIALOG }) + else dispatch({ type: HIDE_CANVAS_DIALOG }) + return () => dispatch({ type: HIDE_CANVAS_DIALOG }) + }, [show, dispatch]) + + const component = show ? ( + + + {dialogProps.title || 'Chat Feedback'} + + + + + + + + + + Save + + + + ) : null + + return createPortal(component, portalElement) +} + +ChatFeedbackDialog.propTypes = { + show: PropTypes.bool, + dialogProps: PropTypes.object, + onCancel: PropTypes.func, + onConfirm: PropTypes.func +} + +export default ChatFeedbackDialog diff --git a/packages/ui/src/ui-component/switch/Switch.js b/packages/ui/src/ui-component/switch/Switch.js index 16a923f1..50ace119 100644 --- a/packages/ui/src/ui-component/switch/Switch.js +++ b/packages/ui/src/ui-component/switch/Switch.js @@ -1,13 +1,21 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import PropTypes from 'prop-types' -import { FormControl, Switch } from '@mui/material' +import { FormControl, Switch, Typography } from '@mui/material' -export const SwitchInput = ({ value, onChange, disabled = false }) => { +export const SwitchInput = ({ label, value, onChange, disabled = false }) => { const [myValue, setMyValue] = useState(!!value ?? false) + useEffect(() => { + setMyValue(value) + }, [value]) + return ( <> - + + {label && {label}} { } SwitchInput.propTypes = { + label: PropTypes.string, value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), onChange: PropTypes.func, disabled: PropTypes.bool diff --git a/packages/ui/src/views/canvas/CanvasHeader.js b/packages/ui/src/views/canvas/CanvasHeader.js index 85408cd8..af9d5e2f 100644 --- a/packages/ui/src/views/canvas/CanvasHeader.js +++ b/packages/ui/src/views/canvas/CanvasHeader.js @@ -17,6 +17,7 @@ import APICodeDialog from 'views/chatflows/APICodeDialog' import AnalyseFlowDialog from 'ui-component/dialog/AnalyseFlowDialog' import ViewMessagesDialog from 'ui-component/dialog/ViewMessagesDialog' import StarterPromptsDialog from 'ui-component/dialog/StarterPromptsDialog' +import ChatFeedbackDialog from 'ui-component/dialog/ChatFeedbackDialog' // API import chatflowsApi from 'api/chatflows' @@ -50,6 +51,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl const [conversationStartersDialogProps, setConversationStartersDialogProps] = useState({}) const [viewMessagesDialogOpen, setViewMessagesDialogOpen] = useState(false) const [viewMessagesDialogProps, setViewMessagesDialogProps] = useState({}) + const [chatFeedbackDialogOpen, setChatFeedbackDialogOpen] = useState(false) + const [chatFeedbackDialogProps, setChatFeedbackDialogProps] = useState({}) const updateChatflowApi = useApi(chatflowsApi.updateChatflow) const canvas = useSelector((state) => state.canvas) @@ -65,6 +68,12 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl chatflow: chatflow }) setConversationStartersDialogOpen(true) + } else if (setting === 'chatFeedback') { + setChatFeedbackDialogProps({ + title: `Chat Feedback - ${chatflow.name}`, + chatflow: chatflow + }) + setChatFeedbackDialogOpen(true) } else if (setting === 'analyseChatflow') { setAnalyseDialogProps({ title: 'Analyse Chatflow', @@ -391,6 +400,12 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl onConfirm={() => setConversationStartersDialogOpen(false)} onCancel={() => setConversationStartersDialogOpen(false)} /> + setChatFeedbackDialogOpen(false)} + onCancel={() => setChatFeedbackDialogOpen(false)} + />