From 41f032efa7660e526cee6875084b616333a29fb0 Mon Sep 17 00:00:00 2001 From: Maryia Lapata Date: Thu, 28 Mar 2019 11:40:40 +0300 Subject: [PATCH] [Vis: Default editor] EUIficate raw json control (#32888) * EUIficate raw json control * Remove unused validate-json directive * Update tests * Update styles * Move validation logic down to control * Fix type --- .../public/discover/controllers/discover.js | 1 - .../public/agg_types/__tests__/utils.test.tsx | 49 ++++++++ .../public/agg_types/controls/raw_json.html | 23 ---- .../ui/public/agg_types/controls/raw_json.tsx | 76 ++++++++++++ .../ui/public/agg_types/param_types/json.js | 4 +- src/legacy/ui/public/agg_types/utils.tsx | 39 ++++++ .../directives/__tests__/validate_json.js | 111 ------------------ .../ui/public/directives/validate_json.js | 64 ---------- .../public/vis/editors/default/_sidebar.scss | 3 + .../public/vis/editors/default/agg_param.js | 11 ++ .../editors/default/agg_param_editor_props.ts | 2 + .../default/agg_param_react_wrapper.tsx | 23 +++- .../translations/translations/zh-CN.json | 1 - 13 files changed, 203 insertions(+), 204 deletions(-) create mode 100644 src/legacy/ui/public/agg_types/__tests__/utils.test.tsx delete mode 100644 src/legacy/ui/public/agg_types/controls/raw_json.html create mode 100644 src/legacy/ui/public/agg_types/controls/raw_json.tsx create mode 100644 src/legacy/ui/public/agg_types/utils.tsx 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/core_plugins/kibana/public/discover/controllers/discover.js b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js index 2eba42eded544..bbbc8802e3fc9 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__/utils.test.tsx b/src/legacy/ui/public/agg_types/__tests__/utils.test.tsx new file mode 100644 index 0000000000000..b2e2b931f9133 --- /dev/null +++ b/src/legacy/ui/public/agg_types/__tests__/utils.test.tsx @@ -0,0 +1,49 @@ +/* + * 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 { 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('')).toBe(true); + }); + + it('should return true when undefine', () => { + expect(isValidJson(undefined as any)).toBe(true); + }); + + it('should return false when invalid string', () => { + expect(isValidJson(input.invalid)).toBe(false); + }); + + it('should return true when valid string', () => { + expect(isValidJson(input.valid)).toBe(true); + }); + + it('should return false if a number', () => { + expect(isValidJson('0')).toBe(false); + }); + }); +}); 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 f7d3f78a1f663..0000000000000 --- a/src/legacy/ui/public/agg_types/controls/raw_json.html +++ /dev/null @@ -1,23 +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 new file mode 100644 index 0000000000000..5dcd555ea969b --- /dev/null +++ b/src/legacy/ui/public/agg_types/controls/raw_json.tsx @@ -0,0 +1,76 @@ +/* + * 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 React from 'react'; + +import { EuiFormRow, EuiIconTip, EuiTextArea } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AggParamEditorProps } from '../../vis/editors/default'; +import { isValidJson } from '../utils'; + +function RawJsonParamEditor({ + agg, + value, + setValue, + isInvalid, + setValidity, +}: AggParamEditorProps) { + const label = ( + <> + {' '} + + + ); + + const onChange = (ev: React.ChangeEvent) => { + const textValue = ev.target.value; + setValue(textValue); + setValidity(isValidJson(textValue)); + }; + + setValidity(isValidJson(value)); + + return ( + + + + ); +} + +export { RawJsonParamEditor }; 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 new file mode 100644 index 0000000000000..98aa18fcc1692 --- /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): boolean { + 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/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'); - }); - }); - }); -}); 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); - } - } - }; -}); diff --git a/src/legacy/ui/public/vis/editors/default/_sidebar.scss b/src/legacy/ui/public/vis/editors/default/_sidebar.scss index ca5961c5ff851..a13935b50d886 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 @@ } } +.visEditorSidebar__aggParamFormRow { + margin-bottom: $euiSizeS; +} 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..75f67091cf981 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_param.js +++ b/src/legacy/ui/public/vis/editors/default/agg_param.js @@ -29,7 +29,9 @@ uiModules ['aggParam', { watchDepth: 'reference' }], ['paramEditor', { wrapApply: false }], ['onChange', { watchDepth: 'reference' }], + ['setValidity', { watchDepth: 'reference' }], 'value', + 'isInvalid' ])) .directive('visAggParamEditor', function (config) { return { @@ -54,6 +56,8 @@ uiModules agg-param="aggParam" on-change="onChange" value="paramValue" + is-invalid="isInvalid" + set-validity="setValidity" >`; } @@ -93,6 +97,13 @@ uiModules ngModelCtrl.$setDirty(); } }; + + $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 ab57153755c91..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,5 +28,7 @@ export interface AggParamEditorProps { agg: AggConfig; aggParam: AggParam; value: T; + isInvalid: boolean; setValue(value: T): void; + setValidity(isValid: boolean): void; } 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..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 @@ -28,12 +28,31 @@ interface AggParamReactWrapperProps { aggParam: AggParam; paramEditor: React.FunctionComponent>; value: T; + isInvalid: boolean; onChange(value: T): void; + setValidity(isValid: boolean): void; } function AggParamReactWrapper(props: AggParamReactWrapperProps) { - const { agg, aggParam, paramEditor: ParamEditor, onChange, value } = props; - return ; + const { + agg, + aggParam, + paramEditor: ParamEditor, + onChange, + value, + isInvalid, + setValidity, + } = props; + return ( + + ); } export { AggParamReactWrapper }; diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 68fb1a4e29375..32c41f20aaaac 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": "- 聚合无效 -",