diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts
index 365776738..2f7d31e25 100644
--- a/packages/server/src/index.ts
+++ b/packages/server/src/index.ts
@@ -1148,28 +1148,52 @@ 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,
+ category: cf.category,
+ updatedDate: cf.updatedDate
+ })
+ })
+ 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 e08baac2d..68113af5b 100644
--- a/packages/ui/src/views/apikey/index.js
+++ b/packages/ui/src/views/apikey/index.js
@@ -6,23 +6,25 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba
import {
Button,
Box,
+ Chip,
Stack,
Table,
TableBody,
- TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
IconButton,
Popover,
+ Collapse,
Typography,
Toolbar,
TextField,
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'
@@ -41,11 +43,146 @@ import useConfirm from 'hooks/useConfirm'
import useNotifier from 'utils/useNotifier'
// Icons
-import { IconTrash, IconEdit, IconCopy, IconX, IconPlus, IconEye, IconEyeOff, IconSearch } from '@tabler/icons'
+import {
+ IconTrash,
+ IconEdit,
+ IconCopy,
+ IconChevronsUp,
+ IconChevronsDown,
+ IconX,
+ IconSearch,
+ IconPlus,
+ IconEye,
+ IconEyeOff
+} from '@tabler/icons'
import APIEmptySVG from 'assets/images/api_empty.svg'
+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)
+ ? 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}
+
+
+
+
+
+
+
+
+
+
+
+ {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) => (
+
+ ))}
+
+
+ ))}
+
+
+
+
+
+
+ )}
+ >
+ )
+}
+
+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)
@@ -118,7 +255,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'
}
@@ -246,6 +386,7 @@ const APIKey = () => {
Key Name
API Key
+ Usage
Created
@@ -253,65 +394,25 @@ const APIKey = () => {
{apiKeys.filter(filterKeys).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.createdAt}
-
- edit(key)}>
-
-
-
-
- deleteKey(key)}>
-
-
-
-
+ {
+ 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)}
+ />
))}