fix(frontend): route remaining copy buttons through ClipboardManager

Direct navigator.clipboard calls fail in non-secure contexts (HTTP on a
LAN IP), making the API-docs code copy and security-tab token copy
silently broken. Both now go through ClipboardManager which falls back
to document.execCommand('copy') when navigator.clipboard is unavailable.
This commit is contained in:
MHSanaei 2026-05-23 14:31:56 +02:00
parent 5af8153e94
commit b5fb9e9fe0
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
2 changed files with 8 additions and 16 deletions

View file

@ -1,6 +1,7 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { message } from 'antd'; import { message } from 'antd';
import { CheckOutlined, CopyOutlined } from '@ant-design/icons'; import { CheckOutlined, CopyOutlined } from '@ant-design/icons';
import { ClipboardManager } from '@/utils';
import './CodeBlock.css'; import './CodeBlock.css';
interface CodeBlockProps { interface CodeBlockProps {
@ -37,12 +38,12 @@ export default function CodeBlock({ code = '', lang = 'json' }: CodeBlockProps)
); );
async function copyCode() { async function copyCode() {
try { const ok = await ClipboardManager.copyText(code);
await navigator.clipboard.writeText(code); if (ok) {
setCopied(true); setCopied(true);
messageApi.success('Copied'); messageApi.success('Copied');
window.setTimeout(() => setCopied(false), 2000); window.setTimeout(() => setCopied(false), 2000);
} catch { } else {
messageApi.error('Copy failed'); messageApi.error('Copy failed');
} }
} }

View file

@ -12,7 +12,7 @@ import {
Switch, Switch,
message, message,
} from 'antd'; } from 'antd';
import { HttpUtil, RandomUtil } from '@/utils'; import { ClipboardManager, HttpUtil, RandomUtil } from '@/utils';
import type { AllSetting } from '@/models/setting'; import type { AllSetting } from '@/models/setting';
import SettingListItem from '@/components/SettingListItem'; import SettingListItem from '@/components/SettingListItem';
import TwoFactorModal from './TwoFactorModal'; import TwoFactorModal from './TwoFactorModal';
@ -143,18 +143,9 @@ export default function SecurityTab({ allSetting, updateSetting }: SecurityTabPr
async function copyToken(token: string) { async function copyToken(token: string) {
if (!token) return; if (!token) return;
try { const ok = await ClipboardManager.copyText(token);
await navigator.clipboard.writeText(token); if (ok) messageApi.success(t('copySuccess'));
messageApi.success(t('copySuccess')); else messageApi.error(t('copyFail') ?? 'Copy failed');
} catch {
const ta = document.createElement('textarea');
ta.value = token;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
messageApi.success(t('copySuccess'));
}
} }
function openCreateModal() { function openCreateModal() {