From b465f74e4acad45e0b01ae68d4a2e33feb2b3067 Mon Sep 17 00:00:00 2001 From: Shaheer Kochai Date: Mon, 20 Jan 2025 10:13:48 +0430 Subject: [PATCH] feat: show/hide timestamp and body fields in logs explorer (raw, default, column views) (#6831) * feat: show/hide timestamp and body fields in logs explorer (raw, default, column views) * fix: add width to log indicator column to ensure that a single column doesn't take half the space --------- Co-authored-by: Nityananda Gohain --- .../src/components/Logs/ListLogView/index.tsx | 50 ++++---- .../src/components/Logs/RawLogView/index.tsx | 40 +++++-- .../Logs/TableView/useTableView.tsx | 108 ++++++++++-------- .../InfinityTableView/index.tsx | 34 +++--- .../InfinityTableView/styles.ts | 2 +- .../src/container/OptionsMenu/constants.ts | 21 +++- .../container/OptionsMenu/useOptionsMenu.ts | 22 +++- 7 files changed, 176 insertions(+), 101 deletions(-) diff --git a/frontend/src/components/Logs/ListLogView/index.tsx b/frontend/src/components/Logs/ListLogView/index.tsx index 1fdd7414dd..4141148165 100644 --- a/frontend/src/components/Logs/ListLogView/index.tsx +++ b/frontend/src/components/Logs/ListLogView/index.tsx @@ -219,12 +219,14 @@ function ListLogView({
- + {updatedSelecedFields.some((field) => field.name === 'body') && ( + + )} {flattenLogData.stream && ( )} - - - {updatedSelecedFields.map((field) => - isValidLogField(flattenLogData[field.name] as never) ? ( - - ) : null, + {updatedSelecedFields.some((field) => field.name === 'timestamp') && ( + )} + + {updatedSelecedFields + .filter((field) => !['timestamp', 'body'].includes(field.name)) + .map((field) => + isValidLogField(flattenLogData[field.name] as never) ? ( + + ) : null, + )}
diff --git a/frontend/src/components/Logs/RawLogView/index.tsx b/frontend/src/components/Logs/RawLogView/index.tsx index 222931ee6d..d738a61a43 100644 --- a/frontend/src/components/Logs/RawLogView/index.tsx +++ b/frontend/src/components/Logs/RawLogView/index.tsx @@ -73,6 +73,7 @@ function RawLogView({ ); const attributesValues = updatedSelecedFields + .filter((field) => !['timestamp', 'body'].includes(field.name)) .map((field) => flattenLogData[field.name]) .filter((attribute) => { // loadash isEmpty doesnot work with numbers @@ -92,19 +93,40 @@ function RawLogView({ const { formatTimezoneAdjustedTimestamp } = useTimezone(); const text = useMemo(() => { - const date = - typeof data.timestamp === 'string' - ? formatTimezoneAdjustedTimestamp(data.timestamp, 'YYYY-MM-DD HH:mm:ss.SSS') - : formatTimezoneAdjustedTimestamp( - data.timestamp / 1e6, - 'YYYY-MM-DD HH:mm:ss.SSS', - ); + const parts = []; - return `${date} | ${attributesText} ${data.body}`; + // Check if timestamp is selected + const showTimestamp = selectedFields.some( + (field) => field.name === 'timestamp', + ); + if (showTimestamp) { + const date = + typeof data.timestamp === 'string' + ? formatTimezoneAdjustedTimestamp( + data.timestamp, + 'YYYY-MM-DD HH:mm:ss.SSS', + ) + : formatTimezoneAdjustedTimestamp( + data.timestamp / 1e6, + 'YYYY-MM-DD HH:mm:ss.SSS', + ); + parts.push(date); + } + + // Check if body is selected + const showBody = selectedFields.some((field) => field.name === 'body'); + if (showBody) { + parts.push(`${attributesText} ${data.body}`); + } else { + parts.push(attributesText); + } + + return parts.join(' | '); }, [ + selectedFields, + attributesText, data.timestamp, data.body, - attributesText, formatTimezoneAdjustedTimestamp, ]); diff --git a/frontend/src/components/Logs/TableView/useTableView.tsx b/frontend/src/components/Logs/TableView/useTableView.tsx index d38e10ce4c..8dbc0c2755 100644 --- a/frontend/src/components/Logs/TableView/useTableView.tsx +++ b/frontend/src/components/Logs/TableView/useTableView.tsx @@ -48,7 +48,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => { const columns: ColumnsType> = useMemo(() => { const fieldColumns: ColumnsType> = fields - .filter((e) => e.name !== 'id') + .filter((e) => !['id', 'body', 'timestamp'].includes(e.name)) .map(({ name }) => ({ title: name, dataIndex: name, @@ -91,55 +91,67 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => { ), }), }, - { - title: 'timestamp', - dataIndex: 'timestamp', - key: 'timestamp', - // https://github.com/ant-design/ant-design/discussions/36886 - render: (field): ColumnTypeRender> => { - const date = - typeof field === 'string' - ? formatTimezoneAdjustedTimestamp(field, 'YYYY-MM-DD HH:mm:ss.SSS') - : formatTimezoneAdjustedTimestamp( - field / 1e6, - 'YYYY-MM-DD HH:mm:ss.SSS', - ); - return { - children: ( -
- - {date} - -
- ), - }; - }, - }, + ...(fields.some((field) => field.name === 'timestamp') + ? [ + { + title: 'timestamp', + dataIndex: 'timestamp', + key: 'timestamp', + // https://github.com/ant-design/ant-design/discussions/36886 + render: ( + field: string | number, + ): ColumnTypeRender> => { + const date = + typeof field === 'string' + ? formatTimezoneAdjustedTimestamp(field, 'YYYY-MM-DD HH:mm:ss.SSS') + : formatTimezoneAdjustedTimestamp( + field / 1e6, + 'YYYY-MM-DD HH:mm:ss.SSS', + ); + return { + children: ( +
+ + {date} + +
+ ), + }; + }, + }, + ] + : []), ...(appendTo === 'center' ? fieldColumns : []), - { - title: 'body', - dataIndex: 'body', - key: 'body', - render: (field): ColumnTypeRender> => ({ - props: { - style: defaultTableStyle, - }, - children: ( - field.name === 'body') + ? [ + { + title: 'body', + dataIndex: 'body', + key: 'body', + render: ( + field: string | number, + ): ColumnTypeRender> => ({ + props: { + style: defaultTableStyle, + }, + children: ( + ), - }} - fontSize={fontSize} - linesPerRow={linesPerRow} - isDarkMode={isDarkMode} - /> - ), - }), - }, + }), + }, + ] + : []), ...(appendTo === 'end' ? fieldColumns : []), ]; }, [ diff --git a/frontend/src/container/LogsExplorerList/InfinityTableView/index.tsx b/frontend/src/container/LogsExplorerList/InfinityTableView/index.tsx index eec6cc032a..9aa982abe7 100644 --- a/frontend/src/container/LogsExplorerList/InfinityTableView/index.tsx +++ b/frontend/src/container/LogsExplorerList/InfinityTableView/index.tsx @@ -121,23 +121,25 @@ const InfinityTable = forwardRef( const tableHeader = useCallback( () => ( - {tableColumns.map((column) => { - const isDragColumn = column.key !== 'expand'; + {tableColumns + .filter((column) => column.key) + .map((column) => { + const isDragColumn = column.key !== 'expand'; - return ( - - {(column.title as string).replace(/^\w/, (c) => c.toUpperCase())} - - ); - })} + return ( + + {(column.title as string).replace(/^\w/, (c) => c.toUpperCase())} + + ); + })} ), [tableColumns, isDarkMode, tableViewProps?.fontSize], diff --git a/frontend/src/container/LogsExplorerList/InfinityTableView/styles.ts b/frontend/src/container/LogsExplorerList/InfinityTableView/styles.ts index 9de75e6642..a22e7a4cc0 100644 --- a/frontend/src/container/LogsExplorerList/InfinityTableView/styles.ts +++ b/frontend/src/container/LogsExplorerList/InfinityTableView/styles.ts @@ -29,7 +29,7 @@ export const TableCellStyled = styled.td` props.$isDarkMode ? 'inherit' : themeColors.whiteCream}; ${({ $isLogIndicator }): string => - $isLogIndicator ? 'padding: 0 0 0 8px;' : ''} + $isLogIndicator ? 'padding: 0 0 0 8px;width: 15px;' : ''} color: ${(props): string => props.$isDarkMode ? themeColors.white : themeColors.bckgGrey}; `; diff --git a/frontend/src/container/OptionsMenu/constants.ts b/frontend/src/container/OptionsMenu/constants.ts index 153981f3c6..7bf6a007d1 100644 --- a/frontend/src/container/OptionsMenu/constants.ts +++ b/frontend/src/container/OptionsMenu/constants.ts @@ -5,7 +5,26 @@ import { FontSize, OptionsQuery } from './types'; export const URL_OPTIONS = 'options'; export const defaultOptionsQuery: OptionsQuery = { - selectColumns: [], + selectColumns: [ + { + key: 'timestamp', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'timestamp--string--tag--true', + isIndexed: false, + }, + { + key: 'body', + dataType: DataTypes.String, + type: 'tag', + isColumn: true, + isJSON: false, + id: 'body--string--tag--true', + isIndexed: false, + }, + ], maxLines: 2, format: 'raw', fontSize: FontSize.SMALL, diff --git a/frontend/src/container/OptionsMenu/useOptionsMenu.ts b/frontend/src/container/OptionsMenu/useOptionsMenu.ts index a4a91d82f4..e81fca43aa 100644 --- a/frontend/src/container/OptionsMenu/useOptionsMenu.ts +++ b/frontend/src/container/OptionsMenu/useOptionsMenu.ts @@ -169,6 +169,15 @@ const useOptionsMenu = ({ const searchedAttributeKeys = useMemo(() => { if (searchedAttributesData?.payload?.attributeKeys?.length) { + if (dataSource === DataSource.LOGS) { + // add timestamp and body to the list of attributes + return [ + ...defaultOptionsQuery.selectColumns, + ...searchedAttributesData.payload.attributeKeys.filter( + (attribute) => attribute.key !== 'body', + ), + ]; + } return searchedAttributesData.payload.attributeKeys; } if (dataSource === DataSource.TRACES) { @@ -198,12 +207,17 @@ const useOptionsMenu = ({ ); const optionsFromAttributeKeys = useMemo(() => { - const filteredAttributeKeys = searchedAttributeKeys.filter( - (item) => item.key !== 'body', - ); + const filteredAttributeKeys = searchedAttributeKeys.filter((item) => { + // For other data sources, only filter out 'body' if it exists + if (dataSource !== DataSource.LOGS) { + return item.key !== 'body'; + } + // For LOGS, keep all keys + return true; + }); return getOptionsFromKeys(filteredAttributeKeys, selectedColumnKeys); - }, [searchedAttributeKeys, selectedColumnKeys]); + }, [dataSource, searchedAttributeKeys, selectedColumnKeys]); const handleRedirectWithOptionsData = useCallback( (newQueryData: OptionsQuery) => {