Co-authored-by: Wylie Conlon <william.conlon@elastic.co>
This commit is contained in:
parent
f4b79d327c
commit
b7a874c7b0
8 changed files with 433 additions and 329 deletions
|
@ -274,6 +274,69 @@ describe('LayerPanel', () => {
|
|||
expect(component.find('EuiFlyoutHeader').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not update the visualization if the datasource is incomplete', () => {
|
||||
(generateId as jest.Mock).mockReturnValueOnce(`newid`);
|
||||
const updateAll = jest.fn();
|
||||
const updateDatasource = jest.fn();
|
||||
|
||||
mockVisualization.getConfiguration.mockReturnValue({
|
||||
groups: [
|
||||
{
|
||||
groupLabel: 'A',
|
||||
groupId: 'a',
|
||||
accessors: [],
|
||||
filterOperations: () => true,
|
||||
supportsMoreColumns: true,
|
||||
dataTestSubj: 'lnsGroup',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const component = mountWithIntl(
|
||||
<LayerPanel
|
||||
{...getDefaultProps()}
|
||||
updateDatasource={updateDatasource}
|
||||
updateAll={updateAll}
|
||||
/>
|
||||
);
|
||||
|
||||
act(() => {
|
||||
component.find('[data-test-subj="lns-empty-dimension"]').first().simulate('click');
|
||||
});
|
||||
component.update();
|
||||
|
||||
expect(mockDatasource.renderDimensionEditor).toHaveBeenCalledWith(
|
||||
expect.any(Element),
|
||||
expect.objectContaining({ columnId: 'newid' })
|
||||
);
|
||||
const stateFn =
|
||||
mockDatasource.renderDimensionEditor.mock.calls[
|
||||
mockDatasource.renderDimensionEditor.mock.calls.length - 1
|
||||
][1].setState;
|
||||
|
||||
act(() => {
|
||||
stateFn({
|
||||
indexPatternId: '1',
|
||||
columns: {},
|
||||
columnOrder: [],
|
||||
incompleteColumns: { newId: { operationType: 'count' } },
|
||||
});
|
||||
});
|
||||
expect(updateAll).not.toHaveBeenCalled();
|
||||
|
||||
act(() => {
|
||||
stateFn(
|
||||
{
|
||||
indexPatternId: '1',
|
||||
columns: {},
|
||||
columnOrder: [],
|
||||
},
|
||||
true
|
||||
);
|
||||
});
|
||||
expect(updateAll).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close the DimensionContainer when the active visualization changes', () => {
|
||||
/**
|
||||
* The ID generation system for new dimensions has been messy before, so
|
||||
|
|
|
@ -503,17 +503,21 @@ export function LayerPanel(
|
|||
columnId: activeId,
|
||||
filterOperations: activeGroup.filterOperations,
|
||||
dimensionGroups: groups,
|
||||
setState: (newState: unknown) => {
|
||||
props.updateAll(
|
||||
datasourceId,
|
||||
newState,
|
||||
activeVisualization.setDimension({
|
||||
layerId,
|
||||
groupId: activeGroup.groupId,
|
||||
columnId: activeId,
|
||||
prevState: props.visualizationState,
|
||||
})
|
||||
);
|
||||
setState: (newState: unknown, shouldUpdateVisualization?: boolean) => {
|
||||
if (shouldUpdateVisualization) {
|
||||
props.updateAll(
|
||||
datasourceId,
|
||||
newState,
|
||||
activeVisualization.setDimension({
|
||||
layerId,
|
||||
groupId: activeGroup.groupId,
|
||||
columnId: activeId,
|
||||
prevState: props.visualizationState,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
props.updateDatasource(datasourceId, newState);
|
||||
}
|
||||
setActiveDimension({
|
||||
...activeDimension,
|
||||
isNew: false,
|
||||
|
|
|
@ -110,6 +110,10 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
} = props;
|
||||
const { fieldByOperation, operationWithoutField } = operationSupportMatrix;
|
||||
|
||||
const setStateWrapper = (layer: IndexPatternLayer) => {
|
||||
setState(mergeLayer({ state, layerId, newLayer: layer }), Boolean(layer.columns[columnId]));
|
||||
};
|
||||
|
||||
const selectedOperationDefinition =
|
||||
selectedColumn && operationDefinitionMap[selectedColumn.operationType];
|
||||
|
||||
|
@ -194,13 +198,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
if (selectedColumn?.operationType === operationType) {
|
||||
// Clear invalid state because we are reseting to a valid column
|
||||
if (incompleteInfo) {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: resetIncomplete(state.layers[layerId], columnId),
|
||||
})
|
||||
);
|
||||
setStateWrapper(resetIncomplete(state.layers[layerId], columnId));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -210,38 +208,30 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
columnId,
|
||||
op: operationType,
|
||||
});
|
||||
setState(mergeLayer({ state, layerId, newLayer }));
|
||||
setStateWrapper(newLayer);
|
||||
trackUiEvent(`indexpattern_dimension_operation_${operationType}`);
|
||||
return;
|
||||
} else if (!selectedColumn || !compatibleWithCurrentField) {
|
||||
const possibleFields = fieldByOperation[operationType] || new Set();
|
||||
|
||||
if (possibleFields.size === 1) {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: insertOrReplaceColumn({
|
||||
layer: props.state.layers[props.layerId],
|
||||
indexPattern: currentIndexPattern,
|
||||
columnId,
|
||||
op: operationType,
|
||||
field: currentIndexPattern.getFieldByName(possibleFields.values().next().value),
|
||||
}),
|
||||
setStateWrapper(
|
||||
insertOrReplaceColumn({
|
||||
layer: props.state.layers[props.layerId],
|
||||
indexPattern: currentIndexPattern,
|
||||
columnId,
|
||||
op: operationType,
|
||||
field: currentIndexPattern.getFieldByName(possibleFields.values().next().value),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: insertOrReplaceColumn({
|
||||
layer: props.state.layers[props.layerId],
|
||||
indexPattern: currentIndexPattern,
|
||||
columnId,
|
||||
op: operationType,
|
||||
field: undefined,
|
||||
}),
|
||||
setStateWrapper(
|
||||
insertOrReplaceColumn({
|
||||
layer: props.state.layers[props.layerId],
|
||||
indexPattern: currentIndexPattern,
|
||||
columnId,
|
||||
op: operationType,
|
||||
field: undefined,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -251,13 +241,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
|
||||
if (selectedColumn.operationType === operationType) {
|
||||
if (incompleteInfo) {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: resetIncomplete(state.layers[layerId], columnId),
|
||||
})
|
||||
);
|
||||
setStateWrapper(resetIncomplete(state.layers[layerId], columnId));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -271,7 +255,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
? currentIndexPattern.getFieldByName(selectedColumn.sourceField)
|
||||
: undefined,
|
||||
});
|
||||
setState(mergeLayer({ state, layerId, newLayer }));
|
||||
setStateWrapper(newLayer);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -333,26 +317,16 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
}
|
||||
incompleteOperation={incompleteOperation}
|
||||
onDeleteColumn={() => {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: deleteColumn({ layer: state.layers[layerId], columnId }),
|
||||
})
|
||||
);
|
||||
setStateWrapper(deleteColumn({ layer: state.layers[layerId], columnId }));
|
||||
}}
|
||||
onChoose={(choice) => {
|
||||
setState(
|
||||
mergeLayer({
|
||||
state,
|
||||
layerId,
|
||||
newLayer: insertOrReplaceColumn({
|
||||
layer: state.layers[layerId],
|
||||
columnId,
|
||||
indexPattern: currentIndexPattern,
|
||||
op: choice.operationType,
|
||||
field: currentIndexPattern.getFieldByName(choice.field),
|
||||
}),
|
||||
setStateWrapper(
|
||||
insertOrReplaceColumn({
|
||||
layer: state.layers[layerId],
|
||||
columnId,
|
||||
indexPattern: currentIndexPattern,
|
||||
op: choice.operationType,
|
||||
field: currentIndexPattern.getFieldByName(choice.field),
|
||||
})
|
||||
);
|
||||
}}
|
||||
|
@ -365,9 +339,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
|
|||
selectedColumn={selectedColumn}
|
||||
columnId={columnId}
|
||||
layer={state.layers[layerId]}
|
||||
updateLayer={(newLayer: IndexPatternLayer) =>
|
||||
setState(mergeLayer({ layerId, state, newLayer }))
|
||||
}
|
||||
updateLayer={setStateWrapper}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
@ -367,23 +367,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([option]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...initialState,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'max',
|
||||
sourceField: 'memory',
|
||||
params: { format: { id: 'bytes' } },
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...initialState,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'max',
|
||||
sourceField: 'memory',
|
||||
params: { format: { id: 'bytes' } },
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should switch operations when selecting a field that requires another operation', () => {
|
||||
|
@ -398,22 +401,25 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([option]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'terms',
|
||||
sourceField: 'source',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'terms',
|
||||
sourceField: 'source',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should keep the field when switching to another operation compatible for this field', () => {
|
||||
|
@ -428,23 +434,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-min"]').simulate('click');
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'min',
|
||||
sourceField: 'bytes',
|
||||
params: { format: { id: 'bytes' } },
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
operationType: 'min',
|
||||
sourceField: 'bytes',
|
||||
params: { format: { id: 'bytes' } },
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should not set the state if selecting the currently active operation', () => {
|
||||
|
@ -498,20 +507,23 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-min"]').simulate('click');
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
label: 'Minimum of bytes',
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
label: 'Minimum of bytes',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should keep the label on operation change if it is custom', () => {
|
||||
|
@ -532,21 +544,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-min"]').simulate('click');
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
label: 'Custom label',
|
||||
customLabel: true,
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
label: 'Custom label',
|
||||
customLabel: true,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
describe('transient invalid state', () => {
|
||||
|
@ -559,20 +574,23 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
.simulate('click');
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
},
|
||||
incompleteColumns: {
|
||||
col1: { operationType: 'terms' },
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
},
|
||||
incompleteColumns: {
|
||||
col1: { operationType: 'terms' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should show error message in invalid state', () => {
|
||||
|
@ -681,17 +699,20 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
wrapper = mount(<IndexPatternDimensionEditorComponent {...defaultProps} columnId={'col2'} />);
|
||||
|
||||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
incompleteColumns: {
|
||||
col2: { operationType: 'avg' },
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
incompleteColumns: {
|
||||
col2: { operationType: 'avg' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
false
|
||||
);
|
||||
|
||||
const comboBox = wrapper
|
||||
.find(EuiComboBox)
|
||||
|
@ -703,23 +724,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([options![1].options![2]]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenLastCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'source',
|
||||
operationType: 'terms',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenLastCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'source',
|
||||
operationType: 'terms',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
columnOrder: ['col2', 'col1'],
|
||||
},
|
||||
columnOrder: ['col2', 'col1'],
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should select the Records field when count is selected', () => {
|
||||
|
@ -800,21 +824,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([option]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenLastCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
sourceField: 'source',
|
||||
operationType: 'terms',
|
||||
}),
|
||||
expect(setState).toHaveBeenLastCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col1: expect.objectContaining({
|
||||
sourceField: 'source',
|
||||
operationType: 'terms',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -887,21 +914,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
.dive()
|
||||
.find('[data-test-subj="indexPattern-time-scaling-enable"]')
|
||||
.prop('onClick')!({} as MouseEvent);
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 's',
|
||||
label: 'Count of records per second',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 's',
|
||||
label: 'Count of records per second',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should carry over time scaling to other operation if possible', () => {
|
||||
|
@ -915,21 +945,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
wrapper
|
||||
.find('button[data-test-subj="lns-indexPatternDimension-count incompatible"]')
|
||||
.simulate('click');
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'Count of records per hour',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'Count of records per hour',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should not carry over time scaling if the other operation does not support it', () => {
|
||||
|
@ -941,21 +974,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
});
|
||||
wrapper = mount(<IndexPatternDimensionEditorComponent {...props} />);
|
||||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: undefined,
|
||||
label: 'Average of bytes',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: undefined,
|
||||
label: 'Average of bytes',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow to change time scaling', () => {
|
||||
|
@ -967,21 +1003,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
.prop('onChange')!(({
|
||||
target: { value: 'h' },
|
||||
} as unknown) as ChangeEvent<HTMLSelectElement>);
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'Count of records per hour',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'Count of records per hour',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should not adjust label if it is custom', () => {
|
||||
|
@ -993,21 +1032,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
.prop('onChange')!(({
|
||||
target: { value: 'h' },
|
||||
} as unknown) as ChangeEvent<HTMLSelectElement>);
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'My label',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: 'h',
|
||||
label: 'My label',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should allow to remove time scaling', () => {
|
||||
|
@ -1020,21 +1062,24 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
{} as any
|
||||
);
|
||||
expect(props.setState).toHaveBeenCalledWith({
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: undefined,
|
||||
label: 'Count of records',
|
||||
}),
|
||||
expect(props.setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...props.state,
|
||||
layers: {
|
||||
first: {
|
||||
...props.state.layers.first,
|
||||
columns: {
|
||||
...props.state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
timeScale: undefined,
|
||||
label: 'Count of records',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1072,19 +1117,22 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
|
||||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
incompleteColumns: {
|
||||
col2: {
|
||||
operationType: 'avg',
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
incompleteColumns: {
|
||||
col2: {
|
||||
operationType: 'avg',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
false
|
||||
);
|
||||
|
||||
const comboBox = wrapper
|
||||
.find(EuiComboBox)
|
||||
|
@ -1095,23 +1143,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([options![1].options![0]]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'bytes',
|
||||
operationType: 'avg',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'bytes',
|
||||
operationType: 'avg',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should select operation directly if only one field is possible', () => {
|
||||
|
@ -1135,23 +1186,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
|
||||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...initialState,
|
||||
layers: {
|
||||
first: {
|
||||
...initialState.layers.first,
|
||||
columns: {
|
||||
...initialState.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'bytes',
|
||||
operationType: 'avg',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...initialState,
|
||||
layers: {
|
||||
first: {
|
||||
...initialState.layers.first,
|
||||
columns: {
|
||||
...initialState.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
sourceField: 'bytes',
|
||||
operationType: 'avg',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should select operation directly if only document is possible', () => {
|
||||
|
@ -1159,22 +1213,25 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
|
||||
wrapper.find('button[data-test-subj="lns-indexPatternDimension-count"]').simulate('click');
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
operationType: 'count',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
operationType: 'count',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should indicate compatible fields when selecting the operation first', () => {
|
||||
|
@ -1284,23 +1341,26 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
comboBox.prop('onChange')!([option]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
operationType: 'range',
|
||||
sourceField: 'bytes',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
...state.layers.first,
|
||||
columns: {
|
||||
...state.layers.first.columns,
|
||||
col2: expect.objectContaining({
|
||||
operationType: 'range',
|
||||
sourceField: 'bytes',
|
||||
// Other parts of this don't matter for this test
|
||||
}),
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
columnOrder: ['col1', 'col2'],
|
||||
},
|
||||
},
|
||||
});
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should use helper function when changing the function', () => {
|
||||
|
@ -1336,17 +1396,20 @@ describe('IndexPatternDimensionEditorPanel', () => {
|
|||
.prop('onChange')!([]);
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledWith({
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
indexPatternId: '1',
|
||||
columns: {},
|
||||
columnOrder: [],
|
||||
incompleteColumns: {},
|
||||
expect(setState).toHaveBeenCalledWith(
|
||||
{
|
||||
...state,
|
||||
layers: {
|
||||
first: {
|
||||
indexPatternId: '1',
|
||||
columns: {},
|
||||
columnOrder: [],
|
||||
incompleteColumns: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('allows custom format', () => {
|
||||
|
|
|
@ -53,7 +53,7 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens
|
|||
[layer, columnId, currentIndexPattern]
|
||||
);
|
||||
|
||||
const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] || null;
|
||||
const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] ?? null;
|
||||
|
||||
if (!selectedColumn) {
|
||||
return null;
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
} from './calculations';
|
||||
import { countOperation, CountIndexPatternColumn } from './count';
|
||||
import { lastValueOperation, LastValueIndexPatternColumn } from './last_value';
|
||||
import { StateSetter, OperationMetadata } from '../../../types';
|
||||
import { OperationMetadata } from '../../../types';
|
||||
import type { BaseIndexPatternColumn, ReferenceBasedIndexPatternColumn } from './column_types';
|
||||
import {
|
||||
IndexPatternPrivateState,
|
||||
|
@ -116,7 +116,7 @@ export {
|
|||
export interface ParamEditorProps<C> {
|
||||
currentColumn: C;
|
||||
state: IndexPatternPrivateState;
|
||||
setState: StateSetter<IndexPatternPrivateState>;
|
||||
setState: (newState: IndexPatternPrivateState) => void;
|
||||
columnId: string;
|
||||
layerId: string;
|
||||
uiSettings: IUiSettingsClient;
|
||||
|
|
|
@ -72,7 +72,8 @@ export function isColumnInvalid(
|
|||
columnId: string,
|
||||
indexPattern: IndexPattern
|
||||
) {
|
||||
const column = layer.columns[columnId];
|
||||
const column: IndexPatternColumn | undefined = layer.columns[columnId];
|
||||
if (!column) return;
|
||||
|
||||
const operationDefinition = column.operationType && operationDefinitionMap[column.operationType];
|
||||
return !!(
|
||||
|
|
|
@ -240,7 +240,8 @@ export type DatasourceDimensionProps<T> = SharedDimensionProps & {
|
|||
|
||||
// The only way a visualization has to restrict the query building
|
||||
export type DatasourceDimensionEditorProps<T = unknown> = DatasourceDimensionProps<T> & {
|
||||
setState: StateSetter<T>;
|
||||
// Not a StateSetter because we have this unique use case of determining valid columns
|
||||
setState: (newState: Parameters<StateSetter<T>>[0], publishToVisualization?: boolean) => void;
|
||||
core: Pick<CoreSetup, 'http' | 'notifications' | 'uiSettings'>;
|
||||
dateRange: DateRange;
|
||||
dimensionGroups: VisualizationDimensionGroupConfig[];
|
||||
|
|
Loading…
Reference in a new issue