diff --git a/client/app/assets/less/ant.less b/client/app/assets/less/ant.less index 978eae5977..199efa57a7 100644 --- a/client/app/assets/less/ant.less +++ b/client/app/assets/less/ant.less @@ -17,6 +17,7 @@ @import '~antd/lib/popover/style/index'; @import '~antd/lib/icon/style/index'; @import '~antd/lib/tag/style/index'; +@import '~antd/lib/grid/style/index'; @import 'inc/ant-variables'; // Remove bold in labels for Ant checkboxes and radio buttons diff --git a/client/app/components/ParameterMappingInput.jsx b/client/app/components/ParameterMappingInput.jsx index fe4b3cf013..f5cb0471ae 100644 --- a/client/app/components/ParameterMappingInput.jsx +++ b/client/app/components/ParameterMappingInput.jsx @@ -1,6 +1,6 @@ /* eslint react/no-multi-comp: 0 */ -import { extend, map, includes, findIndex, find, fromPairs, clone } from 'lodash'; +import { extend, map, includes, findIndex, find, fromPairs, clone, isEmpty } from 'lodash'; import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import Select from 'antd/lib/select'; @@ -10,6 +10,9 @@ import Button from 'antd/lib/button'; import Icon from 'antd/lib/icon'; import Tag from 'antd/lib/tag'; import Input from 'antd/lib/input'; +import Radio from 'antd/lib/radio'; +import Form from 'antd/lib/form'; +import Tooltip from 'antd/lib/tooltip'; import { ParameterValueInput } from '@/components/ParameterValueInput'; import { ParameterMappingType } from '@/services/widget'; import { Parameter } from '@/services/query'; @@ -89,6 +92,7 @@ export class ParameterMappingInput extends React.Component { onChange: PropTypes.func, clientConfig: PropTypes.any, // eslint-disable-line react/forbid-prop-types Query: PropTypes.any, // eslint-disable-line react/forbid-prop-types + inputError: PropTypes.string, }; static defaultProps = { @@ -97,90 +101,106 @@ export class ParameterMappingInput extends React.Component { onChange: () => {}, clientConfig: null, Query: null, + inputError: null, }; - updateParamMapping(mapping, updates) { - this.props.onChange(extend({}, mapping, updates)); + constructor(props) { + super(props); + + this.formItemProps = { + labelCol: { span: 5 }, + wrapperCol: { span: 16 }, + className: 'formItem', + }; + } + + updateParamMapping = (update) => { + const { onChange, mapping } = this.props; + const newMapping = extend({}, mapping, update); + onChange(newMapping); } renderMappingTypeSelector() { - const { mapping, existingParamNames } = this.props; + const noExisting = isEmpty(this.props.existingParamNames); return ( -
- -
+ Existing dashboard parameter{' '} + {noExisting ? ( + + + + ) : null } + + + Widget parameter + + + Static value + + ); } renderDashboardAddNew() { - const { mapping, existingParamNames } = this.props; - const alreadyExists = includes(existingParamNames, mapping.mapTo); + const { mapping: { mapTo } } = this.props; return ( -
- this.updateParamMapping(mapping, { mapTo: event.target.value })} - /> - { alreadyExists && ( -
- Dashboard parameter with this name already exists -
- )} -
+ this.updateParamMapping({ mapTo: e.target.value })} + /> ); } renderDashboardMapToExisting() { const { mapping, existingParamNames } = this.props; + + // if mapped name doesn't already exists + // default to first select option + const shouldDefaultFirst = !includes(existingParamNames, mapping.mapTo); + return ( -
- -
+ ); } + renderWidgetLevel() { + // eslint-disable-next-line no-use-before-define + const value = ParameterMappingListInput.getDefaultValue(this.props.mapping); + return ; + } + renderStaticValue() { const { mapping } = this.props; return ( -
- - this.updateParamMapping(mapping, { value })} - clientConfig={this.props.clientConfig} - Query={this.props.Query} - /> -
+ this.updateParamMapping({ value })} + clientConfig={this.props.clientConfig} + Query={this.props.Query} + /> ); } @@ -189,18 +209,29 @@ export class ParameterMappingInput extends React.Component { switch (mapping.type) { case MappingType.DashboardAddNew: return this.renderDashboardAddNew(); case MappingType.DashboardMapToExisting: return this.renderDashboardMapToExisting(); + case MappingType.WidgetLevel: return this.renderWidgetLevel(); case MappingType.StaticValue: return this.renderStaticValue(); // no default } } render() { - const { mapping } = this.props; + const { inputError } = this.props; + return ( -
- {this.renderMappingTypeSelector()} - {this.renderInputBlock()} -
+
+ + {this.renderMappingTypeSelector()} + + + {this.renderInputBlock()} + +
); } } @@ -225,6 +256,7 @@ class EditMapping extends React.Component { this.state = { visible: false, mapping: clone(this.props.mapping), + inputError: null, }; } @@ -233,16 +265,26 @@ class EditMapping extends React.Component { } onChange = (mapping) => { - this.setState({ mapping }); + let inputError = null; + + if (mapping.type === MappingType.DashboardAddNew) { + if (isEmpty(mapping.mapTo)) { + inputError = 'Keyword must have a value'; + } else if (includes(this.props.existingParamNames, mapping.mapTo)) { + inputError = 'Parameter with this name already exists'; + } + } + + this.setState({ mapping, inputError }); } get content() { - const { mapping } = this.state; + const { mapping, inputError } = this.state; const { clientConfig, Query } = this.props; return (
-
Edit parameter
+
Edit Source and Value
this.wrapperRef.current} clientConfig={clientConfig} Query={Query} + inputError={inputError} />
); diff --git a/client/app/components/ParameterMappingInput.less b/client/app/components/ParameterMappingInput.less index c08ff8ae32..cce24dc04c 100644 --- a/client/app/components/ParameterMappingInput.less +++ b/client/app/components/ParameterMappingInput.less @@ -23,7 +23,17 @@ } .editMapping { - width: 340px; + width: 390px; + + .radio { + display: block; + height: 30px; + line-height: 30px; + } + + .formItem { + margin-bottom: 10px; + } header { padding: 0 16px 10px; @@ -37,7 +47,7 @@ footer { border-top: @border-width-base @border-style-base @border-color-split; padding: 10px 16px 0; - margin: 20px -16px 0; + margin: 0 -16px; text-align: right; button {