mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:49:01 +08:00
Merge branch 'develop' into 417-search-filter
This commit is contained in:
commit
aae6a1adf1
@ -1,11 +1,14 @@
|
||||
/* eslint-disable react/no-unstable-nested-components */
|
||||
import { Input, Slider } from 'antd';
|
||||
import { Slider } from 'antd';
|
||||
import { SliderRangeProps } from 'antd/lib/slider';
|
||||
import getFilters from 'api/trace/getFilters';
|
||||
import dayjs from 'dayjs';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||
@ -15,19 +18,8 @@ import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { Container, InputContainer, Text } from './styles';
|
||||
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
const getMs = (value: string): string => {
|
||||
return parseFloat(
|
||||
dayjs
|
||||
.duration({
|
||||
milliseconds: parseInt(value, 10) / 1000000,
|
||||
})
|
||||
.format('SSS'),
|
||||
).toFixed(2);
|
||||
};
|
||||
import { Container, InputComponent, InputContainer, Text } from './styles';
|
||||
import { getMs } from './util';
|
||||
|
||||
function Duration(): JSX.Element {
|
||||
const {
|
||||
@ -77,17 +69,18 @@ function Duration(): JSX.Element {
|
||||
preLocalMinDuration.current = parseFloat(minDuration);
|
||||
}
|
||||
|
||||
setPreMax(maxDuration);
|
||||
setPreMin(minDuration);
|
||||
setPreMax(getMs(maxDuration));
|
||||
setPreMin(getMs(minDuration));
|
||||
}, [getDuration]);
|
||||
|
||||
const defaultValue = [parseFloat(preMin), parseFloat(preMax)];
|
||||
|
||||
const updatedUrl = async (min: number, max: number): Promise<void> => {
|
||||
const preSelectedFilter = new Map(selectedFilter);
|
||||
const preUserSelected = new Map(userSelectedFilter);
|
||||
|
||||
preSelectedFilter.set('duration', [String(max), String(min)]);
|
||||
preSelectedFilter.set('duration', [
|
||||
String(max * 1000000),
|
||||
String(min * 1000000),
|
||||
]);
|
||||
|
||||
const response = await getFilters({
|
||||
end: String(globalTime.maxTime),
|
||||
@ -137,18 +130,18 @@ function Duration(): JSX.Element {
|
||||
}
|
||||
};
|
||||
|
||||
const onRangeSliderHandler = (number: [number, number]): void => {
|
||||
const onRangeSliderHandler = (number: [string, string]): void => {
|
||||
const [min, max] = number;
|
||||
|
||||
setPreMin(min.toString());
|
||||
setPreMax(max.toString());
|
||||
setPreMin(min);
|
||||
setPreMax(max);
|
||||
};
|
||||
|
||||
const debouncedFunction = useDebouncedFn(
|
||||
(min, max) => {
|
||||
updatedUrl(min as number, max as number);
|
||||
},
|
||||
500,
|
||||
1500,
|
||||
undefined,
|
||||
);
|
||||
|
||||
@ -156,8 +149,8 @@ function Duration(): JSX.Element {
|
||||
event,
|
||||
) => {
|
||||
const { value } = event.target;
|
||||
const min = parseFloat(preMin);
|
||||
const max = parseFloat(value) * 1000000;
|
||||
const min = preMin;
|
||||
const max = value;
|
||||
|
||||
onRangeSliderHandler([min, max]);
|
||||
debouncedFunction(min, max);
|
||||
@ -167,8 +160,9 @@ function Duration(): JSX.Element {
|
||||
event,
|
||||
) => {
|
||||
const { value } = event.target;
|
||||
const min = parseFloat(value) * 1000000;
|
||||
const max = parseFloat(preMax);
|
||||
const min = value;
|
||||
const max = preMax;
|
||||
|
||||
onRangeSliderHandler([min, max]);
|
||||
debouncedFunction(min, max);
|
||||
};
|
||||
@ -177,45 +171,48 @@ function Duration(): JSX.Element {
|
||||
updatedUrl(min, max);
|
||||
};
|
||||
|
||||
const TipComponent = useCallback((value) => {
|
||||
if (value === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
return <div>{`${getMs(value?.toString())}ms`}</div>;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container>
|
||||
<InputContainer>
|
||||
<Text>Min</Text>
|
||||
</InputContainer>
|
||||
<Input
|
||||
<InputComponent
|
||||
addonAfter="ms"
|
||||
type="number"
|
||||
onChange={onChangeMinHandler}
|
||||
value={getMs(preMin)}
|
||||
value={preMin}
|
||||
/>
|
||||
|
||||
<InputContainer>
|
||||
<Text>Max</Text>
|
||||
</InputContainer>
|
||||
<Input
|
||||
<InputComponent
|
||||
addonAfter="ms"
|
||||
type="number"
|
||||
onChange={onChangeMaxHandler}
|
||||
value={getMs(preMax)}
|
||||
value={preMax}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
<Container>
|
||||
<Slider
|
||||
defaultValue={[defaultValue[0], defaultValue[1]]}
|
||||
min={parseFloat((preLocalMinDuration.current || 0).toString())}
|
||||
max={parseFloat((preLocalMaxDuration.current || 0).toString())}
|
||||
min={Number(getMs(String(preLocalMinDuration.current || 0)))}
|
||||
max={Number(getMs(String(preLocalMaxDuration.current || 0)))}
|
||||
range
|
||||
tipFormatter={(value): JSX.Element => {
|
||||
if (value === undefined) {
|
||||
return <div />;
|
||||
}
|
||||
return <div>{`${getMs(value?.toString())}ms`}</div>;
|
||||
}}
|
||||
tipFormatter={TipComponent}
|
||||
onChange={([min, max]): void => {
|
||||
onRangeSliderHandler([min, max]);
|
||||
onRangeSliderHandler([String(min), String(max)]);
|
||||
}}
|
||||
onAfterChange={onRangeHandler}
|
||||
value={[parseFloat(preMin), parseFloat(preMax)]}
|
||||
value={[Number(preMin), Number(preMax)]}
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Typography } from 'antd';
|
||||
import { Input, Typography } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const DurationText = styled.div`
|
||||
@ -9,6 +9,19 @@ export const DurationText = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export const InputComponent = styled(Input)`
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
input[type='number'] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
`;
|
||||
|
||||
export const InputContainer = styled.div`
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
|
@ -0,0 +1,13 @@
|
||||
import dayjs from 'dayjs';
|
||||
import durationPlugin from 'dayjs/plugin/duration';
|
||||
|
||||
dayjs.extend(durationPlugin);
|
||||
|
||||
export const getMs = (value: string): string =>
|
||||
parseFloat(
|
||||
dayjs
|
||||
.duration({
|
||||
milliseconds: parseInt(value, 10) / 1000000,
|
||||
})
|
||||
.format('SSS'),
|
||||
).toFixed(2);
|
@ -73,11 +73,24 @@ function TagsKey(props: TagsKeysProps): JSX.Element {
|
||||
<AutoComplete
|
||||
dropdownClassName="certain-category-search-dropdown"
|
||||
dropdownMatchSelectWidth={500}
|
||||
style={{ width: 300 }}
|
||||
options={options}
|
||||
style={{ width: '100%' }}
|
||||
value={selectedKey}
|
||||
onChange={(value): void => {
|
||||
if (options && options.find((option) => option.value === value)) {
|
||||
allowClear
|
||||
showSearch
|
||||
options={options?.map((e) => ({
|
||||
label: e.label?.toString(),
|
||||
value: e.value,
|
||||
}))}
|
||||
filterOption={(inputValue, option): boolean =>
|
||||
option?.label?.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
|
||||
}
|
||||
onChange={(e): void => setSelectedKey(e)}
|
||||
onSelect={(value: unknown): void => {
|
||||
if (
|
||||
typeof value === 'string' &&
|
||||
options &&
|
||||
options.find((option) => option.value === value)
|
||||
) {
|
||||
setSelectedKey(value);
|
||||
|
||||
setLocalSelectedTags((tags) => [
|
||||
@ -89,8 +102,6 @@ function TagsKey(props: TagsKeysProps): JSX.Element {
|
||||
},
|
||||
...tags.slice(index + 1, tags.length),
|
||||
]);
|
||||
} else {
|
||||
setSelectedKey('');
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Select } from 'antd';
|
||||
import getTagValue from 'api/trace/getTagValue';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { TraceReducer } from 'types/reducer/trace';
|
||||
|
||||
import { SelectComponent } from './styles';
|
||||
import { AutoCompleteComponent } from './styles';
|
||||
|
||||
function TagValue(props: TagValueProps): JSX.Element {
|
||||
const { tag, setLocalSelectedTags, index, tagKey } = props;
|
||||
@ -16,6 +16,7 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
Operator: selectedOperator,
|
||||
Values: selectedValues,
|
||||
} = tag;
|
||||
const [localValue, setLocalValue] = useState<string>(selectedValues[0]);
|
||||
|
||||
const globalReducer = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
@ -34,22 +35,38 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
);
|
||||
|
||||
return (
|
||||
<SelectComponent
|
||||
value={selectedValues[0]}
|
||||
<AutoCompleteComponent
|
||||
options={data?.payload?.map((e) => ({
|
||||
label: e.tagValues,
|
||||
value: e.tagValues,
|
||||
}))}
|
||||
allowClear
|
||||
defaultOpen
|
||||
showSearch
|
||||
filterOption={(inputValue, option): boolean =>
|
||||
option?.label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
|
||||
}
|
||||
disabled={isLoading}
|
||||
value={localValue}
|
||||
onChange={(values): void => {
|
||||
if (typeof values === 'string') {
|
||||
setLocalValue(values);
|
||||
}
|
||||
}}
|
||||
onSelect={(value: unknown): void => {
|
||||
if (typeof value === 'string') {
|
||||
setLocalValue(value);
|
||||
setLocalSelectedTags((tags) => [
|
||||
...tags.slice(0, index),
|
||||
{
|
||||
Key: selectedKey,
|
||||
Operator: selectedOperator,
|
||||
Values: [...selectedValues, value],
|
||||
Values: [value],
|
||||
},
|
||||
...tags.slice(index + 1, tags.length),
|
||||
]);
|
||||
}
|
||||
}}
|
||||
loading={isLoading || false}
|
||||
>
|
||||
{data &&
|
||||
data.payload &&
|
||||
@ -58,7 +75,7 @@ function TagValue(props: TagValueProps): JSX.Element {
|
||||
{suggestion.tagValues}
|
||||
</Select.Option>
|
||||
))}
|
||||
</SelectComponent>
|
||||
</AutoCompleteComponent>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Select, Space } from 'antd';
|
||||
import { AutoComplete, Select, Space } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const SpaceComponent = styled(Space)`
|
||||
@ -9,18 +9,23 @@ export const SpaceComponent = styled(Space)`
|
||||
|
||||
export const SelectComponent = styled(Select)`
|
||||
&&& {
|
||||
min-width: 170px;
|
||||
margin-right: 21.91px;
|
||||
margin-left: 21.92px;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Container = styled.div`
|
||||
export const Container = styled(Space)`
|
||||
&&& {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ant-space-item:not(:last-child, :nth-child(2)) {
|
||||
width: 100%;
|
||||
}
|
||||
.ant-space-item:nth-child(2) {
|
||||
width: 50%;
|
||||
}
|
||||
`;
|
||||
|
||||
export const IconContainer = styled.div`
|
||||
@ -31,3 +36,9 @@ export const IconContainer = styled.div`
|
||||
|
||||
margin-left: 1.125rem;
|
||||
`;
|
||||
|
||||
export const AutoCompleteComponent = styled(AutoComplete)`
|
||||
&&& {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
Loading…
x
Reference in New Issue
Block a user