From 680e58f1154dec757fd9550d88232181358626b5 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Mon, 11 Mar 2019 16:06:40 +0300 Subject: [PATCH 01/12] EUIficate raw json control --- .../buckets/date_histogram/_editor.js | 6 ++ .../public/agg_types/controls/raw_json.html | 24 +----- .../ui/public/agg_types/controls/raw_json.tsx | 74 +++++++++++++++++++ .../agg_types/controls/raw_json_select.js | 30 ++++++++ src/legacy/ui/public/agg_types/index.js | 1 + src/legacy/ui/public/agg_types/utils.tsx | 39 ++++++++++ .../editors/default/__tests__/agg_params.js | 7 ++ .../public/vis/editors/default/agg_params.js | 17 ++++- 8 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 src/legacy/ui/public/agg_types/controls/raw_json.tsx create mode 100644 src/legacy/ui/public/agg_types/controls/raw_json_select.js create mode 100644 src/legacy/ui/public/agg_types/utils.tsx diff --git a/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js b/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js index afacdc522562e..20dea556306ee 100644 --- a/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js +++ b/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js @@ -21,6 +21,7 @@ import _ from 'lodash'; import $ from 'jquery'; import ngMock from 'ng_mock'; import expect from 'expect.js'; +import sinon from 'sinon'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import { VisProvider } from '../../../../vis'; import { intervalOptions } from '../../../buckets/_interval_options'; @@ -58,6 +59,10 @@ describe('editor', function () { ] }); + const formCtrl = { + $addControl: sinon.fake() + }; + const $el = $('' + @@ -68,6 +73,7 @@ describe('editor', function () { $parentScope.groupName = 'buckets'; $parentScope.vis = vis; + $el.data('$formController', formCtrl); $compile($el)($parentScope); $scope = $el.scope(); $scope.$digest(); diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.html b/src/legacy/ui/public/agg_types/controls/raw_json.html index f7d3f78a1f663..04294d6f9e3a5 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.html +++ b/src/legacy/ui/public/agg_types/controls/raw_json.html @@ -1,23 +1 @@ -
- - - -

- -

-
+ diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx new file mode 100644 index 0000000000000..e722f2e76cff1 --- /dev/null +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -0,0 +1,74 @@ +/* + * 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 { EuiFormRow, EuiIcon, EuiTextArea, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { get } from 'lodash'; +import React, { useState } from 'react'; +import { AggConfig } from 'ui/vis/agg_config'; +import { isValidJson } from '../utils'; + +interface RawJSONSelectProps { + agg: AggConfig; + onParamsChange: ( + type: string, + agg: AggConfig, + field: any, + options?: { isValid?: boolean } + ) => void; +} + +function RawJSONSelect({ agg = {}, onParamsChange }: RawJSONSelectProps) { + const [isInvalid, setIsInvalid] = useState(false); + + const label = ( + <> + {' '} + + + + + ); + const onTextAreaChange = (e: React.ChangeEvent) => { + const value: string = get(e, 'target.value'); + const isValid = isValidJson(value); + setIsInvalid(!isValid); + onParamsChange('json', agg, value, { isValid }); + }; + + return ( + + + + ); +} + +export { RawJSONSelect }; diff --git a/src/legacy/ui/public/agg_types/controls/raw_json_select.js b/src/legacy/ui/public/agg_types/controls/raw_json_select.js new file mode 100644 index 0000000000000..f61576b59c3a4 --- /dev/null +++ b/src/legacy/ui/public/agg_types/controls/raw_json_select.js @@ -0,0 +1,30 @@ +/* + * 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 'ngreact'; +import { uiModules } from '../../modules'; +import { RawJSONSelect } from './raw_json'; +import { wrapInI18nContext } from 'ui/i18n'; + +uiModules + .get('app/kibana', ['react']) + .directive('rawJsonSelect', reactDirective => reactDirective(wrapInI18nContext(RawJSONSelect), [ + 'onParamsChange', + ['agg', { watchDepth: 'collection' }] + ])); diff --git a/src/legacy/ui/public/agg_types/index.js b/src/legacy/ui/public/agg_types/index.js index 93ca63ccde786..e1cec60d47db9 100644 --- a/src/legacy/ui/public/agg_types/index.js +++ b/src/legacy/ui/public/agg_types/index.js @@ -19,6 +19,7 @@ import '../directives/validate_agg'; import './agg_params'; +import '../agg_types/controls/raw_json_select'; import { IndexedArray } from '../indexed_array'; import { countMetricAgg } from './metrics/count'; import { avgMetricAgg } from './metrics/avg'; diff --git a/src/legacy/ui/public/agg_types/utils.tsx b/src/legacy/ui/public/agg_types/utils.tsx new file mode 100644 index 0000000000000..4839639e015fd --- /dev/null +++ b/src/legacy/ui/public/agg_types/utils.tsx @@ -0,0 +1,39 @@ +/* + * 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. + */ + +function isValidJson(value: string) { + if (!value || value.length === 0) { + return true; + } + + const trimmedValue = value.trim(); + + if (trimmedValue[0] === '{' || trimmedValue[0] === '[') { + try { + JSON.parse(trimmedValue); + return true; + } catch (e) { + return false; + } + } else { + return false; + } +} + +export { isValidJson }; diff --git a/src/legacy/ui/public/vis/editors/default/__tests__/agg_params.js b/src/legacy/ui/public/vis/editors/default/__tests__/agg_params.js index 9e84cdf4b90ad..d3ee5e5ec3d43 100644 --- a/src/legacy/ui/public/vis/editors/default/__tests__/agg_params.js +++ b/src/legacy/ui/public/vis/editors/default/__tests__/agg_params.js @@ -21,6 +21,7 @@ import angular from 'angular'; import _ from 'lodash'; import expect from 'expect.js'; +import sinon from 'sinon'; import ngMock from 'ng_mock'; import '../agg_params'; import { VisProvider } from '../../..'; @@ -61,6 +62,10 @@ describe('Vis-Editor-Agg-Params plugin directive', function () { orderAggSchema = (new Schemas([config])).all[0]; $parentScope.groupName = 'metrics'; + const formCtrl = { + $addControl: sinon.fake() + }; + const state = { schema: orderAggSchema, type: 'count' @@ -84,6 +89,8 @@ describe('Vis-Editor-Agg-Params plugin directive', function () { `` ); + $elem.data('$formController', formCtrl); + // compile the html compile($elem)($parentScope); diff --git a/src/legacy/ui/public/vis/editors/default/agg_params.js b/src/legacy/ui/public/vis/editors/default/agg_params.js index 9df0029bc9f8e..7a4c33b7c4658 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_params.js +++ b/src/legacy/ui/public/vis/editors/default/agg_params.js @@ -39,7 +39,8 @@ uiModules restrict: 'E', template: aggParamsTemplate, scope: true, - link: function ($scope, $el, attr) { + require: '^form', + link: function ($scope, $el, attr, aggForm) { $scope.$bind('agg', attr.agg); $scope.$bind('groupName', attr.groupName); $scope.$bind('indexPattern', attr.indexPattern); @@ -56,6 +57,20 @@ uiModules updateEditorConfig('default'); }); + $scope.onParamsChange = (type, agg, value, options) => { + if(agg.params[type] !== value) { + agg.params[type] = value; + } + + if (aggForm && aggForm[type]) { + aggForm[type].$setDirty(); + } + + if (options && typeof options.isValid === 'boolean') { + aggForm[type].$setValidity(type, options.isValid); + } + }; + function updateEditorConfig(property = 'fixedValue') { $scope.editorConfig = editorConfigProviders.getConfigForAgg( aggTypes.byType[$scope.groupName], From e05964824f85a9690d7a8fd9b16273ff28cc3d9c Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Tue, 19 Mar 2019 18:03:57 +0300 Subject: [PATCH 02/12] Refactoring --- .../public/agg_types/controls/raw_json.html | 1 - .../ui/public/agg_types/controls/raw_json.tsx | 38 ++++++------------- .../agg_types/controls/raw_json_select.js | 30 --------------- src/legacy/ui/public/agg_types/index.js | 1 - .../ui/public/agg_types/param_types/json.js | 4 +- src/legacy/ui/public/agg_types/utils.tsx | 2 +- .../public/vis/editors/default/agg_param.js | 18 ++++++++- .../editors/default/agg_param_editor_props.ts | 8 +++- .../default/agg_param_react_wrapper.tsx | 17 +++++++-- .../ui/public/vis/editors/default/index.ts | 2 +- .../translations/translations/zh-CN.json | 1 - 11 files changed, 52 insertions(+), 70 deletions(-) delete mode 100644 src/legacy/ui/public/agg_types/controls/raw_json.html delete mode 100644 src/legacy/ui/public/agg_types/controls/raw_json_select.js diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.html b/src/legacy/ui/public/agg_types/controls/raw_json.html deleted file mode 100644 index 04294d6f9e3a5..0000000000000 --- a/src/legacy/ui/public/agg_types/controls/raw_json.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index e722f2e76cff1..c5658400dfdeb 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -16,31 +16,22 @@ * specific language governing permissions and limitations * under the License. */ +import React from 'react'; import { EuiFormRow, EuiIcon, EuiTextArea, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { get } from 'lodash'; -import React, { useState } from 'react'; -import { AggConfig } from 'ui/vis/agg_config'; -import { isValidJson } from '../utils'; - -interface RawJSONSelectProps { - agg: AggConfig; - onParamsChange: ( - type: string, - agg: AggConfig, - field: any, - options?: { isValid?: boolean } - ) => void; -} - -function RawJSONSelect({ agg = {}, onParamsChange }: RawJSONSelectProps) { - const [isInvalid, setIsInvalid] = useState(false); +import { AggParamRequiredEditorProps } from '../../vis/editors/default'; +function RawJsonParamEditor({ + agg, + value, + setValue, + isInvalid, +}: AggParamRequiredEditorProps) { const label = ( <> - {' '} + {' '} ); - const onTextAreaChange = (e: React.ChangeEvent) => { - const value: string = get(e, 'target.value'); - const isValid = isValidJson(value); - setIsInvalid(!isValid); - onParamsChange('json', agg, value, { isValid }); - }; return ( setValue(ev.target.value)} rows={2} /> ); } -export { RawJSONSelect }; +export { RawJsonParamEditor }; diff --git a/src/legacy/ui/public/agg_types/controls/raw_json_select.js b/src/legacy/ui/public/agg_types/controls/raw_json_select.js deleted file mode 100644 index f61576b59c3a4..0000000000000 --- a/src/legacy/ui/public/agg_types/controls/raw_json_select.js +++ /dev/null @@ -1,30 +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 'ngreact'; -import { uiModules } from '../../modules'; -import { RawJSONSelect } from './raw_json'; -import { wrapInI18nContext } from 'ui/i18n'; - -uiModules - .get('app/kibana', ['react']) - .directive('rawJsonSelect', reactDirective => reactDirective(wrapInI18nContext(RawJSONSelect), [ - 'onParamsChange', - ['agg', { watchDepth: 'collection' }] - ])); diff --git a/src/legacy/ui/public/agg_types/index.js b/src/legacy/ui/public/agg_types/index.js index e1cec60d47db9..93ca63ccde786 100644 --- a/src/legacy/ui/public/agg_types/index.js +++ b/src/legacy/ui/public/agg_types/index.js @@ -19,7 +19,6 @@ import '../directives/validate_agg'; import './agg_params'; -import '../agg_types/controls/raw_json_select'; import { IndexedArray } from '../indexed_array'; import { countMetricAgg } from './metrics/count'; import { avgMetricAgg } from './metrics/avg'; diff --git a/src/legacy/ui/public/agg_types/param_types/json.js b/src/legacy/ui/public/agg_types/param_types/json.js index 6eb7e8662b629..fe759090e84b6 100644 --- a/src/legacy/ui/public/agg_types/param_types/json.js +++ b/src/legacy/ui/public/agg_types/param_types/json.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import editorHtml from '../controls/raw_json.html'; +import { RawJsonParamEditor } from '../controls/raw_json'; import { BaseParamType } from './base'; import { createLegacyClass } from '../../utils/legacy_class'; @@ -30,7 +30,7 @@ function JsonParamType(config) { JsonParamType.Super.call(this, config); } -JsonParamType.prototype.editor = editorHtml; +JsonParamType.prototype.editorComponent = RawJsonParamEditor; /** * Write the aggregation parameter. diff --git a/src/legacy/ui/public/agg_types/utils.tsx b/src/legacy/ui/public/agg_types/utils.tsx index 4839639e015fd..98aa18fcc1692 100644 --- a/src/legacy/ui/public/agg_types/utils.tsx +++ b/src/legacy/ui/public/agg_types/utils.tsx @@ -17,7 +17,7 @@ * under the License. */ -function isValidJson(value: string) { +function isValidJson(value: string): boolean { if (!value || value.length === 0) { return true; } diff --git a/src/legacy/ui/public/vis/editors/default/agg_param.js b/src/legacy/ui/public/vis/editors/default/agg_param.js index ec2e6891f6932..b8d9e1f2f0411 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param.js +++ b/src/legacy/ui/public/vis/editors/default/agg_param.js @@ -17,10 +17,11 @@ * under the License. */ -import { isFunction } from 'lodash'; +import { isFunction, noop } from 'lodash'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from '../../../modules'; import { AggParamReactWrapper } from './agg_param_react_wrapper'; +import { isValidJson } from '../../../agg_types/utils'; uiModules .get('app/visualize') @@ -30,6 +31,7 @@ uiModules ['paramEditor', { wrapApply: false }], ['onChange', { watchDepth: 'reference' }], 'value', + 'isInvalid' ])) .directive('visAggParamEditor', function (config) { return { @@ -54,6 +56,7 @@ uiModules agg-param="aggParam" on-change="onChange" value="paramValue" + is-invalid="isInvalid" >`; } @@ -81,6 +84,10 @@ uiModules // Whenever the value of the parameter changed (e.g. by a reset or actually by calling) // we store the new value in $scope.paramValue, which will be passed as a new value to the react component. $scope.paramValue = value; + + if(ngModelCtrl) { + ngModelCtrl.$$runValidators(value, null, noop); + } }, true); } @@ -93,6 +100,15 @@ uiModules ngModelCtrl.$setDirty(); } }; + + if(ngModelCtrl && $scope.aggParam.name === 'json') { + ngModelCtrl.$validators.jsonInput = (modelValue) => { + const isJsonValid = isValidJson(modelValue); + $scope.isInvalid = !isJsonValid; + + return isJsonValid; + }; + } } } }; diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts index 3e7623b6c25fc..71186ab6fa06e 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts +++ b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts @@ -22,9 +22,13 @@ import { AggConfig } from '../../agg_config'; interface AggParamEditorProps { agg: AggConfig; - aggParam: AggParam; + aggParam?: AggParam; value: T; setValue(value: T): void; } -export { AggParamEditorProps }; +interface AggParamRequiredEditorProps extends AggParamEditorProps { + isInvalid: boolean; +} + +export { AggParamEditorProps, AggParamRequiredEditorProps }; diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx index 4b5380c92559c..e15720b60d1d6 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx +++ b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx @@ -21,19 +21,28 @@ import React from 'react'; import { AggParam } from '../../../agg_types'; import { AggConfig } from '../../agg_config'; -import { AggParamEditorProps } from './agg_param_editor_props'; +import { AggParamEditorProps, AggParamRequiredEditorProps } from './agg_param_editor_props'; interface AggParamReactWrapperProps { agg: AggConfig; aggParam: AggParam; - paramEditor: React.FunctionComponent>; + paramEditor: React.FunctionComponent | AggParamRequiredEditorProps>; value: T; + isInvalid: boolean; onChange(value: T): void; } function AggParamReactWrapper(props: AggParamReactWrapperProps) { - const { agg, aggParam, paramEditor: ParamEditor, onChange, value } = props; - return ; + const { agg, aggParam, paramEditor: ParamEditor, onChange, value, isInvalid } = props; + return ( + + ); } export { AggParamReactWrapper }; diff --git a/src/legacy/ui/public/vis/editors/default/index.ts b/src/legacy/ui/public/vis/editors/default/index.ts index 7167a09492b5c..9573a694a8a55 100644 --- a/src/legacy/ui/public/vis/editors/default/index.ts +++ b/src/legacy/ui/public/vis/editors/default/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { AggParamEditorProps } from './agg_param_editor_props'; +export { AggParamEditorProps, AggParamRequiredEditorProps } from './agg_param_editor_props'; diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8f705fa69439d..4ee75ecc7a31c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -161,7 +161,6 @@ "common.ui.aggTypes.ipRanges.toLabel": "到", "common.ui.aggTypes.ipRanges.useCidrMasksButtonLabel": "使用 CIDR 掩码", "common.ui.aggTypes.ipRanges.useFromToButtonLabel": "使用“从”/“到”", - "common.ui.aggTypes.jsonInputLabel": "JSON 输入", "common.ui.aggTypes.jsonInputTooltip": "此处以 JSON 格式添加的任何属性将与此部分的 elasticsearch 聚合定义合并。例如,词聚合上的“shard_size”。", "common.ui.aggTypes.metricLabel": "指标", "common.ui.aggTypes.metrics.aggNotValidErrorMessage": "- 聚合无效 -", From c8cac9c590060dda22b46215a399fcc3b2841bb3 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Tue, 19 Mar 2019 18:06:35 +0300 Subject: [PATCH 03/12] Remove unused validate-json directive --- .../directives/__tests__/validate_json.js | 111 ------------------ .../ui/public/directives/validate_json.js | 64 ---------- 2 files changed, 175 deletions(-) delete mode 100644 src/legacy/ui/public/directives/__tests__/validate_json.js delete mode 100644 src/legacy/ui/public/directives/validate_json.js diff --git a/src/legacy/ui/public/directives/__tests__/validate_json.js b/src/legacy/ui/public/directives/__tests__/validate_json.js deleted file mode 100644 index b59ee7bccf7ec..0000000000000 --- a/src/legacy/ui/public/directives/__tests__/validate_json.js +++ /dev/null @@ -1,111 +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 angular from 'angular'; -import expect from 'expect.js'; -import ngMock from 'ng_mock'; -import '../validate_json'; - -// Load the kibana app dependencies. - -let $parentScope; -let $elemScope; -let $elem; -const mockScope = ''; - -const input = { - valid: '{ "test": "json input" }', - invalid: 'strings are not json' -}; - -const markup = { - textarea: '', - input: '' -}; - -const init = function (type) { - // Load the application - ngMock.module('kibana'); - type = type || 'input'; - const elMarkup = markup[type]; - - // Create the scope - ngMock.inject(function ($injector, $rootScope, $compile) { - // Give us a scope - $parentScope = $rootScope; - $parentScope.mockModel = mockScope; - - $elem = angular.element(elMarkup); - $compile($elem)($parentScope); - $elemScope = $elem.isolateScope(); - }); -}; - -describe('validate-json directive', function () { - const checkValid = function (inputVal, className) { - $parentScope.mockModel = inputVal; - $elem.scope().$digest(); - expect($elem.hasClass(className)).to.be(true); - }; - - describe('initialization', function () { - beforeEach(function () { - init(); - }); - - it('should use the model', function () { - expect($elemScope).to.have.property('ngModel'); - }); - - }); - - Object.keys(markup).forEach(function (inputType) { - describe(inputType, function () { - beforeEach(function () { - init(inputType); - }); - - it('should be an input', function () { - expect($elem.get(0).tagName).to.be(inputType.toUpperCase()); - }); - - it('should set valid state', function () { - checkValid(input.valid, 'ng-valid'); - }); - - it('should be valid when empty', function () { - checkValid('', 'ng-valid'); - }); - - it('should set invalid state', function () { - checkValid(input.invalid, 'ng-invalid'); - }); - - it('should be invalid if a number', function () { - checkValid('0', 'ng-invalid'); - }); - - it('should update validity on changes', function () { - checkValid(input.valid, 'ng-valid'); - checkValid(input.invalid, 'ng-invalid'); - checkValid(input.valid, 'ng-valid'); - }); - }); - }); -}); diff --git a/src/legacy/ui/public/directives/validate_json.js b/src/legacy/ui/public/directives/validate_json.js deleted file mode 100644 index 396cfd13daf88..0000000000000 --- a/src/legacy/ui/public/directives/validate_json.js +++ /dev/null @@ -1,64 +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 { uiModules } from '../modules'; - -const module = uiModules.get('kibana'); - -module.directive('validateJson', function () { - return { - restrict: 'A', - require: 'ngModel', - scope: { - 'ngModel': '=', - 'queryInput': '=?', - }, - link: function ($scope, $elem, attr, ngModel) { - $scope.$watch('ngModel', validator); - - function validator(newValue) { - if (!newValue || newValue.length === 0) { - setValid(); - return; - } - - // We actually need a proper object in all JSON inputs - newValue = (newValue || '').trim(); - if (newValue[0] === '{' || newValue[0] === '[') { - try { - JSON.parse(newValue); - setValid(); - } catch (e) { - setInvalid(); - } - } else { - setInvalid(); - } - } - - function setValid() { - ngModel.$setValidity('jsonInput', true); - } - - function setInvalid() { - ngModel.$setValidity('jsonInput', false); - } - } - }; -}); From 7d8dde46a75b40e327240c4c3b186f6b0f23b230 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Wed, 20 Mar 2019 13:40:14 +0300 Subject: [PATCH 04/12] Update tests --- .../public/discover/controllers/discover.js | 1 - .../buckets/date_histogram/_editor.js | 6 --- .../ui/public/agg_types/controls/raw_json.tsx | 2 +- .../editors/default/__tests__/agg_params.js | 7 --- .../editors/default/__tests__/utils.test.tsx | 50 +++++++++++++++++++ .../vis/editors/default/_agg_select.scss | 4 ++ .../public/vis/editors/default/agg_param.js | 2 +- .../editors/default/agg_param_editor_props.ts | 2 +- .../editors/default}/utils.tsx | 0 9 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx rename src/legacy/ui/public/{agg_types => vis/editors/default}/utils.tsx (100%) diff --git a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js index 3c8da5dd3ab8f..5e6bc1595e74b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js @@ -28,7 +28,6 @@ import dateMath from '@elastic/datemath'; import 'ui/doc_table'; import 'ui/visualize'; import 'ui/fixed_scroll'; -import 'ui/directives/validate_json'; import 'ui/filters/moment'; import 'ui/index_patterns'; import 'ui/state_management/app_state'; diff --git a/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js b/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js index 20dea556306ee..afacdc522562e 100644 --- a/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js +++ b/src/legacy/ui/public/agg_types/__tests__/buckets/date_histogram/_editor.js @@ -21,7 +21,6 @@ import _ from 'lodash'; import $ from 'jquery'; import ngMock from 'ng_mock'; import expect from 'expect.js'; -import sinon from 'sinon'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import { VisProvider } from '../../../../vis'; import { intervalOptions } from '../../../buckets/_interval_options'; @@ -59,10 +58,6 @@ describe('editor', function () { ] }); - const formCtrl = { - $addControl: sinon.fake() - }; - const $el = $('' + @@ -73,7 +68,6 @@ describe('editor', function () { $parentScope.groupName = 'buckets'; $parentScope.vis = vis; - $el.data('$formController', formCtrl); $compile($el)($parentScope); $scope = $el.scope(); $scope.$digest(); diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index c5658400dfdeb..f63cdac70c33f 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -45,7 +45,7 @@ function RawJsonParamEditor({ ); return ( - + ` ); - $elem.data('$formController', formCtrl); - // compile the html compile($elem)($parentScope); diff --git a/src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx b/src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx new file mode 100644 index 0000000000000..99b506ab51e66 --- /dev/null +++ b/src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx @@ -0,0 +1,50 @@ +/* + * 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 expect from 'expect.js'; +import { isValidJson } from '../utils'; + +const input = { + valid: '{ "test": "json input" }', + invalid: 'strings are not json', +}; + +describe('AggType utils', () => { + describe('isValidJson', () => { + it('should return true when empty string', () => { + expect(isValidJson('')).to.be(true); + }); + + it('should return true when undefine', () => { + expect(isValidJson(undefined as any)).to.be(true); + }); + + it('should return fasle when invalid string', () => { + expect(isValidJson(input.invalid)).to.be(false); + }); + + it('should return true when valid string', () => { + expect(isValidJson(input.valid)).to.be(true); + }); + + it('should return fasle if a number', () => { + expect(isValidJson('0')).to.be(false); + }); + }); +}); diff --git a/src/legacy/ui/public/vis/editors/default/_agg_select.scss b/src/legacy/ui/public/vis/editors/default/_agg_select.scss index 501344bc1e4cf..72845b643a5b5 100644 --- a/src/legacy/ui/public/vis/editors/default/_agg_select.scss +++ b/src/legacy/ui/public/vis/editors/default/_agg_select.scss @@ -20,3 +20,7 @@ .visEditorAggSelect__helpLink { @include euiFontSizeXS; } + +vis-agg-select-react-wrapper .euiFormRow { + margin-bottom: 7px; +} diff --git a/src/legacy/ui/public/vis/editors/default/agg_param.js b/src/legacy/ui/public/vis/editors/default/agg_param.js index b8d9e1f2f0411..d4c59bcf58b6d 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param.js +++ b/src/legacy/ui/public/vis/editors/default/agg_param.js @@ -21,7 +21,7 @@ import { isFunction, noop } from 'lodash'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from '../../../modules'; import { AggParamReactWrapper } from './agg_param_react_wrapper'; -import { isValidJson } from '../../../agg_types/utils'; +import { isValidJson } from './utils'; uiModules .get('app/visualize') diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts index 71186ab6fa06e..d019fc3dd9d93 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts +++ b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts @@ -22,7 +22,7 @@ import { AggConfig } from '../../agg_config'; interface AggParamEditorProps { agg: AggConfig; - aggParam?: AggParam; + aggParam: AggParam; value: T; setValue(value: T): void; } diff --git a/src/legacy/ui/public/agg_types/utils.tsx b/src/legacy/ui/public/vis/editors/default/utils.tsx similarity index 100% rename from src/legacy/ui/public/agg_types/utils.tsx rename to src/legacy/ui/public/vis/editors/default/utils.tsx From 0f90229d6314a15249f9c68ff1e5db6a8f069367 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Wed, 20 Mar 2019 14:03:21 +0300 Subject: [PATCH 05/12] Update styles --- src/legacy/ui/public/agg_types/controls/raw_json.tsx | 5 +++-- src/legacy/ui/public/vis/editors/default/_agg_select.scss | 3 --- src/legacy/ui/public/vis/editors/default/_sidebar.scss | 3 +++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index f63cdac70c33f..f3ac8c5916a6e 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -45,13 +45,14 @@ function RawJsonParamEditor({ ); return ( - + setValue(ev.target.value)} rows={2} + fullWidth={true} /> ); diff --git a/src/legacy/ui/public/vis/editors/default/_agg_select.scss b/src/legacy/ui/public/vis/editors/default/_agg_select.scss index 72845b643a5b5..16646c634b650 100644 --- a/src/legacy/ui/public/vis/editors/default/_agg_select.scss +++ b/src/legacy/ui/public/vis/editors/default/_agg_select.scss @@ -21,6 +21,3 @@ @include euiFontSizeXS; } -vis-agg-select-react-wrapper .euiFormRow { - margin-bottom: 7px; -} diff --git a/src/legacy/ui/public/vis/editors/default/_sidebar.scss b/src/legacy/ui/public/vis/editors/default/_sidebar.scss index ca5961c5ff851..60a8e7372c901 100644 --- a/src/legacy/ui/public/vis/editors/default/_sidebar.scss +++ b/src/legacy/ui/public/vis/editors/default/_sidebar.scss @@ -221,3 +221,6 @@ } } +vis-agg-param-react-wrapper .euiFormRow { + margin-bottom: 7px; +} From ec8a521c72d6feebf7a4500a36ed2a03679a0af5 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Thu, 21 Mar 2019 10:29:44 +0300 Subject: [PATCH 06/12] Updates according to SASS guidelines --- .../ui/public/agg_types/controls/raw_json.tsx | 16 ++++++++++------ .../vis/editors/default/__tests__/utils.test.tsx | 4 ++-- .../public/vis/editors/default/_agg_select.scss | 1 - .../ui/public/vis/editors/default/_sidebar.scss | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index f3ac8c5916a6e..25a0cb2f0028c 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; -import { EuiFormRow, EuiIcon, EuiTextArea, EuiToolTip } from '@elastic/eui'; +import { EuiFormRow, EuiIconTip, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AggParamRequiredEditorProps } from '../../vis/editors/default'; @@ -32,20 +32,24 @@ function RawJsonParamEditor({ const label = ( <> {' '} - - - + type="questionInCircle" + /> ); return ( - + { expect(isValidJson(undefined as any)).to.be(true); }); - it('should return fasle when invalid string', () => { + it('should return false when invalid string', () => { expect(isValidJson(input.invalid)).to.be(false); }); @@ -43,7 +43,7 @@ describe('AggType utils', () => { expect(isValidJson(input.valid)).to.be(true); }); - it('should return fasle if a number', () => { + it('should return false if a number', () => { expect(isValidJson('0')).to.be(false); }); }); diff --git a/src/legacy/ui/public/vis/editors/default/_agg_select.scss b/src/legacy/ui/public/vis/editors/default/_agg_select.scss index 16646c634b650..501344bc1e4cf 100644 --- a/src/legacy/ui/public/vis/editors/default/_agg_select.scss +++ b/src/legacy/ui/public/vis/editors/default/_agg_select.scss @@ -20,4 +20,3 @@ .visEditorAggSelect__helpLink { @include euiFontSizeXS; } - diff --git a/src/legacy/ui/public/vis/editors/default/_sidebar.scss b/src/legacy/ui/public/vis/editors/default/_sidebar.scss index 60a8e7372c901..a13935b50d886 100644 --- a/src/legacy/ui/public/vis/editors/default/_sidebar.scss +++ b/src/legacy/ui/public/vis/editors/default/_sidebar.scss @@ -221,6 +221,6 @@ } } -vis-agg-param-react-wrapper .euiFormRow { - margin-bottom: 7px; +.visEditorSidebar__aggParamFormRow { + margin-bottom: $euiSizeS; } From 1c10e3631ee1ab4675f7e034a06450f9f6f4ecbc Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Thu, 21 Mar 2019 15:37:52 +0300 Subject: [PATCH 07/12] Use models's $setViewValue function --- src/legacy/ui/public/vis/editors/default/agg_param.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/legacy/ui/public/vis/editors/default/agg_param.js b/src/legacy/ui/public/vis/editors/default/agg_param.js index d4c59bcf58b6d..bfd9d648c36a5 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param.js +++ b/src/legacy/ui/public/vis/editors/default/agg_param.js @@ -17,7 +17,7 @@ * under the License. */ -import { isFunction, noop } from 'lodash'; +import { isFunction } from 'lodash'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from '../../../modules'; import { AggParamReactWrapper } from './agg_param_react_wrapper'; @@ -86,7 +86,7 @@ uiModules $scope.paramValue = value; if(ngModelCtrl) { - ngModelCtrl.$$runValidators(value, null, noop); + ngModelCtrl.$setViewValue(value); } }, true); } @@ -102,8 +102,8 @@ uiModules }; if(ngModelCtrl && $scope.aggParam.name === 'json') { - ngModelCtrl.$validators.jsonInput = (modelValue) => { - const isJsonValid = isValidJson(modelValue); + ngModelCtrl.$validators.jsonInput = (value) => { + const isJsonValid = isValidJson(value); $scope.isInvalid = !isJsonValid; return isJsonValid; From c2caf7eb6927292d9874e012a4bb221d6b1a0a1b Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Tue, 26 Mar 2019 10:27:40 +0300 Subject: [PATCH 08/12] Remove unused test --- .../directives/__tests__/validate_json.js | 111 ------------------ 1 file changed, 111 deletions(-) delete mode 100644 src/legacy/ui/public/directives/__tests__/validate_json.js diff --git a/src/legacy/ui/public/directives/__tests__/validate_json.js b/src/legacy/ui/public/directives/__tests__/validate_json.js deleted file mode 100644 index dd533851ac4d5..0000000000000 --- a/src/legacy/ui/public/directives/__tests__/validate_json.js +++ /dev/null @@ -1,111 +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 angular from 'angular'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import '../validate_json'; - -// Load the kibana app dependencies. - -let $parentScope; -let $elemScope; -let $elem; -const mockScope = ''; - -const input = { - valid: '{ "test": "json input" }', - invalid: 'strings are not json' -}; - -const markup = { - textarea: '', - input: '' -}; - -const init = function (type) { - // Load the application - ngMock.module('kibana'); - type = type || 'input'; - const elMarkup = markup[type]; - - // Create the scope - ngMock.inject(function ($injector, $rootScope, $compile) { - // Give us a scope - $parentScope = $rootScope; - $parentScope.mockModel = mockScope; - - $elem = angular.element(elMarkup); - $compile($elem)($parentScope); - $elemScope = $elem.isolateScope(); - }); -}; - -describe('validate-json directive', function () { - const checkValid = function (inputVal, className) { - $parentScope.mockModel = inputVal; - $elem.scope().$digest(); - expect($elem.hasClass(className)).to.be(true); - }; - - describe('initialization', function () { - beforeEach(function () { - init(); - }); - - it('should use the model', function () { - expect($elemScope).to.have.property('ngModel'); - }); - - }); - - Object.keys(markup).forEach(function (inputType) { - describe(inputType, function () { - beforeEach(function () { - init(inputType); - }); - - it('should be an input', function () { - expect($elem.get(0).tagName).to.be(inputType.toUpperCase()); - }); - - it('should set valid state', function () { - checkValid(input.valid, 'ng-valid'); - }); - - it('should be valid when empty', function () { - checkValid('', 'ng-valid'); - }); - - it('should set invalid state', function () { - checkValid(input.invalid, 'ng-invalid'); - }); - - it('should be invalid if a number', function () { - checkValid('0', 'ng-invalid'); - }); - - it('should update validity on changes', function () { - checkValid(input.valid, 'ng-valid'); - checkValid(input.invalid, 'ng-invalid'); - checkValid(input.valid, 'ng-valid'); - }); - }); - }); -}); From 955dbcdcb86fd3fcddee8a2bb66d1db860b649d7 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Tue, 26 Mar 2019 13:01:42 +0300 Subject: [PATCH 09/12] Move validation logic down to control --- .../__tests__/utils.test.tsx | 0 .../ui/public/agg_types/controls/raw_json.tsx | 13 +++++++++++- .../editors/default => agg_types}/utils.tsx | 0 .../public/vis/editors/default/agg_param.js | 21 +++++++------------ .../editors/default/agg_param_editor_props.ts | 1 + .../default/agg_param_react_wrapper.tsx | 12 ++++++++++- 6 files changed, 32 insertions(+), 15 deletions(-) rename src/legacy/ui/public/{vis/editors/default => agg_types}/__tests__/utils.test.tsx (100%) rename src/legacy/ui/public/{vis/editors/default => agg_types}/utils.tsx (100%) diff --git a/src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx b/src/legacy/ui/public/agg_types/__tests__/utils.test.tsx similarity index 100% rename from src/legacy/ui/public/vis/editors/default/__tests__/utils.test.tsx rename to src/legacy/ui/public/agg_types/__tests__/utils.test.tsx diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index 25a0cb2f0028c..f95c17a1de806 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -16,18 +16,21 @@ * specific language governing permissions and limitations * under the License. */ +import { get } from 'lodash'; import React from 'react'; import { EuiFormRow, EuiIconTip, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AggParamRequiredEditorProps } from '../../vis/editors/default'; +import { isValidJson } from '../utils'; function RawJsonParamEditor({ agg, value, setValue, isInvalid, + setValidity, }: AggParamRequiredEditorProps) { const label = ( <> @@ -43,6 +46,14 @@ function RawJsonParamEditor({ ); + const onChange = (ev: React.ChangeEvent) => { + const textValue: string = get(ev, 'target.value'); + setValue(textValue); + setValidity(isValidJson(textValue)); + }; + + setValidity(isValidJson(value)); + return ( setValue(ev.target.value)} + onChange={onChange} rows={2} fullWidth={true} /> diff --git a/src/legacy/ui/public/vis/editors/default/utils.tsx b/src/legacy/ui/public/agg_types/utils.tsx similarity index 100% rename from src/legacy/ui/public/vis/editors/default/utils.tsx rename to src/legacy/ui/public/agg_types/utils.tsx diff --git a/src/legacy/ui/public/vis/editors/default/agg_param.js b/src/legacy/ui/public/vis/editors/default/agg_param.js index bfd9d648c36a5..75f67091cf981 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param.js +++ b/src/legacy/ui/public/vis/editors/default/agg_param.js @@ -21,7 +21,6 @@ import { isFunction } from 'lodash'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from '../../../modules'; import { AggParamReactWrapper } from './agg_param_react_wrapper'; -import { isValidJson } from './utils'; uiModules .get('app/visualize') @@ -30,6 +29,7 @@ uiModules ['aggParam', { watchDepth: 'reference' }], ['paramEditor', { wrapApply: false }], ['onChange', { watchDepth: 'reference' }], + ['setValidity', { watchDepth: 'reference' }], 'value', 'isInvalid' ])) @@ -57,6 +57,7 @@ uiModules on-change="onChange" value="paramValue" is-invalid="isInvalid" + set-validity="setValidity" >`; } @@ -84,10 +85,6 @@ uiModules // Whenever the value of the parameter changed (e.g. by a reset or actually by calling) // we store the new value in $scope.paramValue, which will be passed as a new value to the react component. $scope.paramValue = value; - - if(ngModelCtrl) { - ngModelCtrl.$setViewValue(value); - } }, true); } @@ -101,14 +98,12 @@ uiModules } }; - if(ngModelCtrl && $scope.aggParam.name === 'json') { - ngModelCtrl.$validators.jsonInput = (value) => { - const isJsonValid = isValidJson(value); - $scope.isInvalid = !isJsonValid; - - return isJsonValid; - }; - } + $scope.setValidity = (isValid) => { + if(ngModelCtrl) { + $scope.isInvalid = !isValid; + ngModelCtrl.$setValidity(`agg${$scope.agg.id}${$scope.aggParam.name}`, isValid); + } + }; } } }; diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts index d019fc3dd9d93..31a002cb2bdc3 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts +++ b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts @@ -29,6 +29,7 @@ interface AggParamEditorProps { interface AggParamRequiredEditorProps extends AggParamEditorProps { isInvalid: boolean; + setValidity(isValid: boolean): void; } export { AggParamEditorProps, AggParamRequiredEditorProps }; diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx index e15720b60d1d6..75b41a96425b9 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx +++ b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx @@ -30,10 +30,19 @@ interface AggParamReactWrapperProps { value: T; isInvalid: boolean; onChange(value: T): void; + setValidity(isValid: boolean): void; } function AggParamReactWrapper(props: AggParamReactWrapperProps) { - const { agg, aggParam, paramEditor: ParamEditor, onChange, value, isInvalid } = props; + const { + agg, + aggParam, + paramEditor: ParamEditor, + onChange, + value, + isInvalid, + setValidity, + } = props; return ( (props: AggParamReactWrapperProps) { aggParam={aggParam} agg={agg} isInvalid={isInvalid} + setValidity={setValidity} /> ); } From 75c73e9cef88158657d1db46b0a2d2ebb18b9fd3 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Wed, 27 Mar 2019 10:34:07 +0300 Subject: [PATCH 10/12] Fix merge conflict --- .../ui/public/vis/editors/default/agg_param_editor_props.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts index ab57153755c91..464b3bda49b7b 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts +++ b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts @@ -30,3 +30,8 @@ export interface AggParamEditorProps { value: T; setValue(value: T): void; } + +export interface AggParamRequiredEditorProps extends AggParamEditorProps { + isInvalid: boolean; + setValidity(isValid: boolean): void; +} From 620ed23bbd386381ce81d1188b659169626cb54f Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Wed, 27 Mar 2019 14:52:23 +0300 Subject: [PATCH 11/12] Fix code review comments --- src/legacy/ui/public/agg_types/controls/raw_json.tsx | 8 ++++---- .../public/vis/editors/default/agg_param_editor_props.ts | 5 +---- src/legacy/ui/public/vis/editors/default/index.ts | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/legacy/ui/public/agg_types/controls/raw_json.tsx b/src/legacy/ui/public/agg_types/controls/raw_json.tsx index f95c17a1de806..5dcd555ea969b 100644 --- a/src/legacy/ui/public/agg_types/controls/raw_json.tsx +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -16,13 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { get } from 'lodash'; + import React from 'react'; import { EuiFormRow, EuiIconTip, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { AggParamRequiredEditorProps } from '../../vis/editors/default'; +import { AggParamEditorProps } from '../../vis/editors/default'; import { isValidJson } from '../utils'; function RawJsonParamEditor({ @@ -31,7 +31,7 @@ function RawJsonParamEditor({ setValue, isInvalid, setValidity, -}: AggParamRequiredEditorProps) { +}: AggParamEditorProps) { const label = ( <> {' '} @@ -47,7 +47,7 @@ function RawJsonParamEditor({ ); const onChange = (ev: React.ChangeEvent) => { - const textValue: string = get(ev, 'target.value'); + const textValue = ev.target.value; setValue(textValue); setValidity(isValidJson(textValue)); }; diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts index 464b3bda49b7b..9a38de80dc3b1 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts +++ b/src/legacy/ui/public/vis/editors/default/agg_param_editor_props.ts @@ -28,10 +28,7 @@ export interface AggParamEditorProps { agg: AggConfig; aggParam: AggParam; value: T; - setValue(value: T): void; -} - -export interface AggParamRequiredEditorProps extends AggParamEditorProps { isInvalid: boolean; + setValue(value: T): void; setValidity(isValid: boolean): void; } diff --git a/src/legacy/ui/public/vis/editors/default/index.ts b/src/legacy/ui/public/vis/editors/default/index.ts index 9573a694a8a55..7167a09492b5c 100644 --- a/src/legacy/ui/public/vis/editors/default/index.ts +++ b/src/legacy/ui/public/vis/editors/default/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { AggParamEditorProps, AggParamRequiredEditorProps } from './agg_param_editor_props'; +export { AggParamEditorProps } from './agg_param_editor_props'; From 4497150d185417b4bf064cd8381fc49b10417dd9 Mon Sep 17 00:00:00 2001 From: maryia-lapata Date: Wed, 27 Mar 2019 14:58:07 +0300 Subject: [PATCH 12/12] Fix type --- .../ui/public/vis/editors/default/agg_param_react_wrapper.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx index 75b41a96425b9..3146c205dceae 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx +++ b/src/legacy/ui/public/vis/editors/default/agg_param_react_wrapper.tsx @@ -21,12 +21,12 @@ import React from 'react'; import { AggParam } from '../../../agg_types'; import { AggConfig } from '../../agg_config'; -import { AggParamEditorProps, AggParamRequiredEditorProps } from './agg_param_editor_props'; +import { AggParamEditorProps } from './agg_param_editor_props'; interface AggParamReactWrapperProps { agg: AggConfig; aggParam: AggParam; - paramEditor: React.FunctionComponent | AggParamRequiredEditorProps>; + paramEditor: React.FunctionComponent>; value: T; isInvalid: boolean; onChange(value: T): void;