mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-01 04:32:03 +08:00
feat: search in tags is updated (#1788)
* feat: search in tags is updated * chore: placeholder is updated
This commit is contained in:
parent
18d80d47e5
commit
8aae9f53a9
3
frontend/public/locales/en-GB/traceDetails.json
Normal file
3
frontend/public/locales/en-GB/traceDetails.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"search_tags": "Search Tag Names"
|
||||
}
|
3
frontend/public/locales/en/traceDetails.json
Normal file
3
frontend/public/locales/en/traceDetails.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"search_tags": "Search Tag Names"
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import { Tooltip } from 'antd';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { ITraceTag } from 'types/api/trace/getTraceItem';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
import EllipsedButton from '../EllipsedButton';
|
||||
import { CustomSubText, CustomSubTitle, SubTextContainer } from '../styles';
|
||||
import { CommonTagsProps } from '.';
|
||||
import { Container } from './styles';
|
||||
|
||||
function Tag({ tags, onToggleHandler, setText }: TagProps): JSX.Element {
|
||||
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
|
||||
const { value, isEllipsed } = useMemo(() => {
|
||||
const value = tags.key === 'error' ? 'true' : tags.value;
|
||||
|
||||
return {
|
||||
value,
|
||||
isEllipsed: value.length > 24,
|
||||
};
|
||||
}, [tags]);
|
||||
|
||||
return (
|
||||
<React.Fragment key={JSON.stringify(tags)}>
|
||||
{tags.value && (
|
||||
<Container>
|
||||
<CustomSubTitle>{tags.key}</CustomSubTitle>
|
||||
<SubTextContainer isDarkMode={isDarkMode}>
|
||||
<Tooltip overlay={(): string => value}>
|
||||
<CustomSubText
|
||||
ellipsis={{
|
||||
rows: isEllipsed ? 1 : 0,
|
||||
}}
|
||||
isDarkMode={isDarkMode}
|
||||
>
|
||||
{value}
|
||||
</CustomSubText>
|
||||
|
||||
{isEllipsed && (
|
||||
<EllipsedButton
|
||||
{...{
|
||||
event: tags.key,
|
||||
onToggleHandler,
|
||||
setText,
|
||||
value,
|
||||
buttonText: 'View full value',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
</SubTextContainer>
|
||||
</Container>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
interface TagProps extends CommonTagsProps {
|
||||
tags: ITraceTag;
|
||||
}
|
||||
|
||||
export default Tag;
|
@ -0,0 +1,65 @@
|
||||
import { Input, Typography } from 'antd';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ITraceTag } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import { ModalText } from '..';
|
||||
import { Container } from './styles';
|
||||
import Tag from './Tag';
|
||||
|
||||
function Tags({ tags, onToggleHandler, setText }: TagsProps): JSX.Element {
|
||||
const { t } = useTranslation(['traceDetails']);
|
||||
const [allRenderedTags, setAllRenderedTags] = useState(tags);
|
||||
const isSearchVisible = useMemo(() => tags.length > 5, [tags]);
|
||||
|
||||
useEffect(() => {
|
||||
setAllRenderedTags(tags);
|
||||
}, [tags]);
|
||||
|
||||
const onChangeHandler = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const { value } = e.target;
|
||||
const filteredTags = tags.filter((tag) => tag.key.includes(value));
|
||||
setAllRenderedTags(filteredTags);
|
||||
},
|
||||
[tags],
|
||||
);
|
||||
|
||||
if (tags.length === 0) {
|
||||
return <Typography>No tags in selected span</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{isSearchVisible && (
|
||||
<Input.Search
|
||||
placeholder={t('traceDetails:search_tags')}
|
||||
allowClear
|
||||
onChange={onChangeHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{allRenderedTags.map((tag) => (
|
||||
<Tag
|
||||
key={JSON.stringify(tag)}
|
||||
{...{
|
||||
onToggleHandler,
|
||||
setText,
|
||||
tags: tag,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
interface TagsProps extends CommonTagsProps {
|
||||
tags: ITraceTag[];
|
||||
}
|
||||
|
||||
export interface CommonTagsProps {
|
||||
onToggleHandler: (state: boolean) => void;
|
||||
setText: React.Dispatch<React.SetStateAction<ModalText>>;
|
||||
}
|
||||
|
||||
export default Tags;
|
@ -0,0 +1,8 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
export const Container = styled.div`
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
`;
|
@ -5,17 +5,15 @@ import useThemeMode from 'hooks/useThemeMode';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import EllipsedButton from './EllipsedButton';
|
||||
import ErrorTag from './ErrorTag';
|
||||
import {
|
||||
CardContainer,
|
||||
CustomSubText,
|
||||
CustomSubTitle,
|
||||
CustomText,
|
||||
CustomTitle,
|
||||
styles,
|
||||
SubTextContainer,
|
||||
} from './styles';
|
||||
import Tags from './Tags';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
@ -31,7 +29,7 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const [text, setText] = useState({
|
||||
const [text, setText] = useState<ModalText>({
|
||||
text: '',
|
||||
subText: '',
|
||||
});
|
||||
@ -86,48 +84,7 @@ function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||
|
||||
<Tabs defaultActiveKey="1">
|
||||
<TabPane tab="Tags" key="1">
|
||||
{tags.length !== 0 ? (
|
||||
tags.map((tags) => {
|
||||
const value = tags.key === 'error' ? 'true' : tags.value;
|
||||
const isEllipsed = value.length > 24;
|
||||
|
||||
return (
|
||||
<React.Fragment key={JSON.stringify(tags)}>
|
||||
{tags.value && (
|
||||
<>
|
||||
<CustomSubTitle>{tags.key}</CustomSubTitle>
|
||||
<SubTextContainer isDarkMode={isDarkMode}>
|
||||
<Tooltip overlay={(): string => value}>
|
||||
<CustomSubText
|
||||
ellipsis={{
|
||||
rows: isEllipsed ? 1 : 0,
|
||||
}}
|
||||
isDarkMode={isDarkMode}
|
||||
>
|
||||
{value}
|
||||
</CustomSubText>
|
||||
|
||||
{isEllipsed && (
|
||||
<EllipsedButton
|
||||
{...{
|
||||
event: tags.key,
|
||||
onToggleHandler,
|
||||
setText,
|
||||
value,
|
||||
buttonText: 'View full value',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Tooltip>
|
||||
</SubTextContainer>
|
||||
</>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Typography>No tags in selected span</Typography>
|
||||
)}
|
||||
<Tags onToggleHandler={onToggleHandler} setText={setText} tags={tags} />
|
||||
</TabPane>
|
||||
<TabPane tab="Events" key="2">
|
||||
{tree.event && Object.keys(tree.event).length !== 0 ? (
|
||||
@ -153,4 +110,9 @@ SelectedSpanDetails.defaultProps = {
|
||||
tree: undefined,
|
||||
};
|
||||
|
||||
export interface ModalText {
|
||||
text: string;
|
||||
subText: string;
|
||||
}
|
||||
|
||||
export default SelectedSpanDetails;
|
||||
|
Loading…
x
Reference in New Issue
Block a user