feat: enhance backup and download functionalities

- Updated `BackupCenterPage` to support download progress tracking during remote backup downloads.
- Modified `ImportPage` to simplify export functionality by removing unnecessary payload handling.
- Improved `JwtWarningPage` to utilize a new clipboard utility for copying text with feedback.
- Enhanced `PublicSendPage` to show download progress for files being downloaded.
- Updated `RecoverTwoFactorPage` to include autocomplete attributes for better user experience.
- Refactored `SendsPage` to use the new clipboard utility for copying access URLs.
- Enhanced `SettingsPage` to utilize the clipboard utility for copying sensitive information.
- Improved `TotpCodesPage` to use the clipboard utility for copying TOTP codes.
- Updated `VaultPage` and related components to support download progress for attachments.
- Introduced a new `app-notify` module for consistent notification handling across the application.
- Created a `clipboard` utility for improved clipboard interactions with user feedback.
- Added progress tracking for file downloads in the API layer, enhancing user experience during downloads.
This commit is contained in:
shuaiplus
2026-03-15 23:12:45 +08:00
parent 9820c2ed44
commit 4b8cad6d00
33 changed files with 387 additions and 121 deletions
+14
View File
@@ -46,6 +46,7 @@ import useBackupActions from '@/hooks/useBackupActions';
import useVaultSendActions from '@/hooks/useVaultSendActions';
import { useToastManager } from '@/hooks/useToastManager';
import { t } from '@/lib/i18n';
import { APP_NOTIFY_EVENT, type AppNotifyDetail } from '@/lib/app-notify';
import type { AppPhase, Cipher, Folder as VaultFolder, Profile, Send, SessionState } from '@/lib/types';
const IMPORT_ROUTE = '/help/import-export';
@@ -96,6 +97,17 @@ export default function App() {
const refreshAuthorizedDevicesRef = useRef<() => Promise<void>>(async () => {});
const { toasts, pushToast, removeToast } = useToastManager();
useEffect(() => {
const handleAppNotify = (event: Event) => {
const detail = (event as CustomEvent<AppNotifyDetail>).detail;
if (!detail?.text) return;
pushToast(detail.type, detail.text);
};
window.addEventListener(APP_NOTIFY_EVENT, handleAppNotify as EventListener);
return () => window.removeEventListener(APP_NOTIFY_EVENT, handleAppNotify as EventListener);
}, [pushToast]);
useEffect(() => {
const syncInviteFromUrl = () => {
setInviteCodeFromUrl(readInviteCodeFromUrl());
@@ -873,6 +885,8 @@ export default function App() {
onDeleteFolder: vaultSendActions.deleteFolder,
onBulkDeleteFolders: vaultSendActions.bulkDeleteFolders,
onDownloadVaultAttachment: vaultSendActions.downloadVaultAttachment,
downloadingAttachmentKey: vaultSendActions.downloadingAttachmentKey,
attachmentDownloadPercent: vaultSendActions.attachmentDownloadPercent,
onRefreshVault: vaultSendActions.refreshVault,
onCreateSend: vaultSendActions.createSend,
onUpdateSend: vaultSendActions.updateSend,