mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 00:45:57 +08:00
fix: click on field in the list item (#3120)
This commit is contained in:
parent
7818f918a8
commit
8e20ca8405
@ -2,25 +2,19 @@ import { blue, grey, orange } from '@ant-design/colors';
|
||||
import { CopyFilled, ExpandAltOutlined } from '@ant-design/icons';
|
||||
import Convert from 'ansi-to-html';
|
||||
import { Button, Divider, Row, Typography } from 'antd';
|
||||
import ROUTES from 'constants/routes';
|
||||
import dayjs from 'dayjs';
|
||||
import dompurify from 'dompurify';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
// utils
|
||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||
import { generateFilterQuery } from 'lib/logs/generateFilterQuery';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
import { AppState } from 'store/reducers';
|
||||
// interfaces
|
||||
import { IField } from 'types/api/logs/fields';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { ILogsReducer } from 'types/reducer/logs';
|
||||
|
||||
// components
|
||||
import AddToQueryHOC from '../AddToQueryHOC';
|
||||
import AddToQueryHOC, { AddToQueryHOCProps } from '../AddToQueryHOC';
|
||||
import CopyClipboardHOC from '../CopyClipboardHOC';
|
||||
// styles
|
||||
import {
|
||||
@ -39,6 +33,10 @@ interface LogFieldProps {
|
||||
fieldKey: string;
|
||||
fieldValue: string;
|
||||
}
|
||||
|
||||
type LogSelectedFieldProps = LogFieldProps &
|
||||
Pick<AddToQueryHOCProps, 'onAddToQuery'>;
|
||||
|
||||
function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element {
|
||||
const html = useMemo(
|
||||
() => ({
|
||||
@ -62,37 +60,14 @@ function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element {
|
||||
function LogSelectedField({
|
||||
fieldKey = '',
|
||||
fieldValue = '',
|
||||
}: LogFieldProps): JSX.Element {
|
||||
const history = useHistory();
|
||||
const {
|
||||
searchFilter: { queryString },
|
||||
} = useSelector<AppState, ILogsReducer>((state) => state.logs);
|
||||
|
||||
const handleQueryAdd = useCallback(
|
||||
(fieldKey: string, fieldValue: string) => {
|
||||
const generatedQuery = generateFilterQuery({
|
||||
fieldKey,
|
||||
fieldValue,
|
||||
type: 'IN',
|
||||
});
|
||||
|
||||
let updatedQueryString = queryString || '';
|
||||
if (updatedQueryString.length === 0) {
|
||||
updatedQueryString += `${generatedQuery}`;
|
||||
} else {
|
||||
updatedQueryString += ` AND ${generatedQuery}`;
|
||||
}
|
||||
history.replace(`${ROUTES.LOGS}?q=${updatedQueryString}`);
|
||||
},
|
||||
[history, queryString],
|
||||
);
|
||||
|
||||
onAddToQuery,
|
||||
}: LogSelectedFieldProps): JSX.Element {
|
||||
return (
|
||||
<SelectedLog>
|
||||
<AddToQueryHOC
|
||||
fieldKey={fieldKey}
|
||||
fieldValue={fieldValue}
|
||||
onAddToQuery={handleQueryAdd}
|
||||
onAddToQuery={onAddToQuery}
|
||||
>
|
||||
<Typography.Text>
|
||||
<span style={{ color: blue[4] }}>{fieldKey}</span>
|
||||
@ -108,15 +83,17 @@ function LogSelectedField({
|
||||
);
|
||||
}
|
||||
|
||||
interface ListLogViewProps {
|
||||
type ListLogViewProps = {
|
||||
logData: ILog;
|
||||
onOpenDetailedView: (log: ILog) => void;
|
||||
selectedFields: IField[];
|
||||
}
|
||||
} & Pick<AddToQueryHOCProps, 'onAddToQuery'>;
|
||||
|
||||
function ListLogView({
|
||||
logData,
|
||||
selectedFields,
|
||||
onOpenDetailedView,
|
||||
onAddToQuery,
|
||||
}: ListLogViewProps): JSX.Element {
|
||||
const flattenLogData = useMemo(() => FlatLogData(logData), [logData]);
|
||||
|
||||
@ -166,6 +143,7 @@ function ListLogView({
|
||||
key={field.name}
|
||||
fieldKey={field.name}
|
||||
fieldValue={flattenLogData[field.name] as never}
|
||||
onAddToQuery={onAddToQuery}
|
||||
/>
|
||||
) : null,
|
||||
)}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
|
||||
export type LogExplorerDetailedViewProps = {
|
||||
log: ILog | null;
|
||||
onClose: () => void;
|
||||
};
|
@ -1,69 +0,0 @@
|
||||
import LogDetail from 'components/LogDetail';
|
||||
import { QueryBuilderKeys } from 'constants/queryBuilder';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAutocompleteFromCustomValue';
|
||||
import { useCallback } from 'react';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
IQueryAutocompleteResponse,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { LogExplorerDetailedViewProps } from './LogExplorerDetailedView.interfaces';
|
||||
|
||||
function LogExplorerDetailedView({
|
||||
log,
|
||||
onClose,
|
||||
}: LogExplorerDetailedViewProps): JSX.Element {
|
||||
const queryClient = useQueryClient();
|
||||
const { redirectWithQueryBuilderData, currentQuery } = useQueryBuilder();
|
||||
|
||||
const handleAddQuery = useCallback(
|
||||
(fieldKey: string, fieldValue: string): void => {
|
||||
const keysAutocomplete: BaseAutocompleteData[] =
|
||||
queryClient.getQueryData<SuccessResponse<IQueryAutocompleteResponse>>(
|
||||
[QueryBuilderKeys.GET_AGGREGATE_KEYS],
|
||||
{ exact: false },
|
||||
)?.payload.attributeKeys || [];
|
||||
|
||||
const existAutocompleteKey = chooseAutocompleteFromCustomValue(
|
||||
keysAutocomplete,
|
||||
fieldKey,
|
||||
);
|
||||
|
||||
const nextQuery: Query = {
|
||||
...currentQuery,
|
||||
builder: {
|
||||
...currentQuery.builder,
|
||||
queryData: currentQuery.builder.queryData.map((item) => ({
|
||||
...item,
|
||||
filters: {
|
||||
...item.filters,
|
||||
items: [
|
||||
...item.filters.items.filter(
|
||||
(item) => item.key?.id !== existAutocompleteKey.id,
|
||||
),
|
||||
{
|
||||
id: uuid(),
|
||||
key: existAutocompleteKey,
|
||||
op: '=',
|
||||
value: fieldValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
redirectWithQueryBuilderData(nextQuery);
|
||||
},
|
||||
[currentQuery, queryClient, redirectWithQueryBuilderData],
|
||||
);
|
||||
|
||||
return <LogDetail log={log} onClose={onClose} onAddToQuery={handleAddQuery} />;
|
||||
}
|
||||
|
||||
export default LogExplorerDetailedView;
|
@ -1,3 +1,4 @@
|
||||
import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
@ -8,4 +9,4 @@ export type LogsExplorerListProps = {
|
||||
onEndReached: (index: number) => void;
|
||||
onExpand: (log: ILog) => void;
|
||||
onOpenDetailedView: (log: ILog) => void;
|
||||
};
|
||||
} & Pick<AddToQueryHOCProps, 'onAddToQuery'>;
|
||||
|
@ -32,6 +32,7 @@ function LogsExplorerList({
|
||||
onOpenDetailedView,
|
||||
onEndReached,
|
||||
onExpand,
|
||||
onAddToQuery,
|
||||
}: LogsExplorerListProps): JSX.Element {
|
||||
const { initialDataSource } = useQueryBuilder();
|
||||
|
||||
@ -79,6 +80,7 @@ function LogsExplorerList({
|
||||
logData={log}
|
||||
selectedFields={selectedFields}
|
||||
onOpenDetailedView={onOpenDetailedView}
|
||||
onAddToQuery={onAddToQuery}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@ -87,6 +89,7 @@ function LogsExplorerList({
|
||||
options.maxLines,
|
||||
selectedFields,
|
||||
onOpenDetailedView,
|
||||
onAddToQuery,
|
||||
onExpand,
|
||||
],
|
||||
);
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { TabsProps } from 'antd';
|
||||
import axios from 'axios';
|
||||
import LogDetail from 'components/LogDetail';
|
||||
import TabLabel from 'components/TabLabel';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import {
|
||||
initialQueriesMap,
|
||||
PANEL_TYPES,
|
||||
QueryBuilderKeys,
|
||||
} from 'constants/queryBuilder';
|
||||
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
|
||||
import ExportPanel from 'container/ExportPanel';
|
||||
import LogExplorerDetailedView from 'container/LogExplorerDetailedView';
|
||||
import LogsExplorerChart from 'container/LogsExplorerChart';
|
||||
import LogsExplorerList from 'container/LogsExplorerList';
|
||||
// TODO: temporary hide table view
|
||||
@ -20,13 +24,20 @@ import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQuery
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAutocompleteFromCustomValue';
|
||||
import { getPaginationQueryData } from 'lib/newQueryBuilder/getPaginationQueryData';
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { generatePath, useHistory } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
IQueryAutocompleteResponse,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
OrderByPayload,
|
||||
@ -34,6 +45,7 @@ import {
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource, StringOperators } from 'types/common/queryBuilder';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { ActionsWrapper, TabsStyled } from './LogsExplorerViews.styled';
|
||||
|
||||
@ -41,6 +53,8 @@ function LogsExplorerViews(): JSX.Element {
|
||||
const { notifications } = useNotifications();
|
||||
const history = useHistory();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { queryData: pageSize } = useUrlQueryData(
|
||||
queryParamNamesMap.pageSize,
|
||||
DEFAULT_PER_PAGE_VALUE,
|
||||
@ -212,6 +226,48 @@ function LogsExplorerViews(): JSX.Element {
|
||||
[currentStagedQueryData, orderByTimestamp],
|
||||
);
|
||||
|
||||
const handleAddQuery = useCallback(
|
||||
(fieldKey: string, fieldValue: string): void => {
|
||||
const keysAutocomplete: BaseAutocompleteData[] =
|
||||
queryClient.getQueryData<SuccessResponse<IQueryAutocompleteResponse>>(
|
||||
[QueryBuilderKeys.GET_AGGREGATE_KEYS],
|
||||
{ exact: false },
|
||||
)?.payload.attributeKeys || [];
|
||||
|
||||
const existAutocompleteKey = chooseAutocompleteFromCustomValue(
|
||||
keysAutocomplete,
|
||||
fieldKey,
|
||||
);
|
||||
|
||||
const nextQuery: Query = {
|
||||
...currentQuery,
|
||||
builder: {
|
||||
...currentQuery.builder,
|
||||
queryData: currentQuery.builder.queryData.map((item) => ({
|
||||
...item,
|
||||
filters: {
|
||||
...item.filters,
|
||||
items: [
|
||||
...item.filters.items.filter(
|
||||
(item) => item.key?.id !== existAutocompleteKey.id,
|
||||
),
|
||||
{
|
||||
id: uuid(),
|
||||
key: existAutocompleteKey,
|
||||
op: '=',
|
||||
value: fieldValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
redirectWithQueryBuilderData(nextQuery);
|
||||
},
|
||||
[currentQuery, queryClient, redirectWithQueryBuilderData],
|
||||
);
|
||||
|
||||
const handleEndReached = useCallback(
|
||||
(index: number) => {
|
||||
if (isLimit) return;
|
||||
@ -365,6 +421,7 @@ function LogsExplorerViews(): JSX.Element {
|
||||
onOpenDetailedView={handleSetActiveLog}
|
||||
onEndReached={handleEndReached}
|
||||
onExpand={handleSetActiveLog}
|
||||
onAddToQuery={handleAddQuery}
|
||||
/>
|
||||
),
|
||||
},
|
||||
@ -395,6 +452,7 @@ function LogsExplorerViews(): JSX.Element {
|
||||
logs,
|
||||
handleSetActiveLog,
|
||||
handleEndReached,
|
||||
handleAddQuery,
|
||||
data,
|
||||
isError,
|
||||
],
|
||||
@ -444,7 +502,11 @@ function LogsExplorerViews(): JSX.Element {
|
||||
onChange={handleChangeView}
|
||||
destroyInactiveTabPane
|
||||
/>
|
||||
<LogExplorerDetailedView log={activeLog} onClose={handleClearActiveLog} />
|
||||
<LogDetail
|
||||
log={activeLog}
|
||||
onClose={handleClearActiveLog}
|
||||
onAddToQuery={handleAddQuery}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -4,10 +4,13 @@ import ListLogView from 'components/Logs/ListLogView';
|
||||
import RawLogView from 'components/Logs/RawLogView';
|
||||
import LogsTableView from 'components/Logs/TableView';
|
||||
import Spinner from 'components/Spinner';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { contentStyle } from 'container/Trace/Search/config';
|
||||
import useFontFaceObserver from 'hooks/useFontObserver';
|
||||
import { generateFilterQuery } from 'lib/logs/generateFilterQuery';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { AppState } from 'store/reducers';
|
||||
// interfaces
|
||||
@ -29,6 +32,8 @@ type LogsTableProps = {
|
||||
function LogsTable(props: LogsTableProps): JSX.Element {
|
||||
const { viewMode, onClickExpand, linesPerRow } = props;
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useFontFaceObserver(
|
||||
@ -47,6 +52,7 @@ function LogsTable(props: LogsTableProps): JSX.Element {
|
||||
const {
|
||||
logs,
|
||||
fields: { selected },
|
||||
searchFilter: { queryString },
|
||||
isLoading,
|
||||
liveTail,
|
||||
} = useSelector<AppState, ILogsReducer>((state) => state.logs);
|
||||
@ -71,6 +77,25 @@ function LogsTable(props: LogsTableProps): JSX.Element {
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const handleQueryAdd = useCallback(
|
||||
(fieldKey: string, fieldValue: string) => {
|
||||
const generatedQuery = generateFilterQuery({
|
||||
fieldKey,
|
||||
fieldValue,
|
||||
type: 'IN',
|
||||
});
|
||||
|
||||
let updatedQueryString = queryString || '';
|
||||
if (updatedQueryString.length === 0) {
|
||||
updatedQueryString += `${generatedQuery}`;
|
||||
} else {
|
||||
updatedQueryString += ` AND ${generatedQuery}`;
|
||||
}
|
||||
history.replace(`${ROUTES.LOGS}?q=${updatedQueryString}`);
|
||||
},
|
||||
[history, queryString],
|
||||
);
|
||||
|
||||
const getItemContent = useCallback(
|
||||
(index: number): JSX.Element => {
|
||||
const log = logs[index];
|
||||
@ -92,6 +117,7 @@ function LogsTable(props: LogsTableProps): JSX.Element {
|
||||
logData={log}
|
||||
selectedFields={selected}
|
||||
onOpenDetailedView={handleOpenDetailedView}
|
||||
onAddToQuery={handleQueryAdd}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@ -99,9 +125,10 @@ function LogsTable(props: LogsTableProps): JSX.Element {
|
||||
logs,
|
||||
viewMode,
|
||||
selected,
|
||||
handleOpenDetailedView,
|
||||
linesPerRow,
|
||||
onClickExpand,
|
||||
handleOpenDetailedView,
|
||||
handleQueryAdd,
|
||||
],
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user