API Keys: Displaying the names of the chatflows associated with the keys and Warning the user before deletion.

This commit is contained in:
vinodkiran 2023-11-18 16:47:15 +05:30
parent 34702a9ba2
commit 28f5d94c13
2 changed files with 104 additions and 64 deletions

View File

@ -1135,28 +1135,50 @@ export class App {
// API Keys // 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 // Get api keys
this.app.get('/api/v1/apikey', async (req: Request, res: Response) => { this.app.get('/api/v1/apikey', async (req: Request, res: Response) => {
const keys = await getAPIKeys() const keys = await getAPIKeys()
return res.json(keys) return addChatflowsCount(keys, res)
}) })
// Add new api key // Add new api key
this.app.post('/api/v1/apikey', async (req: Request, res: Response) => { this.app.post('/api/v1/apikey', async (req: Request, res: Response) => {
const keys = await addAPIKey(req.body.keyName) const keys = await addAPIKey(req.body.keyName)
return res.json(keys) return addChatflowsCount(keys, res)
}) })
// Update api key // Update api key
this.app.put('/api/v1/apikey/:id', async (req: Request, res: Response) => { this.app.put('/api/v1/apikey/:id', async (req: Request, res: Response) => {
const keys = await updateAPIKey(req.params.id, req.body.keyName) const keys = await updateAPIKey(req.params.id, req.body.keyName)
return res.json(keys) return addChatflowsCount(keys, res)
}) })
// Delete new api key // Delete new api key
this.app.delete('/api/v1/apikey/:id', async (req: Request, res: Response) => { this.app.delete('/api/v1/apikey/:id', async (req: Request, res: Response) => {
const keys = await deleteAPIKey(req.params.id) const keys = await deleteAPIKey(req.params.id)
return res.json(keys) return addChatflowsCount(keys, res)
}) })
// Verify api key // Verify api key

View File

@ -6,6 +6,7 @@ import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackba
import { import {
Button, Button,
Box, Box,
Chip,
Stack, Stack,
Table, Table,
TableBody, TableBody,
@ -37,7 +38,7 @@ import useConfirm from 'hooks/useConfirm'
import useNotifier from 'utils/useNotifier' import useNotifier from 'utils/useNotifier'
// Icons // 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' import APIEmptySVG from 'assets/images/api_empty.svg'
// ==============================|| APIKey ||============================== // // ==============================|| APIKey ||============================== //
@ -106,7 +107,10 @@ const APIKey = () => {
const deleteKey = async (key) => { const deleteKey = async (key) => {
const confirmPayload = { const confirmPayload = {
title: `Delete`, 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', confirmButtonName: 'Delete',
cancelButtonName: 'Cancel' cancelButtonName: 'Cancel'
} }
@ -193,6 +197,7 @@ const APIKey = () => {
<TableRow> <TableRow>
<TableCell>Key Name</TableCell> <TableCell>Key Name</TableCell>
<TableCell>API Key</TableCell> <TableCell>API Key</TableCell>
<TableCell>Usage</TableCell>
<TableCell>Created</TableCell> <TableCell>Created</TableCell>
<TableCell> </TableCell> <TableCell> </TableCell>
<TableCell> </TableCell> <TableCell> </TableCell>
@ -200,65 +205,78 @@ const APIKey = () => {
</TableHead> </TableHead>
<TableBody> <TableBody>
{apiKeys.map((key, index) => ( {apiKeys.map((key, index) => (
<TableRow key={index} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}> <>
<TableCell component='th' scope='row'> <TableRow key={index} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
{key.keyName} <TableCell component='th' scope='row'>
</TableCell> {key.keyName}
<TableCell> </TableCell>
{showApiKeys.includes(key.apiKey) <TableCell>
? key.apiKey {showApiKeys.includes(key.apiKey)
: `${key.apiKey.substring(0, 2)}${'•'.repeat(18)}${key.apiKey.substring( ? key.apiKey
key.apiKey.length - 5 : `${key.apiKey.substring(0, 2)}${'•'.repeat(18)}${key.apiKey.substring(
)}`} key.apiKey.length - 5
<IconButton )}`}
title='Copy' <IconButton
color='success' title='Copy'
onClick={(event) => { color='success'
navigator.clipboard.writeText(key.apiKey) onClick={(event) => {
setAnchorEl(event.currentTarget) navigator.clipboard.writeText(key.apiKey)
setTimeout(() => { setAnchorEl(event.currentTarget)
handleClosePopOver() setTimeout(() => {
}, 1500) handleClosePopOver()
}} }, 1500)
> }}
<IconCopy />
</IconButton>
<IconButton title='Show' color='inherit' onClick={() => onShowApiKeyClick(key.apiKey)}>
{showApiKeys.includes(key.apiKey) ? <IconEyeOff /> : <IconEye />}
</IconButton>
<Popover
open={openPopOver}
anchorEl={anchorEl}
onClose={handleClosePopOver}
anchorOrigin={{
vertical: 'top',
horizontal: 'right'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left'
}}
>
<Typography
variant='h6'
sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}
> >
Copied! <IconCopy />
</Typography> </IconButton>
</Popover> <IconButton title='Show' color='inherit' onClick={() => onShowApiKeyClick(key.apiKey)}>
</TableCell> {showApiKeys.includes(key.apiKey) ? <IconEyeOff /> : <IconEye />}
<TableCell>{key.createdAt}</TableCell> </IconButton>
<TableCell> <Popover
<IconButton title='Edit' color='primary' onClick={() => edit(key)}> open={openPopOver}
<IconEdit /> anchorEl={anchorEl}
</IconButton> onClose={handleClosePopOver}
</TableCell> anchorOrigin={{
<TableCell> vertical: 'top',
<IconButton title='Delete' color='error' onClick={() => deleteKey(key)}> horizontal: 'right'
<IconTrash /> }}
</IconButton> transformOrigin={{
</TableCell> vertical: 'top',
</TableRow> horizontal: 'left'
}}
>
<Typography
variant='h6'
sx={{ pl: 1, pr: 1, color: 'white', background: theme.palette.success.dark }}
>
Copied!
</Typography>
</Popover>
</TableCell>
<TableCell>{key.chatFlows.length}</TableCell>
<TableCell>{key.createdAt}</TableCell>
<TableCell>
<IconButton title='Edit' color='primary' onClick={() => edit(key)}>
<IconEdit />
</IconButton>
</TableCell>
<TableCell>
<IconButton title='Delete' color='error' onClick={() => deleteKey(key)}>
<IconTrash />
</IconButton>
</TableCell>
</TableRow>
{key.chatFlows.length > 0 && (
<TableRow sx={{ verticalAlign: 'middle' }}>
<TableCell colSpan={6}>
<IconCornerDownRight />{' '}
{key.chatFlows.map((flow, index) => (
<Chip key={index} label={flow.flowName} />
))}
</TableCell>
</TableRow>
)}
</>
))} ))}
</TableBody> </TableBody>
</Table> </Table>