diff --git a/AGENTS.md b/AGENTS.md index 42599f6..efec22e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1566,6 +1566,13 @@ export const ReactComponent = ({ someValue }: Props): JSX.Element => { - **Calculated values** - Derived data from props/state - **Return** - JSX markup +### Clipboard operations + +Always use `ClipboardHelper` (`shared/lib/ClipboardHelper.ts`) for clipboard operations — never call `navigator.clipboard` directly. + +- **Copy:** `ClipboardHelper.copyToClipboard(text)` — uses `navigator.clipboard` with `execCommand('copy')` fallback for non-secure contexts (HTTP). +- **Paste:** Check `ClipboardHelper.isClipboardApiAvailable()` first. If available, use `ClipboardHelper.readFromClipboard()`. If not, show `ClipboardPasteModalComponent` (`shared/ui`) which lets the user paste manually via a text input modal. + --- ## Summary diff --git a/backend/internal/features/encryption/secrets/model.go b/backend/internal/features/encryption/secrets/model.go deleted file mode 100644 index b2b97d5..0000000 --- a/backend/internal/features/encryption/secrets/model.go +++ /dev/null @@ -1 +0,0 @@ -package secrets diff --git a/frontend/src/features/backups/ui/AgentRestoreComponent.tsx b/frontend/src/features/backups/ui/AgentRestoreComponent.tsx index 79dc425..a6ebae2 100644 --- a/frontend/src/features/backups/ui/AgentRestoreComponent.tsx +++ b/frontend/src/features/backups/ui/AgentRestoreComponent.tsx @@ -6,6 +6,7 @@ import { useState } from 'react'; import { getApplicationServer } from '../../../constants'; import { type Backup, PgWalBackupType } from '../../../entity/backups'; import { type Database } from '../../../entity/databases'; +import { ClipboardHelper } from '../../../shared/lib/ClipboardHelper'; import { getUserTimeFormat } from '../../../shared/time'; interface Props { @@ -26,7 +27,7 @@ export const AgentRestoreComponent = ({ database, backup }: Props) => { const copyToClipboard = async (text: string) => { try { - await navigator.clipboard.writeText(text); + await ClipboardHelper.copyToClipboard(text); message.success('Copied to clipboard'); } catch { message.error('Failed to copy'); diff --git a/frontend/src/features/billing/ui/DbSizeCommands.tsx b/frontend/src/features/billing/ui/DbSizeCommands.tsx index 7a04a4c..6fb0725 100644 --- a/frontend/src/features/billing/ui/DbSizeCommands.tsx +++ b/frontend/src/features/billing/ui/DbSizeCommands.tsx @@ -1,5 +1,7 @@ import { useState } from 'react'; +import { ClipboardHelper } from '../../../shared/lib/ClipboardHelper'; + interface DbSizeCommand { label: string; code: string; @@ -44,7 +46,7 @@ export function DbSizeCommands({ commands }: Props) { + + + } + > +

+ Automatic clipboard access is not available. Please paste your content below. +

+ setValue(e.target.value)} + placeholder="Paste your connection string here..." + rows={4} + autoFocus + /> + + ); +} diff --git a/frontend/src/shared/ui/index.ts b/frontend/src/shared/ui/index.ts index b7b20d5..73f9757 100644 --- a/frontend/src/shared/ui/index.ts +++ b/frontend/src/shared/ui/index.ts @@ -1,3 +1,4 @@ +export { ClipboardPasteModalComponent } from './ClipboardPasteModalComponent'; export { CloudflareTurnstileWidget } from './CloudflareTurnstileWidget'; export { ConfirmationComponent } from './ConfirmationComponent'; export { StarButtonComponent } from './StarButtonComponent';