Skip to content

Commit

Permalink
[Lens] Add reduced time range option for formula (elastic#142709)
Browse files Browse the repository at this point in the history
* ✅ Add tests for feature

* ✨ Add feature and make tests work

* ✨ Add more ui stuff

* 🐛 Fix missing renders on advanced options change

* 🔧 fix id issue

* 👌 Shorter tooltip message
  • Loading branch information
dej611 authored and WafaaNasr committed Oct 11, 2022
1 parent 0dc69ec commit e4f9e84
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ export interface DimensionEditorProps extends IndexPatternDimensionEditorProps {

const operationDisplay = getOperationDisplay();

function getHelpMessage(flag?: boolean | { helpMessage: string }) {
return flag && typeof flag !== 'boolean' ? flag.helpMessage : null;
}

export function DimensionEditor(props: DimensionEditorProps) {
const {
selectedColumn,
Expand Down Expand Up @@ -135,55 +139,58 @@ export function DimensionEditor(props: DimensionEditorProps) {
[layerId, setState]
);

const setStateWrapper = (
setter:
| IndexPatternLayer
| ((prevLayer: IndexPatternLayer) => IndexPatternLayer)
| GenericIndexPatternColumn,
options: { forceRender?: boolean } = {}
) => {
const layer = state.layers[layerId];
let hypotethicalLayer: IndexPatternLayer;
if (isColumn(setter)) {
hypotethicalLayer = {
...layer,
columns: {
...layer.columns,
[columnId]: setter,
},
};
} else {
hypotethicalLayer = typeof setter === 'function' ? setter(state.layers[layerId]) : setter;
}
const isDimensionComplete = Boolean(hypotethicalLayer.columns[columnId]);
const setStateWrapper = useCallback(
(
setter:
| IndexPatternLayer
| ((prevLayer: IndexPatternLayer) => IndexPatternLayer)
| GenericIndexPatternColumn,
options: { forceRender?: boolean } = {}
) => {
const layer = state.layers[layerId];
let hypotethicalLayer: IndexPatternLayer;
if (isColumn(setter)) {
hypotethicalLayer = {
...layer,
columns: {
...layer.columns,
[columnId]: setter,
},
};
} else {
hypotethicalLayer = typeof setter === 'function' ? setter(state.layers[layerId]) : setter;
}
const isDimensionComplete = Boolean(hypotethicalLayer.columns[columnId]);

setState(
(prevState) => {
let outputLayer: IndexPatternLayer;
const prevLayer = prevState.layers[layerId];
if (isColumn(setter)) {
outputLayer = {
...prevLayer,
columns: {
...prevLayer.columns,
[columnId]: setter,
},
};
} else {
outputLayer = typeof setter === 'function' ? setter(prevState.layers[layerId]) : setter;
setState(
(prevState) => {
let outputLayer: IndexPatternLayer;
const prevLayer = prevState.layers[layerId];
if (isColumn(setter)) {
outputLayer = {
...prevLayer,
columns: {
...prevLayer.columns,
[columnId]: setter,
},
};
} else {
outputLayer = typeof setter === 'function' ? setter(prevState.layers[layerId]) : setter;
}
return mergeLayer({
state: prevState,
layerId,
newLayer: adjustColumnReferencesForChangedColumn(outputLayer, columnId),
});
},
{
isDimensionComplete,
...options,
}
return mergeLayer({
state: prevState,
layerId,
newLayer: adjustColumnReferencesForChangedColumn(outputLayer, columnId),
});
},
{
isDimensionComplete,
...options,
}
);
};
);
},
[columnId, layerId, setState, state.layers]
);

const setIsCloseable = (isCloseable: boolean) => {
setState((prevState) => ({ ...prevState, isDimensionClosePrevented: !isCloseable }));
Expand Down Expand Up @@ -965,6 +972,30 @@ export function DimensionEditor(props: DimensionEditorProps) {
[layerId, selectedColumn, props.indexPatterns, state.layers]
);

/**
* Advanced options can cause side effects on other columns (i.e. formulas)
* so before updating the layer the full insertOrReplaceColumn needs to be performed
*/
const updateAdvancedOption = useCallback(
(newLayer) => {
if (selectedColumn) {
setStateWrapper(
// formula need to regenerate from scratch
selectedColumn.operationType === formulaOperationName
? insertOrReplaceColumn({
op: selectedColumn.operationType,
layer: newLayer,
columnId,
indexPattern: currentIndexPattern,
visualizationGroups: dimensionGroups,
})
: newLayer
);
}
},
[columnId, currentIndexPattern, dimensionGroups, selectedColumn, setStateWrapper]
);

const shouldDisplayAdvancedOptions =
!isFullscreen &&
!currentFieldIsInvalid &&
Expand Down Expand Up @@ -1020,7 +1051,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
selectedColumn={selectedColumn}
columnId={columnId}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
updateLayer={updateAdvancedOption}
/>
) : null,
},
Expand All @@ -1032,13 +1063,8 @@ export function DimensionEditor(props: DimensionEditorProps) {
selectedColumn={selectedColumn}
columnId={columnId}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
helpMessage={
selectedOperationDefinition.filterable &&
typeof selectedOperationDefinition.filterable !== 'boolean'
? selectedOperationDefinition.filterable.helpMessage
: null
}
updateLayer={updateAdvancedOption}
helpMessage={getHelpMessage(selectedOperationDefinition.filterable)}
/>
) : null,
},
Expand All @@ -1050,7 +1076,9 @@ export function DimensionEditor(props: DimensionEditorProps) {
columnId={columnId}
indexPattern={currentIndexPattern}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
updateLayer={updateAdvancedOption}
skipLabelUpdate={hasFormula}
helpMessage={getHelpMessage(selectedOperationDefinition.canReduceTimeRange)}
/>
) : null,
},
Expand All @@ -1069,7 +1097,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
selectedColumn={selectedColumn}
columnId={columnId}
layer={state.layers[layerId]}
updateLayer={setStateWrapper}
updateLayer={updateAdvancedOption}
activeData={props.activeData}
layerId={layerId}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { EuiFormRow, EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
import { EuiFormRow, EuiFlexItem, EuiFlexGroup, EuiIconTip } from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useEffect, useState } from 'react';
Expand All @@ -24,21 +24,23 @@ import { reducedTimeRangeOptions } from '../reduced_time_range_utils';
export function setReducedTimeRange(
columnId: string,
layer: IndexPatternLayer,
reducedTimeRange: string | undefined
reducedTimeRange: string | undefined,
skipLabelUpdate?: boolean
) {
const trimmedReducedTimeRange = reducedTimeRange?.trim();
const currentColumn = layer.columns[columnId];
const label = currentColumn.customLabel
? currentColumn.label
: adjustTimeScaleLabelSuffix(
currentColumn.label,
currentColumn.timeScale,
currentColumn.timeScale,
currentColumn.timeShift,
currentColumn.timeShift,
currentColumn.reducedTimeRange,
trimmedReducedTimeRange
);
const label =
currentColumn.customLabel || skipLabelUpdate
? currentColumn.label
: adjustTimeScaleLabelSuffix(
currentColumn.label,
currentColumn.timeScale,
currentColumn.timeScale,
currentColumn.timeShift,
currentColumn.timeShift,
currentColumn.reducedTimeRange,
trimmedReducedTimeRange
);
return {
...layer,
columns: {
Expand All @@ -62,12 +64,16 @@ export function ReducedTimeRange({
layer,
updateLayer,
indexPattern,
helpMessage,
skipLabelUpdate,
}: {
selectedColumn: GenericIndexPatternColumn;
columnId: string;
layer: IndexPatternLayer;
updateLayer: (newLayer: IndexPatternLayer) => void;
indexPattern: IndexPattern;
helpMessage: string | null;
skipLabelUpdate?: boolean;
}) {
const [localValue, setLocalValue] = useState(selectedColumn.reducedTimeRange);
useEffect(() => {
Expand Down Expand Up @@ -99,16 +105,35 @@ export function ReducedTimeRange({
},
];
}
const label = i18n.translate('xpack.lens.indexPattern.reducedTimeRange.label', {
defaultMessage: 'Reduced time range',
});

return (
<div>
<EuiFormRow
display="rowCompressed"
fullWidth
data-test-subj="indexPattern-dimension-reducedTimeRange-row"
label={i18n.translate('xpack.lens.indexPattern.reducedTimeRange.label', {
defaultMessage: 'Reduced time range',
})}
label={
helpMessage ? (
<>
{label}{' '}
<EuiIconTip
color="subdued"
content={helpMessage}
iconProps={{
className: 'eui-alignTop',
}}
position="top"
size="s"
type="questionInCircle"
/>
</>
) : (
label
)
}
helpText={i18n.translate('xpack.lens.indexPattern.reducedTimeRange.help', {
defaultMessage:
'Reduces the time range specified in the global time filter from the end of the global time filter.',
Expand Down Expand Up @@ -144,22 +169,22 @@ export function ReducedTimeRange({
onCreateOption={(val) => {
const parsedVal = parseTimeShift(val);
if (!isInvalid(parsedVal)) {
updateLayer(setReducedTimeRange(columnId, layer, val));
updateLayer(setReducedTimeRange(columnId, layer, val, skipLabelUpdate));
} else {
setLocalValue(val);
}
}}
onChange={(choices) => {
if (choices.length === 0) {
updateLayer(setReducedTimeRange(columnId, layer, ''));
updateLayer(setReducedTimeRange(columnId, layer, '', skipLabelUpdate));
setLocalValue('');
return;
}

const choice = choices[0].value as string;
const parsedVal = parseTimeShift(choice);
if (!isInvalid(parsedVal)) {
updateLayer(setReducedTimeRange(columnId, layer, choice));
updateLayer(setReducedTimeRange(columnId, layer, choice, skipLabelUpdate));
} else {
setLocalValue(choice);
}
Expand Down
Loading

0 comments on commit e4f9e84

Please sign in to comment.