mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Lens] Fix column order issues (#98261)
This commit is contained in:
parent
b544be6ff2
commit
61d57370fa
6 changed files with 165 additions and 33 deletions
|
@ -1150,6 +1150,83 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('respects groups on moving operations if some columns are not listed in groups', () => {
|
||||
// config:
|
||||
// a: col1,
|
||||
// b: col2, col3
|
||||
// c: col4
|
||||
// col5, col6 not in visualization groups
|
||||
// dragging col3 onto col1 in group a
|
||||
onDrop({
|
||||
...defaultProps,
|
||||
columnId: 'col1',
|
||||
droppedItem: draggingCol3,
|
||||
state: {
|
||||
...testState,
|
||||
layers: {
|
||||
first: {
|
||||
...testState.layers.first,
|
||||
columnOrder: ['col1', 'col2', 'col3', 'col4', 'col5', 'col6'],
|
||||
columns: {
|
||||
...testState.layers.first.columns,
|
||||
col5: {
|
||||
dataType: 'number',
|
||||
operationType: 'count',
|
||||
label: '',
|
||||
isBucketed: false,
|
||||
sourceField: 'Records',
|
||||
},
|
||||
col6: {
|
||||
dataType: 'number',
|
||||
operationType: 'count',
|
||||
label: '',
|
||||
isBucketed: false,
|
||||
sourceField: 'Records',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
groupId: 'a',
|
||||
dimensionGroups: [
|
||||
{ ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] },
|
||||
{ ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] },
|
||||
{ ...dimensionGroups[2] },
|
||||
],
|
||||
dropType: 'move_compatible',
|
||||
});
|
||||
|
||||
expect(setState).toBeCalledTimes(1);
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...testState,
|
||||
layers: {
|
||||
first: {
|
||||
...testState.layers.first,
|
||||
columnOrder: ['col1', 'col2', 'col4', 'col5', 'col6'],
|
||||
columns: {
|
||||
col1: testState.layers.first.columns.col3,
|
||||
col2: testState.layers.first.columns.col2,
|
||||
col4: testState.layers.first.columns.col4,
|
||||
col5: {
|
||||
dataType: 'number',
|
||||
operationType: 'count',
|
||||
label: '',
|
||||
isBucketed: false,
|
||||
sourceField: 'Records',
|
||||
},
|
||||
col6: {
|
||||
dataType: 'number',
|
||||
operationType: 'count',
|
||||
label: '',
|
||||
isBucketed: false,
|
||||
sourceField: 'Records',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('respects groups on duplicating operations between compatible groups with overwrite', () => {
|
||||
// config:
|
||||
// a: col1,
|
||||
|
|
|
@ -147,9 +147,9 @@ function onMoveCompatible(
|
|||
columns: newColumns,
|
||||
};
|
||||
|
||||
const updatedColumnOrder = getColumnOrder(newLayer);
|
||||
let updatedColumnOrder = getColumnOrder(newLayer);
|
||||
|
||||
reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId);
|
||||
updatedColumnOrder = reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId);
|
||||
|
||||
// Time to replace
|
||||
setState(
|
||||
|
@ -342,8 +342,8 @@ function onSwapCompatible({
|
|||
newColumns[targetId] = sourceColumn;
|
||||
newColumns[sourceId] = targetColumn;
|
||||
|
||||
const updatedColumnOrder = swapColumnOrder(layer.columnOrder, sourceId, targetId);
|
||||
reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId);
|
||||
let updatedColumnOrder = swapColumnOrder(layer.columnOrder, sourceId, targetId);
|
||||
updatedColumnOrder = reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId);
|
||||
|
||||
// Time to replace
|
||||
setState(
|
||||
|
|
|
@ -860,6 +860,44 @@ describe('IndexPattern Data Source', () => {
|
|||
expect(operationDefinitionMap.testReference.toExpression).toHaveBeenCalled();
|
||||
expect(ast.chain[2]).toEqual('mock');
|
||||
});
|
||||
|
||||
it('should keep correct column mapping keys with reference columns present', async () => {
|
||||
const queryBaseState: IndexPatternBaseState = {
|
||||
currentIndexPatternId: '1',
|
||||
layers: {
|
||||
first: {
|
||||
indexPatternId: '1',
|
||||
columnOrder: ['col2', 'col1'],
|
||||
columns: {
|
||||
col1: {
|
||||
label: 'Count of records',
|
||||
dataType: 'date',
|
||||
isBucketed: false,
|
||||
sourceField: 'timefield',
|
||||
operationType: 'unique_count',
|
||||
},
|
||||
col2: {
|
||||
label: 'Reference',
|
||||
dataType: 'number',
|
||||
isBucketed: false,
|
||||
// @ts-expect-error not a valid type
|
||||
operationType: 'testReference',
|
||||
references: ['col1'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const state = enrichBaseState(queryBaseState);
|
||||
|
||||
const ast = indexPatternDatasource.toExpression(state, 'first') as Ast;
|
||||
expect(JSON.parse(ast.chain[1].arguments.idMap[0] as string)).toEqual({
|
||||
'col-0-col1': expect.objectContaining({
|
||||
id: 'col1',
|
||||
}),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1106,11 +1106,11 @@ describe('IndexPattern Data Source suggestions', () => {
|
|||
operation: expect.objectContaining({ dataType: 'date', isBucketed: true }),
|
||||
},
|
||||
{
|
||||
columnId: 'newid',
|
||||
columnId: 'ref',
|
||||
operation: expect.objectContaining({ dataType: 'number', isBucketed: false }),
|
||||
},
|
||||
{
|
||||
columnId: 'ref',
|
||||
columnId: 'newid',
|
||||
operation: expect.objectContaining({ dataType: 'number', isBucketed: false }),
|
||||
},
|
||||
],
|
||||
|
@ -1158,15 +1158,6 @@ describe('IndexPattern Data Source suggestions', () => {
|
|||
table: expect.objectContaining({
|
||||
changeType: 'extended',
|
||||
columns: [
|
||||
{
|
||||
columnId: 'newid',
|
||||
operation: {
|
||||
dataType: 'number',
|
||||
isBucketed: false,
|
||||
label: 'Count of records',
|
||||
scale: 'ratio',
|
||||
},
|
||||
},
|
||||
{
|
||||
columnId: 'ref',
|
||||
operation: {
|
||||
|
@ -1176,6 +1167,15 @@ describe('IndexPattern Data Source suggestions', () => {
|
|||
scale: undefined,
|
||||
},
|
||||
},
|
||||
{
|
||||
columnId: 'newid',
|
||||
operation: {
|
||||
dataType: 'number',
|
||||
isBucketed: false,
|
||||
label: 'Count of records',
|
||||
scale: 'ratio',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
|
|
|
@ -712,7 +712,12 @@ function addBucket(
|
|||
// they already had, with an extra level of detail.
|
||||
updatedColumnOrder = [...buckets, addedColumnId, ...metrics, ...references];
|
||||
}
|
||||
reorderByGroups(visualizationGroups, targetGroup, updatedColumnOrder, addedColumnId);
|
||||
updatedColumnOrder = reorderByGroups(
|
||||
visualizationGroups,
|
||||
targetGroup,
|
||||
updatedColumnOrder,
|
||||
addedColumnId
|
||||
);
|
||||
const tempLayer = {
|
||||
...resetIncomplete(layer, addedColumnId),
|
||||
columns: { ...layer.columns, [addedColumnId]: column },
|
||||
|
@ -749,16 +754,24 @@ export function reorderByGroups(
|
|||
});
|
||||
const columnGroupIndex: Record<string, number> = {};
|
||||
updatedColumnOrder.forEach((columnId) => {
|
||||
columnGroupIndex[columnId] = orderedVisualizationGroups.findIndex(
|
||||
const groupIndex = orderedVisualizationGroups.findIndex(
|
||||
(group) =>
|
||||
(columnId === addedColumnId && group.groupId === targetGroup) ||
|
||||
group.accessors.some((acc) => acc.columnId === columnId)
|
||||
);
|
||||
if (groupIndex !== -1) {
|
||||
columnGroupIndex[columnId] = groupIndex;
|
||||
} else {
|
||||
// referenced columns won't show up in visualization groups - put them in the back of the list. This will work as they are always metrics
|
||||
columnGroupIndex[columnId] = updatedColumnOrder.length;
|
||||
}
|
||||
});
|
||||
|
||||
updatedColumnOrder.sort((a, b) => {
|
||||
return [...updatedColumnOrder].sort((a, b) => {
|
||||
return columnGroupIndex[a] - columnGroupIndex[b];
|
||||
});
|
||||
} else {
|
||||
return updatedColumnOrder;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,12 +912,8 @@ export function getColumnOrder(layer: IndexPatternLayer): string[] {
|
|||
}
|
||||
});
|
||||
|
||||
const [direct, referenceBased] = _.partition(
|
||||
entries,
|
||||
([, col]) => operationDefinitionMap[col.operationType].input !== 'fullReference'
|
||||
);
|
||||
// If a reference has another reference as input, put it last in sort order
|
||||
referenceBased.sort(([idA, a], [idB, b]) => {
|
||||
entries.sort(([idA, a], [idB, b]) => {
|
||||
if ('references' in a && a.references.includes(idB)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -913,12 +922,9 @@ export function getColumnOrder(layer: IndexPatternLayer): string[] {
|
|||
}
|
||||
return 0;
|
||||
});
|
||||
const [aggregations, metrics] = _.partition(direct, ([, col]) => col.isBucketed);
|
||||
const [aggregations, metrics] = _.partition(entries, ([, col]) => col.isBucketed);
|
||||
|
||||
return aggregations
|
||||
.map(([id]) => id)
|
||||
.concat(metrics.map(([id]) => id))
|
||||
.concat(referenceBased.map(([id]) => id));
|
||||
return aggregations.map(([id]) => id).concat(metrics.map(([id]) => id));
|
||||
}
|
||||
|
||||
// Splits existing columnOrder into the three categories
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { IUiSettingsClient } from 'kibana/public';
|
||||
import { partition } from 'lodash';
|
||||
import {
|
||||
AggFunctionsMapping,
|
||||
EsaggsExpressionFunctionDefinition,
|
||||
|
@ -57,14 +58,24 @@ function getExpressionForLayer(
|
|||
|
||||
const columnEntries = columnOrder.map((colId) => [colId, columns[colId]] as const);
|
||||
|
||||
if (columnEntries.length) {
|
||||
const [referenceEntries, esAggEntries] = partition(
|
||||
columnEntries,
|
||||
([, col]) => operationDefinitionMap[col.operationType]?.input === 'fullReference'
|
||||
);
|
||||
|
||||
if (referenceEntries.length || esAggEntries.length) {
|
||||
const aggs: ExpressionAstExpressionBuilder[] = [];
|
||||
const expressions: ExpressionAstFunction[] = [];
|
||||
columnEntries.forEach(([colId, col]) => {
|
||||
referenceEntries.forEach(([colId, col]) => {
|
||||
const def = operationDefinitionMap[col.operationType];
|
||||
if (def.input === 'fullReference') {
|
||||
expressions.push(...def.toExpression(layer, colId, indexPattern));
|
||||
} else {
|
||||
}
|
||||
});
|
||||
|
||||
esAggEntries.forEach(([colId, col]) => {
|
||||
const def = operationDefinitionMap[col.operationType];
|
||||
if (def.input !== 'fullReference') {
|
||||
const wrapInFilter = Boolean(def.filterable && col.filter);
|
||||
let aggAst = def.toEsAggsFn(
|
||||
col,
|
||||
|
@ -101,8 +112,8 @@ function getExpressionForLayer(
|
|||
}
|
||||
});
|
||||
|
||||
const idMap = columnEntries.reduce((currentIdMap, [colId, column], index) => {
|
||||
const esAggsId = `col-${columnEntries.length === 1 ? 0 : index}-${colId}`;
|
||||
const idMap = esAggEntries.reduce((currentIdMap, [colId, column], index) => {
|
||||
const esAggsId = `col-${index}-${colId}`;
|
||||
return {
|
||||
...currentIdMap,
|
||||
[esAggsId]: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue