Skip to content

Commit

Permalink
[Widget Params] Restyled source editing
Browse files Browse the repository at this point in the history
  • Loading branch information
ranbena committed Feb 3, 2019
1 parent c798550 commit 028278f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 72 deletions.
1 change: 1 addition & 0 deletions client/app/assets/less/ant.less
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
183 changes: 113 additions & 70 deletions client/app/components/ParameterMappingInput.jsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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 = {
Expand All @@ -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 (
<div>
<Select
className="w-100"
value={mapping.type}
onChange={type => this.updateParamMapping(mapping, { type })}
dropdownClassName="ant-dropdown-in-bootstrap-modal"
<Radio.Group
value={this.props.mapping.type}
onChange={e => this.updateParamMapping({ type: e.target.value })}
>
<Radio className="radio" value={MappingType.DashboardAddNew}>
New dashboard parameter
</Radio>
<Radio
className="radio"
value={MappingType.DashboardMapToExisting}
disabled={noExisting}
>
<Option value={MappingType.DashboardAddNew}>Add the parameter to the dashboard</Option>
{
(existingParamNames.length > 0) &&
<Option value={MappingType.DashboardMapToExisting}>Map to existing parameter</Option>
}
<Option value={MappingType.StaticValue}>Use static value for the parameter</Option>
<Option value={MappingType.WidgetLevel}>Keep the parameter at the widget level</Option>
</Select>
</div>
Existing dashboard parameter{' '}
{noExisting ? (
<Tooltip title="There are no dashboard parameters corresponding to this data type">
<Icon type="question-circle" theme="filled" />
</Tooltip>
) : null }
</Radio>
<Radio className="radio" value={MappingType.WidgetLevel}>
Widget parameter
</Radio>
<Radio className="radio" value={MappingType.StaticValue}>
Static value
</Radio>
</Radio.Group>
);
}

renderDashboardAddNew() {
const { mapping, existingParamNames } = this.props;
const alreadyExists = includes(existingParamNames, mapping.mapTo);
const { mapping: { mapTo } } = this.props;
return (
<div className={'m-t-10' + (alreadyExists ? ' has-error' : '')}>
<input
type="text"
className="form-control"
value={mapping.mapTo}
onChange={event => this.updateParamMapping(mapping, { mapTo: event.target.value })}
/>
{ alreadyExists && (
<div className="help-block">
Dashboard parameter with this name already exists
</div>
)}
</div>
<Input
value={mapTo}
onChange={e => 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 (
<div className="m-t-10">
<Select
className="w-100"
value={mapping.mapTo}
onChange={mapTo => this.updateParamMapping(mapping, { mapTo })}
disabled={existingParamNames.length === 0}
dropdownClassName="ant-dropdown-in-bootstrap-modal"
>
{map(existingParamNames, name => (
<Option value={name} key={name}>{ name }</Option>
))}
</Select>
</div>
<Select
value={mapping.mapTo}
onChange={mapTo => this.updateParamMapping({ mapTo })}
dropdownMatchSelectWidth={false}
defaultActiveFirstOption={shouldDefaultFirst}
>
{map(existingParamNames, name => (
<Option value={name} key={name}>{ name }</Option>
))}
</Select>
);
}

renderWidgetLevel() {
// eslint-disable-next-line no-use-before-define
const value = ParameterMappingListInput.getDefaultValue(this.props.mapping);
return <Input disabled value={value} />;
}

renderStaticValue() {
const { mapping } = this.props;
return (
<div className="m-t-10">
<label htmlFor="parameter-value-input">Change parameter value:</label>
<ParameterValueInput
id="parameter-value-input"
className="w-100"
type={mapping.param.type}
value={mapping.param.normalizedValue}
enumOptions={mapping.param.enumOptions}
queryId={mapping.param.queryId}
onSelect={value => this.updateParamMapping(mapping, { value })}
clientConfig={this.props.clientConfig}
Query={this.props.Query}
/>
</div>
<ParameterValueInput
type={mapping.param.type}
value={mapping.param.normalizedValue}
enumOptions={mapping.param.enumOptions}
queryId={mapping.param.queryId}
onSelect={value => this.updateParamMapping({ value })}
clientConfig={this.props.clientConfig}
Query={this.props.Query}
/>
);
}

Expand All @@ -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 (
<div key={mapping.name}>
{this.renderMappingTypeSelector()}
{this.renderInputBlock()}
</div>
<Form layout="horizontal">
<Form.Item label="Source" {...this.formItemProps}>
{this.renderMappingTypeSelector()}
</Form.Item>
<Form.Item
label="Value"
{...this.formItemProps}
validateStatus={inputError ? 'error' : ''}
help={inputError || '\u00A0'} // empty space so line doesn't collapse
>
{this.renderInputBlock()}
</Form.Item>
</Form>
);
}
}
Expand All @@ -225,6 +256,7 @@ class EditMapping extends React.Component {
this.state = {
visible: false,
mapping: clone(this.props.mapping),
inputError: null,
};
}

Expand All @@ -233,27 +265,38 @@ 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 (
<div className="editMapping">
<header>Edit parameter</header>
<header>Edit Source and Value</header>
<ParameterMappingInput
mapping={mapping}
existingParamNames={this.props.existingParamNames}
onChange={this.onChange}
getContainerElement={() => this.wrapperRef.current}
clientConfig={clientConfig}
Query={Query}
inputError={inputError}
/>
<footer>
<Button onClick={this.hide}>Cancel</Button>
<Button onClick={this.save} type="primary">OK</Button>
<Button onClick={this.save} disabled={!!inputError} type="primary">OK</Button>
</footer>
</div>
);
Expand Down
14 changes: 12 additions & 2 deletions client/app/components/ParameterMappingInput.less
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down

0 comments on commit 028278f

Please sign in to comment.