Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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 @@ -17,7 +17,7 @@ import {
} from '@elastic/eui';
import { EuiFormLabel } from '@elastic/eui';
import { IndexPatternColumn, OperationType } from '../indexpattern';
import { IndexPatternDimensionEditorProps, OperationFieldSupportMatrix } from './dimension_panel';
import { IndexPatternDimensionEditorProps, OperationSupportMatrix } from './dimension_panel';
import {
operationDefinitionMap,
getOperationDisplay,
Expand All @@ -36,7 +36,7 @@ const operationPanels = getOperationDisplay();

export interface DimensionEditorProps extends IndexPatternDimensionEditorProps {
selectedColumn?: IndexPatternColumn;
operationFieldSupportMatrix: OperationFieldSupportMatrix;
operationSupportMatrix: OperationSupportMatrix;
currentIndexPattern: IndexPattern;
}

Expand Down Expand Up @@ -90,22 +90,24 @@ const LabelInput = ({ value, onChange }: { value: string; onChange: (value: stri
export function DimensionEditor(props: DimensionEditorProps) {
const {
selectedColumn,
operationFieldSupportMatrix,
operationSupportMatrix,
state,
columnId,
setState,
layerId,
currentIndexPattern,
hideGrouping,
} = props;
const { operationByField, fieldByOperation } = operationFieldSupportMatrix;
const { operationByField, fieldByOperation } = operationSupportMatrix;
const [
incompatibleSelectedOperationType,
setInvalidOperationType,
] = useState<OperationType | null>(null);

const ParamEditor =
selectedColumn && operationDefinitionMap[selectedColumn.operationType].paramEditor;
const selectedOperationDefinition =
selectedColumn && operationDefinitionMap[selectedColumn.operationType];

const ParamEditor = selectedOperationDefinition?.paramEditor;

const fieldMap: Record<string, IndexPatternField> = useMemo(() => {
const fields: Record<string, IndexPatternField> = {};
Expand All @@ -129,6 +131,10 @@ export function DimensionEditor(props: DimensionEditorProps) {
[
...asOperationOptions(validOperationTypes, true),
...asOperationOptions(possibleOperationTypes, false),
...asOperationOptions(
operationSupportMatrix.operationWithoutField,
!selectedColumn || !hasField(selectedColumn)
),
],
'operationType'
);
Expand Down Expand Up @@ -166,12 +172,30 @@ export function DimensionEditor(props: DimensionEditorProps) {
compatibleWithCurrentField ? '' : ' incompatible'
}`,
onClick() {
// todo: when moving from terms agg to filters, we want to create a filter `$field.name : *`
// it probably has to be re-thought when removing the field name.
const isTermsToFilters =
selectedColumn?.operationType === 'terms' && operationType === 'filters';

if (!selectedColumn || !compatibleWithCurrentField) {
if (operationDefinitionMap[operationType].input === 'none') {
// Clear invalid state because we are creating a valid column
setInvalidOperationType(null);
if (selectedColumn?.operationType === operationType) {
return;
}
setState(
changeColumn({
state,
layerId,
columnId,
newColumn: buildColumn({
columns: props.state.layers[props.layerId].columns,
suggestedPriority: props.suggestedPriority,
layerId: props.layerId,
op: operationType,
indexPattern: currentIndexPattern,
previousColumn: selectedColumn,
}),
})
);
trackUiEvent(`indexpattern_dimension_operation_${operationType}`);
return;
} else if (!selectedColumn || !compatibleWithCurrentField) {
const possibleFields = fieldByOperation[operationType] || [];

if (possibleFields.length === 1) {
Expand All @@ -197,19 +221,20 @@ export function DimensionEditor(props: DimensionEditorProps) {
trackUiEvent(`indexpattern_dimension_operation_${operationType}`);
return;
}
if (incompatibleSelectedOperationType && !isTermsToFilters) {
setInvalidOperationType(null);
}
if (selectedColumn.operationType === operationType) {

setInvalidOperationType(null);

if (selectedColumn?.operationType === operationType) {
return;
}

const newColumn: IndexPatternColumn = buildColumn({
columns: props.state.layers[props.layerId].columns,
suggestedPriority: props.suggestedPriority,
layerId: props.layerId,
op: operationType,
indexPattern: currentIndexPattern,
field: fieldMap[selectedColumn.sourceField],
field: hasField(selectedColumn) ? fieldMap[selectedColumn.sourceField] : undefined,
previousColumn: selectedColumn,
});

Expand Down Expand Up @@ -244,93 +269,97 @@ export function DimensionEditor(props: DimensionEditorProps) {
</div>
<EuiSpacer size="s" />
<div className="lnsIndexPatternDimensionEditor__section lnsIndexPatternDimensionEditor__section--shaded">
<EuiFormRow
data-test-subj="indexPattern-field-selection-row"
label={i18n.translate('xpack.lens.indexPattern.chooseField', {
defaultMessage: 'Choose a field',
})}
fullWidth
isInvalid={Boolean(incompatibleSelectedOperationType)}
error={
selectedColumn
? i18n.translate('xpack.lens.indexPattern.invalidOperationLabel', {
defaultMessage: 'To use this function, select a different field.',
})
: undefined
}
>
<FieldSelect
currentIndexPattern={currentIndexPattern}
existingFields={state.existingFields}
fieldMap={fieldMap}
operationFieldSupportMatrix={operationFieldSupportMatrix}
selectedColumnOperationType={selectedColumn && selectedColumn.operationType}
selectedColumnSourceField={
selectedColumn && hasField(selectedColumn) ? selectedColumn.sourceField : undefined
{!selectedColumn ||
selectedOperationDefinition?.input === 'field' ||
(incompatibleSelectedOperationType &&
operationDefinitionMap[incompatibleSelectedOperationType].input === 'field') ? (
<EuiFormRow
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reviewers: this is an indentation change, not a functional change inside this code.

data-test-subj="indexPattern-field-selection-row"
label={i18n.translate('xpack.lens.indexPattern.chooseField', {
defaultMessage: 'Choose a field',
})}
fullWidth
isInvalid={Boolean(incompatibleSelectedOperationType)}
error={
selectedColumn
? i18n.translate('xpack.lens.indexPattern.invalidOperationLabel', {
defaultMessage: 'To use this function, select a different field.',
})
: undefined
}
incompatibleSelectedOperationType={incompatibleSelectedOperationType}
onDeleteColumn={() => {
setState(
deleteColumn({
state,
layerId,
columnId,
})
);
}}
onChoose={(choice) => {
let column: IndexPatternColumn;
if (
!incompatibleSelectedOperationType &&
selectedColumn &&
'field' in choice &&
choice.operationType === selectedColumn.operationType
) {
// If we just changed the field are not in an error state and the operation didn't change,
// we use the operations onFieldChange method to calculate the new column.
column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]);
} else {
// Otherwise we'll use the buildColumn method to calculate a new column
const compatibleOperations =
('field' in choice &&
operationFieldSupportMatrix.operationByField[choice.field]) ||
[];
let operation;
if (compatibleOperations.length > 0) {
operation =
incompatibleSelectedOperationType &&
compatibleOperations.includes(incompatibleSelectedOperationType)
? incompatibleSelectedOperationType
: compatibleOperations[0];
} else if ('field' in choice) {
operation = choice.operationType;
}
column = buildColumn({
columns: props.state.layers[props.layerId].columns,
field: fieldMap[choice.field],
indexPattern: currentIndexPattern,
layerId: props.layerId,
suggestedPriority: props.suggestedPriority,
op: operation as OperationType,
previousColumn: selectedColumn,
});
>
<FieldSelect
currentIndexPattern={currentIndexPattern}
existingFields={state.existingFields}
fieldMap={fieldMap}
operationSupportMatrix={operationSupportMatrix}
selectedColumnOperationType={selectedColumn && selectedColumn.operationType}
selectedColumnSourceField={
selectedColumn && hasField(selectedColumn) ? selectedColumn.sourceField : undefined
}
incompatibleSelectedOperationType={incompatibleSelectedOperationType}
onDeleteColumn={() => {
setState(
deleteColumn({
state,
layerId,
columnId,
})
);
}}
onChoose={(choice) => {
let column: IndexPatternColumn;
if (
!incompatibleSelectedOperationType &&
selectedColumn &&
'field' in choice &&
choice.operationType === selectedColumn.operationType
) {
// If we just changed the field are not in an error state and the operation didn't change,
// we use the operations onFieldChange method to calculate the new column.
column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]);
} else {
// Otherwise we'll use the buildColumn method to calculate a new column
const compatibleOperations =
('field' in choice && operationSupportMatrix.operationByField[choice.field]) ||
[];
let operation;
if (compatibleOperations.length > 0) {
operation =
incompatibleSelectedOperationType &&
compatibleOperations.includes(incompatibleSelectedOperationType)
? incompatibleSelectedOperationType
: compatibleOperations[0];
} else if ('field' in choice) {
operation = choice.operationType;
}
column = buildColumn({
columns: props.state.layers[props.layerId].columns,
field: fieldMap[choice.field],
indexPattern: currentIndexPattern,
layerId: props.layerId,
suggestedPriority: props.suggestedPriority,
op: operation as OperationType,
previousColumn: selectedColumn,
});
}

setState(
changeColumn({
state,
layerId,
columnId,
newColumn: column,
keepParams: false,
})
);
setInvalidOperationType(null);
}}
/>
</EuiFormRow>
setState(
changeColumn({
state,
layerId,
columnId,
newColumn: column,
keepParams: false,
})
);
setInvalidOperationType(null);
}}
/>
</EuiFormRow>
) : null}

{!incompatibleSelectedOperationType && ParamEditor && (
{!incompatibleSelectedOperationType && selectedColumn && ParamEditor && (
<>
<EuiSpacer size="s" />
<ParamEditor
Expand Down
Loading