mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 20:29:04 +08:00
Fix/check the flows of toggling logs timestamp and body columns (#6992)
* fix: add default timestamp and body columns to live logs * refactor: use convertKeysToColumnFields instead of re-modifying the default columns * fix: remove the local storage selectColumns when clear view is clicked * fix: improve selectColumns migration handling
This commit is contained in:
parent
d910d99689
commit
a84e462a65
@ -25,7 +25,10 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
|
|||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import ExportPanelContainer from 'container/ExportPanel/ExportPanelContainer';
|
import ExportPanelContainer from 'container/ExportPanel/ExportPanelContainer';
|
||||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||||
import { defaultTraceSelectedColumns } from 'container/OptionsMenu/constants';
|
import {
|
||||||
|
defaultLogsSelectedColumns,
|
||||||
|
defaultTraceSelectedColumns,
|
||||||
|
} from 'container/OptionsMenu/constants';
|
||||||
import { OptionsQuery } from 'container/OptionsMenu/types';
|
import { OptionsQuery } from 'container/OptionsMenu/types';
|
||||||
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
|
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
@ -408,6 +411,14 @@ function ExplorerOptions({
|
|||||||
const handleClearSelect = (): void => {
|
const handleClearSelect = (): void => {
|
||||||
removeCurrentViewFromLocalStorage();
|
removeCurrentViewFromLocalStorage();
|
||||||
|
|
||||||
|
handleOptionsChange({
|
||||||
|
...options,
|
||||||
|
selectColumns:
|
||||||
|
sourcepage === DataSource.TRACES
|
||||||
|
? defaultTraceSelectedColumns
|
||||||
|
: defaultLogsSelectedColumns,
|
||||||
|
});
|
||||||
|
|
||||||
history.replace(DATASOURCE_VS_ROUTES[sourcepage]);
|
history.replace(DATASOURCE_VS_ROUTES[sourcepage]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import { InfinityWrapperStyled } from 'container/LogsExplorerList/styles';
|
|||||||
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
|
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
|
||||||
import { Heading } from 'container/LogsTable/styles';
|
import { Heading } from 'container/LogsTable/styles';
|
||||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||||
|
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||||
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
||||||
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
|
||||||
import { useEventSource } from 'providers/EventSource';
|
import { useEventSource } from 'providers/EventSource';
|
||||||
@ -53,7 +54,10 @@ function LiveLogsList({ logs }: LiveLogsListProps): JSX.Element {
|
|||||||
[logs, activeLogId],
|
[logs, activeLogId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedFields = convertKeysToColumnFields(options.selectColumns);
|
const selectedFields = convertKeysToColumnFields([
|
||||||
|
...defaultLogsSelectedColumns,
|
||||||
|
...options.selectColumns,
|
||||||
|
]);
|
||||||
|
|
||||||
const getItemContent = useCallback(
|
const getItemContent = useCallback(
|
||||||
(_: number, log: ILog): JSX.Element => {
|
(_: number, log: ILog): JSX.Element => {
|
||||||
|
@ -5,6 +5,7 @@ import RawLogView from 'components/Logs/RawLogView';
|
|||||||
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
|
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
|
||||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||||
import ShowButton from 'container/LogsContextList/ShowButton';
|
import ShowButton from 'container/LogsContextList/ShowButton';
|
||||||
|
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
|
||||||
import { useOptionsMenu } from 'container/OptionsMenu';
|
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||||
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||||
import { FontSize } from 'container/OptionsMenu/types';
|
import { FontSize } from 'container/OptionsMenu/types';
|
||||||
@ -12,21 +13,12 @@ import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/co
|
|||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { Virtuoso } from 'react-virtuoso';
|
import { Virtuoso } from 'react-virtuoso';
|
||||||
import { IField } from 'types/api/logs/fields';
|
|
||||||
import { ILog } from 'types/api/logs/log';
|
import { ILog } from 'types/api/logs/log';
|
||||||
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource, StringOperators } from 'types/common/queryBuilder';
|
import { DataSource, StringOperators } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
import { useContextLogData } from './useContextLogData';
|
import { useContextLogData } from './useContextLogData';
|
||||||
|
|
||||||
const defaultLogsSelectedFields: IField[] = defaultLogsSelectedColumns.map(
|
|
||||||
(item) => ({
|
|
||||||
name: item.key,
|
|
||||||
type: item.type,
|
|
||||||
dataType: item.dataType,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
function ContextLogRenderer({
|
function ContextLogRenderer({
|
||||||
isEdit,
|
isEdit,
|
||||||
query,
|
query,
|
||||||
@ -119,7 +111,7 @@ function ContextLogRenderer({
|
|||||||
data={logTorender}
|
data={logTorender}
|
||||||
linesPerRow={1}
|
linesPerRow={1}
|
||||||
fontSize={options.fontSize}
|
fontSize={options.fontSize}
|
||||||
selectedFields={defaultLogsSelectedFields}
|
selectedFields={convertKeysToColumnFields(defaultLogsSelectedColumns)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[log.id, options.fontSize],
|
[log.id, options.fontSize],
|
||||||
|
@ -23,7 +23,8 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
|||||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||||
import { isEqual, isNull } from 'lodash-es';
|
import { isEqual, isNull } from 'lodash-es';
|
||||||
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
import { WrapperStyled } from './styles';
|
import { WrapperStyled } from './styles';
|
||||||
@ -86,25 +87,80 @@ function LogsExplorer(): JSX.Element {
|
|||||||
redirectWithQuery: redirectWithOptionsData,
|
redirectWithQuery: redirectWithOptionsData,
|
||||||
} = useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
|
} = useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
|
||||||
|
|
||||||
const migrateOptionsQuery = (query: OptionsQuery): OptionsQuery => {
|
// Get and parse stored columns from localStorage
|
||||||
// If version is missing AND timestamp/body are not in selectColumns, this is an old URL
|
const logListOptionsFromLocalStorage = useMemo(() => {
|
||||||
if (
|
const data = getLocalStorageKey(LOCALSTORAGE.LOGS_LIST_OPTIONS);
|
||||||
!query.version &&
|
|
||||||
!query.selectColumns.some((col) => col.key === 'timestamp') &&
|
if (!data) return null;
|
||||||
!query.selectColumns.some((col) => col.key === 'body')
|
|
||||||
) {
|
try {
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
const hasValidColumns = Array.isArray(parsed?.selectColumns);
|
||||||
|
|
||||||
|
return hasValidColumns ? parsed.selectColumns : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Check if the columns have the required columns (timestamp, body)
|
||||||
|
const hasRequiredColumns = useCallback(
|
||||||
|
(columns?: Array<{ key: string }> | null): boolean => {
|
||||||
|
if (!columns?.length) return false;
|
||||||
|
|
||||||
|
const hasTimestamp = columns.some((col) => col.key === 'timestamp');
|
||||||
|
const hasBody = columns.some((col) => col.key === 'body');
|
||||||
|
|
||||||
|
return hasTimestamp && hasBody;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge the columns with the required columns (timestamp, body) if missing
|
||||||
|
const mergeWithRequiredColumns = useCallback(
|
||||||
|
(columns: BaseAutocompleteData[]): BaseAutocompleteData[] => [
|
||||||
|
// Add required columns (timestamp, body) if missing
|
||||||
|
...(!hasRequiredColumns(columns) ? defaultLogsSelectedColumns : []),
|
||||||
|
...columns,
|
||||||
|
],
|
||||||
|
[hasRequiredColumns],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Migrate the options query to the new format
|
||||||
|
const migrateOptionsQuery = useCallback(
|
||||||
|
(query: OptionsQuery): OptionsQuery => {
|
||||||
|
// Skip if already migrated
|
||||||
|
if (query.version) return query;
|
||||||
|
|
||||||
|
// Case 1: query has columns
|
||||||
|
if (query.selectColumns.length > 0) {
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
version: 1,
|
||||||
|
selectColumns: mergeWithRequiredColumns(query.selectColumns),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: No query columns in but we have localStorage columns
|
||||||
|
if (logListOptionsFromLocalStorage?.selectColumns?.length > 0) {
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
version: 1,
|
||||||
|
selectColumns: mergeWithRequiredColumns(
|
||||||
|
logListOptionsFromLocalStorage.selectColumns,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 3: No columns anywhere, use defaults
|
||||||
return {
|
return {
|
||||||
...query,
|
...query,
|
||||||
version: 1,
|
version: 1,
|
||||||
selectColumns: [
|
selectColumns: defaultLogsSelectedColumns,
|
||||||
// Add default timestamp and body columns
|
|
||||||
...defaultLogsSelectedColumns,
|
|
||||||
...query.selectColumns,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
return query;
|
[mergeWithRequiredColumns, logListOptionsFromLocalStorage?.selectColumns],
|
||||||
};
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const migratedQuery = migrateOptionsQuery(optionsQueryData);
|
const migratedQuery = migrateOptionsQuery(optionsQueryData);
|
||||||
@ -112,7 +168,7 @@ function LogsExplorer(): JSX.Element {
|
|||||||
if (!isEqual(migratedQuery, optionsQueryData)) {
|
if (!isEqual(migratedQuery, optionsQueryData)) {
|
||||||
redirectWithOptionsData(migratedQuery);
|
redirectWithOptionsData(migratedQuery);
|
||||||
}
|
}
|
||||||
}, [optionsQueryData, redirectWithOptionsData]);
|
}, [migrateOptionsQuery, optionsQueryData, redirectWithOptionsData]);
|
||||||
|
|
||||||
const isMultipleQueries = useMemo(
|
const isMultipleQueries = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user