From 8e20ca840578c1622e83ce24831b5b6ffb20a70a Mon Sep 17 00:00:00 2001 From: Yevhen Shevchenko <90138953+yeshev@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:59:33 +0300 Subject: [PATCH] fix: click on field in the list item (#3120) --- .../src/components/Logs/ListLogView/index.tsx | 48 ++++--------- .../LogExplorerDetailedView.interfaces.ts | 6 -- .../LogExplorerDetailedView/index.tsx | 69 ------------------- .../LogsExplorerList.interfaces.ts | 3 +- .../src/container/LogsExplorerList/index.tsx | 3 + .../src/container/LogsExplorerViews/index.tsx | 68 +++++++++++++++++- frontend/src/container/LogsTable/index.tsx | 29 +++++++- 7 files changed, 111 insertions(+), 115 deletions(-) delete mode 100644 frontend/src/container/LogExplorerDetailedView/LogExplorerDetailedView.interfaces.ts delete mode 100644 frontend/src/container/LogExplorerDetailedView/index.tsx diff --git a/frontend/src/components/Logs/ListLogView/index.tsx b/frontend/src/components/Logs/ListLogView/index.tsx index ea4bada737..91d0787a95 100644 --- a/frontend/src/components/Logs/ListLogView/index.tsx +++ b/frontend/src/components/Logs/ListLogView/index.tsx @@ -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; + 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((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 ( {fieldKey} @@ -108,15 +83,17 @@ function LogSelectedField({ ); } -interface ListLogViewProps { +type ListLogViewProps = { logData: ILog; onOpenDetailedView: (log: ILog) => void; selectedFields: IField[]; -} +} & Pick; + 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, )} diff --git a/frontend/src/container/LogExplorerDetailedView/LogExplorerDetailedView.interfaces.ts b/frontend/src/container/LogExplorerDetailedView/LogExplorerDetailedView.interfaces.ts deleted file mode 100644 index ca9620657f..0000000000 --- a/frontend/src/container/LogExplorerDetailedView/LogExplorerDetailedView.interfaces.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ILog } from 'types/api/logs/log'; - -export type LogExplorerDetailedViewProps = { - log: ILog | null; - onClose: () => void; -}; diff --git a/frontend/src/container/LogExplorerDetailedView/index.tsx b/frontend/src/container/LogExplorerDetailedView/index.tsx deleted file mode 100644 index 3bbd7481f8..0000000000 --- a/frontend/src/container/LogExplorerDetailedView/index.tsx +++ /dev/null @@ -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>( - [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 ; -} - -export default LogExplorerDetailedView; diff --git a/frontend/src/container/LogsExplorerList/LogsExplorerList.interfaces.ts b/frontend/src/container/LogsExplorerList/LogsExplorerList.interfaces.ts index b238031ac0..6862fe5ee9 100644 --- a/frontend/src/container/LogsExplorerList/LogsExplorerList.interfaces.ts +++ b/frontend/src/container/LogsExplorerList/LogsExplorerList.interfaces.ts @@ -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; diff --git a/frontend/src/container/LogsExplorerList/index.tsx b/frontend/src/container/LogsExplorerList/index.tsx index 7cfaaf4bc2..54ee339527 100644 --- a/frontend/src/container/LogsExplorerList/index.tsx +++ b/frontend/src/container/LogsExplorerList/index.tsx @@ -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, ], ); diff --git a/frontend/src/container/LogsExplorerViews/index.tsx b/frontend/src/container/LogsExplorerViews/index.tsx index afbca2b470..0a7d643c03 100644 --- a/frontend/src/container/LogsExplorerViews/index.tsx +++ b/frontend/src/container/LogsExplorerViews/index.tsx @@ -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>( + [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 /> - + ); } diff --git a/frontend/src/container/LogsTable/index.tsx b/frontend/src/container/LogsTable/index.tsx index b514aa3ee8..94a4ee9d6c 100644 --- a/frontend/src/container/LogsTable/index.tsx +++ b/frontend/src/container/LogsTable/index.tsx @@ -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((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, ], );