fix: click on field in the list item (#3120)

This commit is contained in:
Yevhen Shevchenko 2023-07-12 16:59:33 +03:00 committed by GitHub
parent 7818f918a8
commit 8e20ca8405
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 111 additions and 115 deletions

View File

@ -2,25 +2,19 @@ import { blue, grey, orange } from '@ant-design/colors';
import { CopyFilled, ExpandAltOutlined } from '@ant-design/icons'; import { CopyFilled, ExpandAltOutlined } from '@ant-design/icons';
import Convert from 'ansi-to-html'; import Convert from 'ansi-to-html';
import { Button, Divider, Row, Typography } from 'antd'; import { Button, Divider, Row, Typography } from 'antd';
import ROUTES from 'constants/routes';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import dompurify from 'dompurify'; import dompurify from 'dompurify';
import { useNotifications } from 'hooks/useNotifications'; import { useNotifications } from 'hooks/useNotifications';
// utils // utils
import { FlatLogData } from 'lib/logs/flatLogData'; import { FlatLogData } from 'lib/logs/flatLogData';
import { generateFilterQuery } from 'lib/logs/generateFilterQuery';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use'; import { useCopyToClipboard } from 'react-use';
import { AppState } from 'store/reducers';
// interfaces // interfaces
import { IField } from 'types/api/logs/fields'; import { IField } from 'types/api/logs/fields';
import { ILog } from 'types/api/logs/log'; import { ILog } from 'types/api/logs/log';
import { ILogsReducer } from 'types/reducer/logs';
// components // components
import AddToQueryHOC from '../AddToQueryHOC'; import AddToQueryHOC, { AddToQueryHOCProps } from '../AddToQueryHOC';
import CopyClipboardHOC from '../CopyClipboardHOC'; import CopyClipboardHOC from '../CopyClipboardHOC';
// styles // styles
import { import {
@ -39,6 +33,10 @@ interface LogFieldProps {
fieldKey: string; fieldKey: string;
fieldValue: string; fieldValue: string;
} }
type LogSelectedFieldProps = LogFieldProps &
Pick<AddToQueryHOCProps, 'onAddToQuery'>;
function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element { function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element {
const html = useMemo( const html = useMemo(
() => ({ () => ({
@ -62,37 +60,14 @@ function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element {
function LogSelectedField({ function LogSelectedField({
fieldKey = '', fieldKey = '',
fieldValue = '', fieldValue = '',
}: LogFieldProps): JSX.Element { onAddToQuery,
const history = useHistory(); }: LogSelectedFieldProps): JSX.Element {
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],
);
return ( return (
<SelectedLog> <SelectedLog>
<AddToQueryHOC <AddToQueryHOC
fieldKey={fieldKey} fieldKey={fieldKey}
fieldValue={fieldValue} fieldValue={fieldValue}
onAddToQuery={handleQueryAdd} onAddToQuery={onAddToQuery}
> >
<Typography.Text> <Typography.Text>
<span style={{ color: blue[4] }}>{fieldKey}</span> <span style={{ color: blue[4] }}>{fieldKey}</span>
@ -108,15 +83,17 @@ function LogSelectedField({
); );
} }
interface ListLogViewProps { type ListLogViewProps = {
logData: ILog; logData: ILog;
onOpenDetailedView: (log: ILog) => void; onOpenDetailedView: (log: ILog) => void;
selectedFields: IField[]; selectedFields: IField[];
} } & Pick<AddToQueryHOCProps, 'onAddToQuery'>;
function ListLogView({ function ListLogView({
logData, logData,
selectedFields, selectedFields,
onOpenDetailedView, onOpenDetailedView,
onAddToQuery,
}: ListLogViewProps): JSX.Element { }: ListLogViewProps): JSX.Element {
const flattenLogData = useMemo(() => FlatLogData(logData), [logData]); const flattenLogData = useMemo(() => FlatLogData(logData), [logData]);
@ -166,6 +143,7 @@ function ListLogView({
key={field.name} key={field.name}
fieldKey={field.name} fieldKey={field.name}
fieldValue={flattenLogData[field.name] as never} fieldValue={flattenLogData[field.name] as never}
onAddToQuery={onAddToQuery}
/> />
) : null, ) : null,
)} )}

View File

@ -1,6 +0,0 @@
import { ILog } from 'types/api/logs/log';
export type LogExplorerDetailedViewProps = {
log: ILog | null;
onClose: () => void;
};

View File

@ -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;

View File

@ -1,3 +1,4 @@
import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
import { ILog } from 'types/api/logs/log'; import { ILog } from 'types/api/logs/log';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
@ -8,4 +9,4 @@ export type LogsExplorerListProps = {
onEndReached: (index: number) => void; onEndReached: (index: number) => void;
onExpand: (log: ILog) => void; onExpand: (log: ILog) => void;
onOpenDetailedView: (log: ILog) => void; onOpenDetailedView: (log: ILog) => void;
}; } & Pick<AddToQueryHOCProps, 'onAddToQuery'>;

View File

@ -32,6 +32,7 @@ function LogsExplorerList({
onOpenDetailedView, onOpenDetailedView,
onEndReached, onEndReached,
onExpand, onExpand,
onAddToQuery,
}: LogsExplorerListProps): JSX.Element { }: LogsExplorerListProps): JSX.Element {
const { initialDataSource } = useQueryBuilder(); const { initialDataSource } = useQueryBuilder();
@ -79,6 +80,7 @@ function LogsExplorerList({
logData={log} logData={log}
selectedFields={selectedFields} selectedFields={selectedFields}
onOpenDetailedView={onOpenDetailedView} onOpenDetailedView={onOpenDetailedView}
onAddToQuery={onAddToQuery}
/> />
); );
}, },
@ -87,6 +89,7 @@ function LogsExplorerList({
options.maxLines, options.maxLines,
selectedFields, selectedFields,
onOpenDetailedView, onOpenDetailedView,
onAddToQuery,
onExpand, onExpand,
], ],
); );

View File

@ -1,13 +1,17 @@
import { TabsProps } from 'antd'; import { TabsProps } from 'antd';
import axios from 'axios'; import axios from 'axios';
import LogDetail from 'components/LogDetail';
import TabLabel from 'components/TabLabel'; import TabLabel from 'components/TabLabel';
import { QueryParams } from 'constants/query'; 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 { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config'; import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
import ExportPanel from 'container/ExportPanel'; import ExportPanel from 'container/ExportPanel';
import LogExplorerDetailedView from 'container/LogExplorerDetailedView';
import LogsExplorerChart from 'container/LogsExplorerChart'; import LogsExplorerChart from 'container/LogsExplorerChart';
import LogsExplorerList from 'container/LogsExplorerList'; import LogsExplorerList from 'container/LogsExplorerList';
// TODO: temporary hide table view // TODO: temporary hide table view
@ -20,13 +24,20 @@ import { useGetExplorerQueryRange } from 'hooks/queryBuilder/useGetExplorerQuery
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useNotifications } from 'hooks/useNotifications'; import { useNotifications } from 'hooks/useNotifications';
import useUrlQueryData from 'hooks/useUrlQueryData'; import useUrlQueryData from 'hooks/useUrlQueryData';
import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAutocompleteFromCustomValue';
import { getPaginationQueryData } from 'lib/newQueryBuilder/getPaginationQueryData'; import { getPaginationQueryData } from 'lib/newQueryBuilder/getPaginationQueryData';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useQueryClient } from 'react-query';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { generatePath, useHistory } from 'react-router-dom'; import { generatePath, useHistory } from 'react-router-dom';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { SuccessResponse } from 'types/api';
import { Dashboard } from 'types/api/dashboard/getAll'; import { Dashboard } from 'types/api/dashboard/getAll';
import { ILog } from 'types/api/logs/log'; import { ILog } from 'types/api/logs/log';
import {
BaseAutocompleteData,
IQueryAutocompleteResponse,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { import {
IBuilderQuery, IBuilderQuery,
OrderByPayload, OrderByPayload,
@ -34,6 +45,7 @@ import {
} from 'types/api/queryBuilder/queryBuilderData'; } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource, StringOperators } from 'types/common/queryBuilder'; import { DataSource, StringOperators } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { v4 as uuid } from 'uuid';
import { ActionsWrapper, TabsStyled } from './LogsExplorerViews.styled'; import { ActionsWrapper, TabsStyled } from './LogsExplorerViews.styled';
@ -41,6 +53,8 @@ function LogsExplorerViews(): JSX.Element {
const { notifications } = useNotifications(); const { notifications } = useNotifications();
const history = useHistory(); const history = useHistory();
const queryClient = useQueryClient();
const { queryData: pageSize } = useUrlQueryData( const { queryData: pageSize } = useUrlQueryData(
queryParamNamesMap.pageSize, queryParamNamesMap.pageSize,
DEFAULT_PER_PAGE_VALUE, DEFAULT_PER_PAGE_VALUE,
@ -212,6 +226,48 @@ function LogsExplorerViews(): JSX.Element {
[currentStagedQueryData, orderByTimestamp], [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( const handleEndReached = useCallback(
(index: number) => { (index: number) => {
if (isLimit) return; if (isLimit) return;
@ -365,6 +421,7 @@ function LogsExplorerViews(): JSX.Element {
onOpenDetailedView={handleSetActiveLog} onOpenDetailedView={handleSetActiveLog}
onEndReached={handleEndReached} onEndReached={handleEndReached}
onExpand={handleSetActiveLog} onExpand={handleSetActiveLog}
onAddToQuery={handleAddQuery}
/> />
), ),
}, },
@ -395,6 +452,7 @@ function LogsExplorerViews(): JSX.Element {
logs, logs,
handleSetActiveLog, handleSetActiveLog,
handleEndReached, handleEndReached,
handleAddQuery,
data, data,
isError, isError,
], ],
@ -444,7 +502,11 @@ function LogsExplorerViews(): JSX.Element {
onChange={handleChangeView} onChange={handleChangeView}
destroyInactiveTabPane destroyInactiveTabPane
/> />
<LogExplorerDetailedView log={activeLog} onClose={handleClearActiveLog} /> <LogDetail
log={activeLog}
onClose={handleClearActiveLog}
onAddToQuery={handleAddQuery}
/>
</> </>
); );
} }

View File

@ -4,10 +4,13 @@ import ListLogView from 'components/Logs/ListLogView';
import RawLogView from 'components/Logs/RawLogView'; import RawLogView from 'components/Logs/RawLogView';
import LogsTableView from 'components/Logs/TableView'; import LogsTableView from 'components/Logs/TableView';
import Spinner from 'components/Spinner'; import Spinner from 'components/Spinner';
import ROUTES from 'constants/routes';
import { contentStyle } from 'container/Trace/Search/config'; import { contentStyle } from 'container/Trace/Search/config';
import useFontFaceObserver from 'hooks/useFontObserver'; import useFontFaceObserver from 'hooks/useFontObserver';
import { generateFilterQuery } from 'lib/logs/generateFilterQuery';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { Virtuoso } from 'react-virtuoso'; import { Virtuoso } from 'react-virtuoso';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
// interfaces // interfaces
@ -29,6 +32,8 @@ type LogsTableProps = {
function LogsTable(props: LogsTableProps): JSX.Element { function LogsTable(props: LogsTableProps): JSX.Element {
const { viewMode, onClickExpand, linesPerRow } = props; const { viewMode, onClickExpand, linesPerRow } = props;
const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
useFontFaceObserver( useFontFaceObserver(
@ -47,6 +52,7 @@ function LogsTable(props: LogsTableProps): JSX.Element {
const { const {
logs, logs,
fields: { selected }, fields: { selected },
searchFilter: { queryString },
isLoading, isLoading,
liveTail, liveTail,
} = useSelector<AppState, ILogsReducer>((state) => state.logs); } = useSelector<AppState, ILogsReducer>((state) => state.logs);
@ -71,6 +77,25 @@ function LogsTable(props: LogsTableProps): JSX.Element {
[dispatch], [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( const getItemContent = useCallback(
(index: number): JSX.Element => { (index: number): JSX.Element => {
const log = logs[index]; const log = logs[index];
@ -92,6 +117,7 @@ function LogsTable(props: LogsTableProps): JSX.Element {
logData={log} logData={log}
selectedFields={selected} selectedFields={selected}
onOpenDetailedView={handleOpenDetailedView} onOpenDetailedView={handleOpenDetailedView}
onAddToQuery={handleQueryAdd}
/> />
); );
}, },
@ -99,9 +125,10 @@ function LogsTable(props: LogsTableProps): JSX.Element {
logs, logs,
viewMode, viewMode,
selected, selected,
handleOpenDetailedView,
linesPerRow, linesPerRow,
onClickExpand, onClickExpand,
handleOpenDetailedView,
handleQueryAdd,
], ],
); );