mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 02:19:02 +08:00
feat: popover is added in the trace tag search (#2118)
* feat: popover is updated * chore: arrow is removed and padding is removed * chore: width is updated
This commit is contained in:
parent
d7a65ba689
commit
f766435acc
@ -16,7 +16,6 @@ import {
|
|||||||
Container,
|
Container,
|
||||||
CurrentTagsContainer,
|
CurrentTagsContainer,
|
||||||
ErrorContainer,
|
ErrorContainer,
|
||||||
Wrapper,
|
|
||||||
} from './styles';
|
} from './styles';
|
||||||
import Tags from './Tag';
|
import Tags from './Tag';
|
||||||
|
|
||||||
@ -90,33 +89,30 @@ function AllTags({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Wrapper>
|
<Typography>Tags</Typography>
|
||||||
<Typography>Tags</Typography>
|
|
||||||
|
|
||||||
<CurrentTagsContainer>
|
<CurrentTagsContainer>
|
||||||
{localSelectedTags.map((tags, index) => (
|
{localSelectedTags.map((tags, index) => (
|
||||||
<Tags
|
<Tags
|
||||||
key={tags.Key.join(',')}
|
key={tags.Key.join(',')}
|
||||||
tag={tags}
|
tag={tags}
|
||||||
index={index}
|
index={index}
|
||||||
onCloseHandler={(): void => onCloseHandler(index)}
|
onCloseHandler={(): void => onCloseHandler(index)}
|
||||||
setLocalSelectedTags={setLocalSelectedTags}
|
setLocalSelectedTags={setLocalSelectedTags}
|
||||||
localSelectedTags={localSelectedTags}
|
localSelectedTags={localSelectedTags}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</CurrentTagsContainer>
|
</CurrentTagsContainer>
|
||||||
|
|
||||||
<Space wrap direction="horizontal">
|
<Space wrap direction="horizontal">
|
||||||
<Button type="primary" onClick={onTagAddHandler} icon={<PlusOutlined />}>
|
<Button type="primary" onClick={onTagAddHandler} icon={<PlusOutlined />}>
|
||||||
Add Tags Filter
|
Add Tags Filter
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Text ellipsis>
|
<Text ellipsis>
|
||||||
Results will include spans with ALL the specified tags ( Rows are `ANDed`
|
Results will include spans with ALL the specified tags ( Rows are `ANDed` )
|
||||||
)
|
</Text>
|
||||||
</Text>
|
</Space>
|
||||||
</Space>
|
|
||||||
</Wrapper>
|
|
||||||
|
|
||||||
<ButtonContainer>
|
<ButtonContainer>
|
||||||
<Space align="start">
|
<Space align="start">
|
||||||
|
@ -2,25 +2,15 @@ import { Card } from 'antd';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const Container = styled(Card)`
|
export const Container = styled(Card)`
|
||||||
top: 120%;
|
|
||||||
min-height: 20vh;
|
min-height: 20vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 2;
|
min-width: 81.5vw;
|
||||||
position: absolute !important;
|
|
||||||
|
|
||||||
.ant-card-body {
|
|
||||||
padding-bottom: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ErrorContainer = styled(Card)`
|
export const ErrorContainer = styled(Card)`
|
||||||
top: 120%;
|
|
||||||
min-height: 20vh;
|
min-height: 20vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -28,13 +18,6 @@ export const ErrorContainer = styled(Card)`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Wrapper = styled.div`
|
|
||||||
&&& {
|
|
||||||
padding-right: 2rem;
|
|
||||||
padding-left: 2rem;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const ButtonContainer = styled(Card)`
|
export const ButtonContainer = styled(Card)`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -45,6 +28,10 @@ export const ButtonContainer = styled(Card)`
|
|||||||
padding-right: 38.01px !important;
|
padding-right: 38.01px !important;
|
||||||
|
|
||||||
margin-top: 1rem !important;
|
margin-top: 1rem !important;
|
||||||
|
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CurrentTagsContainer = styled.div`
|
export const CurrentTagsContainer = styled.div`
|
||||||
|
1
frontend/src/container/Trace/Search/config.ts
Normal file
1
frontend/src/container/Trace/Search/config.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const contentStyle = { padding: 0 };
|
@ -1,5 +1,5 @@
|
|||||||
import { CaretRightFilled } from '@ant-design/icons';
|
import { CaretRightFilled } from '@ant-design/icons';
|
||||||
import useClickOutside from 'hooks/useClickOutside';
|
import { Popover } from 'antd';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { connect, useDispatch, useSelector } from 'react-redux';
|
import { connect, useDispatch, useSelector } from 'react-redux';
|
||||||
import { bindActionCreators, Dispatch } from 'redux';
|
import { bindActionCreators, Dispatch } from 'redux';
|
||||||
@ -13,6 +13,7 @@ import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
|||||||
import { TraceReducer } from 'types/reducer/trace';
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
import Tags from './AllTags';
|
import Tags from './AllTags';
|
||||||
|
import { contentStyle } from './config';
|
||||||
import { Container, SearchComponent } from './styles';
|
import { Container, SearchComponent } from './styles';
|
||||||
import { parseQueryToTags, parseTagsToQuery } from './util';
|
import { parseQueryToTags, parseTagsToQuery } from './util';
|
||||||
|
|
||||||
@ -42,33 +43,6 @@ function Search({
|
|||||||
|
|
||||||
const tagRef = useRef<HTMLDivElement>(null);
|
const tagRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useClickOutside(tagRef, (e: HTMLElement) => {
|
|
||||||
// using this hack as overlay span is voilating this condition
|
|
||||||
if (
|
|
||||||
e.nodeName === 'svg' ||
|
|
||||||
e.nodeName === 'path' ||
|
|
||||||
e.nodeName === 'span' ||
|
|
||||||
e.nodeName === 'button'
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
e.nodeName === 'DIV' &&
|
|
||||||
![
|
|
||||||
'ant-select-item-option-content',
|
|
||||||
'ant-empty-image',
|
|
||||||
'ant-select-item',
|
|
||||||
'ant-col',
|
|
||||||
'ant-select-item-option-active',
|
|
||||||
].find((p) => p.indexOf(e.className) !== -1) &&
|
|
||||||
!(e.ariaSelected === 'true') &&
|
|
||||||
traces.isTagModalOpen
|
|
||||||
) {
|
|
||||||
updateTagVisibility(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const onChangeHandler = (search: string): void => {
|
const onChangeHandler = (search: string): void => {
|
||||||
setValue(search);
|
setValue(search);
|
||||||
};
|
};
|
||||||
@ -77,11 +51,6 @@ function Search({
|
|||||||
updateTagVisibility(value);
|
updateTagVisibility(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFocusHandler: React.FocusEventHandler<HTMLInputElement> = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setIsTagsModalHandler(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateFilters = async (
|
const updateFilters = async (
|
||||||
selectedTags: TraceReducer['selectedTags'],
|
selectedTags: TraceReducer['selectedTags'],
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
@ -116,37 +85,45 @@ function Search({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container ref={tagRef}>
|
<Container ref={tagRef}>
|
||||||
<SearchComponent
|
<Popover
|
||||||
onChange={(event): void => onChangeHandler(event.target.value)}
|
placement="bottomLeft"
|
||||||
value={value}
|
destroyTooltipOnHide
|
||||||
allowClear
|
open={traces.isTagModalOpen}
|
||||||
disabled={traces.filterLoading}
|
trigger="click"
|
||||||
onFocus={onFocusHandler}
|
onOpenChange={setIsTagsModalHandler}
|
||||||
placeholder="Click to filter by tags"
|
showArrow={false}
|
||||||
type="search"
|
overlayInnerStyle={contentStyle}
|
||||||
enterButton={<CaretRightFilled />}
|
content={
|
||||||
onSearch={(string): void => {
|
<Tags updateFilters={updateFilters} onChangeHandler={onChangeHandler} />
|
||||||
if (string.length === 0) {
|
}
|
||||||
updateTagVisibility(false);
|
>
|
||||||
updateFilters([]);
|
<SearchComponent
|
||||||
return;
|
onChange={(event): void => onChangeHandler(event.target.value)}
|
||||||
}
|
value={value}
|
||||||
|
allowClear
|
||||||
|
disabled={traces.filterLoading}
|
||||||
|
placeholder="Click to filter by tags"
|
||||||
|
type="search"
|
||||||
|
enterButton={<CaretRightFilled />}
|
||||||
|
onSearch={(string): void => {
|
||||||
|
if (string.length === 0) {
|
||||||
|
updateTagVisibility(false);
|
||||||
|
updateFilters([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { isError, payload } = parseQueryToTags(string);
|
const { isError, payload } = parseQueryToTags(string);
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
updateTagIsError(true);
|
updateTagIsError(true);
|
||||||
} else {
|
} else {
|
||||||
updateTagIsError(false);
|
updateTagIsError(false);
|
||||||
updateTagVisibility(false);
|
updateTagVisibility(false);
|
||||||
updateFilters(payload);
|
updateFilters(payload);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Popover>
|
||||||
{traces.isTagModalOpen && (
|
|
||||||
<Tags updateFilters={updateFilters} onChangeHandler={onChangeHandler} />
|
|
||||||
)}
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import React, { useCallback, useEffect } from 'react';
|
|
||||||
|
|
||||||
const useClickOutside = (
|
|
||||||
ref: React.RefObject<HTMLElement>,
|
|
||||||
callback: (e: HTMLElement) => void | null,
|
|
||||||
): void => {
|
|
||||||
const listener = useCallback(
|
|
||||||
(e: Event) => {
|
|
||||||
const node = e?.target as HTMLElement;
|
|
||||||
|
|
||||||
if (ref.current && !ref.current.contains(node) && callback) {
|
|
||||||
callback(node);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[callback, ref],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.addEventListener('click', listener);
|
|
||||||
|
|
||||||
return (): void => {
|
|
||||||
document.removeEventListener('click', listener);
|
|
||||||
};
|
|
||||||
}, [ref, callback, listener]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useClickOutside;
|
|
Loading…
x
Reference in New Issue
Block a user