mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-27 18:57:09 +00:00
fix(frontend): make copy buttons work over plain HTTP (#757)
The Clipboard API requires a secure context, so navigator.clipboard is undefined when Sencho is accessed over HTTP on a LAN IP. Most copy buttons therefore failed silently and a few even fired success toasts without writing anything to the clipboard. Extract a shared copyToClipboard helper that prefers the modern API in secure contexts and falls back to a hidden-textarea execCommand path otherwise, then route every existing call site through it.
This commit is contained in:
@@ -8,6 +8,7 @@ import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { toast } from '@/components/ui/toast-store';
|
||||
import { apiFetch } from '@/lib/api';
|
||||
import { copyToClipboard } from '@/lib/clipboard';
|
||||
import { PaidGate } from '@/components/PaidGate';
|
||||
import { CapabilityGate } from '@/components/CapabilityGate';
|
||||
import {
|
||||
@@ -128,9 +129,13 @@ export function WebhooksSection({ isPaid }: { isPaid: boolean }) {
|
||||
} catch { /* ignore */ } finally { setLoadingHistory(null); }
|
||||
};
|
||||
|
||||
const copyToClipboard = (text: string, label: string) => {
|
||||
navigator.clipboard.writeText(text);
|
||||
toast.success(`${label} copied to clipboard.`);
|
||||
const handleCopy = async (text: string, label: string) => {
|
||||
try {
|
||||
await copyToClipboard(text);
|
||||
toast.success(`${label} copied to clipboard.`);
|
||||
} catch {
|
||||
toast.error('Failed to copy to clipboard.');
|
||||
}
|
||||
};
|
||||
|
||||
if (!isPaid) {
|
||||
@@ -204,7 +209,7 @@ export function WebhooksSection({ isPaid }: { isPaid: boolean }) {
|
||||
<p className="text-xs text-muted-foreground">This secret will not be shown again. Store it securely.</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 text-xs font-mono bg-muted px-3 py-2 rounded-lg break-all">{newSecret.secret}</code>
|
||||
<Button variant="outline" size="sm" onClick={() => copyToClipboard(newSecret.secret, 'Secret')}>
|
||||
<Button variant="outline" size="sm" onClick={() => handleCopy(newSecret.secret, 'Secret')}>
|
||||
<Copy className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -256,7 +261,7 @@ export function WebhooksSection({ isPaid }: { isPaid: boolean }) {
|
||||
<Label className="text-xs text-muted-foreground">Trigger URL</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<code className="flex-1 text-[11px] font-mono bg-muted px-2.5 py-1.5 rounded-md truncate">{triggerUrl}</code>
|
||||
<Button variant="outline" size="sm" className="h-7 px-2" onClick={() => copyToClipboard(triggerUrl, 'URL')}>
|
||||
<Button variant="outline" size="sm" className="h-7 px-2" onClick={() => handleCopy(triggerUrl, 'URL')}>
|
||||
<Copy className="w-3 h-3" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user