/****************************************************************************** * Copyright (c) 2026 Contributors to the Eclipse Foundation. * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * https://www.eclipse.org/legal/epl-2.0. * * SPDX-License-Identifier: EPL-2.0 *****************************************************************************/ import { ChangeEvent, FunctionComponent, useState } from 'react'; import { Button, Dialog, DialogTitle, DialogContent, DialogContentText, Box, TextField, DialogActions, IconButton, Tooltip, LinearProgress } from '@mui/material'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import VisibilityIcon from '@mui/icons-material/Visibility'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import InputAdornment from '@mui/material/InputAdornment'; import OutlinedInput from '@mui/material/OutlinedInput'; import copy from 'clipboard-copy'; const TOKEN_DESCRIPTION_SIZE = 255; export const GenerateTokenDialog: FunctionComponent = props => { const [loading, setLoading] = useState(false); const [description, setDescription] = useState(''); const [descriptionError, setDescriptionError] = useState(); const [tokenValue, setTokenValue] = useState(); const [copied, setCopied] = useState(false); const [showToken, setShowToken] = useState(false); const { open, onClose, title = 'Generate new token' } = props; const resetState = () => { setLoading(false); setDescription(''); setDescriptionError(undefined); setTokenValue(undefined); setCopied(false); setShowToken(false); }; const handleClose = () => { if (!loading) { onClose(); resetState(); } }; const handleDescriptionChange = (event: ChangeEvent) => { const value = event.target.value; setDescription(value); setDescriptionError( value.length > TOKEN_DESCRIPTION_SIZE ? `Description must not exceed ${TOKEN_DESCRIPTION_SIZE} characters.` : undefined ); }; const handleGenerate = async () => { setLoading(true); try { const value = await props.onGenerate(description); setTokenValue(value); } catch (err) { props.onError?.(err); } finally { setLoading(false); } }; const handleCopy = () => { if (tokenValue) { copy(tokenValue).then(() => setCopied(true)); setTimeout(() => setCopied(false), 2000); } }; const canGenerate = !descriptionError && !loading; return ( <> {open && ( {title} {loading && } {tokenValue ? ( <> Copy this token now. It will not be shown again. setShowToken(v => !v)}> {showToken ? ( ) : ( )} } /> ) : ( <> You can add an optional description to help identify where this token is used. { if (e.key === 'Enter' && canGenerate) { handleGenerate(); } }} /> )} {!tokenValue && ( )} )} ); }; export interface GenerateTokenDialogProps { open: boolean; onClose: () => void; onGenerate: (description: string) => Promise; onError?: (err: unknown) => void; title?: string; }