mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-07-23 12:32:17 +00:00
Implement visibility toggle for account API keys
This commit is contained in:
@@ -11,6 +11,7 @@ import Loader from '../blocks/Loader.js';
|
||||
import Modal from '../blocks/Modal.js';
|
||||
import FormError from '../blocks/FormError.js';
|
||||
import CopyableText from '../elements/CopyableText';
|
||||
import ToggleText from '../blocks/ToggleText.js';
|
||||
|
||||
const Td = styled.td`
|
||||
padding: 0.5rem 0;
|
||||
@@ -52,8 +53,24 @@ const TableContent = props => {
|
||||
newContent = newContent || content;
|
||||
const sortedContent = [...newContent];
|
||||
sortedContent.sort((a, b) => {
|
||||
let valA = (a[column] && a[column].toLowerCase()) || '';
|
||||
let valB = (b[column] && b[column].toLowerCase()) || '';
|
||||
let valA;
|
||||
let valB;
|
||||
if (!a[column]) {
|
||||
valA = '';
|
||||
valB = '';
|
||||
} else if (typeof a[column] === 'object') {
|
||||
if (a[column].type === 'masked') {
|
||||
valA = a[column].masked;
|
||||
valB = b[column].masked;
|
||||
}
|
||||
if (a[column].type === 'normal') {
|
||||
valA = a[column].content;
|
||||
valB = b[column].content;
|
||||
}
|
||||
} else {
|
||||
valA = (a[column] && a[column].toLowerCase()) || '';
|
||||
valB = (b[column] && b[column].toLowerCase()) || '';
|
||||
}
|
||||
if (newSortOrder === 'asc') {
|
||||
return valA > valB ? 1 : valA < valB ? -1 : 0;
|
||||
} else {
|
||||
@@ -279,6 +296,7 @@ const TableContent = props => {
|
||||
{props.columns.map((c, i) => (
|
||||
<th
|
||||
key={c.key}
|
||||
style={{ width: c.width }}
|
||||
colSpan={!props.addContent && (i === props.columns.length - 1) ? '2' : null}
|
||||
>
|
||||
{selected.length && i === props.columns.length - 1 ? (
|
||||
@@ -361,23 +379,40 @@ const TableContent = props => {
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{props.columns.map((c, i) => (
|
||||
<td key={c.key}>
|
||||
{i === 0 && props.urlParam
|
||||
? <span>
|
||||
<Link
|
||||
to={`/internal/${props.urlParam}/${a.sid}/edit`}
|
||||
tabIndex={modalOpen ? '-1' : ''}
|
||||
>
|
||||
<span tabIndex="-1" title={a[c.key]}>
|
||||
{a[c.key]}
|
||||
</span>
|
||||
</Link>
|
||||
</span>
|
||||
: <span title={a[c.key]}>{a[c.key]}</span>
|
||||
{props.columns.map((c, i) => {
|
||||
let columnContent = '';
|
||||
let columnTitle = null;
|
||||
if (a[c.key]) {
|
||||
if (typeof a[c.key] === 'object') {
|
||||
if (a[c.key].type === 'normal') {
|
||||
columnContent = a[c.key].content;
|
||||
columnTitle = columnContent;
|
||||
} else if (a[c.key].type === 'masked') {
|
||||
columnContent = <ToggleText masked={a[c.key].masked} revealed={a[c.key].revealed} />;
|
||||
}
|
||||
} else {
|
||||
columnContent = a[c.key];
|
||||
columnTitle = columnContent;
|
||||
}
|
||||
</td>
|
||||
))}
|
||||
}
|
||||
return (
|
||||
<td key={c.key} style={{ fontWeight: c.fontWeight }}>
|
||||
{i === 0 && props.urlParam
|
||||
? <span>
|
||||
<Link
|
||||
to={`/internal/${props.urlParam}/${a.sid}/edit`}
|
||||
tabIndex={modalOpen ? '-1' : ''}
|
||||
>
|
||||
<span tabIndex="-1" title={columnTitle}>
|
||||
{columnContent}
|
||||
</span>
|
||||
</Link>
|
||||
</span>
|
||||
: <span title={columnTitle}>{columnContent}</span>
|
||||
}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
<td>
|
||||
{props.rowsHaveDeleteButtons ? (
|
||||
<Button
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components/macro';
|
||||
import { ReactComponent as ViewPassword } from '../../images/ViewPassword.svg';
|
||||
import { ReactComponent as HidePassword } from '../../images/HidePassword.svg';
|
||||
|
||||
const Container = styled.span`
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ToggleVisibilityButton = styled.button`
|
||||
position: absolute;
|
||||
top: -0.5rem;
|
||||
left: 22rem;
|
||||
width: 2.5rem;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
|
||||
& > span {
|
||||
height: 2.25rem;
|
||||
width: 2.5rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: 0;
|
||||
border-radius: 0.25rem;
|
||||
fill: #767676;
|
||||
}
|
||||
|
||||
&:hover > span {
|
||||
fill: #565656;
|
||||
}
|
||||
|
||||
&:focus > span {
|
||||
box-shadow: inset 0 0 0 0.125rem #767676;
|
||||
}
|
||||
`;
|
||||
|
||||
const ToggleText = props => {
|
||||
const [ mode, setMode ] = useState('masked');
|
||||
return (
|
||||
<Container>
|
||||
{mode === 'masked' ? props.masked : props.revealed}
|
||||
<ToggleVisibilityButton
|
||||
onClick={() => setMode(mode === 'masked' ? 'revealed' : 'masked')}
|
||||
>
|
||||
<span tabIndex="-1">
|
||||
{mode === 'masked'
|
||||
? <ViewPassword />
|
||||
: <HidePassword />
|
||||
}
|
||||
</span>
|
||||
</ToggleVisibilityButton>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToggleText;
|
||||
@@ -62,9 +62,16 @@ const AccountsAddEdit = () => {
|
||||
}
|
||||
|
||||
return {
|
||||
sid: a.api_key_sid,
|
||||
token: maskedToken,
|
||||
last_used: lastUsedString,
|
||||
sid: a.api_key_sid,
|
||||
token: {
|
||||
type: 'masked',
|
||||
masked: maskedToken,
|
||||
revealed: token,
|
||||
},
|
||||
last_used: {
|
||||
type: 'normal',
|
||||
content: lastUsedString,
|
||||
},
|
||||
};
|
||||
});
|
||||
return(simplifiedApiKeys);
|
||||
@@ -142,8 +149,8 @@ const AccountsAddEdit = () => {
|
||||
//=============================================================================
|
||||
const formatApiKeyToDelete = apiKey => {
|
||||
const items = [
|
||||
{ name: 'API Key:' , content: apiKey.token || '[none]' },
|
||||
{ name: 'Last Used:' , content: apiKey.last_used || 'Never used' },
|
||||
{ name: 'API Key:' , content: apiKey.token.masked || '[none]' },
|
||||
{ name: 'Last Used:' , content: apiKey.last_used.content || 'Never used' },
|
||||
];
|
||||
return items;
|
||||
};
|
||||
@@ -200,8 +207,8 @@ const AccountsAddEdit = () => {
|
||||
name="API key"
|
||||
getContent={getApiKeys}
|
||||
columns={[
|
||||
{ header: 'API Key', key: 'token' },
|
||||
{ header: 'Last Used', key: 'last_used' },
|
||||
{ header: 'API Key', key: 'token', width: '27rem', fontWeight: 'normal' },
|
||||
{ header: 'Last Used', key: 'last_used', width: '10rem' },
|
||||
]}
|
||||
addContent={createApiKey}
|
||||
formatContentToDelete={formatApiKeyToDelete}
|
||||
|
||||
Reference in New Issue
Block a user