mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: refactor import routes and enhance backup state management with user ID
This commit is contained in:
+22
-29
@@ -119,7 +119,8 @@ type JwtUnsafeReason = 'missing' | 'default' | 'too_short';
|
|||||||
const SEND_KEY_SALT = 'bitwarden-send';
|
const SEND_KEY_SALT = 'bitwarden-send';
|
||||||
const SEND_KEY_PURPOSE = 'send';
|
const SEND_KEY_PURPOSE = 'send';
|
||||||
const IMPORT_ROUTE = '/help/import-export';
|
const IMPORT_ROUTE = '/help/import-export';
|
||||||
const IMPORT_ROUTE_ALIASES = new Set(['/tools/import', '/tools/import-export', '/tools/import-data', '/import', '/import-export']);
|
const IMPORT_ROUTE_PATHS = [IMPORT_ROUTE, '/tools/import', '/tools/import-export', '/tools/import-data', '/import', '/import-export'] as const;
|
||||||
|
const IMPORT_ROUTE_ALIASES = new Set(IMPORT_ROUTE_PATHS.filter((path) => path !== IMPORT_ROUTE));
|
||||||
const SETTINGS_HOME_ROUTE = '/settings';
|
const SETTINGS_HOME_ROUTE = '/settings';
|
||||||
const SETTINGS_ACCOUNT_ROUTE = '/settings/account';
|
const SETTINGS_ACCOUNT_ROUTE = '/settings/account';
|
||||||
|
|
||||||
@@ -1920,6 +1921,20 @@ export default function App() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderImportPageRoute = () => (
|
||||||
|
<div className="stack">
|
||||||
|
{mobileLayout && (
|
||||||
|
<div className="mobile-settings-subhead">
|
||||||
|
<button type="button" className="btn btn-secondary small mobile-settings-back" onClick={() => navigate(SETTINGS_HOME_ROUTE)}>
|
||||||
|
<span className="btn-icon" aria-hidden="true">{"<"}</span>
|
||||||
|
{t('txt_back')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{importPageContent}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (phase === 'app' && location === '/' && !isPublicSendRoute) navigate('/vault');
|
if (phase === 'app' && location === '/' && !isPublicSendRoute) navigate('/vault');
|
||||||
}, [phase, location, isPublicSendRoute, navigate]);
|
}, [phase, location, isPublicSendRoute, navigate]);
|
||||||
@@ -2366,34 +2381,11 @@ export default function App() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={IMPORT_ROUTE}>
|
{IMPORT_ROUTE_PATHS.map((path) => (
|
||||||
<div className="stack">
|
<Route key={path} path={path}>
|
||||||
{mobileLayout && (
|
{renderImportPageRoute()}
|
||||||
<div className="mobile-settings-subhead">
|
</Route>
|
||||||
<button type="button" className="btn btn-secondary small mobile-settings-back" onClick={() => navigate(SETTINGS_HOME_ROUTE)}>
|
))}
|
||||||
<span className="btn-icon" aria-hidden="true">{"<"}</span>
|
|
||||||
{t('txt_back')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{importPageContent}
|
|
||||||
</div>
|
|
||||||
</Route>
|
|
||||||
<Route path="/tools/import">
|
|
||||||
{importPageContent}
|
|
||||||
</Route>
|
|
||||||
<Route path="/tools/import-export">
|
|
||||||
{importPageContent}
|
|
||||||
</Route>
|
|
||||||
<Route path="/tools/import-data">
|
|
||||||
{importPageContent}
|
|
||||||
</Route>
|
|
||||||
<Route path="/import">
|
|
||||||
{importPageContent}
|
|
||||||
</Route>
|
|
||||||
<Route path="/import-export">
|
|
||||||
{importPageContent}
|
|
||||||
</Route>
|
|
||||||
<Route path="/help">
|
<Route path="/help">
|
||||||
{profile?.role === 'admin' ? (
|
{profile?.role === 'admin' ? (
|
||||||
<div className="stack">
|
<div className="stack">
|
||||||
@@ -2407,6 +2399,7 @@ export default function App() {
|
|||||||
)}
|
)}
|
||||||
<Suspense fallback={<RouteContentFallback />}>
|
<Suspense fallback={<RouteContentFallback />}>
|
||||||
<BackupCenterPage
|
<BackupCenterPage
|
||||||
|
currentUserId={profile?.id || null}
|
||||||
onExport={handleBackupExportAction}
|
onExport={handleBackupExportAction}
|
||||||
onImport={handleBackupImportAction}
|
onImport={handleBackupImportAction}
|
||||||
onLoadSettings={handleLoadBackupSettingsAction}
|
onLoadSettings={handleLoadBackupSettingsAction}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { BackupDestinationSidebar } from './backup-center/BackupDestinationSideb
|
|||||||
import { BackupOperationsSidebar } from './backup-center/BackupOperationsSidebar';
|
import { BackupOperationsSidebar } from './backup-center/BackupOperationsSidebar';
|
||||||
|
|
||||||
interface BackupCenterPageProps {
|
interface BackupCenterPageProps {
|
||||||
|
currentUserId: string | null;
|
||||||
onExport: () => Promise<void>;
|
onExport: () => Promise<void>;
|
||||||
onImport: (file: File, replaceExisting?: boolean) => Promise<void>;
|
onImport: (file: File, replaceExisting?: boolean) => Promise<void>;
|
||||||
onLoadSettings: () => Promise<AdminBackupSettings>;
|
onLoadSettings: () => Promise<AdminBackupSettings>;
|
||||||
@@ -41,7 +42,7 @@ interface BackupCenterPageProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function BackupCenterPage(props: BackupCenterPageProps) {
|
export default function BackupCenterPage(props: BackupCenterPageProps) {
|
||||||
const persistedRemoteStateRef = useRef(loadPersistedRemoteBrowserState());
|
const persistedRemoteStateRef = useRef(loadPersistedRemoteBrowserState(props.currentUserId));
|
||||||
const persistedRemoteState = persistedRemoteStateRef.current;
|
const persistedRemoteState = persistedRemoteStateRef.current;
|
||||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
@@ -126,13 +127,13 @@ export default function BackupCenterPage(props: BackupCenterPageProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
persistRemoteBrowserState({
|
persistRemoteBrowserState(props.currentUserId, {
|
||||||
cache: remoteBrowserCache,
|
cache: remoteBrowserCache,
|
||||||
pathByDestination: remoteBrowserPathByDestination,
|
pathByDestination: remoteBrowserPathByDestination,
|
||||||
pageByKey: remoteBrowserPageByKey,
|
pageByKey: remoteBrowserPageByKey,
|
||||||
selectedDestinationId,
|
selectedDestinationId,
|
||||||
});
|
});
|
||||||
}, [remoteBrowserCache, remoteBrowserPageByKey, remoteBrowserPathByDestination, selectedDestinationId]);
|
}, [props.currentUserId, remoteBrowserCache, remoteBrowserPageByKey, remoteBrowserPathByDestination, selectedDestinationId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedDestination?.type === 'placeholder') {
|
if (selectedDestination?.type === 'placeholder') {
|
||||||
|
|||||||
@@ -111,6 +111,13 @@ export function getRemoteBrowserCacheKey(destinationId: string, path: string = '
|
|||||||
return `${destinationId}:${path}`;
|
return `${destinationId}:${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRemoteBrowserStorageKey(userId?: string | null): string {
|
||||||
|
const normalizedUserId = String(userId || '').trim();
|
||||||
|
return normalizedUserId
|
||||||
|
? `${REMOTE_BROWSER_STORAGE_KEY}:${normalizedUserId}`
|
||||||
|
: REMOTE_BROWSER_STORAGE_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
function getRemoteBrowserStorage(): Storage | null {
|
function getRemoteBrowserStorage(): Storage | null {
|
||||||
try {
|
try {
|
||||||
if (typeof window !== 'undefined' && window.localStorage) {
|
if (typeof window !== 'undefined' && window.localStorage) {
|
||||||
@@ -129,10 +136,10 @@ function getRemoteBrowserStorage(): Storage | null {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPersistedRemoteBrowserState(): PersistedRemoteBrowserState {
|
export function loadPersistedRemoteBrowserState(userId?: string | null): PersistedRemoteBrowserState {
|
||||||
try {
|
try {
|
||||||
const storage = getRemoteBrowserStorage();
|
const storage = getRemoteBrowserStorage();
|
||||||
const raw = storage?.getItem(REMOTE_BROWSER_STORAGE_KEY);
|
const raw = storage?.getItem(getRemoteBrowserStorageKey(userId));
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
return {
|
return {
|
||||||
cache: {},
|
cache: {},
|
||||||
@@ -158,10 +165,10 @@ export function loadPersistedRemoteBrowserState(): PersistedRemoteBrowserState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function persistRemoteBrowserState(state: PersistedRemoteBrowserState): void {
|
export function persistRemoteBrowserState(userId: string | null | undefined, state: PersistedRemoteBrowserState): void {
|
||||||
try {
|
try {
|
||||||
const storage = getRemoteBrowserStorage();
|
const storage = getRemoteBrowserStorage();
|
||||||
storage?.setItem(REMOTE_BROWSER_STORAGE_KEY, JSON.stringify(state));
|
storage?.setItem(getRemoteBrowserStorageKey(userId), JSON.stringify(state));
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore cache persistence failures.
|
// Ignore cache persistence failures.
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user