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 (
-
+
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 {