mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[ML] Refactor imports using 'elasticsearch' to '@elastic/elasticsearch'. Extend 'isPopulatedOjbect()'. (#95651)
- Gets rid of imports from 'elasticsearch' and replaces them with '@elastic/elasticsearch'. - Extends isPopulatedObject() to allow an optional array of attributes to check if they exist. Allows us to get rid of the manual and inconsistent usages of hasOwnProperty().
This commit is contained in:
parent
07a3f9eb8d
commit
a1c36e7a06
50 changed files with 383 additions and 300 deletions
|
@ -5,9 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export { HitsTotalRelation, SearchResponse7, HITS_TOTAL_RELATION } from './types/es_client';
|
||||
export { ES_CLIENT_TOTAL_HITS_RELATION } from './types/es_client';
|
||||
export { ChartData } from './types/field_histograms';
|
||||
export { ANOMALY_SEVERITY, ANOMALY_THRESHOLD, SEVERITY_COLORS } from './constants/anomalies';
|
||||
export { getSeverityColor, getSeverityType } from './util/anomaly_utils';
|
||||
export { isPopulatedObject } from './util/object_utils';
|
||||
export { isRuntimeMappings } from './util/runtime_field_utils';
|
||||
export { composeValidators, patternValidator } from './util/validators';
|
||||
export { extractErrorMessage } from './util/errors';
|
||||
|
|
|
@ -5,33 +5,24 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SearchResponse, ShardsResponse } from 'elasticsearch';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { buildEsQuery } from '../../../../../src/plugins/data/common/es_query/es_query';
|
||||
import type { DslQuery } from '../../../../../src/plugins/data/common/es_query/kuery';
|
||||
import type { JsonObject } from '../../../../../src/plugins/kibana_utils/common';
|
||||
|
||||
export const HITS_TOTAL_RELATION = {
|
||||
import { isPopulatedObject } from '../util/object_utils';
|
||||
|
||||
export function isMultiBucketAggregate(arg: unknown): arg is estypes.MultiBucketAggregate {
|
||||
return isPopulatedObject(arg, ['buckets']);
|
||||
}
|
||||
|
||||
export const ES_CLIENT_TOTAL_HITS_RELATION: Record<
|
||||
Uppercase<estypes.TotalHitsRelation>,
|
||||
estypes.TotalHitsRelation
|
||||
> = {
|
||||
EQ: 'eq',
|
||||
GTE: 'gte',
|
||||
} as const;
|
||||
export type HitsTotalRelation = typeof HITS_TOTAL_RELATION[keyof typeof HITS_TOTAL_RELATION];
|
||||
|
||||
// The types specified in `@types/elasticsearch` are out of date and still have `total: number`.
|
||||
interface SearchResponse7Hits<T> {
|
||||
hits: SearchResponse<T>['hits']['hits'];
|
||||
max_score: number;
|
||||
total: {
|
||||
value: number;
|
||||
relation: HitsTotalRelation;
|
||||
};
|
||||
}
|
||||
export interface SearchResponse7<T = any> {
|
||||
took: number;
|
||||
timed_out: boolean;
|
||||
_scroll_id?: string;
|
||||
_shards: ShardsResponse;
|
||||
hits: SearchResponse7Hits<T>;
|
||||
aggregations?: any;
|
||||
}
|
||||
|
||||
export type InfluencersFilterQuery = ReturnType<typeof buildEsQuery> | DslQuery | JsonObject;
|
||||
|
|
|
@ -88,15 +88,11 @@ export function isRegressionTotalFeatureImportance(
|
|||
export function isClassificationFeatureImportanceBaseline(
|
||||
baselineData: any
|
||||
): baselineData is ClassificationFeatureImportanceBaseline {
|
||||
return (
|
||||
isPopulatedObject(baselineData) &&
|
||||
baselineData.hasOwnProperty('classes') &&
|
||||
Array.isArray(baselineData.classes)
|
||||
);
|
||||
return isPopulatedObject(baselineData, ['classes']) && Array.isArray(baselineData.classes);
|
||||
}
|
||||
|
||||
export function isRegressionFeatureImportanceBaseline(
|
||||
baselineData: any
|
||||
): baselineData is RegressionFeatureImportanceBaseline {
|
||||
return isPopulatedObject(baselineData) && baselineData.hasOwnProperty('baseline');
|
||||
return isPopulatedObject(baselineData, ['baseline']);
|
||||
}
|
||||
|
|
50
x-pack/plugins/ml/common/util/object_utils.test.ts
Normal file
50
x-pack/plugins/ml/common/util/object_utils.test.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isPopulatedObject } from './object_utils';
|
||||
|
||||
describe('object_utils', () => {
|
||||
describe('isPopulatedObject()', () => {
|
||||
it('does not allow numbers', () => {
|
||||
expect(isPopulatedObject(0)).toBe(false);
|
||||
});
|
||||
it('does not allow strings', () => {
|
||||
expect(isPopulatedObject('')).toBe(false);
|
||||
});
|
||||
it('does not allow null', () => {
|
||||
expect(isPopulatedObject(null)).toBe(false);
|
||||
});
|
||||
it('does not allow an empty object', () => {
|
||||
expect(isPopulatedObject({})).toBe(false);
|
||||
});
|
||||
it('allows an object with an attribute', () => {
|
||||
expect(isPopulatedObject({ attribute: 'value' })).toBe(true);
|
||||
});
|
||||
it('does not allow an object with a non-existing required attribute', () => {
|
||||
expect(isPopulatedObject({ attribute: 'value' }, ['otherAttribute'])).toBe(false);
|
||||
});
|
||||
it('allows an object with an existing required attribute', () => {
|
||||
expect(isPopulatedObject({ attribute: 'value' }, ['attribute'])).toBe(true);
|
||||
});
|
||||
it('allows an object with two existing required attributes', () => {
|
||||
expect(
|
||||
isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [
|
||||
'attribute1',
|
||||
'attribute2',
|
||||
])
|
||||
).toBe(true);
|
||||
});
|
||||
it('does not allow an object with two required attributes where one does not exist', () => {
|
||||
expect(
|
||||
isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [
|
||||
'attribute1',
|
||||
'otherAttribute',
|
||||
])
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,6 +5,32 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export const isPopulatedObject = <T = Record<string, any>>(arg: any): arg is T => {
|
||||
return typeof arg === 'object' && arg !== null && Object.keys(arg).length > 0;
|
||||
/*
|
||||
* A type guard to check record like object structures.
|
||||
*
|
||||
* Examples:
|
||||
* - `isPopulatedObject({...})`
|
||||
* Limits type to Record<string, unknown>
|
||||
*
|
||||
* - `isPopulatedObject({...}, ['attribute'])`
|
||||
* Limits type to Record<'attribute', unknown>
|
||||
*
|
||||
* - `isPopulatedObject<keyof MyInterface>({...})`
|
||||
* Limits type to a record with keys of the given interface.
|
||||
* Note that you might want to add keys from the interface to the
|
||||
* array of requiredAttributes to satisfy runtime requirements.
|
||||
* Otherwise you'd just satisfy TS requirements but might still
|
||||
* run into runtime issues.
|
||||
*/
|
||||
export const isPopulatedObject = <U extends string = string>(
|
||||
arg: unknown,
|
||||
requiredAttributes: U[] = []
|
||||
): arg is Record<U, unknown> => {
|
||||
return (
|
||||
typeof arg === 'object' &&
|
||||
arg !== null &&
|
||||
Object.keys(arg).length > 0 &&
|
||||
(requiredAttributes.length === 0 ||
|
||||
requiredAttributes.every((d) => ({}.hasOwnProperty.call(arg, d))))
|
||||
);
|
||||
};
|
||||
|
|
102
x-pack/plugins/ml/common/util/runtime_field_utils.test.ts
Normal file
102
x-pack/plugins/ml/common/util/runtime_field_utils.test.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isRuntimeField, isRuntimeMappings } from './runtime_field_utils';
|
||||
|
||||
describe('ML runtime field utils', () => {
|
||||
describe('isRuntimeField()', () => {
|
||||
it('does not allow numbers', () => {
|
||||
expect(isRuntimeField(1)).toBe(false);
|
||||
});
|
||||
it('does not allow null', () => {
|
||||
expect(isRuntimeField(null)).toBe(false);
|
||||
});
|
||||
it('does not allow arrays', () => {
|
||||
expect(isRuntimeField([])).toBe(false);
|
||||
});
|
||||
it('does not allow empty objects', () => {
|
||||
expect(isRuntimeField({})).toBe(false);
|
||||
});
|
||||
it('does not allow objects with non-matching attributes', () => {
|
||||
expect(isRuntimeField({ someAttribute: 'someValue' })).toBe(false);
|
||||
expect(isRuntimeField({ type: 'wrong-type' })).toBe(false);
|
||||
expect(isRuntimeField({ type: 'keyword', someAttribute: 'some value' })).toBe(false);
|
||||
});
|
||||
it('allows objects with type attribute only', () => {
|
||||
expect(isRuntimeField({ type: 'keyword' })).toBe(true);
|
||||
});
|
||||
it('allows objects with both type and script attributes', () => {
|
||||
expect(isRuntimeField({ type: 'keyword', script: 'some script' })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRuntimeMappings()', () => {
|
||||
it('does not allow numbers', () => {
|
||||
expect(isRuntimeMappings(1)).toBe(false);
|
||||
});
|
||||
it('does not allow null', () => {
|
||||
expect(isRuntimeMappings(null)).toBe(false);
|
||||
});
|
||||
it('does not allow arrays', () => {
|
||||
expect(isRuntimeMappings([])).toBe(false);
|
||||
});
|
||||
it('does not allow empty objects', () => {
|
||||
expect(isRuntimeMappings({})).toBe(false);
|
||||
});
|
||||
it('does not allow objects with non-object inner structure', () => {
|
||||
expect(isRuntimeMappings({ someAttribute: 'someValue' })).toBe(false);
|
||||
});
|
||||
it('does not allow objects with objects with unsupported inner structure', () => {
|
||||
expect(isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: 'someValue' })).toBe(
|
||||
false
|
||||
);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName1: { type: 'keyword' },
|
||||
fieldName2: { type: 'keyword', someAttribute: 'some value' },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: 1234 },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { someAttribute: 'some value' } },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { source: 1234 } },
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('allows object with most basic runtime mapping', () => {
|
||||
expect(isRuntimeMappings({ fieldName: { type: 'keyword' } })).toBe(true);
|
||||
});
|
||||
it('allows object with multiple most basic runtime mappings', () => {
|
||||
expect(
|
||||
isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: { type: 'keyword' } })
|
||||
).toBe(true);
|
||||
});
|
||||
it('allows object with runtime mappings including scripts', () => {
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName1: { type: 'keyword' },
|
||||
fieldName2: { type: 'keyword', script: 'some script as script' },
|
||||
})
|
||||
).toBe(true);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { source: 'some script as source' } },
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -9,19 +9,18 @@ import { isPopulatedObject } from './object_utils';
|
|||
import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common';
|
||||
import type { RuntimeField, RuntimeMappings } from '../types/fields';
|
||||
|
||||
type RuntimeType = typeof RUNTIME_FIELD_TYPES[number];
|
||||
|
||||
export function isRuntimeField(arg: unknown): arg is RuntimeField {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
((Object.keys(arg).length === 1 && arg.hasOwnProperty('type')) ||
|
||||
(Object.keys(arg).length === 2 &&
|
||||
arg.hasOwnProperty('type') &&
|
||||
arg.hasOwnProperty('script') &&
|
||||
((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) ||
|
||||
(isPopulatedObject(arg, ['type', 'script']) &&
|
||||
Object.keys(arg).length === 2 &&
|
||||
(typeof arg.script === 'string' ||
|
||||
(isPopulatedObject(arg.script) &&
|
||||
(isPopulatedObject(arg.script, ['source']) &&
|
||||
Object.keys(arg.script).length === 1 &&
|
||||
arg.script.hasOwnProperty('source') &&
|
||||
typeof arg.script.source === 'string')))) &&
|
||||
RUNTIME_FIELD_TYPES.includes(arg.type)
|
||||
RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import {
|
||||
EuiDataGridCellValueElementProps,
|
||||
EuiDataGridPaginationProps,
|
||||
|
@ -15,7 +16,6 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import { Dictionary } from '../../../../common/types/common';
|
||||
import { HitsTotalRelation } from '../../../../common/types/es_client';
|
||||
import { ChartData } from '../../../../common/types/field_histograms';
|
||||
|
||||
import { INDEX_STATUS } from '../../data_frame_analytics/common/analytics';
|
||||
|
@ -27,7 +27,7 @@ export type DataGridItem = Record<string, any>;
|
|||
|
||||
// `undefined` is used to indicate a non-initialized state.
|
||||
export type ChartsVisible = boolean | undefined;
|
||||
export type RowCountRelation = HitsTotalRelation | undefined;
|
||||
export type RowCountRelation = estypes.TotalHitsRelation | undefined;
|
||||
|
||||
export type IndexPagination = Pick<EuiDataGridPaginationProps, 'pageIndex' | 'pageSize'>;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
|
||||
import { EuiDataGridSorting, EuiDataGridColumn } from '@elastic/eui';
|
||||
|
||||
import { HITS_TOTAL_RELATION } from '../../../../common/types/es_client';
|
||||
import { ES_CLIENT_TOTAL_HITS_RELATION } from '../../../../common/types/es_client';
|
||||
import { ChartData } from '../../../../common/types/field_histograms';
|
||||
|
||||
import { INDEX_STATUS } from '../../data_frame_analytics/common';
|
||||
|
@ -146,7 +146,7 @@ export const useDataGrid = (
|
|||
if (chartsVisible === undefined && rowCount > 0 && rowCountRelation !== undefined) {
|
||||
setChartsVisible(
|
||||
rowCount <= COLUMN_CHART_DEFAULT_VISIBILITY_ROWS_THRESHOLED &&
|
||||
rowCountRelation !== HITS_TOTAL_RELATION.GTE
|
||||
rowCountRelation !== ES_CLIENT_TOTAL_HITS_RELATION.GTE
|
||||
);
|
||||
}
|
||||
}, [chartsVisible, rowCount, rowCountRelation]);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import React, { useMemo, useEffect, useState, FC } from 'react';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import {
|
||||
EuiCallOut,
|
||||
EuiComboBox,
|
||||
|
@ -24,7 +26,6 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { extractErrorMessage } from '../../../../common';
|
||||
import { stringHash } from '../../../../common/util/string_utils';
|
||||
import type { SearchResponse7 } from '../../../../common/types/es_client';
|
||||
import type { ResultsSearchQuery } from '../../data_frame_analytics/common/analytics';
|
||||
|
||||
import { useMlApiContext } from '../../contexts/kibana';
|
||||
|
@ -184,7 +185,7 @@ export const ScatterplotMatrix: FC<ScatterplotMatrixProps> = ({
|
|||
}
|
||||
: searchQuery;
|
||||
|
||||
const resp: SearchResponse7 = await esSearch({
|
||||
const resp: estypes.SearchResponse = await esSearch({
|
||||
index,
|
||||
body: {
|
||||
fields: queryFields,
|
||||
|
@ -198,7 +199,7 @@ export const ScatterplotMatrix: FC<ScatterplotMatrixProps> = ({
|
|||
if (!options.didCancel) {
|
||||
const items = resp.hits.hits
|
||||
.map((d) =>
|
||||
getProcessedFields(d.fields, (key: string) =>
|
||||
getProcessedFields(d.fields ?? {}, (key: string) =>
|
||||
key.startsWith(`${resultsField}.feature_importance`)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SearchResponse7 } from '../../../../common/types/es_client';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import { extractErrorMessage } from '../../../../common/util/errors';
|
||||
|
||||
import { EsSorting, UseDataGridReturnType, getProcessedFields } from '../../components/data_grid';
|
||||
|
@ -51,7 +51,7 @@ export const getIndexData = async (
|
|||
|
||||
const { pageIndex, pageSize } = pagination;
|
||||
// TODO: remove results_field from `fields` when possible
|
||||
const resp: SearchResponse7 = await ml.esSearch({
|
||||
const resp: estypes.SearchResponse = await ml.esSearch({
|
||||
index: jobConfig.dest.index,
|
||||
body: {
|
||||
fields: ['*'],
|
||||
|
@ -64,11 +64,15 @@ export const getIndexData = async (
|
|||
});
|
||||
|
||||
if (!options.didCancel) {
|
||||
setRowCount(resp.hits.total.value);
|
||||
setRowCountRelation(resp.hits.total.relation);
|
||||
setRowCount(typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total.value);
|
||||
setRowCountRelation(
|
||||
typeof resp.hits.total === 'number'
|
||||
? ('eq' as estypes.TotalHitsRelation)
|
||||
: resp.hits.total.relation
|
||||
);
|
||||
setTableItems(
|
||||
resp.hits.hits.map((d) =>
|
||||
getProcessedFields(d.fields, (key: string) =>
|
||||
getProcessedFields(d.fields ?? {}, (key: string) =>
|
||||
key.startsWith(`${jobConfig.dest.results_field}.feature_importance`)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiDataGridColumn } from '@elastic/eui';
|
||||
|
||||
import { CoreSetup } from 'src/core/public';
|
||||
|
@ -26,13 +27,12 @@ import {
|
|||
UseIndexDataReturnType,
|
||||
getProcessedFields,
|
||||
} from '../../../../components/data_grid';
|
||||
import type { SearchResponse7 } from '../../../../../../common/types/es_client';
|
||||
import { extractErrorMessage } from '../../../../../../common/util/errors';
|
||||
import { INDEX_STATUS } from '../../../common/analytics';
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
import { getRuntimeFieldsMapping } from '../../../../components/data_grid/common';
|
||||
|
||||
type IndexSearchResponse = SearchResponse7;
|
||||
type IndexSearchResponse = estypes.SearchResponse;
|
||||
|
||||
export const useIndexData = (
|
||||
indexPattern: IndexPattern,
|
||||
|
@ -95,9 +95,13 @@ export const useIndexData = (
|
|||
try {
|
||||
const resp: IndexSearchResponse = await ml.esSearch(esSearchRequest);
|
||||
|
||||
const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields));
|
||||
setRowCount(resp.hits.total.value);
|
||||
setRowCountRelation(resp.hits.total.relation);
|
||||
const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {}));
|
||||
setRowCount(typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total.value);
|
||||
setRowCountRelation(
|
||||
typeof resp.hits.total === 'number'
|
||||
? ('eq' as estypes.TotalHitsRelation)
|
||||
: resp.hits.total.relation
|
||||
);
|
||||
setTableItems(docs);
|
||||
setStatus(INDEX_STATUS.LOADED);
|
||||
} catch (e) {
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
isClassificationAnalysis,
|
||||
isRegressionAnalysis,
|
||||
} from '../../../../../../../common/util/analytics_utils';
|
||||
import { HITS_TOTAL_RELATION } from '../../../../../../../common/types/es_client';
|
||||
import { ES_CLIENT_TOTAL_HITS_RELATION } from '../../../../../../../common/types/es_client';
|
||||
|
||||
import { getToastNotifications } from '../../../../../util/dependency_cache';
|
||||
import { useColorRange, ColorRangeLegend } from '../../../../../components/color_range_legend';
|
||||
|
@ -77,7 +77,7 @@ const getResultsSectionHeaderItems = (
|
|||
defaultMessage="Total docs"
|
||||
/>
|
||||
),
|
||||
value: `${rowCountRelation === HITS_TOTAL_RELATION.GTE ? '>' : ''}${rowCount}`,
|
||||
value: `${rowCountRelation === ES_CLIENT_TOTAL_HITS_RELATION.GTE ? '>' : ''}${rowCount}`,
|
||||
},
|
||||
...(colorRange !== undefined
|
||||
? [
|
||||
|
|
|
@ -22,8 +22,10 @@ interface Response {
|
|||
|
||||
export function filterRuntimeMappings(job: Job, datafeed: Datafeed): Response {
|
||||
if (
|
||||
datafeed.runtime_mappings === undefined ||
|
||||
isPopulatedObject(datafeed.runtime_mappings) === false
|
||||
!(
|
||||
isPopulatedObject(datafeed, ['runtime_mappings']) &&
|
||||
isPopulatedObject(datafeed.runtime_mappings)
|
||||
)
|
||||
) {
|
||||
return {
|
||||
runtime_mappings: {},
|
||||
|
@ -83,7 +85,7 @@ function findFieldsInJob(job: Job, datafeed: Datafeed) {
|
|||
return [...usedFields];
|
||||
}
|
||||
|
||||
function findFieldsInAgg(obj: Record<string, object>) {
|
||||
function findFieldsInAgg(obj: Record<string, unknown>) {
|
||||
const fields: string[] = [];
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (isPopulatedObject(val)) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import { MLJobEditor } from '../../../../../jobs_list/components/ml_job_editor';
|
|||
import { mlJobService } from '../../../../../../services/job_service';
|
||||
import { ML_DATA_PREVIEW_COUNT } from '../../../../../../../../common/util/job_utils';
|
||||
import { isPopulatedObject } from '../../../../../../../../common/util/object_utils';
|
||||
import { isMultiBucketAggregate } from '../../../../../../../../common/types/es_client';
|
||||
|
||||
export const DatafeedPreview: FC<{
|
||||
combinedJob: CombinedJob | null;
|
||||
|
@ -67,7 +68,10 @@ export const DatafeedPreview: FC<{
|
|||
// the first item under aggregations can be any name
|
||||
if (isPopulatedObject(resp.aggregations)) {
|
||||
const accessor = Object.keys(resp.aggregations)[0];
|
||||
data = resp.aggregations[accessor].buckets.slice(0, ML_DATA_PREVIEW_COUNT);
|
||||
const aggregate = resp.aggregations[accessor];
|
||||
if (isMultiBucketAggregate(aggregate)) {
|
||||
data = aggregate.buckets.slice(0, ML_DATA_PREVIEW_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
setPreviewJsonString(JSON.stringify(data, null, 2));
|
||||
|
|
|
@ -90,11 +90,7 @@ export interface SeriesConfigWithMetadata extends SeriesConfig {
|
|||
}
|
||||
|
||||
export const isSeriesConfigWithMetadata = (arg: unknown): arg is SeriesConfigWithMetadata => {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
{}.hasOwnProperty.call(arg, 'bucketSpanSeconds') &&
|
||||
{}.hasOwnProperty.call(arg, 'detectorLabel')
|
||||
);
|
||||
return isPopulatedObject(arg, ['bucketSpanSeconds', 'detectorLabel']);
|
||||
};
|
||||
|
||||
interface ChartRange {
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { TimeRange } from 'src/plugins/data/common/query/timefilter/types';
|
||||
import { CombinedJob, Datafeed, Job } from '../../../common/types/anomaly_detection_jobs';
|
||||
import { Calendar } from '../../../common/types/calendars';
|
||||
|
@ -40,7 +41,7 @@ declare interface JobService {
|
|||
): Promise<any>;
|
||||
createResultsUrl(jobId: string[], start: number, end: number, location: string): string;
|
||||
getJobAndGroupIds(): Promise<ExistingJobsAndGroups>;
|
||||
searchPreview(job: CombinedJob): Promise<SearchResponse<any>>;
|
||||
searchPreview(job: CombinedJob): Promise<estypes.SearchResponse<any>>;
|
||||
getJob(jobId: string): CombinedJob;
|
||||
loadJobsWrapper(): Promise<CombinedJob[]>;
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ export interface SwimLaneDrilldownContext extends EditSwimlanePanelContext {
|
|||
|
||||
export function isSwimLaneEmbeddable(arg: unknown): arg is SwimLaneDrilldownContext {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('embeddable') &&
|
||||
isPopulatedObject(arg, ['embeddable']) &&
|
||||
isPopulatedObject(arg.embeddable, ['type']) &&
|
||||
arg.embeddable.type === ANOMALY_SWIMLANE_EMBEDDABLE_TYPE
|
||||
);
|
||||
}
|
||||
|
@ -130,8 +130,8 @@ export function isAnomalyExplorerEmbeddable(
|
|||
arg: unknown
|
||||
): arg is AnomalyChartsFieldSelectionContext {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('embeddable') &&
|
||||
isPopulatedObject(arg, ['embeddable']) &&
|
||||
isPopulatedObject(arg.embeddable, ['type']) &&
|
||||
arg.embeddable.type === ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE
|
||||
);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ export {
|
|||
getSeverityType,
|
||||
getFormattedSeverityScore,
|
||||
} from '../common/util/anomaly_utils';
|
||||
export { HITS_TOTAL_RELATION } from '../common/types/es_client';
|
||||
export { ES_CLIENT_TOTAL_HITS_RELATION } from '../common/types/es_client';
|
||||
|
||||
export { ANOMALY_SEVERITY } from '../common';
|
||||
export { useMlHref, ML_PAGES, MlUrlGenerator } from './ml_url_generator';
|
||||
|
|
|
@ -25,7 +25,6 @@ import {
|
|||
isClassificationAnalysis,
|
||||
} from '../../../common/util/analytics_utils';
|
||||
import { extractErrorMessage } from '../../../common/util/errors';
|
||||
import { SearchResponse7 } from '../../../common';
|
||||
import {
|
||||
AnalysisConfig,
|
||||
DataFrameAnalyticsConfig,
|
||||
|
@ -42,7 +41,7 @@ interface CardinalityAgg {
|
|||
};
|
||||
}
|
||||
|
||||
type ValidationSearchResult = Omit<SearchResponse7, 'aggregations'> & {
|
||||
type ValidationSearchResult = Omit<estypes.SearchResponse, 'aggregations'> & {
|
||||
aggregations: MissingAgg | CardinalityAgg;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { IScopedClusterClient } from 'kibana/server';
|
||||
import { chunk } from 'lodash';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { CATEGORY_EXAMPLES_SAMPLE_SIZE } from '../../../../../common/constants/categorization_job';
|
||||
import {
|
||||
Token,
|
||||
|
@ -61,7 +62,7 @@ export function categorizationExamplesProvider({
|
|||
}
|
||||
}
|
||||
}
|
||||
const { body } = await asCurrentUser.search<SearchResponse<{ [id: string]: string }>>({
|
||||
const { body } = await asCurrentUser.search<estypes.SearchResponse<{ [id: string]: string }>>({
|
||||
index: indexPatternTitle,
|
||||
size,
|
||||
body: {
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { CategoryId, Category } from '../../../../../common/types/categories';
|
||||
import type { MlClient } from '../../../../lib/ml_client';
|
||||
|
||||
export function topCategoriesProvider(mlClient: MlClient) {
|
||||
async function getTotalCategories(jobId: string): Promise<number> {
|
||||
const { body } = await mlClient.anomalySearch<SearchResponse<any>>(
|
||||
const { body } = await mlClient.anomalySearch<estypes.SearchResponse<any>>(
|
||||
{
|
||||
size: 0,
|
||||
body: {
|
||||
|
@ -35,12 +36,11 @@ export function topCategoriesProvider(mlClient: MlClient) {
|
|||
},
|
||||
[]
|
||||
);
|
||||
// @ts-ignore total is an object here
|
||||
return body?.hits?.total?.value ?? 0;
|
||||
return typeof body.hits.total === 'number' ? body.hits.total : body.hits.total.value;
|
||||
}
|
||||
|
||||
async function getTopCategoryCounts(jobId: string, numberOfCategories: number) {
|
||||
const { body } = await mlClient.anomalySearch<SearchResponse<any>>(
|
||||
const { body } = await mlClient.anomalySearch<estypes.SearchResponse<any>>(
|
||||
{
|
||||
size: 0,
|
||||
body: {
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
import { IScopedClusterClient } from 'kibana/server';
|
||||
|
||||
import { validateJob, ValidateJobPayload } from './job_validation';
|
||||
import { HITS_TOTAL_RELATION } from '../../../common/types/es_client';
|
||||
import { ES_CLIENT_TOTAL_HITS_RELATION } from '../../../common/types/es_client';
|
||||
import type { MlClient } from '../../lib/ml_client';
|
||||
|
||||
const callAs = {
|
||||
fieldCaps: () => Promise.resolve({ body: { fields: [] } }),
|
||||
search: () =>
|
||||
Promise.resolve({ body: { hits: { total: { value: 1, relation: HITS_TOTAL_RELATION.EQ } } } }),
|
||||
Promise.resolve({
|
||||
body: { hits: { total: { value: 1, relation: ES_CLIENT_TOTAL_HITS_RELATION.EQ } } },
|
||||
}),
|
||||
};
|
||||
|
||||
const mlClusterClient = ({
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { KibanaRequest, SavedObjectsClientContract } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import { MlLicense } from '../../../common/license';
|
||||
import { CloudSetup } from '../../../../cloud/server';
|
||||
import { spacesUtilsProvider } from '../../lib/spaces_utils';
|
||||
|
@ -23,7 +24,7 @@ export interface MlSystemProvider {
|
|||
): {
|
||||
mlCapabilities(): Promise<MlCapabilitiesResponse>;
|
||||
mlInfo(): Promise<MlInfoResponse>;
|
||||
mlAnomalySearch<T>(searchParams: any, jobIds: string[]): Promise<SearchResponse<T>>;
|
||||
mlAnomalySearch<T>(searchParams: any, jobIds: string[]): Promise<estypes.SearchResponse<T>>;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -69,7 +70,10 @@ export function getMlSystemProvider(
|
|||
};
|
||||
});
|
||||
},
|
||||
async mlAnomalySearch<T>(searchParams: any, jobIds: string[]): Promise<SearchResponse<T>> {
|
||||
async mlAnomalySearch<T>(
|
||||
searchParams: any,
|
||||
jobIds: string[]
|
||||
): Promise<estypes.SearchResponse<T>> {
|
||||
return await getGuards(request, savedObjectsClient)
|
||||
.isFullLicense()
|
||||
.hasMlCapabilities(['canAccessML'])
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SearchResponse7 } from '../../../ml/common';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import type { EsIndex } from '../types/es_index';
|
||||
import { isPopulatedObject } from '../utils/object_utils';
|
||||
import { isPopulatedObject } from '../shared_imports';
|
||||
|
||||
// To be able to use the type guards on the client side, we need to make sure we don't import
|
||||
// the code of '@kbn/config-schema' but just its types, otherwise the client side code will
|
||||
|
@ -28,20 +28,13 @@ import type { GetTransformsStatsResponseSchema } from './transforms_stats';
|
|||
import type { PostTransformsUpdateResponseSchema } from './update_transforms';
|
||||
|
||||
const isGenericResponseSchema = <T>(arg: any): arg is T => {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
{}.hasOwnProperty.call(arg, 'count') &&
|
||||
{}.hasOwnProperty.call(arg, 'transforms') &&
|
||||
Array.isArray(arg.transforms)
|
||||
);
|
||||
return isPopulatedObject(arg, ['count', 'transforms']) && Array.isArray(arg.transforms);
|
||||
};
|
||||
|
||||
export const isGetTransformNodesResponseSchema = (
|
||||
arg: unknown
|
||||
): arg is GetTransformNodesResponseSchema => {
|
||||
return (
|
||||
isPopulatedObject(arg) && {}.hasOwnProperty.call(arg, 'count') && typeof arg.count === 'number'
|
||||
);
|
||||
return isPopulatedObject(arg, ['count']) && typeof arg.count === 'number';
|
||||
};
|
||||
|
||||
export const isGetTransformsResponseSchema = (arg: unknown): arg is GetTransformsResponseSchema => {
|
||||
|
@ -59,7 +52,7 @@ export const isDeleteTransformsResponseSchema = (
|
|||
): arg is DeleteTransformsResponseSchema => {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
Object.values(arg).every((d) => ({}.hasOwnProperty.call(d, 'transformDeleted')))
|
||||
Object.values(arg).every((d) => isPopulatedObject(d, ['transformDeleted']))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -67,8 +60,22 @@ export const isEsIndices = (arg: unknown): arg is EsIndex[] => {
|
|||
return Array.isArray(arg);
|
||||
};
|
||||
|
||||
export const isEsSearchResponse = (arg: unknown): arg is SearchResponse7 => {
|
||||
return isPopulatedObject(arg) && {}.hasOwnProperty.call(arg, 'hits');
|
||||
export const isEsSearchResponse = (arg: unknown): arg is estypes.SearchResponse => {
|
||||
return isPopulatedObject(arg, ['hits']);
|
||||
};
|
||||
|
||||
type SearchResponseWithAggregations = Required<Pick<estypes.SearchResponse, 'aggregations'>> &
|
||||
estypes.SearchResponse;
|
||||
export const isEsSearchResponseWithAggregations = (
|
||||
arg: unknown
|
||||
): arg is SearchResponseWithAggregations => {
|
||||
return isEsSearchResponse(arg) && {}.hasOwnProperty.call(arg, 'aggregations');
|
||||
};
|
||||
|
||||
export const isMultiBucketAggregate = <TBucket = unknown>(
|
||||
arg: unknown
|
||||
): arg is estypes.MultiBucketAggregate<TBucket> => {
|
||||
return isPopulatedObject(arg, ['buckets']);
|
||||
};
|
||||
|
||||
export const isFieldHistogramsResponseSchema = (
|
||||
|
@ -87,9 +94,7 @@ export const isPostTransformsPreviewResponseSchema = (
|
|||
arg: unknown
|
||||
): arg is PostTransformsPreviewResponseSchema => {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
{}.hasOwnProperty.call(arg, 'generated_dest_index') &&
|
||||
{}.hasOwnProperty.call(arg, 'preview') &&
|
||||
isPopulatedObject(arg, ['generated_dest_index', 'preview']) &&
|
||||
typeof arg.generated_dest_index !== undefined &&
|
||||
Array.isArray(arg.preview)
|
||||
);
|
||||
|
@ -98,21 +103,19 @@ export const isPostTransformsPreviewResponseSchema = (
|
|||
export const isPostTransformsUpdateResponseSchema = (
|
||||
arg: unknown
|
||||
): arg is PostTransformsUpdateResponseSchema => {
|
||||
return isPopulatedObject(arg) && {}.hasOwnProperty.call(arg, 'id') && typeof arg.id === 'string';
|
||||
return isPopulatedObject(arg, ['id']) && typeof arg.id === 'string';
|
||||
};
|
||||
|
||||
export const isPutTransformsResponseSchema = (arg: unknown): arg is PutTransformsResponseSchema => {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
{}.hasOwnProperty.call(arg, 'transformsCreated') &&
|
||||
{}.hasOwnProperty.call(arg, 'errors') &&
|
||||
isPopulatedObject(arg, ['transformsCreated', 'errors']) &&
|
||||
Array.isArray(arg.transformsCreated) &&
|
||||
Array.isArray(arg.errors)
|
||||
);
|
||||
};
|
||||
|
||||
const isGenericSuccessResponseSchema = (arg: unknown) =>
|
||||
isPopulatedObject(arg) && Object.values(arg).every((d) => ({}.hasOwnProperty.call(d, 'success')));
|
||||
isPopulatedObject(arg) && Object.values(arg).every((d) => isPopulatedObject(d, ['success']));
|
||||
|
||||
export const isStartTransformsResponseSchema = (
|
||||
arg: unknown
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export type { HitsTotalRelation, SearchResponse7 } from '../../ml/common';
|
||||
export {
|
||||
composeValidators,
|
||||
isPopulatedObject,
|
||||
isRuntimeMappings,
|
||||
patternValidator,
|
||||
ChartData,
|
||||
HITS_TOTAL_RELATION,
|
||||
} from '../../ml/common';
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
|
||||
import type { IndexPattern } from '../../../../../src/plugins/data/common';
|
||||
|
||||
import { isPopulatedObject } from '../utils/object_utils';
|
||||
import { isPopulatedObject } from '../shared_imports';
|
||||
|
||||
// Custom minimal type guard for IndexPattern to check against the attributes used in transforms code.
|
||||
export function isIndexPattern(arg: any): arg is IndexPattern {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
'getComputedFields' in arg &&
|
||||
typeof arg.getComputedFields === 'function' &&
|
||||
{}.hasOwnProperty.call(arg, 'title') &&
|
||||
isPopulatedObject(arg, ['title', 'fields']) &&
|
||||
// `getComputedFields` is inherited, so it's not possible to
|
||||
// check with `hasOwnProperty` which is used by isPopulatedObject()
|
||||
'getComputedFields' in (arg as IndexPattern) &&
|
||||
typeof (arg as IndexPattern).getComputedFields === 'function' &&
|
||||
typeof arg.title === 'string' &&
|
||||
{}.hasOwnProperty.call(arg, 'fields') &&
|
||||
Array.isArray(arg.fields)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types';
|
||||
import type { LatestFunctionConfig, PutTransformsRequestSchema } from '../api_schemas/transforms';
|
||||
import { isPopulatedObject } from '../utils/object_utils';
|
||||
import { isPopulatedObject } from '../shared_imports';
|
||||
import { PivotGroupByDict } from './pivot_group_by';
|
||||
import { PivotAggDict } from './pivot_aggs';
|
||||
|
||||
|
@ -46,11 +46,11 @@ export type TransformLatestConfig = Omit<TransformBaseConfig, 'pivot'> & {
|
|||
export type TransformConfigUnion = TransformPivotConfig | TransformLatestConfig;
|
||||
|
||||
export function isPivotTransform(transform: unknown): transform is TransformPivotConfig {
|
||||
return isPopulatedObject(transform) && transform.hasOwnProperty('pivot');
|
||||
return isPopulatedObject(transform, ['pivot']);
|
||||
}
|
||||
|
||||
export function isLatestTransform(transform: unknown): transform is TransformLatestConfig {
|
||||
return isPopulatedObject(transform) && transform.hasOwnProperty('latest');
|
||||
return isPopulatedObject(transform, ['latest']);
|
||||
}
|
||||
|
||||
export interface LatestFunctionConfigUI {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { TransformState, TRANSFORM_STATE } from '../constants';
|
||||
import { isPopulatedObject } from '../utils/object_utils';
|
||||
import { isPopulatedObject } from '../shared_imports';
|
||||
import { TransformId } from './transform';
|
||||
|
||||
export interface TransformStats {
|
||||
|
@ -61,7 +61,5 @@ function isTransformState(arg: unknown): arg is TransformState {
|
|||
}
|
||||
|
||||
export function isTransformStats(arg: unknown): arg is TransformStats {
|
||||
return (
|
||||
isPopulatedObject(arg) && {}.hasOwnProperty.call(arg, 'state') && isTransformState(arg.state)
|
||||
);
|
||||
return isPopulatedObject(arg, ['state']) && isTransformState(arg.state);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isPopulatedObject } from './object_utils';
|
||||
import { isPopulatedObject } from '../shared_imports';
|
||||
|
||||
export interface ErrorResponse {
|
||||
body: {
|
||||
|
@ -18,7 +18,11 @@ export interface ErrorResponse {
|
|||
}
|
||||
|
||||
export function isErrorResponse(arg: unknown): arg is ErrorResponse {
|
||||
return isPopulatedObject(arg) && isPopulatedObject(arg.body) && arg?.body?.message !== undefined;
|
||||
return (
|
||||
isPopulatedObject(arg, ['body']) &&
|
||||
isPopulatedObject(arg.body, ['message']) &&
|
||||
arg.body.message !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function getErrorMessage(error: unknown) {
|
||||
|
@ -26,7 +30,7 @@ export function getErrorMessage(error: unknown) {
|
|||
return `${error.body.error}: ${error.body.message}`;
|
||||
}
|
||||
|
||||
if (isPopulatedObject(error) && typeof error.message === 'string') {
|
||||
if (isPopulatedObject(error, ['message']) && typeof error.message === 'string') {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { getNestedProperty, isPopulatedObject } from './object_utils';
|
||||
import { getNestedProperty } from './object_utils';
|
||||
|
||||
describe('object_utils', () => {
|
||||
test('getNestedProperty()', () => {
|
||||
|
@ -68,12 +68,4 @@ describe('object_utils', () => {
|
|||
expect(typeof test11).toBe('number');
|
||||
expect(test11).toBe(0);
|
||||
});
|
||||
|
||||
test('isPopulatedObject()', () => {
|
||||
expect(isPopulatedObject(0)).toBe(false);
|
||||
expect(isPopulatedObject('')).toBe(false);
|
||||
expect(isPopulatedObject(null)).toBe(false);
|
||||
expect(isPopulatedObject({})).toBe(false);
|
||||
expect(isPopulatedObject({ attribute: 'value' })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -51,7 +51,3 @@ export const setNestedProperty = (obj: Record<string, any>, accessor: string, va
|
|||
|
||||
return obj;
|
||||
};
|
||||
|
||||
export const isPopulatedObject = <T = Record<string, unknown>>(arg: unknown): arg is T => {
|
||||
return typeof arg === 'object' && arg !== null && Object.keys(arg).length > 0;
|
||||
};
|
||||
|
|
|
@ -16,4 +16,4 @@ export const useRequest = jest.fn(() => ({
|
|||
export const createSavedSearchesLoader = jest.fn();
|
||||
|
||||
// just passing through the reimports
|
||||
export { getMlSharedImports, HITS_TOTAL_RELATION } from '../../../ml/public';
|
||||
export { getMlSharedImports, ES_CLIENT_TOTAL_HITS_RELATION } from '../../../ml/public';
|
||||
|
|
|
@ -14,7 +14,7 @@ import type { Dictionary } from '../../../common/types/common';
|
|||
import type { EsFieldName } from '../../../common/types/fields';
|
||||
import type { PivotAgg, PivotSupportedAggs } from '../../../common/types/pivot_aggs';
|
||||
import { PIVOT_SUPPORTED_AGGS } from '../../../common/types/pivot_aggs';
|
||||
import { isPopulatedObject } from '../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../common/shared_imports';
|
||||
|
||||
import { getAggFormConfig } from '../sections/create_transform/components/step_define/common/get_agg_form_config';
|
||||
import { PivotAggsConfigFilter } from '../sections/create_transform/components/step_define/common/filter_agg/types';
|
||||
|
@ -166,11 +166,7 @@ export type PivotAggsConfigWithUiSupport =
|
|||
|
||||
export function isPivotAggsConfigWithUiSupport(arg: unknown): arg is PivotAggsConfigWithUiSupport {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('agg') &&
|
||||
arg.hasOwnProperty('aggName') &&
|
||||
arg.hasOwnProperty('dropDownName') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
isPopulatedObject(arg, ['agg', 'aggName', 'dropDownName', 'field']) &&
|
||||
isPivotSupportedAggs(arg.agg)
|
||||
);
|
||||
}
|
||||
|
@ -181,15 +177,12 @@ export function isPivotAggsConfigWithUiSupport(arg: unknown): arg is PivotAggsCo
|
|||
type PivotAggsConfigWithExtendedForm = PivotAggsConfigFilter;
|
||||
|
||||
export function isPivotAggsWithExtendedForm(arg: unknown): arg is PivotAggsConfigWithExtendedForm {
|
||||
return isPopulatedObject(arg) && arg.hasOwnProperty('AggFormComponent');
|
||||
return isPopulatedObject(arg, ['AggFormComponent']);
|
||||
}
|
||||
|
||||
export function isPivotAggsConfigPercentiles(arg: unknown): arg is PivotAggsConfigPercentiles {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('agg') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
arg.hasOwnProperty('percents') &&
|
||||
isPopulatedObject(arg, ['agg', 'field', 'percents']) &&
|
||||
arg.agg === PIVOT_SUPPORTED_AGGS.PERCENTILES
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { AggName } from '../../../common/types/aggregations';
|
|||
import { Dictionary } from '../../../common/types/common';
|
||||
import { EsFieldName } from '../../../common/types/fields';
|
||||
import { GenericAgg } from '../../../common/types/pivot_group_by';
|
||||
import { isPopulatedObject } from '../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../common/shared_imports';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../../src/plugins/data/common';
|
||||
import { PivotAggsConfigWithUiSupport } from './pivot_aggs';
|
||||
|
||||
|
@ -84,30 +84,21 @@ export type PivotGroupByConfigDict = Dictionary<PivotGroupByConfig>;
|
|||
|
||||
export function isGroupByDateHistogram(arg: unknown): arg is GroupByDateHistogram {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('agg') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
arg.hasOwnProperty('calendar_interval') &&
|
||||
isPopulatedObject(arg, ['agg', 'field', 'calendar_interval']) &&
|
||||
arg.agg === PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM
|
||||
);
|
||||
}
|
||||
|
||||
export function isGroupByHistogram(arg: unknown): arg is GroupByHistogram {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('agg') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
arg.hasOwnProperty('interval') &&
|
||||
isPopulatedObject(arg, ['agg', 'field', 'interval']) &&
|
||||
arg.agg === PIVOT_SUPPORTED_GROUP_BY_AGGS.HISTOGRAM
|
||||
);
|
||||
}
|
||||
|
||||
export function isGroupByTerms(arg: unknown): arg is GroupByTerms {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('agg') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
arg.agg === PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS
|
||||
isPopulatedObject(arg, ['agg', 'field']) && arg.agg === PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -124,5 +115,5 @@ export function getEsAggFromGroupByConfig(groupByConfig: GroupByConfigBase): Gen
|
|||
}
|
||||
|
||||
export function isPivotAggConfigWithUiSupport(arg: unknown): arg is PivotAggsConfigWithUiSupport {
|
||||
return isPopulatedObject(arg) && arg.hasOwnProperty('agg') && arg.hasOwnProperty('field');
|
||||
return isPopulatedObject(arg, ['agg', 'field']);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DefaultOperator } from 'elasticsearch';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { HttpFetchError } from '../../../../../../src/core/public';
|
||||
import type { IndexPattern } from '../../../../../../src/plugins/data/public';
|
||||
|
@ -17,7 +17,7 @@ import type {
|
|||
PutTransformsPivotRequestSchema,
|
||||
PutTransformsRequestSchema,
|
||||
} from '../../../common/api_schemas/transforms';
|
||||
import { isPopulatedObject } from '../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../common/shared_imports';
|
||||
import { DateHistogramAgg, HistogramAgg, TermsAgg } from '../../../common/types/pivot_group_by';
|
||||
import { isIndexPattern } from '../../../common/types/index_pattern';
|
||||
|
||||
|
@ -39,7 +39,7 @@ import {
|
|||
export interface SimpleQuery {
|
||||
query_string: {
|
||||
query: string;
|
||||
default_operator?: DefaultOperator;
|
||||
default_operator?: estypes.DefaultOperator;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,14 +59,13 @@ export function getPivotQuery(search: string | SavedSearchQuery): PivotQuery {
|
|||
}
|
||||
|
||||
export function isSimpleQuery(arg: unknown): arg is SimpleQuery {
|
||||
return isPopulatedObject(arg) && arg.hasOwnProperty('query_string');
|
||||
return isPopulatedObject(arg, ['query_string']);
|
||||
}
|
||||
|
||||
export const matchAllQuery = { match_all: {} };
|
||||
export function isMatchAllQuery(query: unknown): boolean {
|
||||
return (
|
||||
isPopulatedObject(query) &&
|
||||
query.hasOwnProperty('match_all') &&
|
||||
isPopulatedObject(query, ['match_all']) &&
|
||||
typeof query.match_all === 'object' &&
|
||||
query.match_all !== null &&
|
||||
Object.keys(query.match_all).length === 0
|
||||
|
@ -101,7 +100,7 @@ export function getCombinedRuntimeMappings(
|
|||
combinedRuntimeMappings = { ...combinedRuntimeMappings, ...runtimeMappings };
|
||||
}
|
||||
|
||||
if (isPopulatedObject<StepDefineExposedState['runtimeMappings']>(combinedRuntimeMappings)) {
|
||||
if (isPopulatedObject<keyof StepDefineExposedState['runtimeMappings']>(combinedRuntimeMappings)) {
|
||||
return combinedRuntimeMappings;
|
||||
}
|
||||
return undefined;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { HttpFetchError } from 'kibana/public';
|
||||
|
||||
import { KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public';
|
||||
|
@ -37,7 +39,6 @@ import type {
|
|||
PostTransformsUpdateResponseSchema,
|
||||
} from '../../../../common/api_schemas/update_transforms';
|
||||
|
||||
import type { SearchResponse7 } from '../../../../common/shared_imports';
|
||||
import { EsIndex } from '../../../../common/types/es_index';
|
||||
|
||||
import type { SavedSearchQuery } from '../use_search_items';
|
||||
|
@ -134,7 +135,7 @@ const apiFactory = () => ({
|
|||
): Promise<GetTransformsAuditMessagesResponseSchema | HttpFetchError> {
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
async esSearch(payload: any): Promise<SearchResponse7 | HttpFetchError> {
|
||||
async esSearch(payload: any): Promise<estypes.SearchResponse | HttpFetchError> {
|
||||
return Promise.resolve({
|
||||
hits: {
|
||||
hits: [],
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
|
||||
import { HttpFetchError } from 'kibana/public';
|
||||
|
||||
import { KBN_FIELD_TYPES } from '../../../../../../src/plugins/data/public';
|
||||
|
@ -44,7 +46,6 @@ import type { GetTransformsStatsResponseSchema } from '../../../common/api_schem
|
|||
import { TransformId } from '../../../common/types/transform';
|
||||
import { API_BASE_PATH } from '../../../common/constants';
|
||||
import { EsIndex } from '../../../common/types/es_index';
|
||||
import type { SearchResponse7 } from '../../../common/shared_imports';
|
||||
|
||||
import { useAppDependencies } from '../app_dependencies';
|
||||
|
||||
|
@ -187,7 +188,7 @@ export const useApi = () => {
|
|||
return e;
|
||||
}
|
||||
},
|
||||
async esSearch(payload: any): Promise<SearchResponse7 | HttpFetchError> {
|
||||
async esSearch(payload: any): Promise<estypes.SearchResponse | HttpFetchError> {
|
||||
try {
|
||||
return await http.post(`${API_BASE_PATH}es_search`, { body: JSON.stringify(payload) });
|
||||
} catch (e) {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
import { EuiDataGridColumn } from '@elastic/eui';
|
||||
import type { estypes } from '@elastic/elasticsearch';
|
||||
import type { EuiDataGridColumn } from '@elastic/eui';
|
||||
|
||||
import {
|
||||
isEsSearchResponse,
|
||||
|
@ -133,10 +134,14 @@ export const useIndexData = (
|
|||
return;
|
||||
}
|
||||
|
||||
const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields));
|
||||
const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {}));
|
||||
|
||||
setRowCount(resp.hits.total.value);
|
||||
setRowCountRelation(resp.hits.total.relation);
|
||||
setRowCount(typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total.value);
|
||||
setRowCountRelation(
|
||||
typeof resp.hits.total === 'number'
|
||||
? ('eq' as estypes.TotalHitsRelation)
|
||||
: resp.hits.total.relation
|
||||
);
|
||||
setTableItems(docs);
|
||||
setStatus(INDEX_STATUS.LOADED);
|
||||
};
|
||||
|
|
|
@ -18,7 +18,11 @@ import type { PreviewMappingsProperties } from '../../../common/api_schemas/tran
|
|||
import { isPostTransformsPreviewResponseSchema } from '../../../common/api_schemas/type_guards';
|
||||
import { getNestedProperty } from '../../../common/utils/object_utils';
|
||||
|
||||
import { RenderCellValue, UseIndexDataReturnType, HITS_TOTAL_RELATION } from '../../shared_imports';
|
||||
import {
|
||||
RenderCellValue,
|
||||
UseIndexDataReturnType,
|
||||
ES_CLIENT_TOTAL_HITS_RELATION,
|
||||
} from '../../shared_imports';
|
||||
import { getErrorMessage } from '../../../common/utils/errors';
|
||||
|
||||
import { useAppDependencies } from '../app_dependencies';
|
||||
|
@ -128,7 +132,7 @@ export const usePivotData = (
|
|||
if (!validationStatus.isValid) {
|
||||
setTableItems([]);
|
||||
setRowCount(0);
|
||||
setRowCountRelation(HITS_TOTAL_RELATION.EQ);
|
||||
setRowCountRelation(ES_CLIENT_TOTAL_HITS_RELATION.EQ);
|
||||
setNoDataMessage(validationStatus.errorMessage!);
|
||||
return;
|
||||
}
|
||||
|
@ -149,7 +153,7 @@ export const usePivotData = (
|
|||
setErrorMessage(getErrorMessage(resp));
|
||||
setTableItems([]);
|
||||
setRowCount(0);
|
||||
setRowCountRelation(HITS_TOTAL_RELATION.EQ);
|
||||
setRowCountRelation(ES_CLIENT_TOTAL_HITS_RELATION.EQ);
|
||||
setPreviewMappingsProperties({});
|
||||
setStatus(INDEX_STATUS.ERROR);
|
||||
return;
|
||||
|
@ -157,7 +161,7 @@ export const usePivotData = (
|
|||
|
||||
setTableItems(resp.preview);
|
||||
setRowCount(resp.preview.length);
|
||||
setRowCountRelation(HITS_TOTAL_RELATION.EQ);
|
||||
setRowCountRelation(ES_CLIENT_TOTAL_HITS_RELATION.EQ);
|
||||
setPreviewMappingsProperties(resp.generated_dest_index.mappings.properties);
|
||||
setStatus(INDEX_STATUS.LOADED);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Privileges } from '../../../../../common/types/privileges';
|
||||
import { isPopulatedObject } from '../../../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../../../common/shared_imports';
|
||||
|
||||
export interface Capabilities {
|
||||
canGetTransform: boolean;
|
||||
|
@ -22,10 +22,8 @@ export type Privilege = [string, string];
|
|||
|
||||
function isPrivileges(arg: unknown): arg is Privileges {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
arg.hasOwnProperty('hasAllPrivileges') &&
|
||||
isPopulatedObject(arg, ['hasAllPrivileges', 'missingPrivileges']) &&
|
||||
typeof arg.hasAllPrivileges === 'boolean' &&
|
||||
arg.hasOwnProperty('missingPrivileges') &&
|
||||
typeof arg.missingPrivileges === 'object' &&
|
||||
arg.missingPrivileges !== null
|
||||
);
|
||||
|
|
|
@ -12,8 +12,9 @@ import { EuiCodeEditor } from '@elastic/eui';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { isRuntimeMappings } from '../../../../../../common/shared_imports';
|
||||
|
||||
import { StepDefineFormHook } from '../step_define';
|
||||
import { isRuntimeMappings } from '../step_define/common/types';
|
||||
|
||||
export const AdvancedRuntimeMappingsEditor: FC<StepDefineFormHook['runtimeMappingsEditor']> = memo(
|
||||
({
|
||||
|
|
|
@ -47,7 +47,7 @@ import {
|
|||
PutTransformsPivotRequestSchema,
|
||||
} from '../../../../../../common/api_schemas/transforms';
|
||||
import type { RuntimeField } from '../../../../../../../../../src/plugins/data/common/index_patterns';
|
||||
import { isPopulatedObject } from '../../../../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../../../../common/shared_imports';
|
||||
import { isLatestTransform } from '../../../../../../common/types/transform';
|
||||
|
||||
export interface StepDetailsExposedState {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { getFilterAggTypeConfig } from '../config';
|
|||
import type { FilterAggType, PivotAggsConfigFilter } from '../types';
|
||||
import type { RuntimeMappings } from '../../types';
|
||||
import { getKibanaFieldTypeFromEsType } from '../../get_pivot_dropdown_options';
|
||||
import { isPopulatedObject } from '../../../../../../../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../../../../../../../common/shared_imports';
|
||||
|
||||
/**
|
||||
* Resolves supported filters for provided field.
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
*/
|
||||
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { EuiComboBox, EuiFormRow } from '@elastic/eui';
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { debounce } from 'lodash';
|
||||
import useUpdateEffect from 'react-use/lib/useUpdateEffect';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isEsSearchResponse } from '../../../../../../../../../common/api_schemas/type_guards';
|
||||
import {
|
||||
isEsSearchResponseWithAggregations,
|
||||
isMultiBucketAggregate,
|
||||
} from '../../../../../../../../../common/api_schemas/type_guards';
|
||||
import { useApi } from '../../../../../../../hooks';
|
||||
import { CreateTransformWizardContext } from '../../../../wizard/wizard';
|
||||
import { FilterAggConfigTerm } from '../types';
|
||||
|
@ -29,7 +33,7 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm
|
|||
const { indexPattern, runtimeMappings } = useContext(CreateTransformWizardContext);
|
||||
const toastNotifications = useToastNotifications();
|
||||
|
||||
const [options, setOptions] = useState([]);
|
||||
const [options, setOptions] = useState<EuiComboBoxOptionOption[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||
|
@ -62,7 +66,12 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm
|
|||
|
||||
setIsLoading(false);
|
||||
|
||||
if (!isEsSearchResponse(response)) {
|
||||
if (
|
||||
!(
|
||||
isEsSearchResponseWithAggregations(response) &&
|
||||
isMultiBucketAggregate<estypes.KeyedBucketKeys>(response.aggregations.field_values)
|
||||
)
|
||||
) {
|
||||
toastNotifications.addWarning(
|
||||
i18n.translate('xpack.transform.agg.popoverForm.filerAgg.term.errorFetchSuggestions', {
|
||||
defaultMessage: 'Unable to fetch suggestions',
|
||||
|
@ -72,9 +81,7 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm
|
|||
}
|
||||
|
||||
setOptions(
|
||||
response.aggregations.field_values.buckets.map(
|
||||
(value: { key: string; doc_count: number }) => ({ label: value.key })
|
||||
)
|
||||
response.aggregations.field_values.buckets.map((value) => ({ label: value.key + '' }))
|
||||
);
|
||||
}, 600),
|
||||
[selectedField]
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from '../../../../../../../../../../src/plugins/data/public';
|
||||
|
||||
import { getNestedProperty } from '../../../../../../../common/utils/object_utils';
|
||||
import { isRuntimeMappings } from '../../../../../../../common/shared_imports';
|
||||
|
||||
import {
|
||||
DropDownLabel,
|
||||
|
@ -26,7 +27,6 @@ import {
|
|||
import { getDefaultAggregationConfig } from './get_default_aggregation_config';
|
||||
import { getDefaultGroupByConfig } from './get_default_group_by_config';
|
||||
import type { Field, StepDefineExposedState } from './types';
|
||||
import { isRuntimeMappings } from './types';
|
||||
|
||||
const illegalEsAggNameChars = /[[\]>]/g;
|
||||
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isRuntimeField, isRuntimeMappings } from './types';
|
||||
|
||||
describe('Transform: step_define type guards', () => {
|
||||
it('isRuntimeField()', () => {
|
||||
expect(isRuntimeField(1)).toBe(false);
|
||||
expect(isRuntimeField(null)).toBe(false);
|
||||
expect(isRuntimeField([])).toBe(false);
|
||||
expect(isRuntimeField({})).toBe(false);
|
||||
expect(isRuntimeField({ someAttribute: 'someValue' })).toBe(false);
|
||||
expect(isRuntimeField({ type: 'wrong-type' })).toBe(false);
|
||||
expect(isRuntimeField({ type: 'keyword', someAttribute: 'some value' })).toBe(false);
|
||||
|
||||
expect(isRuntimeField({ type: 'keyword' })).toBe(true);
|
||||
expect(isRuntimeField({ type: 'keyword', script: 'some script' })).toBe(true);
|
||||
});
|
||||
|
||||
it('isRuntimeMappings()', () => {
|
||||
expect(isRuntimeMappings(1)).toBe(false);
|
||||
expect(isRuntimeMappings(null)).toBe(false);
|
||||
expect(isRuntimeMappings([])).toBe(false);
|
||||
expect(isRuntimeMappings({})).toBe(false);
|
||||
expect(isRuntimeMappings({ someAttribute: 'someValue' })).toBe(false);
|
||||
expect(isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: 'someValue' })).toBe(
|
||||
false
|
||||
);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName1: { type: 'keyword' },
|
||||
fieldName2: { type: 'keyword', someAttribute: 'some value' },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: 1234 },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { someAttribute: 'some value' } },
|
||||
})
|
||||
).toBe(false);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { source: 1234 } },
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
expect(isRuntimeMappings({ fieldName: { type: 'keyword' } })).toBe(true);
|
||||
expect(
|
||||
isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: { type: 'keyword' } })
|
||||
).toBe(true);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName1: { type: 'keyword' },
|
||||
fieldName2: { type: 'keyword', script: 'some script as script' },
|
||||
})
|
||||
).toBe(true);
|
||||
expect(
|
||||
isRuntimeMappings({
|
||||
fieldName: { type: 'long', script: { source: 'some script as source' } },
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
|
@ -24,7 +24,7 @@ import {
|
|||
} from '../../../../../../../common/types/transform';
|
||||
import { LatestFunctionConfig } from '../../../../../../../common/api_schemas/transforms';
|
||||
|
||||
import { isPopulatedObject } from '../../../../../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../../../../../common/shared_imports';
|
||||
|
||||
export interface ErrorMessage {
|
||||
query: string;
|
||||
|
@ -72,30 +72,10 @@ export interface StepDefineExposedState {
|
|||
isRuntimeMappingsEditorEnabled: boolean;
|
||||
}
|
||||
|
||||
export function isRuntimeField(arg: unknown): arg is RuntimeField {
|
||||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
((Object.keys(arg).length === 1 && arg.hasOwnProperty('type')) ||
|
||||
(Object.keys(arg).length === 2 &&
|
||||
arg.hasOwnProperty('type') &&
|
||||
arg.hasOwnProperty('script') &&
|
||||
(typeof arg.script === 'string' ||
|
||||
(isPopulatedObject(arg.script) &&
|
||||
Object.keys(arg.script).length === 1 &&
|
||||
arg.script.hasOwnProperty('source') &&
|
||||
typeof arg.script.source === 'string')))) &&
|
||||
RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType)
|
||||
);
|
||||
}
|
||||
|
||||
export function isRuntimeMappings(arg: unknown): arg is RuntimeMappings {
|
||||
return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d));
|
||||
}
|
||||
|
||||
export function isPivotPartialRequest(arg: unknown): arg is { pivot: PivotConfigDefinition } {
|
||||
return isPopulatedObject(arg) && arg.hasOwnProperty('pivot');
|
||||
return isPopulatedObject(arg, ['pivot']);
|
||||
}
|
||||
|
||||
export function isLatestPartialRequest(arg: unknown): arg is { latest: LatestFunctionConfig } {
|
||||
return isPopulatedObject(arg) && arg.hasOwnProperty('latest');
|
||||
return isPopulatedObject(arg, ['latest']);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ export {
|
|||
UseIndexDataReturnType,
|
||||
EsSorting,
|
||||
RenderCellValue,
|
||||
HITS_TOTAL_RELATION,
|
||||
ES_CLIENT_TOTAL_HITS_RELATION,
|
||||
} from '../../ml/public';
|
||||
|
||||
import { XJson } from '../../../../src/plugins/es_ui_shared/public';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { isPopulatedObject } from '../../../common/utils/object_utils';
|
||||
import { isPopulatedObject } from '../../../common/shared_imports';
|
||||
|
||||
import { RouteDependencies } from '../../types';
|
||||
|
||||
|
@ -24,10 +24,7 @@ export const isNodes = (arg: unknown): arg is Nodes => {
|
|||
return (
|
||||
isPopulatedObject(arg) &&
|
||||
Object.values(arg).every(
|
||||
(node) =>
|
||||
isPopulatedObject(node) &&
|
||||
{}.hasOwnProperty.call(node, NODE_ROLES) &&
|
||||
Array.isArray(node.roles)
|
||||
(node) => isPopulatedObject(node, [NODE_ROLES]) && Array.isArray(node.roles)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue