feat(web): finish Semi UI track workspace
This commit is contained in:
@@ -98,11 +98,14 @@ describe('route recovery boundary', () => {
|
||||
useEffect(() => { mounts += 1; }, []);
|
||||
return <><strong>本地状态 {count}</strong><button onClick={() => setCount((value) => value + 1)}>修改本地状态</button><button onClick={() => setSearchParams({ page: '2' })}>修改查询参数</button></>;
|
||||
}
|
||||
render(<MemoryRouter future={ROUTER_FUTURE} initialEntries={['/alerts']}><RoutePage page={FilterablePage} label="告警中心" /></MemoryRouter>);
|
||||
const view = render(<main className="v2-content"><MemoryRouter future={ROUTER_FUTURE} initialEntries={['/alerts']}><RoutePage page={FilterablePage} label="告警中心" /></MemoryRouter></main>);
|
||||
const content = view.container.querySelector<HTMLElement>('.v2-content')!;
|
||||
content.scrollTop = 240;
|
||||
fireEvent.click(screen.getByRole('button', { name: '修改本地状态' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '修改查询参数' }));
|
||||
expect(screen.getByText('本地状态 1')).toBeInTheDocument();
|
||||
expect(mounts).toBe(1);
|
||||
expect(content.scrollTop).toBe(240);
|
||||
});
|
||||
|
||||
it('retries a failed route when its search scope changes without remounting healthy scopes', () => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { IconAlertTriangle } from '@douyinfe/semi-icons';
|
||||
import { Card, Tag, Typography } from '@douyinfe/semi-ui';
|
||||
import { Component, type ElementType, type ErrorInfo, type ReactNode, Suspense, useCallback, useMemo, useState } from 'react';
|
||||
import { Component, type ElementType, type ErrorInfo, type ReactNode, Suspense, useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { PageLoading } from '../shared/AsyncState';
|
||||
import { RecoveryActions } from '../shared/RecoveryActions';
|
||||
import { resetWorkspaceScroll } from './resetWorkspaceScroll';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const CHUNK_RELOAD_KEY = 'vehicle-platform:route-chunk-reload';
|
||||
@@ -141,6 +142,16 @@ export class PlatformErrorBoundary extends Component<{ children: ReactNode }, {
|
||||
}
|
||||
}
|
||||
|
||||
function RouteScrollReset({ routeKey }: { routeKey: string }) {
|
||||
useLayoutEffect(() => {
|
||||
const reset = () => resetWorkspaceScroll();
|
||||
reset();
|
||||
const frame = window.requestAnimationFrame(reset);
|
||||
return () => window.cancelAnimationFrame(frame);
|
||||
}, [routeKey]);
|
||||
return null;
|
||||
}
|
||||
|
||||
export function RoutePage({ page, recreatePage, label }: { page: ElementType; recreatePage?: () => ElementType; label: string }) {
|
||||
const location = useLocation();
|
||||
const routeKey = `${location.pathname}${location.search}`;
|
||||
@@ -148,6 +159,9 @@ export function RoutePage({ page, recreatePage, label }: { page: ElementType; re
|
||||
const Page = useMemo(() => retryKey && recreatePage ? recreatePage() : page, [page, recreatePage, retryKey]);
|
||||
const retry = useCallback(() => setRetryKey((value) => value + 1), []);
|
||||
return <RecoverableRouteBoundary key={location.pathname} routeKey={routeKey} retryKey={retryKey} onRetry={retry}>
|
||||
<Suspense fallback={<PageLoading label={`正在加载${label}`} />}><Page key={retryKey} /></Suspense>
|
||||
<Suspense fallback={<PageLoading label={`正在加载${label}`} />}>
|
||||
<RouteScrollReset routeKey={location.pathname} />
|
||||
<Page key={retryKey} />
|
||||
</Suspense>
|
||||
</RecoverableRouteBoundary>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export function resetWorkspaceScroll(content = document.querySelector<HTMLElement>('.v2-content')) {
|
||||
if (!content) return;
|
||||
content.scrollTop = 0;
|
||||
content.scrollLeft = 0;
|
||||
content.scrollTo?.({ top: 0, left: 0, behavior: 'auto' });
|
||||
|
||||
const routeRoot = content.firstElementChild;
|
||||
if (!(routeRoot instanceof HTMLElement)) return;
|
||||
routeRoot.scrollTop = 0;
|
||||
routeRoot.scrollLeft = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user