diff --git a/client/app/components/ParameterMappingInput.jsx b/client/app/components/ParameterMappingInput.jsx index 142c752e4a..fe4b3cf013 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 } from 'lodash'; +import { extend, map, includes, findIndex, find, fromPairs, clone } from 'lodash'; import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import Select from 'antd/lib/select'; @@ -9,6 +9,7 @@ import Popover from 'antd/lib/popover'; 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 { ParameterValueInput } from '@/components/ParameterValueInput'; import { ParameterMappingType } from '@/services/widget'; import { Parameter } from '@/services/query'; @@ -108,7 +109,7 @@ export class ParameterMappingInput extends React.Component {
this.updateParamMapping(mapping, { mapTo })} disabled={existingParamNames.length === 0} dropdownClassName="ant-dropdown-in-bootstrap-modal" @@ -193,33 +194,12 @@ export class ParameterMappingInput extends React.Component { } } - renderTitleInput() { - const { mapping } = this.props; - if (mapping.type === MappingType.StaticValue) { - return null; - } - return ( -
- - this.updateParamMapping(mapping, { title: event.target.value })} - placeholder={mapping.param.title} - /> -
- ); - } - render() { const { mapping } = this.props; return (
{this.renderMappingTypeSelector()} {this.renderInputBlock()} - {this.renderTitleInput()}
); } @@ -244,6 +224,7 @@ class EditMapping extends React.Component { super(props); this.state = { visible: false, + mapping: clone(this.props.mapping), }; } @@ -251,8 +232,13 @@ class EditMapping extends React.Component { if (visible) this.show(); else this.hide(); } + onChange = (mapping) => { + this.setState({ mapping }); + } + get content() { - const { mapping, clientConfig, Query, onChange } = this.props; + const { mapping } = this.state; + const { clientConfig, Query } = this.props; return (
@@ -260,20 +246,29 @@ class EditMapping extends React.Component { onChange(mapping, newMapping)} + onChange={this.onChange} getContainerElement={() => this.wrapperRef.current} clientConfig={clientConfig} Query={Query} />
- + +
); } + save = () => { + this.props.onChange(this.props.mapping, this.state.mapping); + this.hide(); + } + show = () => { - this.setState({ visible: true }); + this.setState({ + visible: true, + mapping: clone(this.props.mapping), // restore original state + }); } hide = () => { @@ -283,7 +278,7 @@ class EditMapping extends React.Component { render() { return ( + + ); + } +} + +class EditTitle extends React.Component { + static propTypes = { + mapping: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + onChange: PropTypes.func.isRequired, + getContainerElement: PropTypes.func.isRequired, + }; + + state = { + visible: false, + title: this.props.mapping.title, + } + + onVisibleChange = (visible) => { + this.setState({ + visible, + title: this.props.mapping.title, // reset title + }); + } + + onTitleChange = (event) => { + this.setState({ title: event.target.value }); + } + + get popover() { + const { param: { title: paramTitle } } = this.props.mapping; + + return ( +
+ + + +
+ ); + } + + save = () => { + const newMapping = extend({}, this.props.mapping, { title: this.state.title }); + this.props.onChange(newMapping); + this.hide(); + } + + hide = () => { + this.setState({ visible: false }); + } + + render() { + return ( + + ); @@ -363,6 +432,25 @@ export class ParameterMappingListInput extends React.Component { return this.getStringValue(value); } + static getSourceTypeLabel({ type, mapTo }) { + switch (type) { + case MappingType.DashboardAddNew: + case MappingType.DashboardMapToExisting: + return ( + + Dashboard parameter{' '} + {mapTo} + + ); + case MappingType.WidgetLevel: + return 'Widget parameter'; + case MappingType.StaticValue: + return 'Static value'; + default: + return ''; // won't happen (typescript-ftw) + } + } + updateParamMapping(oldMapping, newMapping) { const mappings = [...this.props.mappings]; const index = findIndex(mappings, oldMapping); @@ -388,32 +476,23 @@ export class ParameterMappingListInput extends React.Component { rowKey={(record, idx) => `row${idx}`} > { - const existingParamsNames = existingParams - .filter(({ type }) => type === mapping.param.type) // exclude mismatching param types - .map(({ name }) => name); // keep names only - + const { title, param: { title: paramTitle } } = mapping; return ( - this.updateParamMapping(oldMapping, newMapping)} - getContainerElement={() => this.wrapperRef.current} - clientConfig={clientConfig} - Query={Query} - /> + + {title || paramTitle}{' '} + this.updateParamMapping(mapping, newMapping)} + getContainerElement={() => this.wrapperRef.current} + /> + ); }} /> - mapping.title || mapping.param.title} - /> { - switch (mapping.type) { - case MappingType.DashboardAddNew: - case MappingType.DashboardMapToExisting: - return ( - - Dashboard parameter{' '} - {mapping.mapTo} - - ); - case MappingType.WidgetLevel: - return 'Widget parameter'; - case MappingType.StaticValue: - return 'Static value'; - default: - return ''; // won't happen (typescript-ftw) - } + const existingParamsNames = existingParams + .filter(({ type }) => type === mapping.param.type) // exclude mismatching param types + .map(({ name }) => name); // keep names only + + return ( + + {this.constructor.getSourceTypeLabel(mapping)}{' '} + this.updateParamMapping(oldMapping, newMapping)} + getContainerElement={() => this.wrapperRef.current} + clientConfig={clientConfig} + Query={Query} + /> + + ); }} /> diff --git a/client/app/components/ParameterMappingInput.less b/client/app/components/ParameterMappingInput.less index ea1090cc53..c08ff8ae32 100644 --- a/client/app/components/ParameterMappingInput.less +++ b/client/app/components/ParameterMappingInput.less @@ -39,5 +39,19 @@ padding: 10px 16px 0; margin: 20px -16px 0; text-align: right; + + button { + margin-left: 8px; + } + } +} + +.editTitle { + input { + width: 100px; + } + + button { + margin-left: 2px; } }