Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table: Show log text not preserved in URL state #979

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/Components/ServiceScene/LogsListScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,22 @@ import {
import { logger } from '../../services/logger';
import { Options } from '@grafana/schema/dist/esm/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen';
import { narrowLogsVisualizationType, narrowSelectedTableRow, unknownToStrings } from '../../services/narrowing';
import { LogLineState } from '../Table/Context/TableColumnsContext';

export interface LogsListSceneState extends SceneObjectState {
loading?: boolean;
panel?: SceneFlexLayout;
visualizationType: LogsVisualizationType;
urlColumns?: string[];
tableLogLineState?: LogLineState;
selectedLine?: SelectedTableRow;
$timeRange?: SceneTimeRangeLike;
displayedFields: string[];
}

export class LogsListScene extends SceneObjectBase<LogsListSceneState> {
protected _urlSync = new SceneObjectUrlSyncConfig(this, {
keys: ['urlColumns', 'selectedLine', 'visualizationType', 'displayedFields'],
keys: ['urlColumns', 'selectedLine', 'visualizationType', 'displayedFields', 'tableLogLineState'],
});
private lineFilterScene?: LineFilterScene = undefined;
private logsPanelScene?: LogsPanelScene = undefined;
Expand All @@ -63,6 +65,7 @@ export class LogsListScene extends SceneObjectBase<LogsListSceneState> {
selectedLine: JSON.stringify(selectedLine),
visualizationType: JSON.stringify(visualizationType),
displayedFields: JSON.stringify(displayedFields),
tableLogLineState: JSON.stringify(this.state.tableLogLineState),
};
}

Expand All @@ -84,20 +87,24 @@ export class LogsListScene extends SceneObjectBase<LogsListSceneState> {
}
}
}

if (typeof values.visualizationType === 'string') {
const decodedVisualizationType = narrowLogsVisualizationType(JSON.parse(values.visualizationType));
if (decodedVisualizationType && decodedVisualizationType !== this.state.visualizationType) {
stateUpdate.visualizationType = decodedVisualizationType;
}
}

if (typeof values.displayedFields === 'string') {
const displayedFields = unknownToStrings(JSON.parse(values.displayedFields));
if (displayedFields && displayedFields.length) {
stateUpdate.displayedFields = displayedFields;
}
}
if (typeof values.tableLogLineState === 'string') {
const tableLogLineState = JSON.parse(values.tableLogLineState);
if (tableLogLineState === LogLineState.labels || tableLogLineState === LogLineState.text) {
stateUpdate.tableLogLineState = tableLogLineState;
}
}
} catch (e) {
// URL Params can be manually changed and it will make JSON.parse() fail.
logger.error(e, { msg: 'LogsListScene: updateFromUrl unexpected error' });
Expand Down Expand Up @@ -147,12 +154,14 @@ export class LogsListScene extends SceneObjectBase<LogsListSceneState> {
const urlColumnsUrl = searchParams.get('urlColumns');
const vizTypeUrl = searchParams.get('visualizationType');
const displayedFieldsUrl = searchParams.get('displayedFields') ?? JSON.stringify(getDisplayedFields(this));
const tableLogLineState = searchParams.get('tableLogLineState');

this.updateFromUrl({
selectedLine: selectedLineUrl,
urlColumns: urlColumnsUrl,
vizType: vizTypeUrl,
displayedFields: displayedFieldsUrl,
tableLogLineState,
});
}

Expand Down
9 changes: 8 additions & 1 deletion src/Components/ServiceScene/LogsTableScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { areArraysEqual } from '../../services/comparison';
import { getLogsPanelFrame } from './ServiceScene';
import { getVariableForLabel } from '../../services/fields';
import { PanelMenu } from '../Panels/PanelMenu';
import { LogLineState } from '../Table/Context/TableColumnsContext';

interface LogsTableSceneState extends SceneObjectState {
menu?: PanelMenu;
Expand All @@ -32,7 +33,7 @@ export class LogsTableScene extends SceneObjectBase<LogsTableSceneState> {
// Get state from parent model
const parentModel = sceneGraph.getAncestor(model, LogsListScene);
const { data } = sceneGraph.getData(model).useState();
const { selectedLine, urlColumns, visualizationType } = parentModel.useState();
const { selectedLine, urlColumns, visualizationType, tableLogLineState } = parentModel.useState();
const { menu } = model.useState();

// Get time range
Expand All @@ -57,6 +58,10 @@ export class LogsTableScene extends SceneObjectBase<LogsTableSceneState> {
}
};

const setUrlTableBodyState = (logLineState: LogLineState) => {
parentModel.setState({ tableLogLineState: logLineState });
};

const clearSelectedLine = () => {
if (parentModel.state.selectedLine) {
parentModel.clearSelectedLine();
Expand All @@ -81,6 +86,8 @@ export class LogsTableScene extends SceneObjectBase<LogsTableSceneState> {
setUrlColumns={setUrlColumns}
dataFrame={dataFrame}
clearSelectedLine={clearSelectedLine}
setUrlTableBodyState={setUrlTableBodyState}
urlTableBodyState={tableLogLineState}
/>
)}
</PanelChrome>
Expand Down
18 changes: 16 additions & 2 deletions src/Components/Table/Context/TableColumnsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,19 @@ export const TableColumnContextProvider = ({
logsFrame,
setUrlColumns,
clearSelectedLine,
setUrlTableBodyState,
urlTableBodyState,
}: {
children: ReactNode;
initialColumns: FieldNameMetaStore;
logsFrame: LogsFrame;
setUrlColumns: (columns: string[]) => void;
clearSelectedLine: () => void;
setUrlTableBodyState: (logLineState: LogLineState) => void;
urlTableBodyState?: LogLineState;
}) => {
const [columns, setColumns] = useState<FieldNameMetaStore>(removeExtraColumns(initialColumns));
const [bodyState, setBodyState] = useState<LogLineState>(LogLineState.auto);
const [bodyState, setBodyState] = useState<LogLineState>(urlTableBodyState ?? LogLineState.auto);
const [filteredColumns, setFilteredColumns] = useState<FieldNameMetaStore | undefined>(undefined);
const [visible, setVisible] = useState(false);
const initialColumnWidths = getColumnWidthsFromLocalStorage();
Expand Down Expand Up @@ -145,6 +149,16 @@ export const TableColumnContextProvider = ({
[setUrlColumns]
);

const handleSetBodyState = useCallback(
(logLineState: LogLineState) => {
setBodyState(logLineState);

// Sync change with url state
setUrlTableBodyState(logLineState);
},
[setUrlTableBodyState]
);

const handleClearSelectedLine = () => {
clearSelectedLine();
};
Expand Down Expand Up @@ -182,7 +196,7 @@ export const TableColumnContextProvider = ({
setColumnWidthMap,
columnWidthMap,
bodyState,
setBodyState,
setBodyState: handleSetBodyState,
setFilteredColumns,
filteredColumns,
columns,
Expand Down
3 changes: 2 additions & 1 deletion src/Components/Table/RawLogLineText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { css } from '@emotion/css';
import { useTheme2 } from '@grafana/ui';
import { testIds } from '../../services/testIds';

export function RawLogLineText(props: { value: unknown }) {
const theme = useTheme2();
const styles = getStyles(theme);
return (
<div className={styles.rawLogLine}>
<div data-testid={testIds.table.rawLogLine} className={styles.rawLogLine}>
<>{props.value}</>
</div>
);
Expand Down
7 changes: 7 additions & 0 deletions src/Components/Table/TableProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AdHocVariableFilter, DataFrame, TimeRange } from '@grafana/data';
import { QueryContextProvider } from 'Components/Table/Context/QueryContext';
import { parseLogsFrame } from '../../services/logsFrame';
import { SelectedTableRow } from './LogLineCellComponent';
import { LogLineState } from './Context/TableColumnsContext';

interface TableProviderProps {
dataFrame: DataFrame;
Expand All @@ -15,6 +16,8 @@ interface TableProviderProps {
timeRange?: TimeRange;
panelWrap: React.RefObject<HTMLDivElement>;
clearSelectedLine: () => void;
setUrlTableBodyState: (logLineState: LogLineState) => void;
urlTableBodyState?: LogLineState;
}

export const TableProvider = ({
Expand All @@ -26,6 +29,8 @@ export const TableProvider = ({
timeRange,
panelWrap,
clearSelectedLine,
setUrlTableBodyState,
urlTableBodyState,
}: TableProviderProps) => {
if (!dataFrame) {
return null;
Expand All @@ -39,7 +44,9 @@ export const TableProvider = ({
return (
<QueryContextProvider addFilter={addFilter} selectedLine={selectedLine} timeRange={timeRange} logsFrame={logsFrame}>
<TableWrap
urlTableBodyState={urlTableBodyState}
setUrlColumns={setUrlColumns}
setUrlTableBodyState={setUrlTableBodyState}
urlColumns={urlColumns}
panelWrap={panelWrap}
clearSelectedLine={clearSelectedLine}
Expand Down
6 changes: 5 additions & 1 deletion src/Components/Table/TableWrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { css } from '@emotion/css';

import { DataFrame, FieldType, FieldWithIndex, getTimeZone, guessFieldTypeFromValue, Labels } from '@grafana/data';

import { TableColumnContextProvider } from 'Components/Table/Context/TableColumnsContext';
import { LogLineState, TableColumnContextProvider } from 'Components/Table/Context/TableColumnsContext';
import { Table } from 'Components/Table/Table';
import { FieldNameMeta, FieldNameMetaStore } from 'Components/Table/TableTypes';
import { useQueryContext } from 'Components/Table/Context/QueryContext';
Expand All @@ -20,9 +20,11 @@ const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3,})?(?:Z|[-+]

interface TableWrapProps {
urlColumns: string[];
urlTableBodyState?: LogLineState;
setUrlColumns: (columns: string[]) => void;
panelWrap: React.RefObject<HTMLDivElement>;
clearSelectedLine: () => void;
setUrlTableBodyState: (logLineState: LogLineState) => void;
}

const getStyles = () => ({
Expand Down Expand Up @@ -110,10 +112,12 @@ export const TableWrap = (props: TableWrapProps) => {
return (
<section className={styles.section}>
<TableColumnContextProvider
setUrlTableBodyState={props.setUrlTableBodyState}
logsFrame={logsFrame}
initialColumns={pendingLabelState}
setUrlColumns={props.setUrlColumns}
clearSelectedLine={props.clearSelectedLine}
urlTableBodyState={props.urlTableBodyState}
>
<Table
logsFrame={logsFrame}
Expand Down
1 change: 1 addition & 0 deletions src/services/testIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,6 @@ export const testIds = {
table: {
wrapper: 'data-testid table-wrapper',
inspectLine: 'data-testid inspect',
rawLogLine: 'data-testid raw-log-line',
},
};
29 changes: 27 additions & 2 deletions tests/exploreServicesBreakDown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ test.describe('explore services breakdown page', () => {
// Switch to table view
await explorePage.getTableToggleLocator().click();

const table = page.getByTestId(testIds.table.wrapper);
await page.getByTestId('data-testid Panel menu Logs').click();
await page.getByTestId('data-testid Panel menu item Explore').click();

Expand All @@ -130,6 +129,32 @@ test.describe('explore services breakdown page', () => {
await expect(page.getByTestId(`data-testid Dashboard template variables submenu Label ${levelName}`)).toBeVisible();
});

test('table log line state should persist in the url', async ({ page }) => {
explorePage.blockAllQueriesExcept({
refIds: ['logsPanelQuery'],
});
await explorePage.getTableToggleLocator().click();
const table = page.getByTestId(testIds.table.wrapper);

// assert the table doesn't contain the raw log line option by default
await expect(table.getByTestId(testIds.table.rawLogLine)).toHaveCount(0);

// Open menu
await page.getByRole('button', { name: 'Show menu' }).nth(1).click();

// Show log text option should be visible by default
await expect(page.getByText('Show log text')).toBeVisible();

// Change the option
await page.getByText('Show log text').click();

// Assert the change was made to the table
await expect(table.getByTestId(testIds.table.rawLogLine).nth(0)).toBeVisible();

await page.reload();
await expect(table.getByTestId(testIds.table.rawLogLine).nth(0)).toBeVisible();
});

test('should show inspect modal', async ({ page }) => {
await explorePage.getTableToggleLocator().click();
// Expect table to be rendered
Expand Down Expand Up @@ -449,7 +474,7 @@ test.describe('explore services breakdown page', () => {
refIds: ['A'],
});
await page.getByTestId(testIds.exploreServiceDetails.tabPatterns).click();
const key = page.getByText('<_>').last().click();
await page.getByText('<_>').last().click();
// `From a sample of` is the indicator that the underlying query perfomed successfully
await expect(page.getByText(`From a sample of`)).toBeVisible();
});
Expand Down
Loading