mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-10-14 06:01:29 +08:00
feat: added goto top feature in list logs veiw (#3146)
This commit is contained in:
parent
7f9ba6c43a
commit
22d0aa951c
29
frontend/src/container/GoToTop/index.tsx
Normal file
29
frontend/src/container/GoToTop/index.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { ArrowUpOutlined } from '@ant-design/icons';
|
||||
import { FloatButton } from 'antd';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
// hooks
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import useScrollToTop from 'hooks/useScrollToTop';
|
||||
|
||||
function GoToTop(): JSX.Element | null {
|
||||
const { isVisible, scrollToTop } = useScrollToTop();
|
||||
|
||||
const { panelType } = useQueryBuilder();
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
if (panelType === PANEL_TYPES.LIST) {
|
||||
return (
|
||||
<FloatButton
|
||||
onClick={scrollToTop}
|
||||
shape="circle"
|
||||
type="primary"
|
||||
icon={<ArrowUpOutlined />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default GoToTop;
|
@ -1,5 +1,4 @@
|
||||
import { TabsProps } from 'antd';
|
||||
import axios from 'axios';
|
||||
import LogDetail from 'components/LogDetail';
|
||||
import TabLabel from 'components/TabLabel';
|
||||
import { QueryParams } from 'constants/query';
|
||||
@ -13,6 +12,7 @@ import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
|
||||
import ExportPanel from 'container/ExportPanel';
|
||||
import GoToTop from 'container/GoToTop';
|
||||
import LogsExplorerChart from 'container/LogsExplorerChart';
|
||||
import LogsExplorerList from 'container/LogsExplorerList';
|
||||
import LogsExplorerTable from 'container/LogsExplorerTable';
|
||||
@ -22,6 +22,7 @@ import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||
import { addEmptyWidgetInDashboardJSONWithQuery } from 'hooks/dashboard/utils';
|
||||
import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQueryRange';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import useAxiosError from 'hooks/useAxiosError';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAutocompleteFromCustomValue';
|
||||
@ -81,6 +82,8 @@ function LogsExplorerViews(): JSX.Element {
|
||||
const [logs, setLogs] = useState<ILog[]>([]);
|
||||
const [requestData, setRequestData] = useState<Query | null>(null);
|
||||
|
||||
const handleAxisError = useAxiosError();
|
||||
|
||||
const currentStagedQueryData = useMemo(() => {
|
||||
if (!stagedQuery || stagedQuery.builder.queryData.length !== 1) return null;
|
||||
|
||||
@ -357,16 +360,16 @@ function LogsExplorerViews(): JSX.Element {
|
||||
|
||||
history.push(dashboardEditView);
|
||||
},
|
||||
onError: (error) => {
|
||||
if (axios.isAxiosError(error)) {
|
||||
notifications.error({
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: handleAxisError,
|
||||
});
|
||||
},
|
||||
[exportDefaultQuery, history, notifications, updateDashboard],
|
||||
[
|
||||
exportDefaultQuery,
|
||||
history,
|
||||
notifications,
|
||||
updateDashboard,
|
||||
handleAxisError,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -511,6 +514,8 @@ function LogsExplorerViews(): JSX.Element {
|
||||
onAddToQuery={handleAddToQuery}
|
||||
onClickActionItem={handleAddToQuery}
|
||||
/>
|
||||
|
||||
<GoToTop />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
29
frontend/src/hooks/useScrollToTop/index.tsx
Normal file
29
frontend/src/hooks/useScrollToTop/index.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import throttle from 'lodash-es/throttle';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { UseScrollToTop } from './types';
|
||||
|
||||
function useScrollToTop(visibleOffset = 200): UseScrollToTop {
|
||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||
|
||||
const scrollToTop = (): void => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const toggleVisibility = throttle(() => {
|
||||
setIsVisible(window.pageYOffset > visibleOffset);
|
||||
}, 300);
|
||||
|
||||
window.addEventListener('scroll', toggleVisibility);
|
||||
|
||||
return (): void => window.removeEventListener('scroll', toggleVisibility);
|
||||
}, [visibleOffset]);
|
||||
|
||||
return { isVisible, scrollToTop };
|
||||
}
|
||||
|
||||
export default useScrollToTop;
|
4
frontend/src/hooks/useScrollToTop/types.ts
Normal file
4
frontend/src/hooks/useScrollToTop/types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface UseScrollToTop {
|
||||
isVisible: boolean;
|
||||
scrollToTop: VoidFunction;
|
||||
}
|
58
frontend/src/hooks/useScrollToTop/useScrollToTop.test.ts
Normal file
58
frontend/src/hooks/useScrollToTop/useScrollToTop.test.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import useScrollToTop from './index';
|
||||
|
||||
// Mocking window.scrollTo method
|
||||
global.scrollTo = jest.fn();
|
||||
|
||||
describe('useScrollToTop hook', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('should change visibility and scroll to top on call', () => {
|
||||
const { result } = renderHook(() => useScrollToTop(100));
|
||||
|
||||
// Simulate scrolling 150px down
|
||||
act(() => {
|
||||
global.pageYOffset = 150;
|
||||
global.dispatchEvent(new Event('scroll'));
|
||||
jest.advanceTimersByTime(300);
|
||||
});
|
||||
|
||||
expect(result.current.isVisible).toBe(true);
|
||||
|
||||
// Simulate scrolling to top
|
||||
act(() => {
|
||||
result.current.scrollToTop();
|
||||
});
|
||||
|
||||
expect(global.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
|
||||
it('should be invisible when scrolled less than offset', () => {
|
||||
const { result } = renderHook(() => useScrollToTop(100));
|
||||
|
||||
// Simulate scrolling 50px down
|
||||
act(() => {
|
||||
global.pageYOffset = 50;
|
||||
global.dispatchEvent(new Event('scroll'));
|
||||
jest.advanceTimersByTime(300);
|
||||
});
|
||||
|
||||
expect(result.current.isVisible).toBe(false);
|
||||
});
|
||||
|
||||
it('should be visible when scrolled more than offset', () => {
|
||||
const { result } = renderHook(() => useScrollToTop(100));
|
||||
|
||||
// Simulate scrolling 50px down
|
||||
act(() => {
|
||||
global.pageYOffset = 200;
|
||||
global.dispatchEvent(new Event('scroll'));
|
||||
jest.advanceTimersByTime(300);
|
||||
});
|
||||
|
||||
expect(result.current.isVisible).toBe(true);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user