diff --git a/ui/src/apikey/ApiKeyList.jsx b/ui/src/apikey/ApiKeyList.jsx index 42a43aa15..2f656111f 100644 --- a/ui/src/apikey/ApiKeyList.jsx +++ b/ui/src/apikey/ApiKeyList.jsx @@ -1,17 +1,45 @@ -import React from 'react' +import React, { useState } from 'react' import { + CreateButton, Datagrid, DateField, Filter, + FunctionField, List, SearchInput, TextField, + useNotify, useTranslate, } from 'react-admin' -import { useMediaQuery } from '@material-ui/core' +import { + IconButton, + makeStyles, + Tooltip, + useMediaQuery, +} from '@material-ui/core' import { SimpleList } from '../common' import AddIcon from '@material-ui/icons/Add' -import { CreateButton } from 'react-admin' +import VisibilityIcon from '@material-ui/icons/Visibility' +import VisibilityOffIcon from '@material-ui/icons/VisibilityOff' +import FileCopyIcon from '@material-ui/icons/FileCopy' + +const useStyles = makeStyles({ + actionContainer: { + display: 'flex', + alignItems: 'center', + }, + keyContainer: { + display: 'flex', + alignItems: 'center', + flex: 1, + }, + visibilityButton: { + padding: 4, + }, + copyButton: { + padding: 4, + }, +}) const ApiKeyFilter = (props) => ( @@ -19,6 +47,80 @@ const ApiKeyFilter = (props) => ( ) +const MaskedKeyField = ({ record, isSimpleMode }) => { + const [visible, setVisible] = useState(false) + const classes = useStyles() + const notify = useNotify() + + if (!record || !record.key) return null + + const maskKey = (key) => { + return '*'.repeat(key.length) + } + + const handleCopy = (e) => { + if (isSimpleMode) { + e.preventDefault() + } else { + e.stopPropagation() + } + navigator.clipboard.writeText(record.key) + notify('API key copied to clipboard', 'info') + } + + const toggleVisibility = (e) => { + if (isSimpleMode) { + e.preventDefault() + } else { + e.stopPropagation() + } + setVisible(!visible) + } + + const keyVisibilityButton = ( + + {visible ? ( + + ) : ( + + )} + + ) + const copyButton = ( + + + + ) + + return ( +
+
+ {visible ? record.key : maskKey(record.key)} +
+ {isSimpleMode ? ( + <>{keyVisibilityButton} + ) : ( + + {keyVisibilityButton} + + )} + {isSimpleMode ? ( + <>{copyButton} + ) : ( + {copyButton} + )} +
+ ) +} + const ApiKeyList = (props) => { const isXsmall = useMediaQuery((theme) => theme.breakpoints.down('xs')) const translate = useTranslate() @@ -40,14 +142,21 @@ const ApiKeyList = (props) => { {isXsmall ? ( r.name} - secondaryText={(r) => r.key} + secondaryText={(r) => ( + + )} tertiaryText={(r) => } linkType={'edit'} /> ) : ( - + ( + + )} + /> )}