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] Provide single-value functions to show the "Last" value of some field #83437

Merged
merged 34 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e2354f5
feat: last value sketch
mbondyra Nov 16, 2020
6a6dd4e
feat: rollup indices
mbondyra Nov 17, 2020
f807858
added disabledStatus
mbondyra Nov 18, 2020
4555d51
update old tests
mbondyra Nov 18, 2020
2e3708f
tests added
mbondyra Nov 18, 2020
1f7b713
Merge branch 'master' into lens/last_value
kibanamachine Nov 18, 2020
df8c5ee
fix i18n message
mbondyra Nov 18, 2020
0c14e4c
cr
mbondyra Nov 20, 2020
dba38a5
(experimental) don't add icon
mbondyra Nov 20, 2020
1357868
fix transferable
mbondyra Nov 23, 2020
b6f3be9
Merge branch 'master' into lens/last_value
kibanamachine Nov 23, 2020
3c76ab4
error handling, tests in progress
mbondyra Nov 23, 2020
7ee756f
tests for hasInvalidReferences
mbondyra Nov 23, 2020
3f1991e
change name
mbondyra Nov 23, 2020
de88213
correct displayName
mbondyra Nov 23, 2020
a4b76d6
test corrected last value
mbondyra Nov 23, 2020
86ee016
fix tests and types
mbondyra Nov 24, 2020
3455a7d
no need to make a function obligatory
mbondyra Nov 24, 2020
b54c73d
hasInvalidreferenced not necessary
mbondyra Nov 24, 2020
8b90db7
eslint
mbondyra Nov 24, 2020
71e8264
addded warnings for pie and xy
mbondyra Nov 24, 2020
3e4b5f7
Update x-pack/plugins/lens/public/indexpattern_datasource/dimension_p…
mbondyra Nov 24, 2020
b3218a6
Merge branch 'master' into lens/last_value
kibanamachine Nov 25, 2020
5be70e4
Merge branch 'lens/accessibility-suggestions-name-focus' into lens/la…
mbondyra Nov 26, 2020
2f844b8
refactor hasInvalidReferences to getErrorMessage
mbondyra Nov 26, 2020
85f3503
ts
mbondyra Nov 26, 2020
f79cafa
Merge branch 'master' into lens/last_value
kibanamachine Nov 30, 2020
808bc29
copy change to more human
mbondyra Nov 30, 2020
8f1ea88
Merge commit '67564b9776abd608434c95375968598bfa082849' into lens/las…
mbondyra Dec 1, 2020
15ba028
design changes
mbondyra Dec 1, 2020
b42d0c5
designs
mbondyra Dec 1, 2020
af5f00e
design
mbondyra Dec 2, 2020
f84c9b5
remove sortOrder
mbondyra Dec 2, 2020
51e0830
Merge commit 'c73de2677337e4054954c068744f8b29ab3ce29c' into lens/las…
mbondyra Dec 2, 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 @@ -45,21 +45,22 @@ export const IndexPatternDimensionTriggerComponent = function IndexPatternDimens
) {
const layerId = props.layerId;
const layer = props.state.layers[layerId];
const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] || null;
const currentIndexPattern = props.state.indexPatterns[layer.indexPatternId];
const { columnId, uniqueLabel } = props;

const currentFieldIsInvalid = useMemo(
() => isColumnInvalid(selectedColumn, currentIndexPattern),
[selectedColumn, currentIndexPattern]
const currentColumnHasErrors = useMemo(
() => isColumnInvalid(layer, columnId, currentIndexPattern),
[layer, columnId, currentIndexPattern]
);

const { columnId, uniqueLabel } = props;
const selectedColumn: IndexPatternColumn | null = layer.columns[props.columnId] || null;

if (!selectedColumn) {
return null;
}
const formattedLabel = wrapOnDot(uniqueLabel);

if (currentFieldIsInvalid) {
if (currentColumnHasErrors) {
return (
<EuiToolTip
content={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const {
getOperationResultType,
operationDefinitionMap,
operationDefinitions,
fieldIsInvalid,
getInvalidFieldMessage,
} = actualOperations;

export const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import { OperationDefinition } from './index';
import { FormattedIndexPatternColumn, FieldBasedIndexPatternColumn } from './column_types';

import { fieldIsInvalid } from '.';
import { getInvalidFieldMessage } from './helpers';

const supportedTypes = new Set(['string', 'boolean', 'number', 'ip', 'date']);

Expand Down Expand Up @@ -44,7 +44,8 @@ export const cardinalityOperation: OperationDefinition<CardinalityIndexPatternCo
return { dataType: 'number', isBucketed: IS_BUCKETED, scale: SCALE };
}
},
hasInvalidReferences: fieldIsInvalid,
getErrorMessage: (layer, columnId, indexPattern) =>
getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern),
isTransferable: (column, newIndexPattern) => {
const newField = newIndexPattern.getFieldByName(column.sourceField);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import { OperationDefinition } from './index';
import { FormattedIndexPatternColumn, FieldBasedIndexPatternColumn } from './column_types';
import { IndexPatternField } from '../../types';
import { fieldIsInvalid } from '.';
import { getInvalidFieldMessage } from './helpers';

const countLabel = i18n.translate('xpack.lens.indexPattern.countOf', {
defaultMessage: 'Count of records',
Expand All @@ -26,7 +26,8 @@ export const countOperation: OperationDefinition<CountIndexPatternColumn, 'field
defaultMessage: 'Count',
}),
input: 'field',
hasInvalidReferences: fieldIsInvalid,
getErrorMessage: (layer, columnId, indexPattern) =>
getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern),
onFieldChange: (oldColumn, field) => {
return {
...oldColumn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { updateColumnParam } from '../layer_helpers';
import { OperationDefinition } from './index';
import { FieldBasedIndexPatternColumn } from './column_types';
import { IndexPatternAggRestrictions, search } from '../../../../../../../src/plugins/data/public';
import { fieldIsInvalid } from '.';
import { getInvalidFieldMessage } from './helpers';

const { isValidInterval } = search.aggs;
const autoInterval = 'auto';
Expand All @@ -47,7 +47,8 @@ export const dateHistogramOperation: OperationDefinition<
}),
input: 'field',
priority: 5, // Highest priority level used
hasInvalidReferences: fieldIsInvalid,
getErrorMessage: (layer, columnId, indexPattern) =>
getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern),
getPossibleOperationForField: ({ aggregationRestrictions, aggregatable, type }) => {
if (
type === 'date' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { useRef } from 'react';
import useDebounce from 'react-use/lib/useDebounce';
import { i18n } from '@kbn/i18n';
import { operationDefinitionMap } from '.';
import { FieldBasedIndexPatternColumn } from './column_types';
import { IndexPattern } from '../../types';
Expand All @@ -32,12 +33,18 @@ export const useDebounceWithOptions = (
);
};

export function fieldIsInvalid(column: FieldBasedIndexPatternColumn, indexPattern: IndexPattern) {
export function getInvalidFieldMessage(
column: FieldBasedIndexPatternColumn,
indexPattern?: IndexPattern
) {
if (!indexPattern) {
return;
}
const { sourceField, operationType } = column;
const field = sourceField ? indexPattern.getFieldByName(sourceField) : undefined;
const operationDefinition = operationType && operationDefinitionMap[operationType];

return Boolean(
const isInvalid = Boolean(
sourceField &&
operationDefinition &&
!(
Expand All @@ -46,4 +53,12 @@ export function fieldIsInvalid(column: FieldBasedIndexPatternColumn, indexPatter
operationDefinition.getPossibleOperationForField(field) !== undefined
)
);
return isInvalid
? [
i18n.translate('xpack.lens.indexPattern.invalidSourceField', {
defaultMessage: 'Field {invalidField} has an invalid reference',
values: { invalidField: sourceField },
}),
]
: undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,16 @@ interface BaseOperationDefinitionProps<C extends BaseIndexPatternColumn> {
*/
getDisabledStatus?: (indexPattern: IndexPattern) => string | undefined;
/**
* Returns true if column contains invalid references
* Validate that the operation has the right preconditions in the state. For example:
*
* - Requires a date histogram operation somewhere before it in order
* - Missing references
*/
hasInvalidReferences?: (column: C, indexPattern: IndexPattern) => boolean;
getErrorMessage?: (
layer: IndexPatternLayer,
columnId: string,
indexPattern?: IndexPattern
) => string[] | undefined;
}

interface BaseBuildColumnArgs {
Expand Down Expand Up @@ -244,6 +251,17 @@ interface FieldBasedOperationDefinition<C extends BaseIndexPatternColumn> {
* together with the agg configs returned from other columns.
*/
toEsAggsConfig: (column: C, columnId: string, indexPattern: IndexPattern) => unknown;
/**
* Validate that the operation has the right preconditions in the state. For example:
*
* - Requires a date histogram operation somewhere before it in order
* - Missing references
*/
getErrorMessage: (
mbondyra marked this conversation as resolved.
Show resolved Hide resolved
layer: IndexPatternLayer,
columnId: string,
indexPattern?: IndexPattern
) => string[] | undefined;
}

export interface RequiredReference {
Expand Down Expand Up @@ -296,13 +314,6 @@ interface FullReferenceOperationDefinition<C extends BaseIndexPatternColumn> {
columnId: string,
indexPattern: IndexPattern
) => ExpressionFunctionAST[];
/**
* Validate that the operation has the right preconditions in the state. For example:
*
* - Requires a date histogram operation somewhere before it in order
* - Missing references
*/
getErrorMessage?: (layer: IndexPatternLayer, columnId: string) => string[] | undefined;
}

interface OperationDefinitionMap<C extends BaseIndexPatternColumn> {
Expand Down Expand Up @@ -359,19 +370,3 @@ export const operationDefinitionMap: Record<
(definitionMap, definition) => ({ ...definitionMap, [definition.type]: definition }),
{}
);

export function fieldIsInvalid(column: FieldBasedIndexPatternColumn, indexPattern: IndexPattern) {
const { sourceField, operationType } = column;
const field = sourceField ? indexPattern.getFieldByName(sourceField) : undefined;
const operationDefinition = operationType && operationDefinitionMap[operationType];

return Boolean(
sourceField &&
operationDefinition &&
!(
field &&
operationDefinition?.input === 'field' &&
operationDefinition.getPossibleOperationForField(field) !== undefined
)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { dataPluginMock } from '../../../../../../../src/plugins/data/public/moc
import { createMockedIndexPattern } from '../../mocks';
import { LastValueIndexPatternColumn } from './last_value';
import { lastValueOperation } from './index';
import { IndexPatternPrivateState, IndexPattern } from '../../types';
import { IndexPatternPrivateState, IndexPattern, IndexPatternLayer } from '../../types';

const defaultProps = {
storage: {} as IStorageWrapper,
Expand Down Expand Up @@ -162,7 +162,7 @@ describe('last_value', () => {
).toEqual({
dataType: 'boolean',
isBucketed: false,
scale: 'ordinal',
scale: 'ratio',
});

expect(
Expand All @@ -176,7 +176,7 @@ describe('last_value', () => {
).toEqual({
dataType: 'ip',
isBucketed: false,
scale: 'ordinal',
scale: 'ratio',
});
});

Expand Down Expand Up @@ -483,47 +483,77 @@ describe('last_value', () => {
});
});

describe('hasInvalidReferences', () => {
describe('getErrorMessage', () => {
let indexPattern: IndexPattern;
let column: LastValueIndexPatternColumn;
let layer: IndexPatternLayer;
beforeEach(() => {
indexPattern = createMockedIndexPattern();
column = {
dataType: 'boolean',
isBucketed: false,
label: 'Last value of test',
operationType: 'last_value',
params: { sortField: 'timestamp', sortOrder: 'desc' },
scale: 'ratio',
sourceField: 'bytes',
layer = {
columns: {
col1: {
dataType: 'boolean',
isBucketed: false,
label: 'Last value of test',
operationType: 'last_value',
params: { sortField: 'timestamp', sortOrder: 'desc' },
scale: 'ratio',
sourceField: 'bytes',
},
},
columnOrder: [],
indexPatternId: '',
};
});
it('returns false if sourceField exists and sortField is of type date ', () => {
expect(lastValueOperation.hasInvalidReferences!(column, indexPattern)).toEqual(false);
it('returns undefined if sourceField exists and sortField is of type date ', () => {
expect(lastValueOperation.getErrorMessage!(layer, 'col1', indexPattern)).toEqual(undefined);
});
it('returns true if the sourceField does not exist in index pattern', () => {
expect(
lastValueOperation.hasInvalidReferences!(
{ ...column, sourceField: 'notExisting' },
indexPattern
)
).toEqual(true);
it('shows error message if the sourceField does not exist in index pattern', () => {
layer = {
...layer,
columns: {
col1: {
...layer.columns.col1,
sourceField: 'notExisting',
} as LastValueIndexPatternColumn,
},
};
expect(lastValueOperation.getErrorMessage!(layer, 'col1', indexPattern)).toEqual([
'Field notExisting has an invalid reference',
]);
});
it('returns true if the sortField does not exist in index pattern', () => {
expect(
lastValueOperation.hasInvalidReferences!(
{ ...column, params: { ...column.params, sortField: 'notExisting' } },
indexPattern
)
).toEqual(true);
it('shows error message if the sortField does not exist in index pattern', () => {
layer = {
...layer,
columns: {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
sortField: 'notExisting',
},
} as LastValueIndexPatternColumn,
},
};
expect(lastValueOperation.getErrorMessage!(layer, 'col1', indexPattern)).toEqual([
'Field notExisting has an invalid reference',
]);
});
it('returns true if the sortField is not date', () => {
expect(
lastValueOperation.hasInvalidReferences!(
{ ...column, params: { ...column.params, sortField: 'bytes' } },
indexPattern
)
).toEqual(true);
it('shows error message if the sortField is not date', () => {
layer = {
...layer,
columns: {
col1: {
...layer.columns.col1,
params: {
...layer.columns.col1.params,
sortField: 'bytes',
},
} as LastValueIndexPatternColumn,
},
};
expect(lastValueOperation.getErrorMessage!(layer, 'col1', indexPattern)).toEqual([
'Field bytes has an invalid reference',
]);
});
});
});
Loading