This commit is contained in:
2025-11-09 13:03:44 +01:00
parent 4bc7357e41
commit bc33f68209
24 changed files with 5665 additions and 5261 deletions
@@ -39,6 +39,10 @@ const ApiTokensSection = ({
const [newTokenExpires, setNewTokenExpires] = useState('');
const [newTokenCapabilitySetId, setNewTokenCapabilitySetId] = useState('');
const [formError, setFormError] = useState(null);
const supportsClipboardWrite = typeof navigator !== 'undefined'
&& Boolean(navigator?.clipboard?.writeText);
const [canCopyToken, setCanCopyToken] = useState(supportsClipboardWrite);
const [copyFeedback, setCopyFeedback] = useState(null);
const capabilitySetOptions = useMemo(
() => capabilitySets.map((set) => ({
@@ -110,19 +114,44 @@ const ApiTokensSection = ({
onRefreshCapabilities?.();
}, [onRefresh, onRefreshCapabilities, onRefreshCapabilitySets]);
const handleCopyToken = useCallback(() => {
if (!createdToken) {
const handleCopyToken = useCallback(async () => {
if (!createdToken || !canCopyToken) {
return;
}
if (navigator?.clipboard?.writeText) {
navigator.clipboard.writeText(createdToken).catch(() => {});
const showSuccess = () =>
setCopyFeedback({ type: 'success', message: 'Token copied to clipboard.' });
const showFailure = () =>
setCopyFeedback({
type: 'error',
message:
'Copy failed. Your browser may require HTTPS access; please select the token manually.',
});
try {
await navigator.clipboard.writeText(createdToken);
showSuccess();
return;
} catch (error) {
// Some browsers expose writeText but still reject outside secure context
setCanCopyToken(false);
}
}, [createdToken]);
showFailure();
}, [createdToken, canCopyToken]);
const handleDismissSecret = useCallback(() => {
setCopyFeedback(null);
onDismissCreatedToken?.();
}, [onDismissCreatedToken]);
useEffect(() => {
setCopyFeedback(null);
if (typeof navigator !== 'undefined') {
setCanCopyToken(Boolean(navigator?.clipboard?.writeText));
}
}, [createdToken]);
const handleNewCapabilitySetChange = useCallback((event) => {
setFormError(null);
setNewTokenCapabilitySetId(event.target.value);
@@ -215,13 +244,20 @@ const ApiTokensSection = ({
</p>
<pre className="token-display">{createdToken}</pre>
<div className="settings-notice__actions">
<button type="button" className="secondary" onClick={handleCopyToken}>
Copy token
</button>
{canCopyToken ? (
<button type="button" className="secondary" onClick={handleCopyToken}>
Copy token
</button>
) : null}
<button type="button" onClick={handleDismissSecret}>
Dismiss
</button>
</div>
{copyFeedback ? (
<p className={copyFeedback.type === 'error' ? 'settings-form__error' : 'settings-status'}>
{copyFeedback.message}
</p>
) : null}
</div>
) : null}