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

[Lens] Introduce 4 new calculation functions: counter rate, cumulative sum, differences, and moving average #84384

Merged
merged 20 commits into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
808a0d0
[Lens] UI for reference-based functions
wylieconlon Dec 2, 2020
119e51b
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 2, 2020
62e9826
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 2, 2020
7066755
Fix tests
wylieconlon Dec 3, 2020
9764879
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 3, 2020
1e4e0ee
Add a few unit tests for reference editor
wylieconlon Dec 3, 2020
bdbe768
Merge remote-tracking branch 'upstream/master' into lens/reference-ui
flash1293 Dec 14, 2020
246892c
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 14, 2020
bd72fa4
Respond to review comments
wylieconlon Dec 15, 2020
2c4d5d3
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 16, 2020
9eafe0d
Update error handling
wylieconlon Dec 16, 2020
e33278d
Update suggestion logic to work with errors and refs
wylieconlon Dec 17, 2020
a6cfe67
Support ParamEditor in references to fix Last Value: refactoring as
wylieconlon Dec 18, 2020
742fb94
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 18, 2020
8820866
Fix error states
wylieconlon Dec 18, 2020
025a714
Merge branch 'master' into lens/reference-ui
kibanamachine Dec 21, 2020
0850115
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 21, 2020
7ac5dde
Merge remote-tracking branch 'origin/master' into lens/reference-ui
wylieconlon Dec 21, 2020
1cf5cd8
Update logic for showing references in dimension editor, add tests
wylieconlon Dec 22, 2020
bc2087a
Fix tests
wylieconlon Dec 22, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export function WorkspacePanel({

const expression = useMemo(
() => {
if (!configurationValidationError || configurationValidationError.length === 0) {
if (!configurationValidationError?.length) {
try {
return buildExpression({
visualization: activeVisualization,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { BucketNestingEditor } from './bucket_nesting_editor';
import { IndexPattern, IndexPatternLayer } from '../types';
import { trackUiEvent } from '../../lens_ui_telemetry';
import { FormatSelector } from './format_selector';
import { ReferenceEditor } from './reference_editor';
import { TimeScaling } from './time_scaling';

const operationPanels = getOperationDisplay();
Expand Down Expand Up @@ -107,7 +108,15 @@ export function DimensionEditor(props: DimensionEditorProps) {
layerId,
currentIndexPattern,
hideGrouping,
dateRange,
} = props;
const services = {
data: props.data,
uiSettings: props.uiSettings,
savedObjectsClient: props.savedObjectsClient,
http: props.http,
storage: props.storage,
};
const { fieldByOperation, operationWithoutField } = operationSupportMatrix;

const setStateWrapper = (layer: IndexPatternLayer) => {
Expand Down Expand Up @@ -148,7 +157,10 @@ export function DimensionEditor(props: DimensionEditorProps) {
(selectedColumn && !hasField(selectedColumn) && definition.input === 'none'),
disabledStatus:
definition.getDisabledStatus &&
definition.getDisabledStatus(state.indexPatterns[state.currentIndexPatternId]),
definition.getDisabledStatus(
state.indexPatterns[state.currentIndexPatternId],
state.layers[layerId]
),
};
});

Expand Down Expand Up @@ -194,9 +206,12 @@ export function DimensionEditor(props: DimensionEditorProps) {
compatibleWithCurrentField ? '' : ' incompatible'
}`,
onClick() {
if (operationDefinitionMap[operationType].input === 'none') {
if (
operationDefinitionMap[operationType].input === 'none' ||
operationDefinitionMap[operationType].input === 'fullReference'
) {
// Clear invalid state because we are reseting to a valid column
if (selectedColumn?.operationType === operationType) {
// Clear invalid state because we are reseting to a valid column
if (incompleteInfo) {
setStateWrapper(resetIncomplete(state.layers[layerId], columnId));
}
Expand Down Expand Up @@ -283,6 +298,35 @@ export function DimensionEditor(props: DimensionEditorProps) {
</div>
<EuiSpacer size="s" />
<div className="lnsIndexPatternDimensionEditor__section lnsIndexPatternDimensionEditor__section--shaded">
{!incompleteInfo &&
selectedColumn &&
'references' in selectedColumn &&
selectedOperationDefinition?.input === 'fullReference' ? (
<>
{selectedColumn.references.map((referenceId, index) => {
const validation = selectedOperationDefinition.requiredReferences[index];

return (
<ReferenceEditor
key={index}
layer={state.layers[layerId]}
columnId={referenceId}
updateLayer={(newLayer: IndexPatternLayer) => {
setState(mergeLayer({ state, layerId, newLayer }));
}}
validation={validation}
currentIndexPattern={currentIndexPattern}
existingFields={state.existingFields}
selectionStyle={selectedOperationDefinition.selectionStyle}
dateRange={dateRange}
{...services}
/>
);
})}
<EuiSpacer size="s" />
</>
) : null}

{!selectedColumn ||
selectedOperationDefinition?.input === 'field' ||
(incompleteOperation && operationDefinitionMap[incompleteOperation].input === 'field') ? (
Expand Down Expand Up @@ -317,7 +361,13 @@ export function DimensionEditor(props: DimensionEditorProps) {
}
incompleteOperation={incompleteOperation}
onDeleteColumn={() => {
setStateWrapper(deleteColumn({ layer: state.layers[layerId], columnId }));
setStateWrapper(
deleteColumn({
layer: state.layers[layerId],
columnId,
indexPattern: currentIndexPattern,
})
);
}}
onChoose={(choice) => {
setStateWrapper(
Expand All @@ -334,32 +384,28 @@ export function DimensionEditor(props: DimensionEditorProps) {
</EuiFormRow>
) : null}

{!currentFieldIsInvalid && !incompleteInfo && selectedColumn && (
<TimeScaling
selectedColumn={selectedColumn}
columnId={columnId}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
/>
)}

{!currentFieldIsInvalid && !incompleteInfo && selectedColumn && ParamEditor && (
<>
<ParamEditor
state={state}
setState={setState}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
columnId={columnId}
currentColumn={state.layers[layerId].columns[columnId]}
storage={props.storage}
uiSettings={props.uiSettings}
savedObjectsClient={props.savedObjectsClient}
layerId={layerId}
http={props.http}
dateRange={props.dateRange}
data={props.data}
indexPattern={currentIndexPattern}
{...services}
/>
</>
)}

{!currentFieldIsInvalid && !incompleteInfo && selectedColumn && (
<TimeScaling
selectedColumn={selectedColumn}
columnId={columnId}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
/>
)}
</div>

<EuiSpacer size="s" />
Expand Down Expand Up @@ -407,12 +453,15 @@ export function DimensionEditor(props: DimensionEditorProps) {
selectedColumn={selectedColumn}
onChange={(newFormat) => {
setState(
updateColumnParam({
mergeLayer({
state,
layerId,
currentColumn: selectedColumn,
paramName: 'format',
value: newFormat,
newLayer: updateColumnParam({
layer: state.layers[layerId],
columnId,
paramName: 'format',
value: newFormat,
}),
})
);
}}
Expand All @@ -425,11 +474,11 @@ export function DimensionEditor(props: DimensionEditorProps) {
}
function getErrorMessage(
selectedColumn: IndexPatternColumn | undefined,
incompatibleSelectedOperationType: boolean,
incompleteOperation: boolean,
input: 'none' | 'field' | 'fullReference' | undefined,
fieldInvalid: boolean
) {
if (selectedColumn && incompatibleSelectedOperationType) {
if (selectedColumn && incompleteOperation) {
if (input === 'field') {
return i18n.translate('xpack.lens.indexPattern.invalidOperationLabel', {
defaultMessage: 'To use this function, select a different field.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
dataType: 'date',
isBucketed: true,
label: '',
customLabel: true,
operationType: 'date_histogram',
sourceField: 'ts',
params: {
Expand All @@ -872,6 +873,7 @@ describe('IndexPatternDimensionEditorPanel', () => {
columnId: 'col2',
};
}

it('should not show custom options if time scaling is not available', () => {
wrapper = mount(
<IndexPatternDimensionEditorComponent
Expand Down Expand Up @@ -1149,15 +1151,15 @@ describe('IndexPatternDimensionEditorPanel', () => {
layers: {
first: {
...state.layers.first,
columnOrder: ['col1', 'col2'],
columns: {
...state.layers.first.columns,
col2: expect.objectContaining({
sourceField: 'bytes',
operationType: 'avg',
// Other parts of this don't matter for this test
sourceField: 'bytes',
}),
},
columnOrder: ['col1', 'col2'],
incompleteColumns: {},
},
},
},
Expand Down Expand Up @@ -1237,7 +1239,9 @@ describe('IndexPatternDimensionEditorPanel', () => {
it('should indicate compatible fields when selecting the operation first', () => {
wrapper = mount(<IndexPatternDimensionEditorComponent {...defaultProps} columnId={'col2'} />);

wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
act(() => {
wrapper.find('button[data-test-subj="lns-indexPatternDimension-avg"]').simulate('click');
});

const options = wrapper
.find(EuiComboBox)
Expand Down Expand Up @@ -1317,10 +1321,14 @@ describe('IndexPatternDimensionEditorPanel', () => {
expect(items.map(({ label }: { label: React.ReactNode }) => label)).toEqual([
'Average',
'Count',
'Counter rate',
'Cumulative sum',
'Differences',
'Last value',
'Maximum',
'Median',
'Minimum',
'Moving average',
'Sum',
'Unique count',
]);
Expand Down Expand Up @@ -1536,4 +1544,41 @@ describe('IndexPatternDimensionEditorPanel', () => {
},
});
});

it('should hide the top level field selector when switching from non-reference to reference', () => {
wrapper = mount(<IndexPatternDimensionEditorComponent {...defaultProps} />);

expect(wrapper.find('ReferenceEditor')).toHaveLength(0);

wrapper
.find('button[data-test-subj="lns-indexPatternDimension-derivative incompatible"]')
.simulate('click');

expect(wrapper.find('ReferenceEditor')).toHaveLength(1);
});

it('should hide the reference editors when switching from reference to non-reference', () => {
const stateWithReferences: IndexPatternPrivateState = getStateWithColumns({
col1: {
label: 'Differences of (incomplete)',
dataType: 'number',
isBucketed: false,
operationType: 'derivative',
references: ['col2'],
params: {},
},
});

wrapper = mount(
<IndexPatternDimensionEditorComponent {...defaultProps} state={stateWithReferences} />
);

expect(wrapper.find('ReferenceEditor')).toHaveLength(1);

wrapper
.find('button[data-test-subj="lns-indexPatternDimension-avg incompatible"]')
.simulate('click');

expect(wrapper.find('ReferenceEditor')).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix
supportedFieldsByOperation[operation.operationType] = new Set();
}
supportedFieldsByOperation[operation.operationType]?.add(operation.field);
} else if (operation.type === 'none') {
} else {
supportedOperationsWithoutField.add(operation.operationType);
}
});
Expand Down
Loading