mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-11 17:09:01 +08:00
chore: behaviour for dropdown is updated
This commit is contained in:
parent
5556d1d6fc
commit
32e8e48928
@ -1,63 +0,0 @@
|
|||||||
import { Select, Spin } from 'antd';
|
|
||||||
import { SelectProps } from 'antd/es/select';
|
|
||||||
import debounce from 'lodash-es/debounce';
|
|
||||||
import React, { useRef, useState } from 'react';
|
|
||||||
|
|
||||||
export interface DebounceSelectProps<ValueType = any>
|
|
||||||
extends Omit<SelectProps<ValueType>, 'options' | 'children'> {
|
|
||||||
fetchOptions: (search: string) => Promise<ValueType[]>;
|
|
||||||
debounceTimeout: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function DebounceSelect<
|
|
||||||
ValueType extends {
|
|
||||||
key?: string;
|
|
||||||
label: React.ReactNode;
|
|
||||||
value: string | number;
|
|
||||||
} = never
|
|
||||||
>({
|
|
||||||
fetchOptions,
|
|
||||||
debounceTimeout = 800,
|
|
||||||
...props
|
|
||||||
}: DebounceSelectProps): JSX.Element {
|
|
||||||
const [fetching, setFetching] = useState(false);
|
|
||||||
const [options, setOptions] = useState<ValueType[]>([]);
|
|
||||||
const fetchRef = useRef(0);
|
|
||||||
|
|
||||||
const debounceFetcher = React.useMemo(() => {
|
|
||||||
const loadOptions = (value: string): void => {
|
|
||||||
fetchRef.current += 1;
|
|
||||||
const fetchId = fetchRef.current;
|
|
||||||
setOptions([]);
|
|
||||||
setFetching(true);
|
|
||||||
|
|
||||||
fetchOptions(value).then((newOptions) => {
|
|
||||||
if (fetchId !== fetchRef.current) {
|
|
||||||
// for fetch callback order
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptions(newOptions);
|
|
||||||
setFetching(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return debounce(loadOptions, debounceTimeout);
|
|
||||||
}, [fetchOptions, debounceTimeout]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Select<ValueType>
|
|
||||||
labelInValue
|
|
||||||
filterOption={false}
|
|
||||||
onSearch={debounceFetcher}
|
|
||||||
notFoundContent={fetching ? <Spin size="small" /> : null}
|
|
||||||
style={{ width: '170px' }}
|
|
||||||
// as all other props are from SelectProps only
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
||||||
{...props}
|
|
||||||
options={options}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DebounceSelect;
|
|
69
frontend/src/container/Trace/Search/AllTags/Tag/TagValue.tsx
Normal file
69
frontend/src/container/Trace/Search/AllTags/Tag/TagValue.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Select } from 'antd';
|
||||||
|
import { DefaultOptionType } from 'antd/lib/select';
|
||||||
|
import getTagValue from 'api/trace/getTagValue';
|
||||||
|
import useFetch from 'hooks/useFetch';
|
||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { PayloadProps, Props } from 'types/api/trace/getTagValue';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
|
import { Value } from '.';
|
||||||
|
import { SelectComponent } from './styles';
|
||||||
|
|
||||||
|
function TagValue(props: TagValueProps): JSX.Element {
|
||||||
|
const { tag, setLocalSelectedTags, index, tagKey } = props;
|
||||||
|
const {
|
||||||
|
Key: selectedKey,
|
||||||
|
Operator: selectedOperator,
|
||||||
|
Values: selectedValues,
|
||||||
|
} = tag;
|
||||||
|
|
||||||
|
const globalReducer = useSelector<AppState, GlobalReducer>(
|
||||||
|
(state) => state.globalTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
const valueSuggestion = useFetch<PayloadProps, Props>(getTagValue, {
|
||||||
|
end: globalReducer.maxTime,
|
||||||
|
start: globalReducer.minTime,
|
||||||
|
tagKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SelectComponent
|
||||||
|
onSelect={(value: unknown): void => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
setLocalSelectedTags((tags) => [
|
||||||
|
...tags.slice(0, index),
|
||||||
|
{
|
||||||
|
Key: selectedKey,
|
||||||
|
Operator: selectedOperator,
|
||||||
|
Values: [...selectedValues, value],
|
||||||
|
},
|
||||||
|
...tags.slice(index + 1, tags.length),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
loading={valueSuggestion.loading || false}
|
||||||
|
>
|
||||||
|
{valueSuggestion.payload &&
|
||||||
|
valueSuggestion.payload.map((suggestion) => (
|
||||||
|
<Select.Option key={suggestion.tagValues} value={suggestion.tagValues}>
|
||||||
|
{suggestion.tagValues}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</SelectComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TagValueProps {
|
||||||
|
index: number;
|
||||||
|
tag: FlatArray<TraceReducer['selectedTags'], 1>;
|
||||||
|
setLocalSelectedTags: React.Dispatch<
|
||||||
|
React.SetStateAction<TraceReducer['selectedTags']>
|
||||||
|
>;
|
||||||
|
tagKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TagValue;
|
@ -1,28 +0,0 @@
|
|||||||
import getTagValue from 'api/trace/getTagValue';
|
|
||||||
|
|
||||||
// Usage of DebounceSelect
|
|
||||||
export interface TagValue {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchTag(
|
|
||||||
globalStart: number,
|
|
||||||
globalEnd: number,
|
|
||||||
tagKey: string,
|
|
||||||
): Promise<TagValue[]> {
|
|
||||||
const response = await getTagValue({
|
|
||||||
end: globalEnd,
|
|
||||||
start: globalStart,
|
|
||||||
tagKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.statusCode !== 200 || !response.payload) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.payload.map((e) => ({
|
|
||||||
label: e.tagValues,
|
|
||||||
value: e.tagValues,
|
|
||||||
}));
|
|
||||||
}
|
|
@ -3,13 +3,11 @@ import { Select } from 'antd';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
import { TraceReducer } from 'types/reducer/trace';
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
import { fetchTag, TagValue } from './config';
|
|
||||||
import DebounceSelect from './DebounceSelect';
|
|
||||||
import { Container, IconContainer, SelectComponent } from './styles';
|
import { Container, IconContainer, SelectComponent } from './styles';
|
||||||
import TagsKey from './TagKey';
|
import TagsKey from './TagKey';
|
||||||
|
import TagValue from './TagValue';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@ -33,9 +31,6 @@ const AllMenu: AllMenuProps[] = [
|
|||||||
|
|
||||||
function SingleTags(props: AllTagsProps): JSX.Element {
|
function SingleTags(props: AllTagsProps): JSX.Element {
|
||||||
const traces = useSelector<AppState, TraceReducer>((state) => state.traces);
|
const traces = useSelector<AppState, TraceReducer>((state) => state.traces);
|
||||||
const globalReducer = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { tag, onCloseHandler, setLocalSelectedTags, index } = props;
|
const { tag, onCloseHandler, setLocalSelectedTags, index } = props;
|
||||||
const {
|
const {
|
||||||
@ -69,7 +64,6 @@ function SingleTags(props: AllTagsProps): JSX.Element {
|
|||||||
tag={tag}
|
tag={tag}
|
||||||
setLocalSelectedTags={setLocalSelectedTags}
|
setLocalSelectedTags={setLocalSelectedTags}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SelectComponent
|
<SelectComponent
|
||||||
onChange={onChangeOperatorHandler}
|
onChange={onChangeOperatorHandler}
|
||||||
value={AllMenu.find((e) => e.key === selectedOperator)?.value || ''}
|
value={AllMenu.find((e) => e.key === selectedOperator)?.value || ''}
|
||||||
@ -81,24 +75,16 @@ function SingleTags(props: AllTagsProps): JSX.Element {
|
|||||||
))}
|
))}
|
||||||
</SelectComponent>
|
</SelectComponent>
|
||||||
|
|
||||||
<DebounceSelect
|
{selectedKey[0] ? (
|
||||||
fetchOptions={(): Promise<TagValue[]> =>
|
<TagValue
|
||||||
fetchTag(globalReducer.minTime, globalReducer.maxTime, selectedKey[index])
|
index={index}
|
||||||
}
|
tag={tag}
|
||||||
debounceTimeout={300}
|
setLocalSelectedTags={setLocalSelectedTags}
|
||||||
onSelect={(value: Value): void => {
|
tagKey={selectedKey[0]}
|
||||||
setLocalSelectedTags((tags) => [
|
/>
|
||||||
...tags.slice(0, index),
|
) : (
|
||||||
{
|
<SelectComponent />
|
||||||
Key: selectedKey,
|
)}
|
||||||
Operator: selectedOperator,
|
|
||||||
Values: [...selectedValues, value.value],
|
|
||||||
},
|
|
||||||
...tags.slice(index + 1, tags.length),
|
|
||||||
]);
|
|
||||||
}}
|
|
||||||
mode="multiple"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IconContainer role="button" onClick={(): void => onDeleteTagHandler(index)}>
|
<IconContainer role="button" onClick={(): void => onDeleteTagHandler(index)}>
|
||||||
<CloseOutlined />
|
<CloseOutlined />
|
||||||
@ -116,7 +102,7 @@ interface AllTagsProps {
|
|||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Value {
|
export interface Value {
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user