mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 07:06:01 +08:00
feat: sort logs in ascending order (#2895)
* feat: sort logs in ascending order Co-authored-by: gitstart <gitstart@gitstart.com> Co-authored-by: Rubens Rafael <70234898+RubensRafael@users.noreply.github.com> Co-authored-by: RubensRafael <rubensrafael2@live.com> * refactor: requested changes Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: niteshsingh1357 <niteshsingh1357@gmail.com> Co-authored-by: RubensRafael <rubensrafael2@live.com> * fix: lint Co-authored-by: niteshsingh1357 <niteshsingh1357@gmail.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: RubensRafael <rubensrafael2@live.com> * chore: removed the magic string --------- Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: gitstart <gitstart@gitstart.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Rubens Rafael <70234898+RubensRafael@users.noreply.github.com> Co-authored-by: Palash Gupta <palashgdev@gmail.com> Co-authored-by: RubensRafael <rubensrafael2@live.com> Co-authored-by: Vishal Sharma <makeavish786@gmail.com> Co-authored-by: niteshsingh1357 <niteshsingh1357@gmail.com>
This commit is contained in:
parent
1eabacbaf4
commit
64d4532a6b
@ -14,4 +14,6 @@ export enum QueryParams {
|
||||
resourceAttributes = 'resourceAttribute',
|
||||
graphType = 'graphType',
|
||||
widgetId = 'widgetId',
|
||||
order = 'order',
|
||||
q = 'q',
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { getMinMax } from 'container/TopNav/AutoRefresh/config';
|
||||
import dayjs from 'dayjs';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||
import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import * as Papa from 'papaparse';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
@ -31,6 +32,7 @@ function LogControls(): JSX.Element | null {
|
||||
isLoading: isLogsLoading,
|
||||
isLoadingAggregate,
|
||||
logs,
|
||||
order,
|
||||
} = useSelector<AppState, ILogsReducer>((state) => state.logs);
|
||||
const globalTime = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
@ -160,6 +162,7 @@ function LogControls(): JSX.Element | null {
|
||||
loading={isLoading}
|
||||
size="small"
|
||||
type="link"
|
||||
disabled={order === OrderPreferenceItems.ASC}
|
||||
onClick={handleGoToLatest}
|
||||
>
|
||||
<FastBackwardOutlined /> Go to latest
|
||||
|
@ -2,6 +2,7 @@ import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
|
||||
import { Button, Col, Popover } from 'antd';
|
||||
import getStep from 'lib/getStep';
|
||||
import { generateFilterQuery } from 'lib/logs/generateFilterQuery';
|
||||
import { getIdConditions } from 'pages/Logs/utils';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
@ -45,6 +46,7 @@ function ActionItem({
|
||||
idStart,
|
||||
liveTail,
|
||||
idEnd,
|
||||
order,
|
||||
} = useSelector<AppState, ILogsReducer>((store) => store.logs);
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
|
||||
@ -72,11 +74,10 @@ function ActionItem({
|
||||
q: updatedQueryString,
|
||||
limit: logLinesPerPage,
|
||||
orderBy: 'timestamp',
|
||||
order: 'desc',
|
||||
order,
|
||||
timestampStart: minTime,
|
||||
timestampEnd: maxTime,
|
||||
...(idStart ? { idGt: idStart } : {}),
|
||||
...(idEnd ? { idLt: idEnd } : {}),
|
||||
...getIdConditions(idStart, idEnd, order),
|
||||
});
|
||||
getLogsAggregate({
|
||||
timestampStart: minTime,
|
||||
|
@ -2,6 +2,7 @@ import { Input, InputRef, Popover } from 'antd';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import getStep from 'lib/getStep';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
import { getIdConditions } from 'pages/Logs/utils';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
@ -33,7 +34,7 @@ function SearchFilter({
|
||||
const [searchText, setSearchText] = useState(queryString);
|
||||
const [showDropDown, setShowDropDown] = useState(false);
|
||||
const searchRef = useRef<InputRef>(null);
|
||||
const { logLinesPerPage, idEnd, idStart, liveTail } = useSelector<
|
||||
const { logLinesPerPage, idEnd, idStart, liveTail, order } = useSelector<
|
||||
AppState,
|
||||
ILogsReducer
|
||||
>((state) => state.logs);
|
||||
@ -99,11 +100,10 @@ function SearchFilter({
|
||||
q: customQuery,
|
||||
limit: logLinesPerPage,
|
||||
orderBy: 'timestamp',
|
||||
order: 'desc',
|
||||
order,
|
||||
timestampStart: minTime,
|
||||
timestampEnd: maxTime,
|
||||
...(idStart ? { idGt: idStart } : {}),
|
||||
...(idEnd ? { idLt: idEnd } : {}),
|
||||
...getIdConditions(idStart, idEnd, order),
|
||||
});
|
||||
|
||||
getLogsAggregate({
|
||||
@ -128,6 +128,7 @@ function SearchFilter({
|
||||
logLinesPerPage,
|
||||
globalTime,
|
||||
getLogsFields,
|
||||
order,
|
||||
],
|
||||
);
|
||||
|
||||
@ -160,6 +161,7 @@ function SearchFilter({
|
||||
dispatch,
|
||||
globalTime.maxTime,
|
||||
globalTime.minTime,
|
||||
order,
|
||||
]);
|
||||
|
||||
const onPopOverChange = useCallback(
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { getMinMax } from 'container/TopNav/AutoRefresh/config';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import history from 'lib/history';
|
||||
@ -25,6 +26,7 @@ export function useSearchParser(): {
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
const {
|
||||
searchFilter: { parsedQuery, queryString },
|
||||
order,
|
||||
} = useSelector<AppState, ILogsReducer>((store) => store.logs);
|
||||
|
||||
const urlQuery = useUrlQuery();
|
||||
@ -39,7 +41,7 @@ export function useSearchParser(): {
|
||||
(updatedQueryString: string) => {
|
||||
history.replace({
|
||||
pathname: history.location.pathname,
|
||||
search: `?q=${updatedQueryString}`,
|
||||
search: `?${QueryParams.q}=${updatedQueryString}&${QueryParams.order}=${order}`,
|
||||
});
|
||||
|
||||
const globalTime = getMinMax(selectedTime, minTime, maxTime);
|
||||
|
@ -25,3 +25,24 @@ export const logsOptions = ['raw', 'table'];
|
||||
export const defaultSelectStyle: CSSProperties = {
|
||||
minWidth: '6rem',
|
||||
};
|
||||
|
||||
export enum OrderPreferenceItems {
|
||||
DESC = 'desc',
|
||||
ASC = 'asc',
|
||||
}
|
||||
|
||||
export const orderItems: OrderPreference[] = [
|
||||
{
|
||||
name: 'Descending',
|
||||
enum: OrderPreferenceItems.DESC,
|
||||
},
|
||||
{
|
||||
name: 'Ascending',
|
||||
enum: OrderPreferenceItems.ASC,
|
||||
},
|
||||
];
|
||||
|
||||
export interface OrderPreference {
|
||||
name: string;
|
||||
enum: OrderPreferenceItems;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Button, Col, Divider, Popover, Row, Select, Space } from 'antd';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import LogControls from 'container/LogControls';
|
||||
import LogDetailedView from 'container/LogDetailedView';
|
||||
import LogLiveTail from 'container/LogLiveTail';
|
||||
@ -6,20 +7,31 @@ import LogsAggregate from 'container/LogsAggregate';
|
||||
import LogsFilters from 'container/LogsFilters';
|
||||
import LogsSearchFilter from 'container/LogsSearchFilter';
|
||||
import LogsTable from 'container/LogsTable';
|
||||
import history from 'lib/history';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { Dispatch } from 'redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppActions from 'types/actions';
|
||||
import { SET_DETAILED_LOG_DATA } from 'types/actions/logs';
|
||||
import { SET_DETAILED_LOG_DATA, SET_LOGS_ORDER } from 'types/actions/logs';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { ILogsReducer } from 'types/reducer/logs';
|
||||
|
||||
import { defaultSelectStyle, logsOptions } from './config';
|
||||
import {
|
||||
defaultSelectStyle,
|
||||
logsOptions,
|
||||
orderItems,
|
||||
OrderPreferenceItems,
|
||||
} from './config';
|
||||
import { useSelectedLogView } from './hooks';
|
||||
import PopoverContent from './PopoverContent';
|
||||
import SpaceContainer from './styles';
|
||||
|
||||
function Logs(): JSX.Element {
|
||||
const dispatch = useDispatch<Dispatch<AppActions>>();
|
||||
const { order } = useSelector<AppState, ILogsReducer>((store) => store.logs);
|
||||
const location = useLocation();
|
||||
|
||||
const showExpandedLog = useCallback(
|
||||
(logData: ILog) => {
|
||||
@ -67,6 +79,16 @@ function Logs(): JSX.Element {
|
||||
[handleViewModeOptionChange],
|
||||
);
|
||||
|
||||
const handleChangeOrder = (value: OrderPreferenceItems): void => {
|
||||
dispatch({
|
||||
type: SET_LOGS_ORDER,
|
||||
payload: value,
|
||||
});
|
||||
const params = new URLSearchParams(location.search);
|
||||
params.set(QueryParams.order, value);
|
||||
history.push({ search: params.toString() });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SpaceContainer
|
||||
@ -101,6 +123,16 @@ function Logs(): JSX.Element {
|
||||
<Button>Format</Button>
|
||||
</Popover>
|
||||
)}
|
||||
|
||||
<Select
|
||||
style={defaultSelectStyle}
|
||||
defaultValue={order}
|
||||
onChange={handleChangeOrder}
|
||||
>
|
||||
{orderItems.map((item) => (
|
||||
<Select.Option key={item.enum}>{item.name}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Space>
|
||||
</Col>
|
||||
|
||||
|
@ -1,7 +1,29 @@
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
|
||||
import { viewModeOptionList } from './config';
|
||||
import { OrderPreferenceItems, viewModeOptionList } from './config';
|
||||
|
||||
export const isLogViewMode = (value: unknown): value is LogViewMode =>
|
||||
typeof value === 'string' &&
|
||||
viewModeOptionList.some((option) => option.key === value);
|
||||
|
||||
export const getIdConditions = (
|
||||
idStart: string,
|
||||
idEnd: string,
|
||||
order: OrderPreferenceItems,
|
||||
): Record<string, string> => {
|
||||
const idConditions: Record<string, string> = {};
|
||||
|
||||
if (idStart && order === OrderPreferenceItems.ASC) {
|
||||
idConditions.idLt = idStart;
|
||||
} else if (idStart) {
|
||||
idConditions.idGt = idStart;
|
||||
}
|
||||
|
||||
if (idEnd && order === OrderPreferenceItems.ASC) {
|
||||
idConditions.idGt = idEnd;
|
||||
} else if (idEnd) {
|
||||
idConditions.idLt = idEnd;
|
||||
}
|
||||
|
||||
return idConditions;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { parseQuery } from 'lib/logql';
|
||||
import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import {
|
||||
ADD_SEARCH_FIELD_QUERY_STRING,
|
||||
FLUSH_LOGS,
|
||||
@ -17,6 +18,7 @@ import {
|
||||
SET_LOG_LINES_PER_PAGE,
|
||||
SET_LOGS,
|
||||
SET_LOGS_AGGREGATE_SERIES,
|
||||
SET_LOGS_ORDER,
|
||||
SET_SEARCH_QUERY_PARSED_PAYLOAD,
|
||||
SET_SEARCH_QUERY_STRING,
|
||||
SET_VIEW_MODE,
|
||||
@ -49,6 +51,10 @@ const initialState: ILogsReducer = {
|
||||
liveTailStartRange: 15,
|
||||
selectedLogId: null,
|
||||
detailedLog: null,
|
||||
order:
|
||||
(new URLSearchParams(window.location.search).get(
|
||||
'order',
|
||||
) as ILogsReducer['order']) ?? OrderPreferenceItems.DESC,
|
||||
};
|
||||
|
||||
export const LogsReducer = (
|
||||
@ -129,6 +135,17 @@ export const LogsReducer = (
|
||||
logs: logsData,
|
||||
};
|
||||
}
|
||||
|
||||
case SET_LOGS_ORDER: {
|
||||
const order = action.payload;
|
||||
return {
|
||||
...state,
|
||||
order,
|
||||
idStart: '',
|
||||
idEnd: '',
|
||||
};
|
||||
}
|
||||
|
||||
case SET_LOG_LINES_PER_PAGE: {
|
||||
return {
|
||||
...state,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { ILogQLParsedQueryItem } from 'lib/logql/types';
|
||||
import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import { IField, IFieldMoveToSelected, IFields } from 'types/api/logs/fields';
|
||||
import { TLogsLiveTailState } from 'types/api/logs/liveTail';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
@ -34,6 +35,7 @@ export const SET_LINES_PER_ROW = 'SET_LINES_PER_ROW';
|
||||
export const SET_VIEW_MODE = 'SET_VIEW_MODE';
|
||||
export const UPDATE_SELECTED_FIELDS = 'LOGS_UPDATE_SELECTED_FIELDS';
|
||||
export const UPDATE_INTERESTING_FIELDS = 'LOGS_UPDATE_INTERESTING_FIELDS';
|
||||
export const SET_LOGS_ORDER = 'SET_LOGS_ORDER';
|
||||
|
||||
export interface GetFields {
|
||||
type: typeof GET_FIELDS;
|
||||
@ -141,6 +143,11 @@ export interface UpdateSelectedInterestFields {
|
||||
};
|
||||
}
|
||||
|
||||
export interface SetLogsOrder {
|
||||
type: typeof SET_LOGS_ORDER;
|
||||
payload: OrderPreferenceItems;
|
||||
}
|
||||
|
||||
export type LogsActions =
|
||||
| GetFields
|
||||
| SetFields
|
||||
@ -164,4 +171,5 @@ export type LogsActions =
|
||||
| SetLiveTailStartTime
|
||||
| SetLinesPerRow
|
||||
| SetViewMode
|
||||
| UpdateSelectedInterestFields;
|
||||
| UpdateSelectedInterestFields
|
||||
| SetLogsOrder;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { ILogQLParsedQueryItem } from 'lib/logql/types';
|
||||
import { OrderPreferenceItems } from 'pages/Logs/config';
|
||||
import { IFields } from 'types/api/logs/fields';
|
||||
import { TLogsLiveTailState } from 'types/api/logs/liveTail';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
@ -25,6 +26,7 @@ export interface ILogsReducer {
|
||||
detailedLog: null | ILog;
|
||||
liveTail: TLogsLiveTailState;
|
||||
liveTailStartRange: number; // time in minutes
|
||||
order: OrderPreferenceItems;
|
||||
}
|
||||
|
||||
export default ILogsReducer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user