mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-16 14:57:15 +00:00
feat(provider): support Codex subscriptions with ChatGPT sign-in (#2513)
* feat(provider): support Codex subscriptions with ChatGPT sign-in * style: format Codex live integration test * fix(provider): preserve Codex identity in temporary model tests * fix(web): portal provider selector without dialog overflow * fix(web): allow native scrolling in provider dropdown * fix(provider): surface safe Codex quota and upstream errors * fix(web): provide reliable Codex copy feedback in dialogs * feat(provider): confirm cascade deletion from edit dialog * fix(persistence): discard connections after failed commit * fix(web): polish provider loading and confirmation motion --------- Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
This commit is contained in:
@@ -1,39 +1,39 @@
|
||||
/**
|
||||
* Copy text to clipboard with fallback support
|
||||
* Tries to use modern Clipboard API first, falls back to execCommand if not available
|
||||
*
|
||||
* @param text - The text to copy to clipboard
|
||||
* @returns Promise<boolean> - true if successful, false otherwise
|
||||
*/
|
||||
/** Copy text using the Clipboard API, with a focus-trap-safe legacy fallback. */
|
||||
export async function copyToClipboard(text: string): Promise<boolean> {
|
||||
// Try modern Clipboard API first
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
try {
|
||||
try {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error('[Clipboard] Modern API failed, trying fallback:', err);
|
||||
// Fall through to legacy method
|
||||
}
|
||||
} catch {
|
||||
// Permission/security errors can include sensitive text; do not log them.
|
||||
}
|
||||
|
||||
// Fallback to legacy execCommand method
|
||||
const previousFocus = document.activeElement as HTMLElement | null;
|
||||
const textArea = document.createElement('textarea');
|
||||
try {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = text;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
textArea.style.top = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
// Radix modal focus scopes reject focus on elements appended to body.
|
||||
const container =
|
||||
previousFocus?.closest('[role="dialog"], [role="alertdialog"]') ??
|
||||
document.body;
|
||||
container.appendChild(textArea);
|
||||
textArea.focus({ preventScroll: true });
|
||||
textArea.select();
|
||||
|
||||
const successful = document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
|
||||
return successful;
|
||||
} catch (err) {
|
||||
console.error('[Clipboard] Fallback method failed:', err);
|
||||
if (
|
||||
document.activeElement !== textArea ||
|
||||
textArea.selectionEnd !== text.length
|
||||
)
|
||||
return false;
|
||||
return document.execCommand('copy');
|
||||
} catch {
|
||||
return false;
|
||||
} finally {
|
||||
textArea.remove();
|
||||
if (previousFocus?.isConnected)
|
||||
previousFocus.focus({ preventScroll: true });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user