refactor: consolidate security devices UI and remove pending auth requests from settings

- Merge device management and authorized devices sections into a single card in SecurityDevicesPage
- Remove PendingAuthRequestsPanel from SettingsPage and its related props
- Clean up unused auth request prop drilling in AppMainRoutes

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shuaiplus
2026-06-25 01:49:17 +08:00
co-authored by Claude
parent bf51309fbb
commit c694f1bfce
3 changed files with 32 additions and 56 deletions
-5
View File
@@ -275,11 +275,6 @@ export default function AppMainRoutes(props: AppMainRoutesProps) {
onCreateAccountPasskey={props.onCreateAccountPasskey} onCreateAccountPasskey={props.onCreateAccountPasskey}
onEnableAccountPasskeyDirectUnlock={props.onEnableAccountPasskeyDirectUnlock} onEnableAccountPasskeyDirectUnlock={props.onEnableAccountPasskeyDirectUnlock}
onDeleteAccountPasskey={props.onDeleteAccountPasskey} onDeleteAccountPasskey={props.onDeleteAccountPasskey}
pendingAuthRequests={props.pendingAuthRequests}
pendingAuthRequestsLoading={props.pendingAuthRequestsLoading}
onRefreshPendingAuthRequests={props.onRefreshPendingAuthRequests}
onApproveAuthRequest={props.onApproveAuthRequest}
onDenyAuthRequest={props.onDenyAuthRequest}
onLockTimeoutChange={props.onLockTimeoutChange} onLockTimeoutChange={props.onLockTimeoutChange}
onSessionTimeoutActionChange={props.onSessionTimeoutActionChange} onSessionTimeoutActionChange={props.onSessionTimeoutActionChange}
onNotify={props.onNotify} onNotify={props.onNotify}
+31 -35
View File
@@ -89,42 +89,38 @@ export default function SecurityDevicesPage(props: SecurityDevicesPageProps) {
/> />
<section className="card"> <section className="card">
<div className="section-head"> <div className="section-head">
<div> <div>
<h3 className="flush-title">{t('txt_device_management')}</h3> <h3 className="flush-title">{t('txt_authorized_devices')}</h3>
<div className="muted-inline section-note"> <div className="muted-inline section-note">
{t('txt_manage_device_sessions_and_30_day_totp_trusted_sessions')} {t('txt_manage_device_sessions_and_30_day_totp_trusted_sessions')}
</div>
</div>
<div className="actions">
<button type="button" className="btn btn-secondary small" disabled={props.loading} onClick={props.onRefresh}>
<RefreshCw size={14} className="btn-icon" />
{t('txt_refresh')}
</button>
<button type="button" className="btn btn-danger small" onClick={props.onRevokeAll}>
<ShieldOff size={14} className="btn-icon" />
{t('txt_revoke_all_trusted')}
</button>
<button type="button" className="btn btn-danger small" onClick={props.onRemoveAll}>
<Trash2 size={14} className="btn-icon" />
{t('txt_remove_all_devices')}
</button>
</div> </div>
</div> </div>
<div className="actions"> {!!props.error && (
<button type="button" className="btn btn-secondary small" disabled={props.loading} onClick={props.onRefresh}> <div className="local-error">
<RefreshCw size={14} className="btn-icon" /> <span>{props.error}</span>
{t('txt_refresh')} <button type="button" className="btn btn-secondary small" disabled={props.loading} onClick={props.onRefresh}>
</button> <RefreshCw size={14} className="btn-icon" />
<button type="button" className="btn btn-danger small" onClick={props.onRevokeAll}> {t('txt_refresh')}
<ShieldOff size={14} className="btn-icon" /> </button>
{t('txt_revoke_all_trusted')} </div>
</button> )}
<button type="button" className="btn btn-danger small" onClick={props.onRemoveAll}> <table className="table authorized-devices-table">
<Trash2 size={14} className="btn-icon" />
{t('txt_remove_all_devices')}
</button>
</div>
</div>
</section>
<section className="card">
<h3 className="section-title-flush">{t('txt_authorized_devices')}</h3>
{!!props.error && (
<div className="local-error">
<span>{props.error}</span>
<button type="button" className="btn btn-secondary small" disabled={props.loading} onClick={props.onRefresh}>
<RefreshCw size={14} className="btn-icon" />
{t('txt_refresh')}
</button>
</div>
)}
<table className="table authorized-devices-table">
<colgroup> <colgroup>
<col className="authorized-devices-col-device" /> <col className="authorized-devices-col-device" />
<col className="authorized-devices-col-type" /> <col className="authorized-devices-col-type" />
@@ -233,7 +229,7 @@ export default function SecurityDevicesPage(props: SecurityDevicesPageProps) {
</tr> </tr>
)} )}
</tbody> </tbody>
</table> </table>
</section> </section>
</div> </div>
+1 -16
View File
@@ -2,10 +2,9 @@ import { useEffect, useMemo, useState } from 'preact/hooks';
import { Clipboard, KeyRound, RefreshCw, ShieldCheck, ShieldOff, Trash2 } from 'lucide-preact'; import { Clipboard, KeyRound, RefreshCw, ShieldCheck, ShieldOff, Trash2 } from 'lucide-preact';
import { copyTextToClipboard } from '@/lib/clipboard'; import { copyTextToClipboard } from '@/lib/clipboard';
import qrcode from 'qrcode-generator'; import qrcode from 'qrcode-generator';
import type { AccountPasskeyCredential, AuthRequest, Profile } from '@/lib/types'; import type { AccountPasskeyCredential, Profile } from '@/lib/types';
import { AVAILABLE_LOCALES, getLocale, setLocale, t, type Locale } from '@/lib/i18n'; import { AVAILABLE_LOCALES, getLocale, setLocale, t, type Locale } from '@/lib/i18n';
import ConfirmDialog from '@/components/ConfirmDialog'; import ConfirmDialog from '@/components/ConfirmDialog';
import PendingAuthRequestsPanel from '@/components/PendingAuthRequestsPanel';
interface SettingsPageProps { interface SettingsPageProps {
profile: Profile; profile: Profile;
@@ -23,11 +22,6 @@ interface SettingsPageProps {
onCreateAccountPasskey: (name: string, masterPassword: string, directUnlock: boolean) => Promise<AccountPasskeyCredential | null>; onCreateAccountPasskey: (name: string, masterPassword: string, directUnlock: boolean) => Promise<AccountPasskeyCredential | null>;
onEnableAccountPasskeyDirectUnlock: (id: string, masterPassword: string) => Promise<void>; onEnableAccountPasskeyDirectUnlock: (id: string, masterPassword: string) => Promise<void>;
onDeleteAccountPasskey: (id: string, masterPassword: string) => Promise<void>; onDeleteAccountPasskey: (id: string, masterPassword: string) => Promise<void>;
pendingAuthRequests: AuthRequest[];
pendingAuthRequestsLoading: boolean;
onRefreshPendingAuthRequests: () => Promise<void>;
onApproveAuthRequest: (request: AuthRequest) => Promise<void>;
onDenyAuthRequest: (request: AuthRequest) => Promise<void>;
onLockTimeoutChange: (minutes: 0 | 1 | 5 | 15 | 30) => void; onLockTimeoutChange: (minutes: 0 | 1 | 5 | 15 | 30) => void;
onSessionTimeoutActionChange: (action: 'lock' | 'logout') => void; onSessionTimeoutActionChange: (action: 'lock' | 'logout') => void;
onNotify?: (type: 'success' | 'error' | 'warning', text: string) => void; onNotify?: (type: 'success' | 'error' | 'warning', text: string) => void;
@@ -515,15 +509,6 @@ export default function SettingsPage(props: SettingsPageProps) {
)} )}
</div> </div>
</section> </section>
<PendingAuthRequestsPanel
pendingAuthRequests={props.pendingAuthRequests}
pendingAuthRequestsLoading={props.pendingAuthRequestsLoading}
onRefreshPendingAuthRequests={props.onRefreshPendingAuthRequests}
onApproveAuthRequest={props.onApproveAuthRequest}
onDenyAuthRequest={props.onDenyAuthRequest}
/>
<section className="settings-module sensitive-actions-module"> <section className="settings-module sensitive-actions-module">
<div className="sensitive-actions-grid"> <div className="sensitive-actions-grid">
<div className="sensitive-action"> <div className="sensitive-action">