/******************************************************************************** * Copyright (c) 2019 TypeFox and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ import { FunctionComponent, ReactNode, useContext, useEffect, useState, useRef } from 'react'; import { Theme, Typography, Box, Paper, Button, Link, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material'; import { styled } from '@mui/material/styles'; import { Link as RouteLink } from 'react-router-dom'; import { DelayedLoadIndicator } from '../../components/delayed-load-indicator'; import { Timestamp } from '../../components/timestamp'; import { PersonalAccessToken } from '../../extension-registry-types'; import { MainContext } from '../../context'; import { GenerateAccessTokenDialog } from './generate-access-token-dialog'; import { UserSettingsRoutes } from './user-settings-routes'; const link = ({ theme }: { theme: Theme }) => ({ color: theme.palette.secondary.main, textDecoration: 'none', '&:hover': { textDecoration: 'underline' } }); const StyledLink = styled(Link)(link); const StyledRouteLink = styled(RouteLink)(link); const EmptyTypography = styled(Typography)(({ theme }: { theme: Theme }) => ({ [theme.breakpoints.down('sm')]: { textAlign: 'center' } })); const DeleteButton = styled(Button)(({ theme }: { theme: Theme }) => ({ color: theme.palette.error.main, height: 36 })); export const UserSettingsTokens: FunctionComponent = () => { const { service, user, handleError, pageSettings } = useContext(MainContext); const [tokens, setTokens] = useState(new Array()); const [loading, setLoading] = useState(true); const [showDeleteAll, setShowDeleteAll] = useState(false); const abortController = useRef(new AbortController()); useEffect(() => { updateTokens(); return () => { abortController.current.abort(); }; }, []); const updateTokens = async() => { if (!user) { return; } try { const tokens = await service.getAccessTokens(abortController.current, user); setTokens(tokens); setLoading(false); } catch (err) { handleError(err); setLoading(false); } }; const handleDelete = async (token: PersonalAccessToken) => { setLoading(true); try { await service.deleteAccessToken(abortController.current, token); updateTokens(); } catch (err) { handleError(err); } }; const onShowDeleteAll = () => setShowDeleteAll(true); const onHideDeleteAll = () => setShowDeleteAll(false); const handleDeleteAll = async () => { onHideDeleteAll(); setLoading(true); try { await service.deleteAllAccessTokens(abortController.current, tokens); updateTokens(); } catch (err) { handleError(err); } }; const handleTokenGenerated = () => { setLoading(true); updateTokens(); }; const renderToken = (token: PersonalAccessToken): ReactNode => { return {token.description} Created: Expires: {token.expiresTimestamp ? : 'never'} Accessed: {token.accessedTimestamp ? : 'never'} handleDelete(token)} disabled={loading}> Delete ; }; const agreement = user?.publisherAgreement; if (agreement && (agreement.status === 'none' || agreement.status === 'outdated')) { const publisherAgreementName = pageSettings?.publisherAgreement?.name ?? ''; const publisherAgreementContact = pageSettings?.publisherAgreement?.email; return Access tokens cannot be created as you currently do not have an {publisherAgreementName} Publisher Agreement signed. Please return to your Profile page to sign the Publisher Agreement. { publisherAgreementContact !== undefined && <> Should you believe this is in error, please contact {publisherAgreementContact}. } ; } return <> Access Tokens Delete all { tokens.length === 0 && !loading ? You currently have no tokens. : null } {tokens.map(token => renderToken(token))} Delete all access tokens Are you sure you want to delete all access tokens? ; };