Add "last access" to access tokens

This commit is contained in:
binwiederhier 2023-01-28 20:29:06 -05:00
parent 000bf27c87
commit e596834096
15 changed files with 276 additions and 145 deletions

View file

@ -226,6 +226,7 @@
"account_tokens_description": "Use access tokens when publishing and subscribing via the ntfy API, so you don't have to send your account credentials. Check out the <Link>documentation</Link> to learn more.",
"account_tokens_table_token_header": "Token",
"account_tokens_table_label_header": "Label",
"account_tokens_table_last_access_header": "Last access",
"account_tokens_table_expires_header": "Expires",
"account_tokens_table_never_expires": "Never expires",
"account_tokens_table_current_session": "Current browser session",
@ -233,6 +234,7 @@
"account_tokens_table_copied_to_clipboard": "Access token copied",
"account_tokens_table_cannot_delete_or_edit": "Cannot edit or delete current session token",
"account_tokens_table_create_token_button": "Create access token",
"account_tokens_table_last_origin_tooltip": "From IP address {{ip}}, click to lookup",
"account_tokens_dialog_title_create": "Create access token",
"account_tokens_dialog_title_edit": "Edit access token",
"account_tokens_dialog_title_delete": "Delete access token",

View file

@ -27,7 +27,7 @@ import DialogContent from "@mui/material/DialogContent";
import TextField from "@mui/material/TextField";
import routes from "./routes";
import IconButton from "@mui/material/IconButton";
import {formatBytes, formatShortDate, formatShortDateTime, truncateString, validUrl} from "../app/utils";
import {formatBytes, formatShortDate, formatShortDateTime, openUrl, truncateString, validUrl} from "../app/utils";
import accountApi, {IncorrectPasswordError, UnauthorizedError} from "../app/AccountApi";
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import {Pref, PrefGroup} from "./Pref";
@ -43,7 +43,7 @@ import userManager from "../app/UserManager";
import {Paragraph} from "./styles";
import CloseIcon from "@mui/icons-material/Close";
import DialogActions from "@mui/material/DialogActions";
import {ContentCopy} from "@mui/icons-material";
import {ContentCopy, Public} from "@mui/icons-material";
import MenuItem from "@mui/material/MenuItem";
import ListItemIcon from "@mui/material/ListItemIcon";
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
@ -506,6 +506,7 @@ const TokensTable = (props) => {
<TableCell sx={{paddingLeft: 0}}>{t("account_tokens_table_token_header")}</TableCell>
<TableCell>{t("account_tokens_table_label_header")}</TableCell>
<TableCell>{t("account_tokens_table_expires_header")}</TableCell>
<TableCell>{t("account_tokens_table_last_access_header")}</TableCell>
<TableCell/>
</TableRow>
</TableHead>
@ -513,11 +514,11 @@ const TokensTable = (props) => {
{tokens.map(token => (
<TableRow
key={token.token}
sx={{'&:last-child td, &:last-child th': {border: 0}}}
sx={{'&:last-child td, &:last-child th': { border: 0 }}}
>
<TableCell component="th" scope="row" sx={{paddingLeft: 0}} aria-label={t("account_tokens_table_token_header")}>
<TableCell component="th" scope="row" sx={{ paddingLeft: 0, whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_token_header")}>
<span>
<span style={{fontFamily: "Monospace", fontSize: "0.9rem"}}>{token.token.slice(0, 20)}</span>
<span style={{fontFamily: "Monospace", fontSize: "0.9rem"}}>{token.token.slice(0, 12)}</span>
...
<Tooltip title={t("account_tokens_table_copy_to_clipboard")} placement="right">
<IconButton onClick={() => handleCopy(token.token)}><ContentCopy/></IconButton>
@ -531,7 +532,17 @@ const TokensTable = (props) => {
<TableCell aria-label={t("account_tokens_table_expires_header")}>
{token.expires ? formatShortDateTime(token.expires) : <em>{t("account_tokens_table_never_expires")}</em>}
</TableCell>
<TableCell align="right">
<TableCell aria-label={t("account_tokens_table_last_access_header")}>
<div style={{ display: "flex", alignItems: "center" }}>
<span>{formatShortDateTime(token.last_access)}</span>
<Tooltip title={t("account_tokens_table_last_origin_tooltip", { ip: token.last_origin })}>
<IconButton onClick={() => openUrl(`https://whatismyipaddress.com/ip/${token.last_origin}`)}>
<Public />
</IconButton>
</Tooltip>
</div>
</TableCell>
<TableCell align="right" sx={{ whiteSpace: "nowrap" }}>
{token.token !== session.token() &&
<>
<IconButton onClick={() => handleEditClick(token)} aria-label={t("account_tokens_dialog_title_edit")}>

View file

@ -300,10 +300,9 @@ const UserTable = (props) => {
key={user.baseUrl}
sx={{'&:last-child td, &:last-child th': {border: 0}}}
>
<TableCell component="th" scope="row" sx={{paddingLeft: 0}}
aria-label={t("prefs_users_table_user_header")}>{user.username}</TableCell>
<TableCell component="th" scope="row" sx={{paddingLeft: 0}} aria-label={t("prefs_users_table_user_header")}>{user.username}</TableCell>
<TableCell aria-label={t("prefs_users_table_base_url_header")}>{user.baseUrl}</TableCell>
<TableCell align="right">
<TableCell align="right" sx={{ whiteSpace: "nowrap" }}>
{(!session.exists() || user.baseUrl !== config.base_url) &&
<>
<IconButton onClick={() => handleEditClick(user)} aria-label={t("prefs_users_edit_button")}>
@ -597,7 +596,7 @@ const ReservationsTable = (props) => {
{props.reservations.map(reservation => (
<TableRow
key={reservation.topic}
sx={{'&:last-child td, &:last-child th': {border: 0}}}
sx={{'&:last-child td, &:last-child th': { border: 0 }}}
>
<TableCell component="th" scope="row" sx={{paddingLeft: 0}} aria-label={t("prefs_reservations_table_topic_header")}>
{reservation.topic}
@ -628,7 +627,7 @@ const ReservationsTable = (props) => {
</>
}
</TableCell>
<TableCell align="right">
<TableCell align="right" sx={{ whiteSpace: "nowrap" }}>
{!localSubscriptions[reservation.topic] &&
<Chip icon={<Info/>} label="Not subscribed" color="primary" variant="outlined"/>
}