From f21f5257cac9a50661e2408017729641f00a69f5 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 14 Nov 2023 14:35:47 +0530 Subject: [PATCH 01/13] UX Changes: Ability to view as table and search on the dashboard --- .../src/ui-component/button/StyledButton.js | 8 ++ .../src/ui-component/table/FlowListTable.js | 133 ++++++++++++++++++ .../ui/src/ui-component/toolbar/Toolbar.js | 24 ++++ packages/ui/src/views/chatflows/index.js | 96 ++++++++++--- 4 files changed, 240 insertions(+), 21 deletions(-) create mode 100644 packages/ui/src/ui-component/table/FlowListTable.js create mode 100644 packages/ui/src/ui-component/toolbar/Toolbar.js diff --git a/packages/ui/src/ui-component/button/StyledButton.js b/packages/ui/src/ui-component/button/StyledButton.js index 6e0c7078..29e17f80 100644 --- a/packages/ui/src/ui-component/button/StyledButton.js +++ b/packages/ui/src/ui-component/button/StyledButton.js @@ -1,5 +1,6 @@ import { styled } from '@mui/material/styles' import { Button } from '@mui/material' +import MuiToggleButton from '@mui/material/ToggleButton' export const StyledButton = styled(Button)(({ theme, color = 'primary' }) => ({ color: 'white', @@ -9,3 +10,10 @@ export const StyledButton = styled(Button)(({ theme, color = 'primary' }) => ({ backgroundImage: `linear-gradient(rgb(0 0 0/10%) 0 0)` } })) + +export const StyledToggleButton = styled(MuiToggleButton)(({ theme, color = 'primary' }) => ({ + '&.Mui-selected, &.Mui-selected:hover': { + color: 'white', + backgroundColor: theme.palette[color].main + } +})) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js new file mode 100644 index 00000000..819a49cb --- /dev/null +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -0,0 +1,133 @@ +import PropTypes from 'prop-types' +import { useNavigate } from 'react-router-dom' +import { IconEdit } from '@tabler/icons' +import moment from 'moment' +import { styled } from '@mui/material/styles' +import Table from '@mui/material/Table' +import TableBody from '@mui/material/TableBody' +import TableCell, { tableCellClasses } from '@mui/material/TableCell' +import TableContainer from '@mui/material/TableContainer' +import TableHead from '@mui/material/TableHead' +import TableRow from '@mui/material/TableRow' +import Paper from '@mui/material/Paper' +import { Button, Typography } from '@mui/material' + +const StyledTableCell = styled(TableCell)(({ theme }) => ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white + }, + [`&.${tableCellClasses.body}`]: { + fontSize: 14 + } +})) + +const StyledTableRow = styled(TableRow)(({ theme }) => ({ + '&:nth-of-type(odd)': { + backgroundColor: theme.palette.action.hover + }, + // hide last border + '&:last-child td, &:last-child th': { + border: 0 + } +})) + +export const FlowListTable = ({ data, images, filterFunction }) => { + const navigate = useNavigate() + const goToCanvas = (selectedChatflow) => { + navigate(`/canvas/${selectedChatflow.id}`) + } + return ( + <> + + + + + + Name + + + Nodes + + + Last Modified Date + + + Actions + + + + + {data.filter(filterFunction).map((row, index) => ( + + + + {row.templateName || row.name} + + + + + {images[row.id] && ( +
+ {images[row.id].map((img) => ( +
+ +
+ ))} +
+ )} +
+ {moment(row.updatedDate).format('dddd, MMMM Do, YYYY h:mm:ss A')} + + + +
+ ))} +
+
+
+ + ) +} + +FlowListTable.propTypes = { + data: PropTypes.object, + images: PropTypes.array, + filterFunction: PropTypes.func +} diff --git a/packages/ui/src/ui-component/toolbar/Toolbar.js b/packages/ui/src/ui-component/toolbar/Toolbar.js new file mode 100644 index 00000000..f72ba339 --- /dev/null +++ b/packages/ui/src/ui-component/toolbar/Toolbar.js @@ -0,0 +1,24 @@ +import * as React from 'react' +import ViewListIcon from '@mui/icons-material/ViewList' +import ViewModuleIcon from '@mui/icons-material/ViewModule' +import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' +import { StyledToggleButton } from '../button/StyledButton' + +export default function Toolbar() { + const [view, setView] = React.useState('list') + + const handleChange = (event, nextView) => { + setView(nextView) + } + + return ( + + + + + + + + + ) +} diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index 6712623e..e01a9373 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom' import { useSelector } from 'react-redux' // material-ui -import { Grid, Box, Stack } from '@mui/material' +import { Grid, Box, Stack, Toolbar, ToggleButton, ButtonGroup, Typography, InputAdornment, TextField } from '@mui/material' import { useTheme } from '@mui/material/styles' // project imports @@ -11,7 +11,6 @@ import MainCard from 'ui-component/cards/MainCard' import ItemCard from 'ui-component/cards/ItemCard' import { gridSpacing } from 'store/constant' import WorkflowEmptySVG from 'assets/images/workflow_empty.svg' -import { StyledButton } from 'ui-component/button/StyledButton' import LoginDialog from 'ui-component/dialog/LoginDialog' // API @@ -24,7 +23,13 @@ import useApi from 'hooks/useApi' import { baseURL } from 'store/constant' // icons -import { IconPlus } from '@tabler/icons' +import { IconPlus, IconSearch } from '@tabler/icons' +import * as React from 'react' +import ViewListIcon from '@mui/icons-material/ViewList' +import ViewModuleIcon from '@mui/icons-material/ViewModule' +import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' +import { FlowListTable } from '../../ui-component/table/FlowListTable' +import { StyledButton } from '../../ui-component/button/StyledButton' // ==============================|| CHATFLOWS ||============================== // @@ -35,10 +40,24 @@ const Chatflows = () => { const [isLoading, setLoading] = useState(true) const [images, setImages] = useState({}) + const [search, setSearch] = useState('') const [loginDialogOpen, setLoginDialogOpen] = useState(false) const [loginDialogProps, setLoginDialogProps] = useState({}) const getAllChatflowsApi = useApi(chatflowsApi.getAllChatflows) + const [view, setView] = React.useState('card') + + const handleChange = (event, nextView) => { + setView(nextView) + } + + const onSearchChange = (event) => { + setSearch(event.target.value) + } + + function filterFlows(data) { + return data.name.toLowerCase().indexOf(search.toLowerCase()) > -1 + } const onLoginClick = (username, password) => { localStorage.setItem('username', username) @@ -102,26 +121,61 @@ const Chatflows = () => { return ( - -

Chatflows

- - - - }> - Add New - + + + + + Chatflows + + + + + + ) + }} + /> + + + + + + + + + + + + + + + }> + Add New + + + + + + {!isLoading && (!view || view === 'card') && getAllChatflowsApi.data && ( + + {getAllChatflowsApi.data.filter(filterFlows).map((data, index) => ( + + goToCanvas(data)} data={data} images={images[data.id]} /> + + ))} - + )} + {!isLoading && view === 'list' && getAllChatflowsApi.data && ( + + )}
- - {!isLoading && - getAllChatflowsApi.data && - getAllChatflowsApi.data.map((data, index) => ( - - goToCanvas(data)} data={data} images={images[data.id]} /> - - ))} - + {!isLoading && (!getAllChatflowsApi.data || getAllChatflowsApi.data.length === 0) && ( From 77994ce2178e2c7ba456a1a950bf6c89cde83040 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 14 Nov 2023 15:15:34 +0530 Subject: [PATCH 02/13] UX Changes: adding a placeholder for chatflow search. --- packages/ui/src/views/chatflows/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index e01a9373..f7d1497d 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -132,6 +132,7 @@ const Chatflows = () => { size='small' sx={{ width: 400 }} variant='outlined' + placeholder='Search Chatflows' onChange={onSearchChange} InputProps={{ startAdornment: ( From 7ef817bc996200d89c4d5f11d4a556f2ac5a16df Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 14 Nov 2023 15:48:14 +0530 Subject: [PATCH 03/13] UX Changes: limiting display of node icons to 5 and with label to indicate additional. --- packages/ui/src/ui-component/table/FlowListTable.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index 819a49cb..896ce3ea 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -37,6 +37,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { const goToCanvas = (selectedChatflow) => { navigate(`/canvas/${selectedChatflow.id}`) } + let nodeCount = 0 return ( <> @@ -53,7 +54,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { Name - Nodes + Nodes (Showing first 5) Last Modified Date @@ -84,7 +85,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { marginTop: 5 }} > - {images[row.id].map((img) => ( + {images[row.id].slice(0, images[row.id].length > 5 ? 5 : images[row.id].length).map((img) => (
{ />
))} + {images[row.id].length > 5 && ( + + + {images[row.id].length - 5} More + + )} )} From 57b31130397ca0097ef04db78137cccc79d7b63e Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 14 Nov 2023 20:13:24 +0530 Subject: [PATCH 04/13] UX Changes: minor UI tweaks/adjustments and fixes for small screens --- .../src/ui-component/table/FlowListTable.js | 20 ++++++------- packages/ui/src/views/chatflows/index.js | 28 +++++++++++++------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index 896ce3ea..9dfc9522 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -37,26 +37,20 @@ export const FlowListTable = ({ data, images, filterFunction }) => { const goToCanvas = (selectedChatflow) => { navigate(`/canvas/${selectedChatflow.id}`) } - let nodeCount = 0 + return ( <> - + Name - + Nodes (Showing first 5) - + Last Modified Date @@ -75,7 +69,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { - + {images[row.id] && (
{
)}
- {moment(row.updatedDate).format('dddd, MMMM Do, YYYY h:mm:ss A')} + + {moment(row.updatedDate).format('dddd, MMMM Do, YYYY h:mm:ss A')} + + ) + } + }) + } + } + + const handleDelete = async () => { + setAnchorEl(null) + const confirmPayload = { + title: `Delete`, + description: `Delete chatflow ${chatflow.name}?`, + confirmButtonName: 'Delete', + cancelButtonName: 'Cancel' + } + const isConfirmed = await confirm(confirmPayload) + + if (isConfirmed) { + try { + await chatflowsApi.deleteChatflow(chatflow.id) + await updateFlowsApi.request() + } catch (error) { + const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` + enqueueSnackbar({ + message: errorData, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } + } + + const handleDuplicate = () => { + setAnchorEl(null) + try { + localStorage.setItem('duplicatedFlowData', chatflow.flowData) + window.open(`${uiBaseURL}/canvas`, '_blank') + } catch (e) { + console.error(e) + } + } + const handleExport = () => { + setAnchorEl(null) + try { + const flowData = JSON.parse(chatflow.flowData) + let dataStr = JSON.stringify(generateExportFlowData(flowData), null, 2) + let dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr) + + let exportFileDefaultName = `${chatflow.name} Chatflow.json` + + let linkElement = document.createElement('a') + linkElement.setAttribute('href', dataUri) + linkElement.setAttribute('download', exportFileDefaultName) + linkElement.click() + } catch (e) { + console.error(e) + } + } + + return ( +
+ + + + + Rename + + + + Duplicate + + + + Export + + + + + Delete + + + + setFlowDialogOpen(false)} + onConfirm={saveFlowRename} + /> +
+ ) +} + +FlowListMenu.propTypes = { + chatflow: PropTypes.object, + updateFlowsApi: PropTypes.object +} diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index 9dfc9522..8dc25e96 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -1,6 +1,5 @@ import PropTypes from 'prop-types' import { useNavigate } from 'react-router-dom' -import { IconEdit } from '@tabler/icons' import moment from 'moment' import { styled } from '@mui/material/styles' import Table from '@mui/material/Table' @@ -10,7 +9,8 @@ import TableContainer from '@mui/material/TableContainer' import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' import Paper from '@mui/material/Paper' -import { Button, Typography } from '@mui/material' +import { Button, Stack, Typography } from '@mui/material' +import FlowListMenu from '../button/FlowListMenu' const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -32,7 +32,7 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({ } })) -export const FlowListTable = ({ data, images, filterFunction }) => { +export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) => { const navigate = useNavigate() const goToCanvas = (selectedChatflow) => { navigate(`/canvas/${selectedChatflow.id}`) @@ -44,7 +44,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => {
- + Name @@ -53,7 +53,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { Last Modified Date - + Actions @@ -65,7 +65,7 @@ export const FlowListTable = ({ data, images, filterFunction }) => { - {row.templateName || row.name} + @@ -111,15 +111,13 @@ export const FlowListTable = ({ data, images, filterFunction }) => { {moment(row.updatedDate).format('dddd, MMMM Do, YYYY h:mm:ss A')} - - + + + {/**/} + + ))} @@ -133,5 +131,6 @@ export const FlowListTable = ({ data, images, filterFunction }) => { FlowListTable.propTypes = { data: PropTypes.object, images: PropTypes.array, - filterFunction: PropTypes.func + filterFunction: PropTypes.func, + updateFlowsApi: PropTypes.object } diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index b7784a89..f008bfa8 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -23,10 +23,8 @@ import useApi from 'hooks/useApi' import { baseURL } from 'store/constant' // icons -import { IconPlus, IconSearch } from '@tabler/icons' +import { IconPlus, IconSearch, IconLayoutCards, IconLayoutColumns } from '@tabler/icons' import * as React from 'react' -import ViewListIcon from '@mui/icons-material/ViewList' -import ViewModuleIcon from '@mui/icons-material/ViewModule' import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' import { FlowListTable } from '../../ui-component/table/FlowListTable' import { StyledButton } from '../../ui-component/button/StyledButton' @@ -159,10 +157,10 @@ const Chatflows = () => { > - + - + @@ -185,7 +183,13 @@ const Chatflows = () => { )} {!isLoading && view === 'list' && getAllChatflowsApi.data && ( - + )} From a7b34848cd3fe814b4e3820c2409c77f0d67c5ca Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Thu, 16 Nov 2023 08:29:06 +0530 Subject: [PATCH 06/13] UX Changes: Ability to set category (tags) to each chatflow; corresponding changes to table display and table search --- .../server/src/database/entities/ChatFlow.ts | 3 + .../1699900910291-AddCategoryToChatFlow.ts | 12 +++ .../src/database/migrations/mysql/index.ts | 4 +- .../1699900910291-AddCategoryToChatFlow.ts | 11 +++ .../src/database/migrations/postgres/index.ts | 4 +- .../1699900910291-AddCategoryToChatFlow.ts | 11 +++ .../src/database/migrations/sqlite/index.ts | 4 +- .../src/ui-component/button/FlowListMenu.js | 55 ++++++++++- .../ui/src/ui-component/dialog/TagDialog.js | 91 +++++++++++++++++++ .../src/ui-component/table/FlowListTable.js | 35 +++++-- packages/ui/src/views/chatflows/index.js | 7 +- 11 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 packages/server/src/database/migrations/mysql/1699900910291-AddCategoryToChatFlow.ts create mode 100644 packages/server/src/database/migrations/postgres/1699900910291-AddCategoryToChatFlow.ts create mode 100644 packages/server/src/database/migrations/sqlite/1699900910291-AddCategoryToChatFlow.ts create mode 100644 packages/ui/src/ui-component/dialog/TagDialog.js diff --git a/packages/server/src/database/entities/ChatFlow.ts b/packages/server/src/database/entities/ChatFlow.ts index 376a100b..b3131c2e 100644 --- a/packages/server/src/database/entities/ChatFlow.ts +++ b/packages/server/src/database/entities/ChatFlow.ts @@ -36,4 +36,7 @@ export class ChatFlow implements IChatFlow { @UpdateDateColumn() updatedDate: Date + + @Column({ nullable: true, type: 'text' }) + category?: string } diff --git a/packages/server/src/database/migrations/mysql/1699900910291-AddCategoryToChatFlow.ts b/packages/server/src/database/migrations/mysql/1699900910291-AddCategoryToChatFlow.ts new file mode 100644 index 00000000..424f3b0e --- /dev/null +++ b/packages/server/src/database/migrations/mysql/1699900910291-AddCategoryToChatFlow.ts @@ -0,0 +1,12 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddCategoryToChatFlow1699900910291 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const columnExists = await queryRunner.hasColumn('chat_flow', 'category') + if (!columnExists) queryRunner.query(`ALTER TABLE \`chat_flow\` ADD COLUMN \`category\` TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE \`chat_flow\` DROP COLUMN \`category\`;`) + } +} diff --git a/packages/server/src/database/migrations/mysql/index.ts b/packages/server/src/database/migrations/mysql/index.ts index 4b7b8a95..53d652ee 100644 --- a/packages/server/src/database/migrations/mysql/index.ts +++ b/packages/server/src/database/migrations/mysql/index.ts @@ -8,6 +8,7 @@ import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic' import { AddChatHistory1694658767766 } from './1694658767766-AddChatHistory' import { AddAssistantEntity1699325775451 } from './1699325775451-AddAssistantEntity' import { AddUsedToolsToChatMessage1699481607341 } from './1699481607341-AddUsedToolsToChatMessage' +import { AddCategoryToChatFlow1699900910291 } from './1699900910291-AddCategoryToChatFlow' export const mysqlMigrations = [ Init1693840429259, @@ -19,5 +20,6 @@ export const mysqlMigrations = [ AddAnalytic1694432361423, AddChatHistory1694658767766, AddAssistantEntity1699325775451, - AddUsedToolsToChatMessage1699481607341 + AddUsedToolsToChatMessage1699481607341, + AddCategoryToChatFlow1699900910291 ] diff --git a/packages/server/src/database/migrations/postgres/1699900910291-AddCategoryToChatFlow.ts b/packages/server/src/database/migrations/postgres/1699900910291-AddCategoryToChatFlow.ts new file mode 100644 index 00000000..f5d96439 --- /dev/null +++ b/packages/server/src/database/migrations/postgres/1699900910291-AddCategoryToChatFlow.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddCategoryToChatFlow1699900910291 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN IF NOT EXISTS "category" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "category";`) + } +} diff --git a/packages/server/src/database/migrations/postgres/index.ts b/packages/server/src/database/migrations/postgres/index.ts index 75562c0b..70642eb6 100644 --- a/packages/server/src/database/migrations/postgres/index.ts +++ b/packages/server/src/database/migrations/postgres/index.ts @@ -8,6 +8,7 @@ import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic' import { AddChatHistory1694658756136 } from './1694658756136-AddChatHistory' import { AddAssistantEntity1699325775451 } from './1699325775451-AddAssistantEntity' import { AddUsedToolsToChatMessage1699481607341 } from './1699481607341-AddUsedToolsToChatMessage' +import { AddCategoryToChatFlow1699900910291 } from './1699900910291-AddCategoryToChatFlow' export const postgresMigrations = [ Init1693891895163, @@ -19,5 +20,6 @@ export const postgresMigrations = [ AddAnalytic1694432361423, AddChatHistory1694658756136, AddAssistantEntity1699325775451, - AddUsedToolsToChatMessage1699481607341 + AddUsedToolsToChatMessage1699481607341, + AddCategoryToChatFlow1699900910291 ] diff --git a/packages/server/src/database/migrations/sqlite/1699900910291-AddCategoryToChatFlow.ts b/packages/server/src/database/migrations/sqlite/1699900910291-AddCategoryToChatFlow.ts new file mode 100644 index 00000000..270b2998 --- /dev/null +++ b/packages/server/src/database/migrations/sqlite/1699900910291-AddCategoryToChatFlow.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class AddCategoryToChatFlow1699900910291 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "category" TEXT;`) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "category";`) + } +} diff --git a/packages/server/src/database/migrations/sqlite/index.ts b/packages/server/src/database/migrations/sqlite/index.ts index 4a14fc40..fe7611ea 100644 --- a/packages/server/src/database/migrations/sqlite/index.ts +++ b/packages/server/src/database/migrations/sqlite/index.ts @@ -8,6 +8,7 @@ import { AddAnalytic1694432361423 } from './1694432361423-AddAnalytic' import { AddChatHistory1694657778173 } from './1694657778173-AddChatHistory' import { AddAssistantEntity1699325775451 } from './1699325775451-AddAssistantEntity' import { AddUsedToolsToChatMessage1699481607341 } from './1699481607341-AddUsedToolsToChatMessage' +import { AddCategoryToChatFlow1699900910291 } from './1699900910291-AddCategoryToChatFlow' export const sqliteMigrations = [ Init1693835579790, @@ -19,5 +20,6 @@ export const sqliteMigrations = [ AddAnalytic1694432361423, AddChatHistory1694657778173, AddAssistantEntity1699325775451, - AddUsedToolsToChatMessage1699481607341 + AddUsedToolsToChatMessage1699481607341, + AddCategoryToChatFlow1699900910291 ] diff --git a/packages/ui/src/ui-component/button/FlowListMenu.js b/packages/ui/src/ui-component/button/FlowListMenu.js index fb759505..f4ffbd32 100644 --- a/packages/ui/src/ui-component/button/FlowListMenu.js +++ b/packages/ui/src/ui-component/button/FlowListMenu.js @@ -7,6 +7,7 @@ import Divider from '@mui/material/Divider' import FileCopyIcon from '@mui/icons-material/FileCopy' import FileDownloadIcon from '@mui/icons-material/Downloading' import FileDeleteIcon from '@mui/icons-material/Delete' +import FileCategoryIcon from '@mui/icons-material/Category' import Button from '@mui/material/Button' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' import PropTypes from 'prop-types' @@ -22,6 +23,7 @@ import ConfirmDialog from '../dialog/ConfirmDialog' import SaveChatflowDialog from '../dialog/SaveChatflowDialog' import { useState } from 'react' import useApi from '../../hooks/useApi' +import TagDialog from '../dialog/TagDialog' const StyledMenu = styled((props) => ( dispatch(enqueueSnackbarAction(...args)) const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) - const [anchorEl, setAnchorEl] = React.useState(null) const open = Boolean(anchorEl) const handleClick = (event) => { @@ -79,12 +83,10 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { const handleClose = () => { setAnchorEl(null) } - const handleFlowRename = () => { setAnchorEl(null) setFlowDialogOpen(true) } - const saveFlowRename = async (chatflowName) => { const updateBody = { name: chatflowName, @@ -110,7 +112,39 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { }) } } - + const handleFlowCategory = () => { + setAnchorEl(null) + if (chatflow.category) setCategoryValues(chatflow.category.split(';')) + else setCategoryValues([]) + setCategoryDialogOpen(true) + } + const saveFlowCategory = async (categories) => { + // save categories as string + const categoryTags = categories.join(';') + const updateBody = { + category: categoryTags, + chatflow + } + try { + await updateChatflowApi.request(chatflow.id, updateBody) + await updateFlowsApi.request() + } catch (error) { + const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` + enqueueSnackbar({ + message: errorData, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } const handleDelete = async () => { setAnchorEl(null) const confirmPayload = { @@ -143,7 +177,6 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { } } } - const handleDuplicate = () => { setAnchorEl(null) try { @@ -206,6 +239,11 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { Export + + + Update Category + + Delete @@ -222,6 +260,13 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { onCancel={() => setFlowDialogOpen(false)} onConfirm={saveFlowRename} /> + setCategoryDialogOpen(false)} + tags={categoryValues} + setTags={setCategoryValues} + onSubmit={saveFlowCategory} + /> ) } diff --git a/packages/ui/src/ui-component/dialog/TagDialog.js b/packages/ui/src/ui-component/dialog/TagDialog.js new file mode 100644 index 00000000..be133fa4 --- /dev/null +++ b/packages/ui/src/ui-component/dialog/TagDialog.js @@ -0,0 +1,91 @@ +import { useState } from 'react' +import Dialog from '@mui/material/Dialog' +import Box from '@mui/material/Box' +import Button from '@mui/material/Button' +import TextField from '@mui/material/TextField' +import Chip from '@mui/material/Chip' +import PropTypes from 'prop-types' +import { DialogActions, DialogContent, DialogTitle } from '@mui/material' + +const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { + const [inputValue, setInputValue] = useState('') + + const handleInputChange = (event) => { + setInputValue(event.target.value) + } + + const handleInputKeyDown = (event) => { + if (event.key === 'Enter' && inputValue.trim()) { + event.preventDefault() + if (!tags.includes(inputValue)) { + setTags([...tags, inputValue]) + setInputValue('') + } + } + } + + const handleDeleteTag = (tagToDelete) => { + setTags(tags.filter((tag) => tag !== tagToDelete)) + } + + const handleSubmit = (event) => { + event.preventDefault() + onSubmit(tags) + onClose() + } + + return ( + + + Set Chatflow Category Tags + + + +
+
+ {tags.map((tag, index) => ( + handleDeleteTag(tag)} + style={{ marginRight: 5, marginBottom: 5 }} + /> + ))} +
+ + +
+
+ + + + +
+ ) +} + +TagDialog.propTypes = { + isOpen: PropTypes.bool, + onClose: PropTypes.func, + tags: PropTypes.array, + setTags: PropTypes.func, + onSubmit: PropTypes.func +} + +export default TagDialog diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index 8dc25e96..08caed57 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -11,6 +11,7 @@ import TableRow from '@mui/material/TableRow' import Paper from '@mui/material/Paper' import { Button, Stack, Typography } from '@mui/material' import FlowListMenu from '../button/FlowListMenu' +import Chip from '@mui/material/Chip' const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { @@ -47,13 +48,16 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) Name - - Nodes (Showing first 5) + + Category - Last Modified Date + Nodes (Showing first 5) + Last Modified Date + + Actions @@ -68,8 +72,25 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) - +
+   + {row.category && + row.category + .split(';') + .map((tag, index) => ( + + ))} +
+
+ {images[row.id] && (
)} - - {moment(row.updatedDate).format('dddd, MMMM Do, YYYY h:mm:ss A')} - + {moment(row.updatedDate).format('MMMM Do, YYYY')} + + {/**/} diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index 44c670d6..34c6523b 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -23,7 +23,7 @@ import useApi from 'hooks/useApi' import { baseURL } from 'store/constant' // icons -import { IconPlus, IconSearch, IconLayoutCards, IconLayoutColumns } from '@tabler/icons' +import { IconPlus, IconSearch, IconLayoutGrid, IconList } from '@tabler/icons' import * as React from 'react' import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' import { FlowListTable } from '../../ui-component/table/FlowListTable' @@ -138,7 +138,7 @@ const Chatflows = () => {

Chatflows

{ }} /> - + - - - + + + - - + + From 97247713ef7c2f0134c3114c1de84fea040a47f5 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 17 Nov 2023 11:24:55 +0530 Subject: [PATCH 08/13] UX Changes: Fixed 2 edge cases, (1) UI-tag not added, when the user clicks the submit without hitting enter and (2) server side error when the update/rename is attempted before any flow is opened --- packages/server/src/index.ts | 8 ++++++-- packages/ui/src/ui-component/dialog/TagDialog.js | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ba6c3ce0..5a5b2eda 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -355,8 +355,12 @@ export class App { this.AppDataSource.getRepository(ChatFlow).merge(chatflow, updateChatFlow) const result = await this.AppDataSource.getRepository(ChatFlow).save(chatflow) - // Update chatflowpool inSync to false, to build Langchain again because data has been changed - this.chatflowPool.updateInSync(chatflow.id, false) + // chatFlowPool is initialized only when a flow is opened + // if the user attempts to rename/update category without opening any flow, chatFlowPool will be undefined + if (this.chatflowPool) { + // Update chatflowpool inSync to false, to build Langchain again because data has been changed + this.chatflowPool.updateInSync(chatflow.id, false) + } return res.json(result) }) diff --git a/packages/ui/src/ui-component/dialog/TagDialog.js b/packages/ui/src/ui-component/dialog/TagDialog.js index be133fa4..778bf2cc 100644 --- a/packages/ui/src/ui-component/dialog/TagDialog.js +++ b/packages/ui/src/ui-component/dialog/TagDialog.js @@ -5,7 +5,7 @@ import Button from '@mui/material/Button' import TextField from '@mui/material/TextField' import Chip from '@mui/material/Chip' import PropTypes from 'prop-types' -import { DialogActions, DialogContent, DialogTitle } from '@mui/material' +import { DialogActions, DialogContent, DialogTitle, Typography } from '@mui/material' const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { const [inputValue, setInputValue] = useState('') @@ -30,6 +30,9 @@ const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { const handleSubmit = (event) => { event.preventDefault() + if (inputValue.trim() && !tags.includes(inputValue)) { + setTags([...tags, inputValue]) + } onSubmit(tags) onClose() } @@ -67,6 +70,9 @@ const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { label='Add a tag' variant='outlined' /> + + Enter a tag and press enter to add it to the list. You can add as many tags as you want. + From a0397c008e035ec64e8063b4b2c7859a5d2eadc8 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Fri, 17 Nov 2023 11:25:59 +0530 Subject: [PATCH 09/13] UX Changes: Column display fixes for 'xs' mode --- packages/ui/src/ui-component/table/FlowListTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index 68641d44..e33a8ba1 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -48,7 +48,7 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) Name - + Category @@ -72,7 +72,7 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) - +
Date: Fri, 17 Nov 2023 12:29:14 +0530 Subject: [PATCH 10/13] UX Changes: Addition of search filters for API Keys and Credentials. --- packages/ui/src/views/apikey/index.js | 71 ++++++++++++++--- packages/ui/src/views/credentials/index.js | 88 ++++++++++++++++++---- 2 files changed, 136 insertions(+), 23 deletions(-) diff --git a/packages/ui/src/views/apikey/index.js b/packages/ui/src/views/apikey/index.js index a2b2e639..e08baac2 100644 --- a/packages/ui/src/views/apikey/index.js +++ b/packages/ui/src/views/apikey/index.js @@ -16,7 +16,11 @@ import { Paper, IconButton, Popover, - Typography + Typography, + Toolbar, + TextField, + InputAdornment, + ButtonGroup } from '@mui/material' import { useTheme } from '@mui/material/styles' @@ -37,7 +41,7 @@ import useConfirm from 'hooks/useConfirm' import useNotifier from 'utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconCopy, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons' +import { IconTrash, IconEdit, IconCopy, IconX, IconPlus, IconEye, IconEyeOff, IconSearch } from '@tabler/icons' import APIEmptySVG from 'assets/images/api_empty.svg' // ==============================|| APIKey ||============================== // @@ -59,6 +63,14 @@ const APIKey = () => { const [showApiKeys, setShowApiKeys] = useState([]) const openPopOver = Boolean(anchorEl) + const [search, setSearch] = useState('') + const onSearchChange = (event) => { + setSearch(event.target.value) + } + function filterKeys(data) { + return data.keyName.toLowerCase().indexOf(search.toLowerCase()) > -1 + } + const { confirm } = useConfirm() const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys) @@ -171,12 +183,53 @@ const APIKey = () => { <> -

API Keys 

- - - }> - Create Key - + + +

API Keys 

+ + + + ) + }} + /> + + + + } + > + Create Key + + + +
+
{apiKeys.length <= 0 && ( @@ -199,7 +252,7 @@ const APIKey = () => { - {apiKeys.map((key, index) => ( + {apiKeys.filter(filterKeys).map((key, index) => ( {key.keyName} diff --git a/packages/ui/src/views/credentials/index.js b/packages/ui/src/views/credentials/index.js index 9db990a7..31e35831 100644 --- a/packages/ui/src/views/credentials/index.js +++ b/packages/ui/src/views/credentials/index.js @@ -4,7 +4,23 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba import moment from 'moment' // material-ui -import { Button, Box, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, IconButton } from '@mui/material' +import { + Button, + Box, + Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Paper, + IconButton, + Toolbar, + TextField, + InputAdornment, + ButtonGroup +} from '@mui/material' import { useTheme } from '@mui/material/styles' // project imports @@ -25,7 +41,7 @@ import useConfirm from 'hooks/useConfirm' import useNotifier from 'utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconX, IconPlus } from '@tabler/icons' +import { IconTrash, IconEdit, IconX, IconPlus, IconSearch } from '@tabler/icons' import CredentialEmptySVG from 'assets/images/credential_empty.svg' // const @@ -56,6 +72,14 @@ const Credentials = () => { const getAllCredentialsApi = useApi(credentialsApi.getAllCredentials) const getAllComponentsCredentialsApi = useApi(credentialsApi.getAllComponentsCredentials) + const [search, setSearch] = useState('') + const onSearchChange = (event) => { + setSearch(event.target.value) + } + function filterCredentials(data) { + return data.credentialName.toLowerCase().indexOf(search.toLowerCase()) > -1 + } + const listCredential = () => { const dialogProp = { title: 'Add New Credential', @@ -168,17 +192,53 @@ const Credentials = () => { <> -

Credentials 

- - - } - > - Add Credential - + + +

Credentials 

+ + + + ) + }} + /> + + + + } + > + Add Credential + + + +
+
{credentials.length <= 0 && ( @@ -205,7 +265,7 @@ const Credentials = () => {
- {credentials.map((credential, index) => ( + {credentials.filter(filterCredentials).map((credential, index) => (
Date: Fri, 17 Nov 2023 12:35:01 +0000 Subject: [PATCH 11/13] add fix where tags are not added when submit is clicked without enter --- .../src/ui-component/button/FlowListMenu.js | 57 ++++++++++------- .../ui/src/ui-component/dialog/TagDialog.js | 63 +++++++++++-------- .../src/ui-component/table/FlowListTable.js | 2 +- 3 files changed, 75 insertions(+), 47 deletions(-) diff --git a/packages/ui/src/ui-component/button/FlowListMenu.js b/packages/ui/src/ui-component/button/FlowListMenu.js index 44192298..b242d2cb 100644 --- a/packages/ui/src/ui-component/button/FlowListMenu.js +++ b/packages/ui/src/ui-component/button/FlowListMenu.js @@ -1,4 +1,7 @@ -import * as React from 'react' +import { useState } from 'react' +import { useDispatch } from 'react-redux' +import PropTypes from 'prop-types' + import { styled, alpha } from '@mui/material/styles' import Menu from '@mui/material/Menu' import MenuItem from '@mui/material/MenuItem' @@ -10,21 +13,22 @@ import FileDeleteIcon from '@mui/icons-material/Delete' import FileCategoryIcon from '@mui/icons-material/Category' import Button from '@mui/material/Button' import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' -import PropTypes from 'prop-types' -import { uiBaseURL } from '../../store/constant' -import { generateExportFlowData } from '../../utils/genericHelper' -import chatflowsApi from 'api/chatflows' -import useConfirm from 'hooks/useConfirm' -import useNotifier from '../../utils/useNotifier' -import { closeSnackbar as closeSnackbarAction, enqueueSnackbar as enqueueSnackbarAction } from '../../store/actions' import { IconX } from '@tabler/icons' -import { useDispatch } from 'react-redux' + +import chatflowsApi from 'api/chatflows' + +import useApi from '../../hooks/useApi' +import useConfirm from 'hooks/useConfirm' +import { uiBaseURL } from '../../store/constant' +import { closeSnackbar as closeSnackbarAction, enqueueSnackbar as enqueueSnackbarAction } from '../../store/actions' + import ConfirmDialog from '../dialog/ConfirmDialog' import SaveChatflowDialog from '../dialog/SaveChatflowDialog' -import { useState } from 'react' -import useApi from '../../hooks/useApi' import TagDialog from '../dialog/TagDialog' +import { generateExportFlowData } from '../../utils/genericHelper' +import useNotifier from '../../utils/useNotifier' + const StyledMenu = styled((props) => ( ( export default function FlowListMenu({ chatflow, updateFlowsApi }) { const { confirm } = useConfirm() const dispatch = useDispatch() - const [flowDialogOpen, setFlowDialogOpen] = useState(false) - const [categoryValues, setCategoryValues] = useState([]) - - const [categoryDialogOpen, setCategoryDialogOpen] = useState(false) const updateChatflowApi = useApi(chatflowsApi.updateChatflow) - // ==============================|| Snackbar ||============================== // useNotifier() const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) - const [anchorEl, setAnchorEl] = React.useState(null) + + const [flowDialogOpen, setFlowDialogOpen] = useState(false) + const [categoryDialogOpen, setCategoryDialogOpen] = useState(false) + const [categoryDialogProps, setCategoryDialogProps] = useState({}) + const [anchorEl, setAnchorEl] = useState(null) const open = Boolean(anchorEl) + const handleClick = (event) => { setAnchorEl(event.currentTarget) } + const handleClose = () => { setAnchorEl(null) } + const handleFlowRename = () => { setAnchorEl(null) setFlowDialogOpen(true) } + const saveFlowRename = async (chatflowName) => { const updateBody = { name: chatflowName, @@ -111,13 +118,19 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { }) } } + const handleFlowCategory = () => { setAnchorEl(null) - if (chatflow.category) setCategoryValues(chatflow.category.split(';')) - else setCategoryValues([]) + if (chatflow.category) { + setCategoryDialogProps({ + category: chatflow.category.split(';') + }) + } setCategoryDialogOpen(true) } + const saveFlowCategory = async (categories) => { + setCategoryDialogOpen(false) // save categories as string const categoryTags = categories.join(';') const updateBody = { @@ -144,6 +157,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { }) } } + const handleDelete = async () => { setAnchorEl(null) const confirmPayload = { @@ -176,6 +190,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { } } } + const handleDuplicate = () => { setAnchorEl(null) try { @@ -185,6 +200,7 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { console.error(e) } } + const handleExport = () => { setAnchorEl(null) try { @@ -261,9 +277,8 @@ export default function FlowListMenu({ chatflow, updateFlowsApi }) { /> setCategoryDialogOpen(false)} - tags={categoryValues} - setTags={setCategoryValues} onSubmit={saveFlowCategory} />
diff --git a/packages/ui/src/ui-component/dialog/TagDialog.js b/packages/ui/src/ui-component/dialog/TagDialog.js index 778bf2cc..82c35dde 100644 --- a/packages/ui/src/ui-component/dialog/TagDialog.js +++ b/packages/ui/src/ui-component/dialog/TagDialog.js @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useState, useEffect } from 'react' import Dialog from '@mui/material/Dialog' import Box from '@mui/material/Box' import Button from '@mui/material/Button' @@ -7,8 +7,9 @@ import Chip from '@mui/material/Chip' import PropTypes from 'prop-types' import { DialogActions, DialogContent, DialogTitle, Typography } from '@mui/material' -const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { +const TagDialog = ({ isOpen, dialogProps, onClose, onSubmit }) => { const [inputValue, setInputValue] = useState('') + const [categoryValues, setCategoryValues] = useState([]) const handleInputChange = (event) => { setInputValue(event.target.value) @@ -17,34 +18,44 @@ const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { const handleInputKeyDown = (event) => { if (event.key === 'Enter' && inputValue.trim()) { event.preventDefault() - if (!tags.includes(inputValue)) { - setTags([...tags, inputValue]) + if (!categoryValues.includes(inputValue)) { + setCategoryValues([...categoryValues, inputValue]) setInputValue('') } } } - const handleDeleteTag = (tagToDelete) => { - setTags(tags.filter((tag) => tag !== tagToDelete)) + const handleDeleteTag = (categoryToDelete) => { + setCategoryValues(categoryValues.filter((category) => category !== categoryToDelete)) } const handleSubmit = (event) => { event.preventDefault() - if (inputValue.trim() && !tags.includes(inputValue)) { - setTags([...tags, inputValue]) + let newCategories = [...categoryValues] + if (inputValue.trim() && !categoryValues.includes(inputValue)) { + newCategories = [...newCategories, inputValue] + setCategoryValues(newCategories) } - onSubmit(tags) - onClose() + onSubmit(newCategories) } + useEffect(() => { + if (dialogProps.category) setCategoryValues(dialogProps.category) + + return () => { + setInputValue('') + setCategoryValues([]) + } + }, [dialogProps]) + return ( Set Chatflow Category Tags @@ -52,17 +63,20 @@ const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => {
-
- {tags.map((tag, index) => ( - handleDeleteTag(tag)} - style={{ marginRight: 5, marginBottom: 5 }} - /> - ))} -
+ {categoryValues.length > 0 && ( +
+ {categoryValues.map((category, index) => ( + handleDeleteTag(category)} + style={{ marginRight: 5, marginBottom: 5 }} + /> + ))} +
+ )} { label='Add a tag' variant='outlined' /> - + Enter a tag and press enter to add it to the list. You can add as many tags as you want. @@ -88,9 +102,8 @@ const TagDialog = ({ isOpen, onClose, tags, setTags, onSubmit }) => { TagDialog.propTypes = { isOpen: PropTypes.bool, + dialogProps: PropTypes.object, onClose: PropTypes.func, - tags: PropTypes.array, - setTags: PropTypes.func, onSubmit: PropTypes.func } diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index e33a8ba1..c879d82d 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -9,9 +9,9 @@ import TableContainer from '@mui/material/TableContainer' import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' import Paper from '@mui/material/Paper' +import Chip from '@mui/material/Chip' import { Button, Stack, Typography } from '@mui/material' import FlowListMenu from '../button/FlowListMenu' -import Chip from '@mui/material/Chip' const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { From 0b4bf0193123e955fc990a8180139528ff7f6cd5 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 17 Nov 2023 12:44:16 +0000 Subject: [PATCH 12/13] unhide columns when xs mode --- .../ui/src/ui-component/table/FlowListTable.js | 14 ++++++-------- packages/ui/src/views/chatflows/index.js | 7 +------ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/ui/src/ui-component/table/FlowListTable.js b/packages/ui/src/ui-component/table/FlowListTable.js index c879d82d..e3baa2e2 100644 --- a/packages/ui/src/ui-component/table/FlowListTable.js +++ b/packages/ui/src/ui-component/table/FlowListTable.js @@ -51,13 +51,13 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) Category - + Nodes - + Last Modified Date - + Actions
@@ -90,7 +90,7 @@ export const FlowListTable = ({ data, images, filterFunction, updateFlowsApi }) ))}
- + {images[row.id] && (
)} - - {moment(row.updatedDate).format('MMMM Do, YYYY')} - - + {moment(row.updatedDate).format('MMMM Do, YYYY')} + diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index 34c6523b..7f288a95 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -152,12 +152,7 @@ const Chatflows = () => { /> - + Date: Mon, 20 Nov 2023 18:19:25 +0530 Subject: [PATCH 13/13] UX Changes: persist user display choice in localStorage --- packages/ui/src/views/chatflows/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/views/chatflows/index.js b/packages/ui/src/views/chatflows/index.js index 7f288a95..3c4b8972 100644 --- a/packages/ui/src/views/chatflows/index.js +++ b/packages/ui/src/views/chatflows/index.js @@ -43,9 +43,10 @@ const Chatflows = () => { const [loginDialogProps, setLoginDialogProps] = useState({}) const getAllChatflowsApi = useApi(chatflowsApi.getAllChatflows) - const [view, setView] = React.useState('card') + const [view, setView] = React.useState(localStorage.getItem('flowDisplayStyle') || 'card') const handleChange = (event, nextView) => { + localStorage.setItem('flowDisplayStyle', nextView) setView(nextView) }