Skip to content

Commit

Permalink
use bound time fields for field information
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 committed Apr 12, 2021
1 parent c401211 commit dcc34e4
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 63 deletions.
56 changes: 40 additions & 16 deletions x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import './datapanel.scss';
import { uniq, groupBy } from 'lodash';
import { uniq, groupBy, isEqual } from 'lodash';
import React, { useState, memo, useCallback, useMemo, useRef, useEffect } from 'react';
import {
EuiFlexGroup,
Expand Down Expand Up @@ -57,6 +57,7 @@ import { LensFieldIcon } from './lens_field_icon';
import { ChangeIndexPattern } from './change_indexpattern';
import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public';
import { FieldGroups, FieldList } from './field_list';
import { getBoundTimeFields } from './utils';

function sortFields(fieldA: IndexPatternField, fieldB: IndexPatternField) {
return fieldA.displayName.localeCompare(fieldB.displayName, undefined, { sensitivity: 'base' });
Expand Down Expand Up @@ -141,21 +142,39 @@ export function IndexPatternDataPanel({
[setState]
);

const indexPatternList = uniq(
Object.values(state.layers)
.map((l) => l.indexPatternId)
.concat(currentIndexPatternId)
)
.filter((id) => !!indexPatterns[id])
.sort((a, b) => a.localeCompare(b))
.map((id) => ({
id,
title: indexPatterns[id].title,
timeFieldName: indexPatterns[id].timeFieldName,
fields: indexPatterns[id].fields,
hasRestrictions: indexPatterns[id].hasRestrictions,
}));
const indexPatternList = useMemo(
() =>
uniq(
Object.values(state.layers)
.map((l) => l.indexPatternId)
.concat(currentIndexPatternId)
)
.filter((id) => !!indexPatterns[id])
.sort((a, b) => a.localeCompare(b))
.map((id) => ({
id,
title: indexPatterns[id].title,
timeFieldNames: getBoundTimeFields(
Object.values(state.layers).find((layer) => layer.indexPatternId === id),
indexPatterns[id]
),
fields: indexPatterns[id].fields,
hasRestrictions: indexPatterns[id].hasRestrictions,
})),
[state.layers, indexPatterns, currentIndexPatternId]
);

const currentIndexPatternBoundTimeFields = indexPatternList.find(
(pattern) => pattern.id === currentIndexPatternId
)?.timeFieldNames;
const boundTimeFieldsRef = useRef<string[]>([]);
// only change the reference if the list actually changed
if (
currentIndexPatternBoundTimeFields &&
!isEqual(currentIndexPatternBoundTimeFields, boundTimeFieldsRef.current)
) {
boundTimeFieldsRef.current = currentIndexPatternBoundTimeFields;
}
const dslQuery = buildSafeEsQuery(
indexPatterns[currentIndexPatternId] as IIndexPattern,
query,
Expand Down Expand Up @@ -183,7 +202,7 @@ export function IndexPatternDataPanel({
filters,
dateRange.fromDate,
dateRange.toDate,
indexPatternList.map((x) => `${x.title}:${x.timeFieldName}`).join(','),
indexPatternList.map((x) => `${x.title}:${x.timeFieldNames.join(',')}`).join(','),
state.indexPatterns,
]}
/>
Expand Down Expand Up @@ -232,6 +251,7 @@ export function IndexPatternDataPanel({
existenceFetchFailed={state.existenceFetchFailed}
dropOntoWorkspace={dropOntoWorkspace}
hasSuggestionForField={hasSuggestionForField}
boundTimeFields={boundTimeFieldsRef.current}
/>
)}
</>
Expand Down Expand Up @@ -284,6 +304,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
charts,
dropOntoWorkspace,
hasSuggestionForField,
boundTimeFields,
}: Omit<DatasourceDataPanelProps, 'state' | 'setState' | 'showNoDataPopover' | 'core'> & {
data: DataPublicPluginStart;
core: CoreStart;
Expand All @@ -297,6 +318,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
charts: ChartsPluginSetup;
indexPatternFieldEditor: IndexPatternFieldEditorStart;
existenceFetchFailed?: boolean;
boundTimeFields: string[];
}) {
const [localState, setLocalState] = useState<DataPanelState>({
nameFilter: '',
Expand Down Expand Up @@ -568,6 +590,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
query,
filters,
chartsThemeService: charts.theme,
boundTimeFields,
}),
[
core,
Expand All @@ -576,6 +599,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
dateRange,
query,
filters,
boundTimeFields,
localState.nameFilter,
charts.theme,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export interface FieldItemProps {
editField?: (name: string) => void;
removeField?: (name: string) => void;
hasSuggestionForField: DatasourceDataPanelProps['hasSuggestionForField'];
boundTimeFields: string[];
}

interface State {
Expand Down Expand Up @@ -102,6 +103,7 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) {
exists,
query,
dateRange,
boundTimeFields,
filters,
hideDetails,
itemIndex,
Expand Down Expand Up @@ -167,6 +169,7 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) {
fromDate: dateRange.fromDate,
toDate: dateRange.toDate,
fieldName: field.name,
timeFieldNames: boundTimeFields,
}),
})
.then((results: FieldStatsResponse<string | number>) => {
Expand Down
7 changes: 2 additions & 5 deletions x-pack/plugins/lens/public/indexpattern_datasource/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ export async function syncExistingFields({
id: string;
title: string;
fields: IndexPatternField[];
timeFieldName?: string | null;
timeFieldNames: string[];
hasRestrictions: boolean;
}>;
fetchJson: HttpSetup['post'];
Expand All @@ -419,12 +419,9 @@ export async function syncExistingFields({
dslQuery,
fromDate: dateRange.fromDate,
toDate: dateRange.toDate,
timeFieldNames: pattern.timeFieldNames,
};

if (pattern.timeFieldName) {
body.timeFieldName = pattern.timeFieldName;
}

return fetchJson(`${BASE_API_URL}/existing_fields/${pattern.id}`, {
body: JSON.stringify(body),
}) as Promise<ExistingFields>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { IndexPatternColumn } from './indexpattern';
import { operationDefinitionMap } from './operations';
import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types';
import { OriginalColumn } from './rename_columns';
import { dateHistogramOperation } from './operations/definitions';
import { getBoundTimeFields } from './utils';

function getExpressionForLayer(
layer: IndexPatternLayer,
Expand Down Expand Up @@ -196,11 +196,7 @@ function getExpressionForLayer(
}
);

const allDateHistogramFields = Object.values(columns)
.map((column) =>
column.operationType === dateHistogramOperation.type ? column.sourceField : null
)
.filter((field): field is string => Boolean(field));
const boundTimeFields = getBoundTimeFields(layer, indexPattern);

return {
type: 'expression',
Expand All @@ -215,7 +211,7 @@ function getExpressionForLayer(
aggs,
metricsAtAllLevels: false,
partialRows: false,
timeFields: allDateHistogramFields,
timeFields: boundTimeFields,
}).toAst(),
{
type: 'function',
Expand Down
23 changes: 23 additions & 0 deletions x-pack/plugins/lens/public/indexpattern_datasource/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { uniq } from 'lodash';
import { DataType } from '../types';
import { IndexPattern, IndexPatternLayer, DraggedField } from './types';
import type {
Expand All @@ -15,6 +16,7 @@ import type {
import { operationDefinitionMap, IndexPatternColumn } from './operations';

import { getInvalidFieldMessage } from './operations/definitions/helpers';
import { dateHistogramOperation } from './operations/definitions';

/**
* Normalizes the specified operation type. (e.g. document operations
Expand Down Expand Up @@ -46,6 +48,27 @@ export function isDraggedField(fieldCandidate: unknown): fieldCandidate is Dragg
);
}

export function getBoundTimeFields(
layer: IndexPatternLayer | undefined,
indexPattern: { timeFieldName?: string | null }
) {
const allDateHistogramFields = Object.values(layer?.columns || {})
.map((column) =>
column.operationType === dateHistogramOperation.type ? column.sourceField : null
)
.filter((field): field is string => Boolean(field));

if (allDateHistogramFields.length > 0) {
return uniq(allDateHistogramFields).sort();
}

if (indexPattern.timeFieldName) {
return [indexPattern.timeFieldName];
}

return [];
}

export function isColumnInvalid(
layer: IndexPatternLayer,
columnId: string,
Expand Down
42 changes: 21 additions & 21 deletions x-pack/plugins/lens/server/routes/existing_fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export async function existingFieldsRoute(setup: CoreSetup<PluginStartContract>,
dslQuery: schema.object({}, { unknowns: 'allow' }),
fromDate: schema.maybe(schema.string()),
toDate: schema.maybe(schema.string()),
timeFieldName: schema.maybe(schema.string()),
timeFieldNames: schema.arrayOf(schema.string()),
}),
},
},
Expand Down Expand Up @@ -94,15 +94,15 @@ async function fetchFieldExistence({
dslQuery = { match_all: {} },
fromDate,
toDate,
timeFieldName,
timeFieldNames,
}: {
indexPatternId: string;
context: RequestHandlerContext;
indexPatternsService: IndexPatternsService;
dslQuery: object;
fromDate?: string;
toDate?: string;
timeFieldName?: string;
timeFieldNames: string[];
}) {
const metaFields: string[] = await context.core.uiSettings.client.get(UI_SETTINGS.META_FIELDS);
const indexPattern = await indexPatternsService.get(indexPatternId);
Expand All @@ -114,7 +114,7 @@ async function fetchFieldExistence({
dslQuery,
client: context.core.elasticsearch.client.asCurrentUser,
index: indexPattern.title,
timeFieldName: timeFieldName || indexPattern.timeFieldName,
timeFieldNames,
fields,
});

Expand Down Expand Up @@ -146,33 +146,30 @@ async function fetchIndexPatternStats({
client,
index,
dslQuery,
timeFieldName,
timeFieldNames,
fromDate,
toDate,
fields,
}: {
client: ElasticsearchClient;
index: string;
dslQuery: object;
timeFieldName?: string;
timeFieldNames: string[];
fromDate?: string;
toDate?: string;
fields: Field[];
}) {
const filter =
timeFieldName && fromDate && toDate
? [
{
range: {
[timeFieldName]: {
gte: fromDate,
lte: toDate,
},
},
},
dslQuery,
]
: [dslQuery];
const filter = [
...timeFieldNames.map((timeFieldName) => ({
range: {
[timeFieldName]: {
gte: fromDate,
lte: toDate,
},
},
})),
dslQuery,
];

const query = {
bool: {
Expand All @@ -187,7 +184,10 @@ async function fetchIndexPatternStats({
body: {
size: SAMPLE_SIZE,
query,
sort: timeFieldName && fromDate && toDate ? [{ [timeFieldName]: 'desc' }] : [],
sort:
fromDate && toDate
? timeFieldNames.map((timeFieldName) => ({ [timeFieldName]: 'desc' }))
: [],
fields: ['*'],
_source: false,
runtime_mappings: runtimeFields.reduce((acc, field) => {
Expand Down
26 changes: 12 additions & 14 deletions x-pack/plugins/lens/server/routes/field_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ export async function initFieldsRoute(setup: CoreSetup<PluginStartContract>) {
fromDate: schema.string(),
toDate: schema.string(),
fieldName: schema.string(),
timeFieldNames: schema.arrayOf(schema.string()),
},
{ unknowns: 'allow' }
),
},
},
async (context, req, res) => {
const requestClient = context.core.elasticsearch.client.asCurrentUser;
const { fromDate, toDate, fieldName, dslQuery } = req.body;
const { fromDate, toDate, fieldName, dslQuery, timeFieldNames } = req.body;

const [{ savedObjects, elasticsearch }, { data }] = await setup.getStartServices();
const savedObjectsClient = savedObjects.getScopedClient(req);
Expand All @@ -51,26 +52,23 @@ export async function initFieldsRoute(setup: CoreSetup<PluginStartContract>) {
try {
const indexPattern = await indexPatternsService.get(req.params.indexPatternId);

const timeFieldName = indexPattern.timeFieldName;
const field = indexPattern.fields.find((f) => f.name === fieldName);

if (!field) {
throw new Error(`Field {fieldName} not found in index pattern ${indexPattern.title}`);
}

const filter = timeFieldName
? [
{
range: {
[timeFieldName]: {
gte: fromDate,
lte: toDate,
},
},
const filter = [
...timeFieldNames.map((timeFieldName) => ({
range: {
[timeFieldName]: {
gte: fromDate,
lte: toDate,
},
dslQuery,
]
: [dslQuery];
},
})),
dslQuery,
];

const query = {
bool: {
Expand Down

0 comments on commit dcc34e4

Please sign in to comment.