fix[logs][FE]: live tail is fixed (#1759)

* fix: live tail is fixed

* fix: graph state is updated

* chore: step size is updated

* chore: xaxis config is updated

* chore: isDisabled state is updated for top navigation

* chore: selected interval is updated in the reducer

* fix: build is fixed

* chore: xAxis config is updated

Co-authored-by: Pranay Prateek <pranay@signoz.io>
Co-authored-by: Ankit Nayan <ankit@signoz.io>
This commit is contained in:
Palash Gupta 2022-11-28 15:44:33 +05:30 committed by GitHub
parent d06d41af87
commit 6c9036fbf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 67 deletions

View File

@ -4,9 +4,6 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
interface ITimeUnit {
[key: string]: TimeUnit;
}
interface IAxisTimeUintConfig {
unitName: TimeUnit;
multiplier: number;
@ -22,7 +19,7 @@ export interface ITimeRange {
maxTime: number | null;
}
export const TIME_UNITS: ITimeUnit = {
export const TIME_UNITS: Record<TimeUnit, TimeUnit> = {
millisecond: 'millisecond',
second: 'second',
minute: 'minute',
@ -31,6 +28,7 @@ export const TIME_UNITS: ITimeUnit = {
week: 'week',
month: 'month',
year: 'year',
quarter: 'quarter',
};
const TIME_UNITS_CONFIG: IAxisTimeUintConfig[] = [
@ -93,6 +91,7 @@ export const convertTimeRange = (
} catch (error) {
console.error(error);
}
return {
unitName: relevantTimeUnit.unitName,
stepSize: Math.floor(stepSize) || 1,

View File

@ -11,6 +11,7 @@ import { throttle } from 'lodash-es';
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { UPDATE_AUTO_REFRESH_DISABLED } from 'types/actions/globalTime';
import {
FLUSH_LOGS,
PUSH_LIVE_TAIL_EVENT,
@ -19,6 +20,7 @@ import {
} from 'types/actions/logs';
import { TLogsLiveTailState } from 'types/api/logs/liveTail';
import AppReducer from 'types/reducer/app';
import { GlobalReducer } from 'types/reducer/globalTime';
import { ILogsReducer } from 'types/reducer/logs';
import { TIME_PICKER_OPTIONS } from './config';
@ -34,12 +36,20 @@ function LogLiveTail(): JSX.Element {
logs,
} = useSelector<AppState, ILogsReducer>((state) => state.logs);
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const { selectedAutoRefreshInterval } = useSelector<AppState, GlobalReducer>(
(state) => state.globalTime,
);
const dispatch = useDispatch();
const handleLiveTail = (toggleState: TLogsLiveTailState): void => {
dispatch({
type: TOGGLE_LIVE_TAIL,
payload: toggleState,
});
dispatch({
type: UPDATE_AUTO_REFRESH_DISABLED,
payload: toggleState === 'PLAYING',
});
};
const batchedEventsRef = useRef<Record<string, unknown>[]>([]);
@ -131,6 +141,10 @@ function LogLiveTail(): JSX.Element {
[dispatch, liveTail, liveTailStartRange],
);
const isDisabled = useMemo(() => selectedAutoRefreshInterval?.length > 0, [
selectedAutoRefreshInterval,
]);
return (
<TimePickerCard>
<Space size={0} align="center">
@ -149,6 +163,7 @@ function LogLiveTail(): JSX.Element {
type="primary"
onClick={handleLiveTailStart}
title="Start live tail"
disabled={isDisabled}
>
Go Live <PlayCircleOutlined />
</Button>

View File

@ -31,6 +31,7 @@ function LogsAggregate({ getLogsAggregate }: LogsAggregateProps): JSX.Element {
);
const reFetchIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
switch (liveTail) {
case 'STOPPED': {
@ -38,18 +39,6 @@ function LogsAggregate({ getLogsAggregate }: LogsAggregateProps): JSX.Element {
clearInterval(reFetchIntervalRef.current);
}
reFetchIntervalRef.current = null;
// getLogsAggregate({
// timestampStart: minTime,
// timestampEnd: maxTime,
// step: getStep({
// start: minTime,
// end: maxTime,
// inputFormat: 'ns',
// }),
// q: queryString,
// ...(idStart ? { idGt: idStart } : {}),
// ...(idEnd ? { idLt: idEnd } : {}),
// });
break;
}
@ -106,7 +95,7 @@ function LogsAggregate({ getLogsAggregate }: LogsAggregateProps): JSX.Element {
}}
type="bar"
containerHeight="100%"
animate={false}
animate
/>
)}
</Container>

View File

@ -21,7 +21,7 @@ import { v4 } from 'uuid';
import { SearchFieldsProps } from '..';
import FieldKey from '../FieldKey';
import { QueryConditionContainer, QueryFieldContainer } from '../styles';
import { QueryFieldContainer } from '../styles';
import { createParsedQueryStructure } from '../utils';
import { Container, QueryWrapper } from './styles';
import { hashCode, parseQuery } from './utils';
@ -32,33 +32,27 @@ function QueryConditionField({
query,
queryIndex,
onUpdate,
style,
}: QueryConditionFieldProps): JSX.Element {
const allOptions = Object.values(ConditionalOperators);
return (
<QueryConditionContainer style={{ ...style }}>
<Select
defaultValue={
(query as any).value &&
(((query as any)?.value as any) as string).toUpperCase()
}
onChange={(e): void => {
onUpdate({ ...query, value: e }, queryIndex);
}}
>
{Object.values(ConditionalOperators).map((cond) => (
<Option key={cond} value={cond} label={cond}>
{cond}
</Option>
))}
</Select>
</QueryConditionContainer>
<Select
defaultValue={
(query as any).value &&
(((query as any)?.value as any) as string).toUpperCase()
}
onChange={(e): void => {
onUpdate({ ...query, value: e }, queryIndex);
}}
>
{allOptions.map((cond) => (
<Option key={cond} value={cond} label={cond}>
{cond}
</Option>
))}
</Select>
);
}
QueryConditionField.defaultProps = {
style: undefined,
};
interface QueryFieldProps {
query: Query;
queryIndex: number;
@ -174,7 +168,6 @@ interface QueryConditionFieldProps {
query: { value: string | string[]; type: string }[];
queryIndex: number;
onUpdate: (arg0: unknown, arg1: number) => void;
style?: React.CSSProperties;
}
export type Query = { value: string | string[]; type: string }[];
@ -233,12 +226,13 @@ function QueryBuilder({
);
return (
<QueryConditionField
key={keyPrefix + idx}
query={query}
queryIndex={idx}
onUpdate={handleUpdate as never}
/>
<div key={keyPrefix + idx}>
<QueryConditionField
query={query}
queryIndex={idx}
onUpdate={handleUpdate as never}
/>
</div>
);
});

View File

@ -14,8 +14,3 @@ export const QueryFieldContainer = styled.div`
background: ${blue[6]};
}
`;
export const QueryConditionContainer = styled.div`
display: flex;
flex-direction: row;
`;

View File

@ -104,7 +104,8 @@ function SearchFilter({
useEffect(() => {
handleSearch(urlQueryString || '');
}, [handleSearch, urlQueryString]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [urlQueryString, maxTime, minTime]);
return (
<Container>

View File

@ -22,19 +22,28 @@ import { useInterval } from 'react-use';
import { Dispatch } from 'redux';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { UPDATE_TIME_INTERVAL } from 'types/actions/globalTime';
import {
UPDATE_AUTO_REFRESH_INTERVAL,
UPDATE_TIME_INTERVAL,
} from 'types/actions/globalTime';
import { GlobalReducer } from 'types/reducer/globalTime';
import { options } from './config';
import { ButtonContainer, Container } from './styles';
function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
const { minTime: initialMinTime, selectedTime } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const {
minTime: initialMinTime,
selectedTime,
isAutoRefreshDisabled,
} = useSelector<AppState, GlobalReducer>((state) => state.globalTime);
const { pathname } = useLocation();
const isDisabled = useMemo(() => disabled || isAutoRefreshDisabled, [
isAutoRefreshDisabled,
disabled,
]);
const localStorageData = JSON.parse(get(DASHBOARD_TIME_IN_DURATION) || '{}');
const localStorageValue = useMemo(() => localStorageData[pathname], [
@ -46,13 +55,19 @@ function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
Boolean(localStorageValue),
);
const dispatch = useDispatch<Dispatch<AppActions>>();
useEffect(() => {
setIsAutoRefreshfreshEnabled(Boolean(localStorageValue));
}, [localStorageValue]);
const isAutoRefreshEnabled = Boolean(localStorageValue);
dispatch({
type: UPDATE_AUTO_REFRESH_INTERVAL,
payload: localStorageValue,
});
setIsAutoRefreshfreshEnabled(isAutoRefreshEnabled);
}, [localStorageValue, dispatch]);
const params = useUrlQuery();
const dispatch = useDispatch<Dispatch<AppActions>>();
const [selectedOption, setSelectedOption] = useState<string>(
localStorageValue || options[0].key,
);
@ -69,7 +84,7 @@ function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
useInterval(() => {
const selectedValue = getOption?.value;
if (disabled || !isAutoRefreshEnabled) {
if (isDisabled || !isAutoRefreshEnabled) {
return;
}
@ -125,21 +140,23 @@ function AutoRefresh({ disabled = false }: AutoRefreshProps): JSX.Element {
<Checkbox
onChange={onChangeAutoRefreshHandler}
checked={isAutoRefreshEnabled}
disabled={disabled}
disabled={isDisabled}
>
Auto Refresh
</Checkbox>
<Divider />
<Typography.Paragraph>Refresh Interval</Typography.Paragraph>
<Typography.Paragraph disabled={isDisabled}>
Refresh Interval
</Typography.Paragraph>
<Radio.Group onChange={onChangeHandler} value={selectedOption}>
<Space direction="vertical">
{options
.filter((e) => e.label !== 'off')
.map((option) => (
<Radio key={option.key} value={option.key}>
<Radio disabled={isDisabled} key={option.key} value={option.key}>
{option.label}
</Radio>
))}

View File

@ -2,6 +2,8 @@ import { getDefaultOption } from 'container/TopNav/DateTimeSelection/config';
import {
GLOBAL_TIME_LOADING_START,
GlobalTimeAction,
UPDATE_AUTO_REFRESH_DISABLED,
UPDATE_AUTO_REFRESH_INTERVAL,
UPDATE_TIME_INTERVAL,
} from 'types/actions/globalTime';
import { GlobalReducer } from 'types/reducer/globalTime';
@ -13,6 +15,8 @@ const intitalState: GlobalReducer = {
selectedTime: getDefaultOption(
typeof window !== 'undefined' ? window?.location?.pathname : '',
),
isAutoRefreshDisabled: false,
selectedAutoRefreshInterval: '',
};
const globalTimeReducer = (
@ -35,6 +39,20 @@ const globalTimeReducer = (
};
}
case UPDATE_AUTO_REFRESH_DISABLED: {
return {
...state,
isAutoRefreshDisabled: action.payload,
};
}
case UPDATE_AUTO_REFRESH_INTERVAL: {
return {
...state,
selectedAutoRefreshInterval: action.payload,
};
}
default:
return state;
}

View File

@ -106,7 +106,6 @@ export const LogsReducer = (
}${action.payload}`;
const updatedParsedQuery = parseQuery(updatedQueryString);
console.log({ updatedParsedQuery, updatedQueryString, action });
return {
...state,
searchFilter: {

View File

@ -2,6 +2,8 @@ import { Time } from 'container/TopNav/DateTimeSelection/config';
export const UPDATE_TIME_INTERVAL = 'UPDATE_TIME_INTERVAL';
export const GLOBAL_TIME_LOADING_START = 'GLOBAL_TIME_LOADING_START';
export const UPDATE_AUTO_REFRESH_DISABLED = 'UPDATE_AUTO_REFRESH_DISABLED';
export const UPDATE_AUTO_REFRESH_INTERVAL = 'UPDATE_AUTO_REFRESH_INTERVAL';
export type GlobalTime = {
maxTime: number;
@ -17,8 +19,22 @@ interface UpdateTimeInterval {
payload: UpdateTime;
}
interface UpdateAutoRefreshDisabled {
type: typeof UPDATE_AUTO_REFRESH_DISABLED;
payload: boolean;
}
interface GlobalTimeLoading {
type: typeof GLOBAL_TIME_LOADING_START;
}
export type GlobalTimeAction = UpdateTimeInterval | GlobalTimeLoading;
interface UpdateAutoRefreshInterval {
type: typeof UPDATE_AUTO_REFRESH_INTERVAL;
payload: string;
}
export type GlobalTimeAction =
| UpdateTimeInterval
| GlobalTimeLoading
| UpdateAutoRefreshDisabled
| UpdateAutoRefreshInterval;

View File

@ -6,4 +6,6 @@ export interface GlobalReducer {
minTime: GlobalTime['minTime'];
loading: boolean;
selectedTime: Time;
isAutoRefreshDisabled: boolean;
selectedAutoRefreshInterval: string;
}