From 28f5d94c1343e4c122d9929fefb6fce1d598cf55 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Sat, 18 Nov 2023 16:47:15 +0530 Subject: [PATCH 1/4] API Keys: Displaying the names of the chatflows associated with the keys and Warning the user before deletion. --- packages/server/src/index.ts | 30 +++++- packages/ui/src/views/apikey/index.js | 138 +++++++++++++++----------- 2 files changed, 104 insertions(+), 64 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ba6c3ce0e..4307946ba 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1135,28 +1135,50 @@ export class App { // API Keys // ---------------------------------------- + const addChatflowsCount = async (keys: any, res: Response) => { + if (keys) { + const updatedKeys: any[] = [] + //iterate through keys and get chatflows + for (const key of keys) { + const chatflows = await this.AppDataSource.getRepository(ChatFlow) + .createQueryBuilder('cf') + .where('cf.apikeyid = :apikeyid', { apikeyid: key.id }) + .getMany() + const linkedChatFlows: any[] = [] + chatflows.map((cf) => { + linkedChatFlows.push({ + flowName: cf.name + }) + }) + key.chatFlows = linkedChatFlows + updatedKeys.push(key) + } + return res.json(updatedKeys) + } + return res.json(keys) + } // Get api keys this.app.get('/api/v1/apikey', async (req: Request, res: Response) => { const keys = await getAPIKeys() - return res.json(keys) + return addChatflowsCount(keys, res) }) // Add new api key this.app.post('/api/v1/apikey', async (req: Request, res: Response) => { const keys = await addAPIKey(req.body.keyName) - return res.json(keys) + return addChatflowsCount(keys, res) }) // Update api key this.app.put('/api/v1/apikey/:id', async (req: Request, res: Response) => { const keys = await updateAPIKey(req.params.id, req.body.keyName) - return res.json(keys) + return addChatflowsCount(keys, res) }) // Delete new api key this.app.delete('/api/v1/apikey/:id', async (req: Request, res: Response) => { const keys = await deleteAPIKey(req.params.id) - return res.json(keys) + return addChatflowsCount(keys, res) }) // Verify api key diff --git a/packages/ui/src/views/apikey/index.js b/packages/ui/src/views/apikey/index.js index a2b2e639f..226baaee3 100644 --- a/packages/ui/src/views/apikey/index.js +++ b/packages/ui/src/views/apikey/index.js @@ -6,6 +6,7 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba import { Button, Box, + Chip, Stack, Table, TableBody, @@ -37,7 +38,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, IconCornerDownRight, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons' import APIEmptySVG from 'assets/images/api_empty.svg' // ==============================|| APIKey ||============================== // @@ -106,7 +107,10 @@ const APIKey = () => { const deleteKey = async (key) => { const confirmPayload = { title: `Delete`, - description: `Delete key ${key.keyName}?`, + description: + key.chatFlows.length === 0 + ? `Delete key [${key.keyName}] ? ` + : `Delete key [${key.keyName}] ?\n There are ${key.chatFlows.length} chatflows using this key.`, confirmButtonName: 'Delete', cancelButtonName: 'Cancel' } @@ -193,6 +197,7 @@ const APIKey = () => { Key Name API Key + Usage Created @@ -200,65 +205,78 @@ const APIKey = () => { {apiKeys.map((key, index) => ( - - - {key.keyName} - - - {showApiKeys.includes(key.apiKey) - ? key.apiKey - : `${key.apiKey.substring(0, 2)}${'•'.repeat(18)}${key.apiKey.substring( - key.apiKey.length - 5 - )}`} - { - navigator.clipboard.writeText(key.apiKey) - setAnchorEl(event.currentTarget) - setTimeout(() => { - handleClosePopOver() - }, 1500) - }} - > - - - onShowApiKeyClick(key.apiKey)}> - {showApiKeys.includes(key.apiKey) ? : } - - - + + + {key.keyName} + + + {showApiKeys.includes(key.apiKey) + ? key.apiKey + : `${key.apiKey.substring(0, 2)}${'•'.repeat(18)}${key.apiKey.substring( + key.apiKey.length - 5 + )}`} + { + navigator.clipboard.writeText(key.apiKey) + setAnchorEl(event.currentTarget) + setTimeout(() => { + handleClosePopOver() + }, 1500) + }} > - Copied! - - - - {key.createdAt} - - edit(key)}> - - - - - deleteKey(key)}> - - - - + + + onShowApiKeyClick(key.apiKey)}> + {showApiKeys.includes(key.apiKey) ? : } + + + + Copied! + + + + {key.chatFlows.length} + {key.createdAt} + + edit(key)}> + + + + + deleteKey(key)}> + + + + + {key.chatFlows.length > 0 && ( + + + {' '} + {key.chatFlows.map((flow, index) => ( + + ))} + + + )} + ))} From a4a1e7d562dff040f9dd00cc51762e426fe2318f Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Mon, 20 Nov 2023 13:03:28 +0530 Subject: [PATCH 2/4] API Key: Changes to API Key Dashboard to show usage details (chatflows) --- packages/server/src/index.ts | 3 +- packages/ui/src/views/apikey/index.js | 204 ++++++++++++++++---------- 2 files changed, 131 insertions(+), 76 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 4307946ba..a8745db73 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1147,7 +1147,8 @@ export class App { const linkedChatFlows: any[] = [] chatflows.map((cf) => { linkedChatFlows.push({ - flowName: cf.name + flowName: cf.name, + updatedDate: cf.updatedDate }) }) key.chatFlows = linkedChatFlows diff --git a/packages/ui/src/views/apikey/index.js b/packages/ui/src/views/apikey/index.js index 226baaee3..72b73baf6 100644 --- a/packages/ui/src/views/apikey/index.js +++ b/packages/ui/src/views/apikey/index.js @@ -6,7 +6,6 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba import { Button, Box, - Chip, Stack, Table, TableBody, @@ -17,7 +16,8 @@ import { Paper, IconButton, Popover, - Typography + Typography, + Collapse } from '@mui/material' import { useTheme } from '@mui/material/styles' @@ -38,11 +38,118 @@ import useConfirm from 'hooks/useConfirm' import useNotifier from 'utils/useNotifier' // Icons -import { IconTrash, IconEdit, IconCopy, IconCornerDownRight, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons' +import { IconTrash, IconEdit, IconCopy, IconChevronsUp, IconChevronsDown, IconX, IconPlus, IconEye, IconEyeOff } from '@tabler/icons' import APIEmptySVG from 'assets/images/api_empty.svg' +import * as PropTypes from 'prop-types' // ==============================|| APIKey ||============================== // +function APIKeyRow(props) { + const [open, setOpen] = useState(false) + return ( + <> + *': { borderBottom: 'unset' } }}> + + {props.apiKey.keyName} + + + {props.showApiKeys.includes(props.apiKey.apiKey) + ? props.apiKey.apiKey + : `${props.apiKey.apiKey.substring(0, 2)}${'•'.repeat(18)}${props.apiKey.apiKey.substring( + props.apiKey.apiKey.length - 5 + )}`} + + + + + {props.showApiKeys.includes(props.apiKey.apiKey) ? : } + + + + Copied! + + + + + {props.apiKey.chatFlows.length}{' '} + {props.apiKey.chatFlows.length > 0 && ( + setOpen(!open)}> + {props.apiKey.chatFlows.length > 0 && open ? : } + + )} + + {props.apiKey.createdAt} + + + + + + + + + + + + + + + + + + + Chatflow Name + Modified On + Category + + + + {props.apiKey.chatFlows.map((flow, index) => ( + + + {flow.flowName} + + {flow.updatedDate} + + + ))} + +
+
+
+
+
+ + ) +} + +APIKeyRow.propTypes = { + apiKey: PropTypes.any, + showApiKeys: PropTypes.arrayOf(PropTypes.any), + onCopyClick: PropTypes.func, + onShowAPIClick: PropTypes.func, + open: PropTypes.bool, + anchorEl: PropTypes.any, + onClose: PropTypes.func, + theme: PropTypes.any, + onEditClick: PropTypes.func, + onDeleteClick: PropTypes.func +} const APIKey = () => { const theme = useTheme() const customization = useSelector((state) => state.customization) @@ -205,78 +312,25 @@ const APIKey = () => { {apiKeys.map((key, index) => ( - <> - - - {key.keyName} - - - {showApiKeys.includes(key.apiKey) - ? key.apiKey - : `${key.apiKey.substring(0, 2)}${'•'.repeat(18)}${key.apiKey.substring( - key.apiKey.length - 5 - )}`} - { - navigator.clipboard.writeText(key.apiKey) - setAnchorEl(event.currentTarget) - setTimeout(() => { - handleClosePopOver() - }, 1500) - }} - > - - - onShowApiKeyClick(key.apiKey)}> - {showApiKeys.includes(key.apiKey) ? : } - - - - Copied! - - - - {key.chatFlows.length} - {key.createdAt} - - edit(key)}> - - - - - deleteKey(key)}> - - - - - {key.chatFlows.length > 0 && ( - - - {' '} - {key.chatFlows.map((flow, index) => ( - - ))} - - - )} - + { + navigator.clipboard.writeText(key.apiKey) + setAnchorEl(event.currentTarget) + setTimeout(() => { + handleClosePopOver() + }, 1500) + }} + onShowAPIClick={() => onShowApiKeyClick(key.apiKey)} + open={openPopOver} + anchorEl={anchorEl} + onClose={handleClosePopOver} + theme={theme} + onEditClick={() => edit(key)} + onDeleteClick={() => deleteKey(key)} + /> ))} From c716c1972aeebf50aa7a9bc9086061a72a9716a5 Mon Sep 17 00:00:00 2001 From: vinodkiran Date: Tue, 21 Nov 2023 18:40:20 +0530 Subject: [PATCH 3/4] API Key: UX Fixes and adjustments post the dashboard updates --- packages/server/src/index.ts | 1 + packages/ui/src/views/apikey/index.js | 36 +++++++++++++++------------ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 922aa307e..2f7d31e25 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1161,6 +1161,7 @@ export class App { chatflows.map((cf) => { linkedChatFlows.push({ flowName: cf.name, + category: cf.category, updatedDate: cf.updatedDate }) }) diff --git a/packages/ui/src/views/apikey/index.js b/packages/ui/src/views/apikey/index.js index 96b0d1de0..73224cb2e 100644 --- a/packages/ui/src/views/apikey/index.js +++ b/packages/ui/src/views/apikey/index.js @@ -6,6 +6,7 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba import { Button, Box, + Chip, Stack, Table, TableBody, @@ -56,6 +57,7 @@ import { } from '@tabler/icons' import APIEmptySVG from 'assets/images/api_empty.svg' import * as PropTypes from 'prop-types' +import moment from 'moment/moment' // ==============================|| APIKey ||============================== // @@ -63,10 +65,8 @@ function APIKeyRow(props) { const [open, setOpen] = useState(false) return ( <> - *': { borderBottom: 'unset' } }}> - - {props.apiKey.keyName} - + + {props.apiKey.keyName} {props.showApiKeys.includes(props.apiKey.apiKey) ? props.apiKey.apiKey @@ -118,19 +118,15 @@ function APIKeyRow(props) { - + - +
- Chatflow Name - Modified On - Category + Chatflow Name + Modified On + Category @@ -139,8 +135,16 @@ function APIKeyRow(props) { {flow.flowName} - {flow.updatedDate} - + {moment(flow.updatedDate).format('DD-MMM-YY')} + +   + {flow.category && + flow.category + .split(';') + .map((tag, index) => ( + + ))} + ))} @@ -375,7 +379,7 @@ const APIKey = () => { - {apiKeys.map((key, index) => ( + {apiKeys.filter(filterKeys).map((key, index) => ( Date: Wed, 22 Nov 2023 23:55:00 +0000 Subject: [PATCH 4/4] slight ui update --- packages/ui/src/views/apikey/index.js | 92 +++++++++++++++------------ 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/packages/ui/src/views/apikey/index.js b/packages/ui/src/views/apikey/index.js index 73224cb2e..68113af5b 100644 --- a/packages/ui/src/views/apikey/index.js +++ b/packages/ui/src/views/apikey/index.js @@ -10,7 +10,6 @@ import { Stack, Table, TableBody, - TableCell, TableContainer, TableHead, TableRow, @@ -24,7 +23,8 @@ import { InputAdornment, ButtonGroup } from '@mui/material' -import { useTheme } from '@mui/material/styles' +import TableCell, { tableCellClasses } from '@mui/material/TableCell' +import { useTheme, styled } from '@mui/material/styles' // project imports import MainCard from 'ui-component/cards/MainCard' @@ -60,12 +60,24 @@ import * as PropTypes from 'prop-types' import moment from 'moment/moment' // ==============================|| APIKey ||============================== // +const StyledTableCell = styled(TableCell)(({ theme }) => ({ + [`&.${tableCellClasses.head}`]: { + backgroundColor: theme.palette.action.hover + } +})) + +const StyledTableRow = styled(TableRow)(() => ({ + // hide last border + '&:last-child td, &:last-child th': { + border: 0 + } +})) function APIKeyRow(props) { const [open, setOpen] = useState(false) return ( <> - + {props.apiKey.keyName} {props.showApiKeys.includes(props.apiKey.apiKey) @@ -100,7 +112,7 @@ function APIKeyRow(props) { {props.apiKey.chatFlows.length}{' '} {props.apiKey.chatFlows.length > 0 && ( - setOpen(!open)}> + setOpen(!open)}> {props.apiKey.chatFlows.length > 0 && open ? : } )} @@ -117,42 +129,44 @@ function APIKeyRow(props) { - - - - -
- - - Chatflow Name - Modified On - Category - - - - {props.apiKey.chatFlows.map((flow, index) => ( - - - {flow.flowName} - - {moment(flow.updatedDate).format('DD-MMM-YY')} - -   - {flow.category && - flow.category - .split(';') - .map((tag, index) => ( - - ))} - + {open && ( + + + + +
+ + + + Chatflow Name + + Modified On + Category - ))} - -
-
-
-
-
+ + + {props.apiKey.chatFlows.map((flow, index) => ( + + {flow.flowName} + {moment(flow.updatedDate).format('DD-MMM-YY')} + +   + {flow.category && + flow.category + .split(';') + .map((tag, index) => ( + + ))} + + + ))} + + + + + +
+ )} ) }