mirror of
https://github.com/SigNoz/signoz.git
synced 2026-06-16 13:30:36 +01:00
Compare commits
1 Commits
issue_4203
...
reduce-mot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebaa44c743 |
@@ -90,4 +90,20 @@ describe('RouteTab component', () => {
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
|
||||
expect(onChangeHandler).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('unmounts inactive tab pane content after switching', () => {
|
||||
const history = createMemoryHistory({ initialEntries: ['/tab1'] });
|
||||
render(
|
||||
<Router history={history}>
|
||||
<RouteTab history={history} routes={testRoutes} activeKey="Tab1" />
|
||||
</Router>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('Dummy Component 1')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: 'Tab2' }));
|
||||
|
||||
expect(screen.queryByText('Dummy Component 1')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('Dummy Component 2')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ function RouteTab({
|
||||
destroyInactiveTabPane
|
||||
activeKey={currentRoute?.key || activeKey}
|
||||
defaultActiveKey={currentRoute?.key || activeKey}
|
||||
animated
|
||||
animated={{ inkBar: true, tabPane: false }}
|
||||
items={items}
|
||||
tabBarExtraContent={
|
||||
showRightSection && (
|
||||
|
||||
@@ -11,6 +11,7 @@ import CreateAlertV2 from 'container/CreateAlertV2';
|
||||
import FormAlertRules, { AlertDetectionTypes } from 'container/FormAlertRules';
|
||||
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
|
||||
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
|
||||
import useReducedMotion from 'hooks/useReducedMotion';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { AlertListTabs } from 'pages/AlertList/types';
|
||||
@@ -26,6 +27,7 @@ import './CreateAlertRule.styles.scss';
|
||||
|
||||
function CreateRules(): JSX.Element {
|
||||
const [formInstance] = Form.useForm();
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
const compositeQuery = useGetCompositeQueryParam();
|
||||
const queryParams = useUrlQuery();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
@@ -41,7 +43,7 @@ function CreateRules(): JSX.Element {
|
||||
|
||||
useEffect(() => {
|
||||
if (isTypeSelectionMode) {
|
||||
logEvent('Alert: New alert data source selection page visited', {});
|
||||
void logEvent('Alert: New alert data source selection page visited', {});
|
||||
}
|
||||
}, [isTypeSelectionMode]);
|
||||
|
||||
@@ -187,6 +189,7 @@ function CreateRules(): JSX.Element {
|
||||
return (
|
||||
<Tabs
|
||||
destroyInactiveTabPane
|
||||
animated={!prefersReducedMotion}
|
||||
items={items}
|
||||
activeKey={AlertListTabs.ALERT_RULES}
|
||||
onChange={handleTabChange}
|
||||
|
||||
80
frontend/src/hooks/__tests__/useReducedMotion.test.ts
Normal file
80
frontend/src/hooks/__tests__/useReducedMotion.test.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import useReducedMotion from 'hooks/useReducedMotion';
|
||||
|
||||
type ChangeListener = (e: Partial<MediaQueryListEvent>) => void;
|
||||
|
||||
function mockMatchMedia(matches: boolean): {
|
||||
setMatches: (next: boolean) => void;
|
||||
} {
|
||||
const listeners: ChangeListener[] = [];
|
||||
let currentMatches = matches;
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn(() => ({
|
||||
get matches() {
|
||||
return currentMatches;
|
||||
},
|
||||
addEventListener: jest.fn((_: string, fn: ChangeListener) => {
|
||||
listeners.push(fn);
|
||||
}),
|
||||
removeEventListener: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
return {
|
||||
setMatches: (next: boolean): void => {
|
||||
currentMatches = next;
|
||||
listeners.forEach((fn) => fn({ matches: next } as MediaQueryListEvent));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('useReducedMotion', () => {
|
||||
it('returns false when prefers-reduced-motion is not set', () => {
|
||||
mockMatchMedia(false);
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true when prefers-reduced-motion: reduce is active', () => {
|
||||
mockMatchMedia(true);
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('updates when system preference changes at runtime', () => {
|
||||
const { setMatches } = mockMatchMedia(false);
|
||||
const { result } = renderHook(() => useReducedMotion());
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
act(() => {
|
||||
setMatches(true);
|
||||
});
|
||||
expect(result.current).toBe(true);
|
||||
|
||||
act(() => {
|
||||
setMatches(false);
|
||||
});
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('removes event listener on unmount', () => {
|
||||
const removeEventListener = jest.fn();
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn(() => ({
|
||||
matches: false,
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener,
|
||||
})),
|
||||
});
|
||||
|
||||
const { unmount } = renderHook(() => useReducedMotion());
|
||||
unmount();
|
||||
expect(removeEventListener).toHaveBeenCalledWith(
|
||||
'change',
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
});
|
||||
20
frontend/src/hooks/useReducedMotion.ts
Normal file
20
frontend/src/hooks/useReducedMotion.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
function useReducedMotion(): boolean {
|
||||
const [prefersReducedMotion, setPrefersReducedMotion] = useState<boolean>(
|
||||
() => window.matchMedia('(prefers-reduced-motion: reduce)').matches,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
const onChange = (e: MediaQueryListEvent): void => {
|
||||
setPrefersReducedMotion(e.matches);
|
||||
};
|
||||
mediaQuery.addEventListener('change', onChange);
|
||||
return (): void => mediaQuery.removeEventListener('change', onChange);
|
||||
}, []);
|
||||
|
||||
return prefersReducedMotion;
|
||||
}
|
||||
|
||||
export default useReducedMotion;
|
||||
@@ -8,6 +8,7 @@ import AllAlertRules from 'container/ListAlertRules';
|
||||
import { PlannedDowntime } from 'container/PlannedDowntime/PlannedDowntime';
|
||||
import RoutingPolicies from 'container/RoutingPolicies';
|
||||
import TriggeredAlerts from 'container/TriggeredAlerts';
|
||||
import useReducedMotion from 'hooks/useReducedMotion';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { GalleryVerticalEnd, Pyramid } from '@signozhq/icons';
|
||||
@@ -21,6 +22,7 @@ function AllAlertList(): JSX.Element {
|
||||
const urlQuery = useUrlQuery();
|
||||
const location = useLocation();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
|
||||
const tab = urlQuery.get('tab');
|
||||
const subTab = urlQuery.get('subTab');
|
||||
@@ -101,6 +103,7 @@ function AllAlertList(): JSX.Element {
|
||||
return (
|
||||
<Tabs
|
||||
destroyInactiveTabPane
|
||||
animated={!prefersReducedMotion}
|
||||
items={items}
|
||||
activeKey={tab || AlertListTabs.ALERT_RULES}
|
||||
onChange={(tab): void => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import DBCall from 'container/MetricsApplication/Tabs/DBCall';
|
||||
import External from 'container/MetricsApplication/Tabs/External';
|
||||
import Overview from 'container/MetricsApplication/Tabs/Overview';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import useReducedMotion from 'hooks/useReducedMotion';
|
||||
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
|
||||
@@ -20,6 +21,7 @@ function MetricsApplication(): JSX.Element {
|
||||
}>();
|
||||
|
||||
const activeKey = useMetricsApplicationTabKey();
|
||||
const prefersReducedMotion = useReducedMotion();
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
@@ -56,6 +58,7 @@ function MetricsApplication(): JSX.Element {
|
||||
activeKey={activeKey}
|
||||
className="service-route-tab"
|
||||
destroyInactiveTabPane
|
||||
animated={!prefersReducedMotion}
|
||||
onChange={onTabChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user