From 1d136a09be594687aeca1ca9eac18856677fafd5 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Wed, 21 Nov 2018 13:00:53 +0100 Subject: [PATCH] Use buildEsQuery for table, series and annotations --- .../metrics/public/components/_error.scss | 2 +- .../public/kbn_vis_types/request_handler.js | 10 +-- .../lib/vis_data/build_annotation_request.js | 4 +- .../server/lib/vis_data/get_annotations.js | 44 +++++++------ .../server/lib/vis_data/get_panel_data.js | 4 +- .../server/lib/vis_data/get_series_data.js | 63 +++++++++++-------- .../server/lib/vis_data/get_table_data.js | 15 +++-- .../get_es_query_uisettings.js} | 24 +++---- .../get_index_pattern.js} | 33 +++++----- .../request_processors/annotations/query.js | 25 +++----- .../request_processors/series/query.js | 17 ++--- .../request_processors/table/query.js | 20 +++--- .../lib/vis_data/series/build_request_body.js | 4 +- .../lib/vis_data/series/get_request_params.js | 29 ++++----- .../lib/vis_data/table/build_request_body.js | 4 +- .../lib/vis_data/table/get_column_data.js | 56 ----------------- 16 files changed, 151 insertions(+), 203 deletions(-) rename src/core_plugins/metrics/server/lib/vis_data/{table/get_request_params.js => helpers/get_es_query_uisettings.js} (67%) rename src/core_plugins/metrics/server/lib/vis_data/{table/handle_response_body.js => helpers/get_index_pattern.js} (52%) delete mode 100644 src/core_plugins/metrics/server/lib/vis_data/table/get_column_data.js diff --git a/src/core_plugins/metrics/public/components/_error.scss b/src/core_plugins/metrics/public/components/_error.scss index 607863ccbf04808..b9905c101136329 100644 --- a/src/core_plugins/metrics/public/components/_error.scss +++ b/src/core_plugins/metrics/public/components/_error.scss @@ -5,7 +5,7 @@ display: flex; align-items: center; justify-content: center; - + flex-direction: column; // Calculate colors similar to EuiCallout $tempBackgroundColor: tintOrShade($euiColorDanger, 90%, 70%); background-color: $tempBackgroundColor; diff --git a/src/core_plugins/metrics/public/kbn_vis_types/request_handler.js b/src/core_plugins/metrics/public/kbn_vis_types/request_handler.js index 592f7720bd8b84c..cd066cc510b5d35 100644 --- a/src/core_plugins/metrics/public/kbn_vis_types/request_handler.js +++ b/src/core_plugins/metrics/public/kbn_vis_types/request_handler.js @@ -20,14 +20,13 @@ import { validateInterval } from '../lib/validate_interval'; import { timezoneProvider } from 'ui/vis/lib/timezone'; import { timefilter } from 'ui/timefilter'; -import { buildEsQuery } from '@kbn/es-query'; const MetricsRequestHandlerProvider = function (Private, Notifier, config, $http) { const notify = new Notifier({ location: 'Metrics' }); return { name: 'metrics', - handler: function ({ aggs, uiState, timeRange, filters, query, visParams }) { + handler: function ({ uiState, timeRange, filters, query, visParams }) { const timezone = Private(timezoneProvider)(); return new Promise((resolve) => { const panel = visParams; @@ -35,14 +34,11 @@ const MetricsRequestHandlerProvider = function (Private, Notifier, config, $http const parsedTimeRange = timefilter.calculateBounds(timeRange); const scaledDataFormat = config.get('dateFormat:scaled'); const dateFormat = config.get('dateFormat'); - const esQueryConfigs = { - allowLeadingWildcards: config.get('query:allowLeadingWildcards'), - queryStringOptions: config.get('query:queryString:options'), - }; if (panel && panel.id) { const params = { timerange: { timezone, ...parsedTimeRange }, - filters: [buildEsQuery(aggs.indexPattern, [query], filters, esQueryConfigs)], + query, + filters, panels: [panel], state: uiStateObj }; diff --git a/src/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js b/src/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js index 92902a999b43fc1..1796f3a0a7927b5 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js +++ b/src/core_plugins/metrics/server/lib/vis_data/build_annotation_request.js @@ -20,8 +20,8 @@ import buildProcessorFunction from './build_processor_function'; import processors from './request_processors/annotations'; -export default function buildAnnotationRequest(req, panel, annotation) { - const processor = buildProcessorFunction(processors, req, panel, annotation); +export default function buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPattern) { + const processor = buildProcessorFunction(processors, req, panel, annotation, esQueryConfig, indexPattern); const doc = processor({}); return doc; } diff --git a/src/core_plugins/metrics/server/lib/vis_data/get_annotations.js b/src/core_plugins/metrics/server/lib/vis_data/get_annotations.js index 513cf9ba40d7a28..566757cb40b2a0a 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/get_annotations.js +++ b/src/core_plugins/metrics/server/lib/vis_data/get_annotations.js @@ -19,6 +19,7 @@ import buildAnnotationRequest from './build_annotation_request'; import handleAnnotationResponse from './handle_annotation_response'; +import { getIndexPatternObject } from './helpers/get_index_pattern'; function validAnnotation(annotation) { return annotation.index_pattern && @@ -28,28 +29,19 @@ function validAnnotation(annotation) { annotation.template; } -export default async (req, panel) => { +export default async (req, panel, esQueryConfig) => { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); - const bodies = panel.annotations + const bodiesPromises = panel.annotations .filter(validAnnotation) .map(annotation => { - - const indexPattern = annotation.index_pattern; - const bodies = []; - - bodies.push({ - index: indexPattern, - ignore: [404], - timeout: '90s', - requestTimeout: 90000, - ignoreUnavailable: true, - }); - - bodies.push(buildAnnotationRequest(req, panel, annotation)); - return bodies; + return getAnnotationBody(req, panel, annotation, esQueryConfig); }); - - if (!bodies.length) return { responses: [] }; + const bodies = await Promise.all(bodiesPromises); + if (!bodies.length) { + return { + responses: [], + }; + } try { const resp = await callWithRequest(req, 'msearch', { body: bodies.reduce((acc, item) => acc.concat(item), []) @@ -66,6 +58,20 @@ export default async (req, panel) => { if (error.message === 'missing-indices') return { responses: [] }; throw error; } - }; +async function getAnnotationBody(req, panel, annotation, esQueryConfig) { + const indexPatternString = annotation.index_pattern; + const indexPatternObject = await getIndexPatternObject(req, indexPatternString); + const request = buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPatternObject); + return [ + { + index: indexPatternString, + ignore: [404], + timeout: '90s', + requestTimeout: 90000, + ignoreUnavailable: true, + }, + request, + ]; +} \ No newline at end of file diff --git a/src/core_plugins/metrics/server/lib/vis_data/get_panel_data.js b/src/core_plugins/metrics/server/lib/vis_data/get_panel_data.js index d22ca5e2ff4d9a4..865e97f370288c1 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/get_panel_data.js +++ b/src/core_plugins/metrics/server/lib/vis_data/get_panel_data.js @@ -21,7 +21,9 @@ import { getTableData } from './get_table_data'; import { getSeriesData } from './get_series_data'; export default function getPanelData(req) { return panel => { - if (panel.type === 'table') return getTableData(req, panel); + if (panel.type === 'table') { + return getTableData(req, panel); + } return getSeriesData(req, panel); }; } diff --git a/src/core_plugins/metrics/server/lib/vis_data/get_series_data.js b/src/core_plugins/metrics/server/lib/vis_data/get_series_data.js index 4dd8b609b8ee1ba..5f74f09a24ff5d5 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/get_series_data.js +++ b/src/core_plugins/metrics/server/lib/vis_data/get_series_data.js @@ -21,33 +21,44 @@ import getRequestParams from './series/get_request_params'; import handleResponseBody from './series/handle_response_body'; import handleErrorResponse from './handle_error_response'; import getAnnotations from './get_annotations'; -export function getSeriesData(req, panel) { +import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; + +export async function getSeriesData(req, panel) { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); - const bodies = panel.series.map(series => getRequestParams(req, panel, series)); - const params = { - body: bodies.reduce((acc, items) => acc.concat(items), []) - }; - return callWithRequest(req, 'msearch', params) - .then(resp => { - const series = resp.responses.map(handleResponseBody(panel)); - return { - [panel.id]: { - id: panel.id, - series: series.reduce((acc, series) => acc.concat(series), []) - } - }; - }) - .then(resp => { - if (!panel.annotations || panel.annotations.length === 0) return resp; - return getAnnotations(req, panel).then(annotations => { - resp[panel.id].annotations = annotations; + const esQueryConfig = await getEsQueryConfig(req); + + try { + const bodiesPromises = panel.series.map(series => getRequestParams(req, panel, series, esQueryConfig)); + const bodies = await Promise.all(bodiesPromises); + const params = { + body: bodies.reduce((acc, items) => acc.concat(items), []) + }; + return callWithRequest(req, 'msearch', params) + .then(resp => { + const series = resp.responses.map(handleResponseBody(panel)); + return { + [panel.id]: { + id: panel.id, + series: series.reduce((acc, series) => acc.concat(series), []) + } + }; + }) + .then(resp => { + if (!panel.annotations || panel.annotations.length === 0) return resp; + return getAnnotations(req, panel, esQueryConfig).then(annotations => { + resp[panel.id].annotations = annotations; + return resp; + }); + }) + .then(resp => { + resp.type = panel.type; return resp; - }); - }) - .then(resp => { - resp.type = panel.type; - return resp; - }) - .catch(handleErrorResponse(panel)); + }) + .catch(handleErrorResponse(panel)); + } catch(e) { + console.error(e); + // TODO handle kql query errors + return handleErrorResponse(e); + } } diff --git a/src/core_plugins/metrics/server/lib/vis_data/get_table_data.js b/src/core_plugins/metrics/server/lib/vis_data/get_table_data.js index ea202a94af41edf..e894b989b77ba32 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/get_table_data.js +++ b/src/core_plugins/metrics/server/lib/vis_data/get_table_data.js @@ -16,16 +16,23 @@ * specific language governing permissions and limitations * under the License. */ - +import { get } from 'lodash'; import buildRequestBody from './table/build_request_body'; import handleErrorResponse from './handle_error_response'; -import { get } from 'lodash'; import processBucket from './table/process_bucket'; +import { getIndexPatternObject } from './helpers/get_index_pattern'; +import { getEsQueryConfig } from './helpers/get_es_query_uisettings'; + + export async function getTableData(req, panel) { const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('data'); + const indexPatternString = panel.index_pattern; + + const esQueryConfig = await getEsQueryConfig(req); + const indexPatternObject = await getIndexPatternObject(req, indexPatternString); const params = { - index: panel.index_pattern, - body: buildRequestBody(req, panel) + index: indexPatternString, + body: buildRequestBody(req, panel, esQueryConfig, indexPatternObject) }; try { const resp = await callWithRequest(req, 'search', params); diff --git a/src/core_plugins/metrics/server/lib/vis_data/table/get_request_params.js b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_es_query_uisettings.js similarity index 67% rename from src/core_plugins/metrics/server/lib/vis_data/table/get_request_params.js rename to src/core_plugins/metrics/server/lib/vis_data/helpers/get_es_query_uisettings.js index c24d812c263fb7d..f5ee2335cd121f7 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/table/get_request_params.js +++ b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_es_query_uisettings.js @@ -17,18 +17,12 @@ * under the License. */ -import buildRequestBody from './build_request_body'; -export default (req, panel, entities) => { - const bodies = []; - entities.forEach(entity => { - bodies.push({ - index: panel.index_pattern, - ignore: [404], - timeout: '90s', - requestTimeout: 90000, - ignoreUnavailable: true, - }); - bodies.push(buildRequestBody(req, panel, entity)); - }); - return bodies; -}; +export async function getEsQueryConfig(req) { + const uiSettings = req.getUiSettingsService(); + const allowLeadingWildcards = await uiSettings.get('query:allowLeadingWildcards'); + const queryStringOptions = await uiSettings.get('query:queryString:options'); + return { + allowLeadingWildcards, + queryStringOptions: JSON.parse(queryStringOptions), + }; +} diff --git a/src/core_plugins/metrics/server/lib/vis_data/table/handle_response_body.js b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js similarity index 52% rename from src/core_plugins/metrics/server/lib/vis_data/table/handle_response_body.js rename to src/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js index 106dda20f0e0c3e..391f36cd439ba46 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/table/handle_response_body.js +++ b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_index_pattern.js @@ -17,20 +17,25 @@ * under the License. */ -import buildProcessorFunction from '../build_processor_function'; -import _ from 'lodash'; -import processors from '../response_processors/table'; +export async function getIndexPatternObject(req, indexPatternString) { + // getting the matching index pattern + const savedObjectClient = req.getSavedObjectsClient(); + const indexPatternObjects = await savedObjectClient.find({ + type: 'index-pattern', + fields: ['title', 'fields'], + search: `"${indexPatternString}"`, + search_fields: ['title'], + }); -export default function handleResponseBody(panel) { - return resp => { - if (resp.error) { - const err = new Error(resp.error.type); - err.response = JSON.stringify(resp); - throw err; - } - return panel.columns.map(column => { - const processor = buildProcessorFunction(processors, resp, panel, column); - return _.first(processor([])); + // getting the index pattern fields + const indexPatterns = indexPatternObjects.saved_objects + .filter(obj => obj.attributes.title === indexPatternString) + .map(indexPattern => { + const { title, fields } = indexPattern.attributes; + return { + title, + fields: JSON.parse(fields), + }; }); - }; + return indexPatterns.length === 1 ? indexPatterns[0] : null; } diff --git a/src/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js b/src/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js index 922a945883dd095..3cb5a3940f14f8a 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js +++ b/src/core_plugins/metrics/server/lib/vis_data/request_processors/annotations/query.js @@ -19,21 +19,19 @@ import getBucketSize from '../../helpers/get_bucket_size'; import getTimerange from '../../helpers/get_timerange'; -export default function query(req, panel, annotation) { +import { buildEsQuery } from '@kbn/es-query'; + +export default function query(req, panel, annotation, esQueryConfig, indexPattern) { return next => doc => { const timeField = annotation.time_field; - const { - bucketSize - } = getBucketSize(req, 'auto'); + const { bucketSize } = getBucketSize(req, 'auto'); const { from, to } = getTimerange(req); doc.size = 0; - doc.query = { - bool: { - must: [] - } - }; - + const queries = req.payload.query ? [req.payload.query] : []; + console.log(JSON.stringify(annotation, null, 2)); + const filters = !annotation.ignore_global_filters ? req.payload.filters : []; + doc.query = buildEsQuery(indexPattern, queries, filters, esQueryConfig); const timerange = { range: { [timeField]: { @@ -54,11 +52,6 @@ export default function query(req, panel, annotation) { }); } - const globalFilters = req.payload.filters; - if (!annotation.ignore_global_filters) { - doc.query.bool.must = doc.query.bool.must.concat(globalFilters); - } - if (!annotation.ignore_panel_filters && panel.filter) { doc.query.bool.must.push({ query_string: { @@ -76,7 +69,5 @@ export default function query(req, panel, annotation) { } return next(doc); - }; } - diff --git a/src/core_plugins/metrics/server/lib/vis_data/request_processors/series/query.js b/src/core_plugins/metrics/server/lib/vis_data/request_processors/series/query.js index 65813ff42a80885..e5cdc0a45800ba8 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/request_processors/series/query.js +++ b/src/core_plugins/metrics/server/lib/vis_data/request_processors/series/query.js @@ -19,17 +19,17 @@ import offsetTime from '../../offset_time'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; -export default function query(req, panel, series) { +import { buildEsQuery } from '@kbn/es-query'; + +export default function query(req, panel, series, esQueryConfig, indexPattern) { return next => doc => { const { timeField } = getIntervalAndTimefield(panel, series); const { from, to } = offsetTime(req, series.offset_time); doc.size = 0; - doc.query = { - bool: { - must: [] - } - }; + const queries = req.payload.query ? [req.payload.query] : []; + const filters = !panel.ignore_global_filter ? req.payload.filters : []; + doc.query = buildEsQuery(indexPattern, queries, filters, esQueryConfig); const timerange = { range: { @@ -42,11 +42,6 @@ export default function query(req, panel, series) { }; doc.query.bool.must.push(timerange); - const globalFilters = req.payload.filters; - if (globalFilters && !panel.ignore_global_filter) { - doc.query.bool.must = doc.query.bool.must.concat(globalFilters); - } - if (panel.filter) { doc.query.bool.must.push({ query_string: { diff --git a/src/core_plugins/metrics/server/lib/vis_data/request_processors/table/query.js b/src/core_plugins/metrics/server/lib/vis_data/request_processors/table/query.js index 77a970003d93ca0..c12579625e54917 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/request_processors/table/query.js +++ b/src/core_plugins/metrics/server/lib/vis_data/request_processors/table/query.js @@ -16,20 +16,21 @@ * specific language governing permissions and limitations * under the License. */ - +import { buildEsQuery } from '@kbn/es-query'; import getTimerange from '../../helpers/get_timerange'; import getIntervalAndTimefield from '../../get_interval_and_timefield'; -export default function query(req, panel) { + +export default function query(req, panel, esQueryConfig, indexPattern) { return next => doc => { const { timeField } = getIntervalAndTimefield(panel); const { from, to } = getTimerange(req); doc.size = 0; - doc.query = { - bool: { - must: [] - } - }; + + const queries = req.payload.query ? [req.payload.query] : []; + const filters = !panel.ignore_global_filter ? req.payload.filters : []; + doc.query = buildEsQuery(indexPattern, queries, filters, esQueryConfig); + const timerange = { range: { @@ -42,11 +43,6 @@ export default function query(req, panel) { }; doc.query.bool.must.push(timerange); - const globalFilters = req.payload.filters; - if (globalFilters && !panel.ignore_global_filter) { - doc.query.bool.must = doc.query.bool.must.concat(globalFilters); - } - if (panel.filter) { doc.query.bool.must.push({ query_string: { diff --git a/src/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js b/src/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js index 0afe2869b72fa52..c25127b68a6bcd0 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js +++ b/src/core_plugins/metrics/server/lib/vis_data/series/build_request_body.js @@ -20,8 +20,8 @@ import buildProcessorFunction from '../build_processor_function'; import processors from '../request_processors/series'; -function buildRequestBody(req, panel, series) { - const processor = buildProcessorFunction(processors, req, panel, series); +function buildRequestBody(req, panel, series, esQueryConfig, indexPattern) { + const processor = buildProcessorFunction(processors, req, panel, series, esQueryConfig, indexPattern); const doc = processor({}); return doc; } diff --git a/src/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js b/src/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js index 5196ef7ead1975b..d68ebeb7b9f92e8 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js +++ b/src/core_plugins/metrics/server/lib/vis_data/series/get_request_params.js @@ -18,19 +18,20 @@ */ import buildRequestBody from './build_request_body'; +import { getIndexPatternObject } from '../helpers/get_index_pattern'; -export default (req, panel, series) => { - const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern; - const bodies = []; - - bodies.push({ - index: indexPattern, - ignore: [404], - timeout: '90s', - requestTimeout: 90000, - ignoreUnavailable: true, - }); - - bodies.push(buildRequestBody(req, panel, series)); - return bodies; +export default async (req, panel, series, esQueryConfig) => { + const indexPatternString = series.override_index_pattern && series.series_index_pattern || panel.index_pattern; + const indexPatternObject = await getIndexPatternObject(req, indexPatternString); + const request = buildRequestBody(req, panel, series, esQueryConfig, indexPatternObject); + return [ + { + index: indexPatternString, + ignore: [404], + timeout: '90s', + requestTimeout: 90000, + ignoreUnavailable: true, + }, + request, + ]; }; diff --git a/src/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js b/src/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js index 8a71a7ba79f0a3f..7e509a5ebf2e5e7 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js +++ b/src/core_plugins/metrics/server/lib/vis_data/table/build_request_body.js @@ -20,8 +20,8 @@ import buildProcessorFunction from '../build_processor_function'; import processors from '../request_processors/table'; -function buildRequestBody(req, panel) { - const processor = buildProcessorFunction(processors, req, panel); +function buildRequestBody(req, panel, esQueryConfig, indexPattern) { + const processor = buildProcessorFunction(processors, req, panel, esQueryConfig, indexPattern); const doc = processor({}); return doc; } diff --git a/src/core_plugins/metrics/server/lib/vis_data/table/get_column_data.js b/src/core_plugins/metrics/server/lib/vis_data/table/get_column_data.js deleted file mode 100644 index 6e5a2d0d544eb66..000000000000000 --- a/src/core_plugins/metrics/server/lib/vis_data/table/get_column_data.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import getRequestParams from './get_request_params'; -import handleResponseBody from './handle_response_body'; -import handleErrorResponse from '../handle_error_response'; -import getLastValue from '../../../../common/get_last_value'; -import _ from 'lodash'; -import regression from 'regression'; -export function getColumnData(req, panel, entities, client) { - const elasticsearch = _.get(req, 'server.plugins.elasticsearch'); - if (elasticsearch) { - const { callWithRequest } = elasticsearch.getCluster('data'); - if (!client) { - client = callWithRequest.bind(null, req); - } - } - const params = { - body: getRequestParams(req, panel, entities) - }; - return client('msearch', params) - .then(resp => { - const handler = handleResponseBody(panel); - return entities.map((entity, index) => { - entity.data = {}; - handler(resp.responses[index]).forEach(row => { - const linearRegression = regression('linear', row.data); - entity.data[row.id] = { - last: getLastValue(row.data), - slope: linearRegression.equation[0], - yIntercept: linearRegression.equation[1], - label: row.label - }; - }); - return entity; - }); - }) - .catch(handleErrorResponse(panel)); -} -