mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* EUIficate raw json control * Remove unused validate-json directive * Update tests * Update styles * Move validation logic down to control * Fix type
This commit is contained in:
parent
8e7f1a3ce2
commit
4f7ba1111e
13 changed files with 203 additions and 204 deletions
|
@ -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';
|
||||
|
|
49
src/legacy/ui/public/agg_types/__tests__/utils.test.tsx
Normal file
49
src/legacy/ui/public/agg_types/__tests__/utils.test.tsx
Normal file
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,23 +0,0 @@
|
|||
<div class="form-group regex">
|
||||
<span class="hintbox-label">
|
||||
<label for="visEditorRawJson{{agg.id}}">
|
||||
<span
|
||||
i18n-id="common.ui.aggTypes.jsonInputLabel"
|
||||
i18n-default-message="JSON Input"
|
||||
></span>
|
||||
<icon-tip
|
||||
position="'right'"
|
||||
content="::'common.ui.aggTypes.jsonInputTooltip' | i18n: { defaultMessage: 'Any JSON formatted properties you add here will be merged with the elasticsearch aggregation definition for this section. For example \'shard_size\' on a terms aggregation.' }"
|
||||
></icon-tip>
|
||||
</label>
|
||||
</span>
|
||||
<p>
|
||||
<textarea
|
||||
type="text"
|
||||
id="visEditorRawJson{{agg.id}}"
|
||||
class="form-control"
|
||||
ng-model="agg.params.json"
|
||||
validate-json
|
||||
></textarea>
|
||||
</p>
|
||||
</div>
|
76
src/legacy/ui/public/agg_types/controls/raw_json.tsx
Normal file
76
src/legacy/ui/public/agg_types/controls/raw_json.tsx
Normal file
|
@ -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<string>) {
|
||||
const label = (
|
||||
<>
|
||||
<FormattedMessage id="common.ui.aggTypes.jsonInputLabel" defaultMessage="JSON input" />{' '}
|
||||
<EuiIconTip
|
||||
position="right"
|
||||
content={i18n.translate('common.ui.aggTypes.jsonInputTooltip', {
|
||||
defaultMessage:
|
||||
"Any JSON formatted properties you add here will be merged with the elasticsearch aggregation definition for this section. For example 'shard_size' on a terms aggregation.",
|
||||
})}
|
||||
type="questionInCircle"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
const onChange = (ev: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const textValue = ev.target.value;
|
||||
setValue(textValue);
|
||||
setValidity(isValidJson(textValue));
|
||||
};
|
||||
|
||||
setValidity(isValidJson(value));
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label={label}
|
||||
isInvalid={isInvalid}
|
||||
fullWidth={true}
|
||||
className="visEditorSidebar__aggParamFormRow"
|
||||
>
|
||||
<EuiTextArea
|
||||
id={`visEditorRawJson${agg.id}`}
|
||||
isInvalid={isInvalid}
|
||||
value={value || ''}
|
||||
onChange={onChange}
|
||||
rows={2}
|
||||
fullWidth={true}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
export { RawJsonParamEditor };
|
|
@ -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.
|
||||
|
|
39
src/legacy/ui/public/agg_types/utils.tsx
Normal file
39
src/legacy/ui/public/agg_types/utils.tsx
Normal file
|
@ -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 };
|
|
@ -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: '<textarea ng-model="mockModel" validate-json></textarea>',
|
||||
input: '<input type="text" ng-model="mockModel" validate-json>'
|
||||
};
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
|
@ -221,3 +221,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.visEditorSidebar__aggParamFormRow {
|
||||
margin-bottom: $euiSizeS;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
></vis-agg-param-react-wrapper>`;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,5 +28,7 @@ export interface AggParamEditorProps<T> {
|
|||
agg: AggConfig;
|
||||
aggParam: AggParam;
|
||||
value: T;
|
||||
isInvalid: boolean;
|
||||
setValue(value: T): void;
|
||||
setValidity(isValid: boolean): void;
|
||||
}
|
||||
|
|
|
@ -28,12 +28,31 @@ interface AggParamReactWrapperProps<T> {
|
|||
aggParam: AggParam;
|
||||
paramEditor: React.FunctionComponent<AggParamEditorProps<T>>;
|
||||
value: T;
|
||||
isInvalid: boolean;
|
||||
onChange(value: T): void;
|
||||
setValidity(isValid: boolean): void;
|
||||
}
|
||||
|
||||
function AggParamReactWrapper<T>(props: AggParamReactWrapperProps<T>) {
|
||||
const { agg, aggParam, paramEditor: ParamEditor, onChange, value } = props;
|
||||
return <ParamEditor value={value} setValue={onChange} aggParam={aggParam} agg={agg} />;
|
||||
const {
|
||||
agg,
|
||||
aggParam,
|
||||
paramEditor: ParamEditor,
|
||||
onChange,
|
||||
value,
|
||||
isInvalid,
|
||||
setValidity,
|
||||
} = props;
|
||||
return (
|
||||
<ParamEditor
|
||||
value={value}
|
||||
setValue={onChange}
|
||||
aggParam={aggParam}
|
||||
agg={agg}
|
||||
isInvalid={isInvalid}
|
||||
setValidity={setValidity}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { AggParamReactWrapper };
|
||||
|
|
|
@ -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": "- 聚合无效 -",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue