mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Logs Panel: Table UI - Refactor to use includeByName transformation (#78070)
* remove excludeByName logic from LogsTable.tsx, migrate to includeByName. Update tests
This commit is contained in:
parent
fcc2f01c7e
commit
a18eee4093
@ -122,6 +122,12 @@ describe('LogsTable', () => {
|
||||
it('should render extracted labels as columns (elastic)', async () => {
|
||||
setup({
|
||||
logsFrames: [getMockElasticFrame()],
|
||||
columnsWithMeta: {
|
||||
counter: { active: true, percentOfLinesWithLabel: 3 },
|
||||
level: { active: true, percentOfLinesWithLabel: 3 },
|
||||
line: { active: true, percentOfLinesWithLabel: 3 },
|
||||
'@timestamp': { active: true, percentOfLinesWithLabel: 3 },
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@ -137,6 +143,8 @@ describe('LogsTable', () => {
|
||||
setup({
|
||||
columnsWithMeta: {
|
||||
foo: { active: true, percentOfLinesWithLabel: 3 },
|
||||
Time: { active: true, percentOfLinesWithLabel: 3 },
|
||||
line: { active: true, percentOfLinesWithLabel: 3 },
|
||||
},
|
||||
});
|
||||
|
||||
@ -196,7 +204,16 @@ describe('LogsTable', () => {
|
||||
});
|
||||
|
||||
it('should render a datalink for each row', async () => {
|
||||
render(getComponent({}, getMockLokiFrameDataPlane()));
|
||||
render(
|
||||
getComponent(
|
||||
{
|
||||
columnsWithMeta: {
|
||||
traceID: { active: true, percentOfLinesWithLabel: 3 },
|
||||
},
|
||||
},
|
||||
getMockLokiFrameDataPlane()
|
||||
)
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
const links = screen.getAllByRole('link');
|
||||
@ -229,12 +246,13 @@ describe('LogsTable', () => {
|
||||
setup({
|
||||
columnsWithMeta: {
|
||||
foo: { active: true, percentOfLinesWithLabel: 3 },
|
||||
line: { active: true, percentOfLinesWithLabel: 3 },
|
||||
Time: { active: true, percentOfLinesWithLabel: 3 },
|
||||
},
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const columns = screen.getAllByRole('columnheader');
|
||||
|
||||
expect(columns[0].textContent).toContain('Time');
|
||||
expect(columns[1].textContent).toContain('line');
|
||||
expect(columns[2].textContent).toContain('foo');
|
||||
|
@ -19,7 +19,6 @@ import {
|
||||
import { config } from '@grafana/runtime';
|
||||
import { AdHocFilterItem, Table } from '@grafana/ui';
|
||||
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR } from '@grafana/ui/src/components/Table/types';
|
||||
import { separateVisibleFields } from 'app/features/logs/components/logParser';
|
||||
import { LogsFrame, parseLogsFrame } from 'app/features/logs/logsFrame';
|
||||
|
||||
import { getFieldLinksForExplore } from '../utils/links';
|
||||
@ -110,17 +109,25 @@ export function LogsTable(props: Props) {
|
||||
let dataFrame = logFrameRaw;
|
||||
|
||||
// create extract JSON transformation for every field that is `json.RawMessage`
|
||||
const transformations: Array<DataTransformerConfig | CustomTransformOperator> =
|
||||
extractFieldsAndExclude(dataFrame);
|
||||
const transformations: Array<DataTransformerConfig | CustomTransformOperator> = extractFields(dataFrame);
|
||||
|
||||
// remove hidden fields
|
||||
transformations.push(...removeHiddenFields(dataFrame));
|
||||
let labelFilters = buildLabelFilters(columnsWithMeta, logsFrame);
|
||||
let labelFilters = buildLabelFilters(columnsWithMeta);
|
||||
|
||||
// Add the label filters to the transformations
|
||||
const transform = getLabelFiltersTransform(labelFilters);
|
||||
if (transform) {
|
||||
transformations.push(transform);
|
||||
} else {
|
||||
// If no fields are filtered, filter the default fields, so we don't render all columns
|
||||
transformations.push({
|
||||
id: 'organize',
|
||||
options: {
|
||||
includeByName: {
|
||||
[logsFrame.bodyField.name]: true,
|
||||
[logsFrame.timeField.name]: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (transformations.length > 0) {
|
||||
@ -181,7 +188,7 @@ const isFieldFilterable = (field: Field, logsFrame?: LogsFrame | undefined) => {
|
||||
|
||||
// TODO: explore if `logsFrame.ts` can help us with getting the right fields
|
||||
// TODO Why is typeInfo not defined on the Field interface?
|
||||
function extractFieldsAndExclude(dataFrame: DataFrame) {
|
||||
function extractFields(dataFrame: DataFrame) {
|
||||
return dataFrame.fields
|
||||
.filter((field: Field & { typeInfo?: { frame: string } }) => {
|
||||
const isFieldLokiLabels =
|
||||
@ -203,72 +210,19 @@ function extractFieldsAndExclude(dataFrame: DataFrame) {
|
||||
source: field.name,
|
||||
},
|
||||
},
|
||||
// hide the field that was extracted
|
||||
{
|
||||
id: 'organize',
|
||||
options: {
|
||||
excludeByName: {
|
||||
[field.name]: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
function removeHiddenFields(dataFrame: DataFrame): Array<DataTransformerConfig | CustomTransformOperator> {
|
||||
const transformations: Array<DataTransformerConfig | CustomTransformOperator> = [];
|
||||
const hiddenFields = separateVisibleFields(dataFrame, { keepBody: true, keepTimestamp: true }).hidden;
|
||||
hiddenFields.forEach((field: Field) => {
|
||||
transformations.push({
|
||||
id: 'organize',
|
||||
options: {
|
||||
excludeByName: {
|
||||
[field.name]: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return transformations;
|
||||
}
|
||||
|
||||
function buildLabelFilters(columnsWithMeta: Record<string, fieldNameMeta>, logsFrame: LogsFrame) {
|
||||
// Create object of label filters to filter out any columns not selected by the user
|
||||
function buildLabelFilters(columnsWithMeta: Record<string, fieldNameMeta>) {
|
||||
// Create object of label filters to include columns selected by the user
|
||||
let labelFilters: Record<string, true> = {};
|
||||
Object.keys(columnsWithMeta)
|
||||
.filter((key) => !columnsWithMeta[key].active)
|
||||
.filter((key) => columnsWithMeta[key].active)
|
||||
.forEach((key) => {
|
||||
labelFilters[key] = true;
|
||||
});
|
||||
|
||||
// We could be getting fresh data
|
||||
const uniqueLabels = new Set<string>();
|
||||
const logFrameLabels = logsFrame?.getLogFrameLabelsAsLabels();
|
||||
|
||||
// Populate the set with all labels from latest dataframe
|
||||
logFrameLabels?.forEach((labels) => {
|
||||
Object.keys(labels).forEach((label) => {
|
||||
uniqueLabels.add(label);
|
||||
});
|
||||
});
|
||||
|
||||
// Check if there are labels in the data, that aren't yet in the labelFilters, and set them to be hidden by the transform
|
||||
Object.keys(labelFilters).forEach((label) => {
|
||||
if (!uniqueLabels.has(label)) {
|
||||
labelFilters[label] = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Check if there are labels in the label filters that aren't yet in the data, and set those to also be hidden
|
||||
// The next time the column filters are synced any extras will be removed
|
||||
Array.from(uniqueLabels).forEach((label) => {
|
||||
if (label in columnsWithMeta && !columnsWithMeta[label]?.active) {
|
||||
labelFilters[label] = true;
|
||||
} else if (!labelFilters[label] && !(label in columnsWithMeta)) {
|
||||
labelFilters[label] = true;
|
||||
}
|
||||
});
|
||||
return labelFilters;
|
||||
}
|
||||
|
||||
@ -277,7 +231,7 @@ function getLabelFiltersTransform(labelFilters: Record<string, true>) {
|
||||
return {
|
||||
id: 'organize',
|
||||
options: {
|
||||
excludeByName: labelFilters,
|
||||
includeByName: labelFilters,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user