From a02678136986d1e1009be5c378fe6d84a656f012 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 16 Jun 2019 16:24:42 -0300 Subject: [PATCH 01/39] Draft for Date Dynamic values --- client/app/components/DateRangeInput.jsx | 2 + client/app/components/DateTimeRangeInput.jsx | 2 + .../components/EditDateParameterDialog.jsx | 103 ++++++++++++++++++ client/app/components/ParameterValueInput.jsx | 71 +++++++++++- client/app/services/query.js | 9 +- 5 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 client/app/components/EditDateParameterDialog.jsx diff --git a/client/app/components/DateRangeInput.jsx b/client/app/components/DateRangeInput.jsx index 8dc2bd973f..3961e252dc 100644 --- a/client/app/components/DateRangeInput.jsx +++ b/client/app/components/DateRangeInput.jsx @@ -12,6 +12,7 @@ export function DateRangeInput({ value, onSelect, className, + ...props }) { const format = clientConfig.dateFormat || 'YYYY-MM-DD'; const additionalAttributes = {}; @@ -24,6 +25,7 @@ export function DateRangeInput({ {...additionalAttributes} format={format} onChange={onSelect} + {...props} /> ); } diff --git a/client/app/components/DateTimeRangeInput.jsx b/client/app/components/DateTimeRangeInput.jsx index d6c17ab130..fc7ec37bf2 100644 --- a/client/app/components/DateTimeRangeInput.jsx +++ b/client/app/components/DateTimeRangeInput.jsx @@ -13,6 +13,7 @@ export function DateTimeRangeInput({ withSeconds, onSelect, className, + ...props }) { const format = (clientConfig.dateFormat || 'YYYY-MM-DD') + (withSeconds ? ' HH:mm:ss' : ' HH:mm'); @@ -36,6 +37,7 @@ export function DateTimeRangeInput({ } } }} + {...props} /> ); } diff --git a/client/app/components/EditDateParameterDialog.jsx b/client/app/components/EditDateParameterDialog.jsx new file mode 100644 index 0000000000..a38d4fd5d9 --- /dev/null +++ b/client/app/components/EditDateParameterDialog.jsx @@ -0,0 +1,103 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { findIndex, isEqual } from 'lodash'; +import InputNumber from 'antd/lib/input-number'; +import Form from 'antd/lib/form'; +import Modal from 'antd/lib/modal'; +import Radio from 'antd/lib/radio'; +import { wrap as wrapDialog, DialogPropType } from '@/components/DialogWrapper'; + +const DATE_INTERVAL_OPTIONS = [ + { name: 'Last week', start: 7 * 24 * 60 * 60 * 1000, end: 0 }, + { name: 'Last month', start: 30 * 24 * 60 * 60 * 1000, end: 0 }, + { name: 'Last year', start: 365 * 24 * 60 * 60 * 1000, end: 0 }, +]; + +class EditDateParameterDialog extends React.Component { + static propTypes = { + dialog: DialogPropType.isRequired, + defaultOption: PropTypes.object, // eslint-disable-line react/forbid-prop-types + }; + + static defaultProps = { + defaultOption: null, + }; + + state = { + currentOption: 0, + }; + + formItemProps = { + labelCol: { span: 5 }, + wrapperCol: { span: 16 }, + }; + + constructor(props) { + super(props); + const currentOption = findIndex(DATE_INTERVAL_OPTIONS, v => isEqual(v, props.defaultOption)); + this.state = { + currentOption: currentOption === -1 ? 'static' : currentOption, + }; + } + + getValue = () => { + const { currentOption } = this.state; + switch (currentOption) { + case 'static': + return null; + default: + return DATE_INTERVAL_OPTIONS[currentOption]; + } + } + + onChange = (e) => { + this.setState({ currentOption: e.target.value }); + } + + onOk = () => { + this.props.dialog.close(this.getValue()); + } + + renderCustomOptions() { + return ( + + year(s) + month(s) + day(s) + + ); + } + + render() { + const { dialog } = this.props; + const radioStyle = { + display: 'block', + height: '30px', + lineHeight: '30px', + }; + return ( + +
+ + + + Static value + + {DATE_INTERVAL_OPTIONS.map((option, key) => ( + + {option.name} + + ))} + + Custom + + + + {this.state.currentOption === 'custom' && this.renderCustomOptions()} +
+
+ ); + } +} + +export default wrapDialog(EditDateParameterDialog); diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index e4f0475ef5..0d4b01eb16 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -1,11 +1,16 @@ import React from 'react'; import PropTypes from 'prop-types'; import { react2angular } from 'react2angular'; +import moment from 'moment'; import Button from 'antd/lib/button'; import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; import InputNumber from 'antd/lib/input-number'; -import { isFunction } from 'lodash'; +import Icon from 'antd/lib/icon'; +import Tag from 'antd/lib/tag'; +import Tooltip from 'antd/lib/tooltip'; +import EditDateParameterDialog from '@/components/EditDateParameterDialog'; +import { defer, isFunction, includes } from 'lodash'; import { DateInput } from './DateInput'; import { DateRangeInput } from './DateRangeInput'; import { DateTimeInput } from './DateTimeInput'; @@ -41,9 +46,26 @@ export class ParameterValueInput extends React.Component { constructor(props) { super(props); - this.state = { value: props.value }; + this.state = { + value: props.value, + hasDynamicDateTime: !!(props.parameter && props.parameter.dynamicDateTime), + }; } + openDateParameterDialog = (e) => { + e.stopPropagation(); + + const { onSelect, parameter } = this.props; + EditDateParameterDialog.showModal({ defaultOption: parameter.dynamicDateTime }).result + .then((datePeriod) => { + parameter.dynamicDateTime = datePeriod; + if (datePeriod) { + onSelect([moment().subtract(datePeriod.start), moment().add(datePeriod.end)]); + } + this.setState({ hasDynamicDateTime: !!datePeriod }); + }); + }; + renderApplyButton() { const { onSelect } = this.props; const { value } = this.state; @@ -59,6 +81,19 @@ export class ParameterValueInput extends React.Component { ); } + renderDynamicOptionButton() { + return ( + + + + ); + } + renderDateTimeWithSecondsInput() { const { value, onSelect } = this.props; return ( @@ -101,6 +136,8 @@ export class ParameterValueInput extends React.Component { value={value} onSelect={onSelect} withSeconds + suffixIcon={this.renderDynamicOptionButton()} + allowClear={false} /> ); } @@ -112,6 +149,8 @@ export class ParameterValueInput extends React.Component { className={this.props.className} value={value} onSelect={onSelect} + suffixIcon={this.renderDynamicOptionButton()} + allowClear={false} /> ); } @@ -123,10 +162,22 @@ export class ParameterValueInput extends React.Component { className={this.props.className} value={value} onSelect={onSelect} + suffixIcon={this.renderDynamicOptionButton()} + allowClear={false} /> ); } + renderDynamicDateRangeTag() { + const { parameter } = this.props; + return ( +
+ {parameter.dynamicDateTime.name} + {this.renderDynamicOptionButton()} +
+ ); + } + renderEnumInput() { const { value, onSelect, enumOptions } = this.props; const enumOptionsArray = enumOptions.split('\n').filter(v => v !== ''); @@ -219,6 +270,12 @@ export class ParameterValueInput extends React.Component { render() { const { type } = this.props; + const isDateRangeType = includes(['datetime-range-with-seconds', 'datetime-range', 'date-range'], type); + + if (this.state.hasDynamicDateTime && isDateRangeType) { + return this.renderDynamicDateRangeTag(); + } + switch (type) { case 'datetime-with-seconds': return this.renderDateTimeWithSecondsInput(); case 'datetime-local': return this.renderDateTimeInput(); @@ -255,10 +312,12 @@ export default function init(ngModule) { controller($scope) { this.setValue = (value) => { this.param.setValue(value); - $scope.$apply(); - if (isFunction(this.onChange)) { - this.onChange(); - } + defer(() => { + $scope.$apply(); + if (isFunction(this.onChange)) { + this.onChange(); + } + }); }; }, }); diff --git a/client/app/services/query.js b/client/app/services/query.js index 8c00829ca1..4708ebaaad 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -55,6 +55,7 @@ export class Parameter { this.name = parameter.name; this.type = parameter.type; this.useCurrentDateTime = parameter.useCurrentDateTime; + this.dynamicDateTime = parameter.dynamicDateTime; this.global = parameter.global; // backward compatibility in Widget service this.enumOptions = parameter.enumOptions; this.queryId = parameter.queryId; @@ -88,8 +89,14 @@ export class Parameter { } static getValue(param) { - const { value, type, useCurrentDateTime } = param; + const { value, type, useCurrentDateTime, dynamicDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); + if (isDateRangeParameter(type) && dynamicDateTime) { + return { + start: moment().subtract(dynamicDateTime.start).format(DATETIME_FORMATS[type]), + end: moment().add(dynamicDateTime.end).format(DATETIME_FORMATS[type]), + }; + } if (isEmptyValue) { if ( includes(['date', 'datetime-local', 'datetime-with-seconds'], type) && From 1e98d07fde84f7dcb574aa7be830d2e99fe147be Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 17 Jun 2019 14:57:22 -0300 Subject: [PATCH 02/39] Use value with prefix instead of specific attr --- .../components/EditDateParameterDialog.jsx | 15 ++-- client/app/components/ParameterValueInput.jsx | 12 ++-- client/app/services/query.js | 68 ++++++++++++++++--- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/client/app/components/EditDateParameterDialog.jsx b/client/app/components/EditDateParameterDialog.jsx index a38d4fd5d9..e4aec4dac3 100644 --- a/client/app/components/EditDateParameterDialog.jsx +++ b/client/app/components/EditDateParameterDialog.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { findIndex, isEqual } from 'lodash'; +import { findIndex } from 'lodash'; import InputNumber from 'antd/lib/input-number'; import Form from 'antd/lib/form'; import Modal from 'antd/lib/modal'; @@ -8,19 +8,20 @@ import Radio from 'antd/lib/radio'; import { wrap as wrapDialog, DialogPropType } from '@/components/DialogWrapper'; const DATE_INTERVAL_OPTIONS = [ - { name: 'Last week', start: 7 * 24 * 60 * 60 * 1000, end: 0 }, - { name: 'Last month', start: 30 * 24 * 60 * 60 * 1000, end: 0 }, - { name: 'Last year', start: 365 * 24 * 60 * 60 * 1000, end: 0 }, + { name: 'Last week', value: 'd_last_week' }, + { name: 'Last month', value: 'd_last_month' }, + { name: 'Last year', value: 'd_last_year' }, + { name: 'Last 7 days', value: 'd_last_7_days' }, ]; class EditDateParameterDialog extends React.Component { static propTypes = { dialog: DialogPropType.isRequired, - defaultOption: PropTypes.object, // eslint-disable-line react/forbid-prop-types + defaultValue: PropTypes.any, // eslint-disable-line react/forbid-prop-types }; static defaultProps = { - defaultOption: null, + defaultValue: null, }; state = { @@ -34,7 +35,7 @@ class EditDateParameterDialog extends React.Component { constructor(props) { super(props); - const currentOption = findIndex(DATE_INTERVAL_OPTIONS, v => isEqual(v, props.defaultOption)); + const currentOption = findIndex(DATE_INTERVAL_OPTIONS, v => v.value === props.defaultValue); this.state = { currentOption: currentOption === -1 ? 'static' : currentOption, }; diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index 0d4b01eb16..6a4815615f 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { react2angular } from 'react2angular'; -import moment from 'moment'; import Button from 'antd/lib/button'; import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; @@ -48,7 +47,7 @@ export class ParameterValueInput extends React.Component { super(props); this.state = { value: props.value, - hasDynamicDateTime: !!(props.parameter && props.parameter.dynamicDateTime), + hasDynamicDateTime: !!(props.parameter && props.parameter.hasDynamicValue), }; } @@ -56,13 +55,12 @@ export class ParameterValueInput extends React.Component { e.stopPropagation(); const { onSelect, parameter } = this.props; - EditDateParameterDialog.showModal({ defaultOption: parameter.dynamicDateTime }).result + EditDateParameterDialog.showModal({ defaultValue: parameter.value }).result .then((datePeriod) => { - parameter.dynamicDateTime = datePeriod; if (datePeriod) { - onSelect([moment().subtract(datePeriod.start), moment().add(datePeriod.end)]); + onSelect(datePeriod.value); } - this.setState({ hasDynamicDateTime: !!datePeriod }); + this.setState({ hasDynamicDateTime: parameter.hasDynamicValue }); }); }; @@ -172,7 +170,7 @@ export class ParameterValueInput extends React.Component { const { parameter } = this.props; return (
- {parameter.dynamicDateTime.name} + {parameter.dynamicValue.name} {this.renderDynamicOptionButton()}
); diff --git a/client/app/services/query.js b/client/app/services/query.js index 4708ebaaad..a6b0387c4c 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -4,6 +4,7 @@ import Mustache from 'mustache'; import { zipObject, isEmpty, map, filter, includes, union, uniq, has, isNull, isUndefined, isArray, isObject, identity, extend, each, + startsWith, } from 'lodash'; Mustache.escape = identity; // do not html-escape values @@ -22,6 +23,31 @@ const DATETIME_FORMATS = { 'datetime-range-with-seconds': 'YYYY-MM-DD HH:mm:ss', }; +const DYNAMIC_DATE_PREFIX = 'd_'; + +const DYNAMIC_DATE_RANGES = { + last_week: { + name: 'Last week', + value: () => [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')], + }, + last_month: { + name: 'Last month', + value: () => [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')], + }, + last_year: { + name: 'Last year', + value: () => [moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year')], + }, + last_7_days: { + name: 'Last 7 days', + value: () => [moment().subtract(7, 'days'), moment()], + }, +}; + +function isDynamicValue(value) { + return startsWith(value, DYNAMIC_DATE_PREFIX); +} + function normalizeNumericValue(value, defaultValue = null) { const result = parseFloat(value); return isFinite(result) ? result : defaultValue; @@ -55,7 +81,6 @@ export class Parameter { this.name = parameter.name; this.type = parameter.type; this.useCurrentDateTime = parameter.useCurrentDateTime; - this.dynamicDateTime = parameter.dynamicDateTime; this.global = parameter.global; // backward compatibility in Widget service this.enumOptions = parameter.enumOptions; this.queryId = parameter.queryId; @@ -84,18 +109,31 @@ export class Parameter { return isNull(this.getValue()); } + get hasDynamicValue() { + return isDynamicValue(this.value); + } + + get dynamicValue() { + return this.hasDynamicValue ? DYNAMIC_DATE_RANGES[this.value.substring(DYNAMIC_DATE_PREFIX.length)] : null; + } + getValue() { return this.constructor.getValue(this); } static getValue(param) { - const { value, type, useCurrentDateTime, dynamicDateTime } = param; + const { value, type, useCurrentDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); - if (isDateRangeParameter(type) && dynamicDateTime) { - return { - start: moment().subtract(dynamicDateTime.start).format(DATETIME_FORMATS[type]), - end: moment().add(dynamicDateTime.end).format(DATETIME_FORMATS[type]), - }; + if (isDateRangeParameter(type) && startsWith(value, DYNAMIC_DATE_PREFIX)) { + const dynamicValue = value.substring(DYNAMIC_DATE_PREFIX.length); + if (DYNAMIC_DATE_RANGES[dynamicValue]) { + const dateRange = DYNAMIC_DATE_RANGES[dynamicValue].value(); + return { + start: dateRange[0].format(DATETIME_FORMATS[type]), + end: dateRange[1].format(DATETIME_FORMATS[type]), + }; + } + return null; } if (isEmptyValue) { if ( @@ -130,6 +168,12 @@ export class Parameter { }; this.$$value = value; } + } else if (isDynamicValue(value)) { + const dynamicValue = DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)].value(); + if (dynamicValue) { + this.value = value; + this.$$value = [dynamicValue[0], dynamicValue[1]]; + } } } else if (isDateParameter(this.type)) { this.value = null; @@ -175,23 +219,29 @@ export class Parameter { return {}; } const prefix = this.urlPrefix; - if (isDateRangeParameter(this.type)) { + if (isDateRangeParameter(this.type) && isObject(this.value)) { return { [`${prefix}${this.name}.start`]: this.value.start, [`${prefix}${this.name}.end`]: this.value.end, + [`${prefix}${this.name}`]: null, }; } return { [`${prefix}${this.name}`]: this.value, + [`${prefix}${this.name}.start`]: null, + [`${prefix}${this.name}.end`]: null, }; } fromUrlParams(query) { const prefix = this.urlPrefix; if (isDateRangeParameter(this.type)) { + const key = `${prefix}${this.name}`; const keyStart = `${prefix}${this.name}.start`; const keyEnd = `${prefix}${this.name}.end`; - if (has(query, keyStart) && has(query, keyEnd)) { + if (has(query, key) && isDynamicValue(query[key])) { + this.setValue(query[key]); + } else if (has(query, keyStart) && has(query, keyEnd)) { this.setValue([query[keyStart], query[keyEnd]]); } } else { From f7cca044c3d80e3439214f0870a7661b3e492f26 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 17 Jun 2019 19:49:44 -0300 Subject: [PATCH 03/39] Fix not possible to select static value --- client/app/components/ParameterValueInput.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index 6a4815615f..4a58e97b16 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -59,6 +59,8 @@ export class ParameterValueInput extends React.Component { .then((datePeriod) => { if (datePeriod) { onSelect(datePeriod.value); + } else { + onSelect(parameter.getValue()); } this.setState({ hasDynamicDateTime: parameter.hasDynamicValue }); }); From e595dc319ecc1a62c0e1094f30aa1807ff7574e2 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 23 Jun 2019 19:53:22 -0300 Subject: [PATCH 04/39] Update antd version --- package-lock.json | 480 ++++++++++++++++++++++++---------------------- package.json | 2 +- 2 files changed, 257 insertions(+), 225 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3676f63d9e..cbebe636ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,17 +27,34 @@ "right-now": "^1.0.0" } }, + "@ant-design/colors": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.1.0.tgz", + "integrity": "sha512-Td7g1P53sNFyT4Gya6836e70TrhoVZ+HjZs6mpWIHrxl4/VqsjjOyzj/8ktOuw0lCx+BfYu9UO1CiJ0MoYYfhg==", + "requires": { + "tinycolor2": "^1.4.1" + } + }, + "@ant-design/create-react-context": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.4.tgz", + "integrity": "sha512-8sw+/w6r+aEbd+OJ62ojoSE4zDt/3yfQydmbWFznoftjr8v/opOswGjM+/MU0rSaREbluqzOmZ6xdecHpSaS2w==", + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, "@ant-design/icons": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-1.1.16.tgz", - "integrity": "sha512-0zNVP5JYBJkfMi9HotN6QBQjF3SFmUlumJNJXZIH+pZWp/5EbrCczzlG3YTmBWoyRHAsuOGIjSFIy8v/76DTPg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.0.1.tgz", + "integrity": "sha512-SqiNhgoivKczEqIJc/9hntgtvmq4R3Ef73ehibqDPAT059IjsXXM7nze0S5P8F4HP76jgPiv5od+2JUhQl/nig==" }, "@ant-design/icons-react": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-1.1.2.tgz", - "integrity": "sha512-7Fgt9d8ABgxrhZxsFjHk/VpPcxodQJJhbJO8Lsh7u58pGN4NoxxW++92naeGTXCyqZsbDPBReP+SC0bdBtbsGQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-2.0.1.tgz", + "integrity": "sha512-r1QfoltMuruJZqdiKcbPim3d8LNsVPB733U0gZEUSxBLuqilwsW28K2rCTWSMTjmFX7Mfpf+v/wdiFe/XCqThw==", "requires": { - "ant-design-palettes": "^1.1.3", + "@ant-design/colors": "^3.1.0", "babel-runtime": "^6.26.0" } }, @@ -1116,6 +1133,14 @@ "@types/react": "*" } }, + "@types/react-slick": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.4.tgz", + "integrity": "sha512-vXoIy4GUfB7/YgqubR4H7RALo+pRdMYCeLgWwV3MPwl5pggTlEkFBTF19R7u+LJc85uMqC7RfsbkqPLMQ4ab+A==", + "requires": { + "@types/react": "*" + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -1570,69 +1595,63 @@ "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=" }, - "ant-design-palettes": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ant-design-palettes/-/ant-design-palettes-1.1.3.tgz", - "integrity": "sha512-UpkkTp8egEN21KZNvY7sTcabLlkHvLvS71EVPk4CYi77Z9AaGGCaVn7i72tbOgWDrQp2wjIg8WgMbKBdK7GtWA==", - "requires": { - "tinycolor2": "^1.4.1" - } - }, "antd": { - "version": "3.13.6", - "resolved": "https://registry.npmjs.org/antd/-/antd-3.13.6.tgz", - "integrity": "sha512-V98EecoaKhHAxulhj07Uy9K4Hxzi+JkmdgYtimZIlaVnAGG3rIfIVgKVkWRK8uHTvvUZJtRIB621BNkhuHW1wQ==", - "requires": { - "@ant-design/icons": "~1.1.16", - "@ant-design/icons-react": "~1.1.2", + "version": "3.19.7", + "resolved": "https://registry.npmjs.org/antd/-/antd-3.19.7.tgz", + "integrity": "sha512-xc1AematIhMenb5aFk5J0vXUxIRKoIqQxjYJbv6bzL0iiFxoZBxplXR0zs0rMTILKFGWXeUuLPt9Id71t5rLzw==", + "requires": { + "@ant-design/create-react-context": "^0.2.4", + "@ant-design/icons": "~2.0.0", + "@ant-design/icons-react": "~2.0.1", + "@types/react-slick": "^0.23.4", "array-tree-filter": "^2.1.0", "babel-runtime": "6.x", "classnames": "~2.2.6", - "create-react-class": "^15.6.3", - "create-react-context": "0.2.2", + "copy-to-clipboard": "^3.2.0", "css-animation": "^1.5.0", "dom-closest": "^0.2.0", "enquire.js": "^2.1.6", "lodash": "^4.17.11", "moment": "^2.24.0", - "omit.js": "^1.0.0", - "prop-types": "^15.6.2", - "raf": "^3.4.0", - "rc-animate": "^2.5.4", - "rc-calendar": "~9.10.3", - "rc-cascader": "~0.17.0", - "rc-checkbox": "~2.1.5", - "rc-collapse": "~1.10.2", - "rc-dialog": "~7.3.0", - "rc-drawer": "~1.7.6", + "omit.js": "^1.0.2", + "prop-types": "^15.7.2", + "raf": "^3.4.1", + "rc-animate": "^2.8.3", + "rc-calendar": "~9.15.0", + "rc-cascader": "~0.17.4", + "rc-checkbox": "~2.1.6", + "rc-collapse": "~1.11.3", + "rc-dialog": "~7.4.0", + "rc-drawer": "~1.9.8", "rc-dropdown": "~2.4.1", - "rc-editor-mention": "^1.1.7", - "rc-form": "^2.4.0", - "rc-input-number": "~4.3.7", - "rc-menu": "~7.4.12", - "rc-notification": "~3.3.0", - "rc-pagination": "~1.17.7", + "rc-editor-mention": "^1.1.13", + "rc-form": "^2.4.5", + "rc-input-number": "~4.4.5", + "rc-mentions": "~0.3.1", + "rc-menu": "~7.4.23", + "rc-notification": "~3.3.1", + "rc-pagination": "~1.20.1", "rc-progress": "~2.3.0", "rc-rate": "~2.5.0", - "rc-select": "^8.6.7", - "rc-slider": "~8.6.5", - "rc-steps": "~3.3.0", + "rc-select": "~9.1.4", + "rc-slider": "~8.6.11", + "rc-steps": "~3.4.1", "rc-switch": "~1.9.0", - "rc-table": "~6.4.0", - "rc-tabs": "~9.6.0", - "rc-time-picker": "~3.6.1", + "rc-table": "~6.6.0", + "rc-tabs": "~9.6.4", + "rc-time-picker": "~3.6.6", "rc-tooltip": "~3.7.3", - "rc-tree": "~1.14.6", - "rc-tree-select": "~2.5.0", + "rc-tree": "~2.1.0", + "rc-tree-select": "~2.9.1", "rc-trigger": "^2.6.2", - "rc-upload": "~2.6.0", - "rc-util": "^4.5.1", + "rc-upload": "~2.6.7", + "rc-util": "^4.6.0", "react-lazy-load": "^3.0.13", "react-lifecycles-compat": "^3.0.4", - "react-slick": "~0.23.2", - "resize-observer-polyfill": "^1.5.0", + "react-slick": "~0.24.0", + "resize-observer-polyfill": "^1.5.1", "shallowequal": "^1.1.0", - "warning": "~4.0.2" + "warning": "~4.0.3" } }, "any-observable": { @@ -2494,7 +2513,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { "readable-stream": "^2.3.5", @@ -2508,7 +2527,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -2726,7 +2745,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -3875,6 +3894,14 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "copy-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.2.0.tgz", + "integrity": "sha512-eOZERzvCmxS8HWzugj4Uxl8OJxa7T2k1Gi0X5qavwydHIfuSHq2dTD09LOg/XyGq4Zpb5IsR/2OJ5lbOegz78w==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, "copy-webpack-plugin": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", @@ -4773,9 +4800,9 @@ } }, "dom-align": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.8.1.tgz", - "integrity": "sha512-0EPUDSr/Cha3IlS60bFTVj1eq7weXdzDNpdQDSfjsqAeftNPIW27wxmXpglboh10C0qV7/FdOvhp278XHkiM6Q==" + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.8.3.tgz", + "integrity": "sha512-thE1qB8mvtRZgwN4+IGFz1rv7zVsr08c2/IEYtOJIeTzW4YDadIOd5nQ4BpiiAvUWg55xTeGq7zLTDxDYWDrnw==" }, "dom-closest": { "version": "0.2.0", @@ -4867,13 +4894,6 @@ "fbjs": "^0.8.15", "immutable": "~3.7.4", "object-assign": "^4.1.0" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - } } }, "draw-svg-path": { @@ -6315,7 +6335,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "dev": true, "requires": { @@ -8821,7 +8841,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -9153,7 +9173,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -9247,7 +9267,7 @@ }, "html-webpack-plugin": { "version": "3.2.0", - "resolved": "http://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "dev": true, "requires": { @@ -9503,9 +9523,9 @@ "optional": true }, "immutable": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", - "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" }, "import-fresh": { "version": "3.0.0", @@ -9872,11 +9892,6 @@ "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.0.0.tgz", "integrity": "sha512-k2+p7BBCzhqHMdYJwGUNNo+6zegGiMIVbM6bEPzxWXpQV6BUzV892UW0oDFgqxT6DygO7LdxRbwC0xmOhJdbew==" }, - "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -9894,7 +9909,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-observable": { @@ -10056,9 +10071,9 @@ "dev": true }, "ismobilejs": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-0.5.1.tgz", - "integrity": "sha512-QX4STsOcBYqlTjVGuAdP1MiRVxtiUbRHOKH0v7Gn1EvfUVIQnrSdgCM4zB4VCZuIejnb2NUMUx0Bwd3EIG6yyA==" + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-0.5.2.tgz", + "integrity": "sha512-ta9UdV60xVZk/ZafFtSFslQaE76SvNkcs1r73d2PVR21zVzx9xuYv9tNe4MxA1NN7WoeCc2RjGot3Bz1eHDx3Q==" }, "isobject": { "version": "3.0.1", @@ -11452,7 +11467,7 @@ }, "magic-string": { "version": "0.22.5", - "resolved": "http://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "requires": { "vlq": "^0.2.2" @@ -11564,12 +11579,12 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -11768,7 +11783,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -11964,7 +11979,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -12465,7 +12480,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -12796,9 +12811,9 @@ "dev": true }, "omit.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.0.tgz", - "integrity": "sha512-O1rwbvEfAdhtonTv+v6IQeMOKTi/wlHcXpI3hehyPDlujkjSBQC6Vtzg0mdy+v2KVDmuPf7hAbHlTBM6q1bUHQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz", + "integrity": "sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ==", "requires": { "babel-runtime": "^6.23.0" } @@ -12867,7 +12882,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, @@ -13956,11 +13971,6 @@ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "dev": true }, - "prettier": { - "version": "1.16.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", - "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==" - }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -14339,9 +14349,9 @@ } }, "rc-animate": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.6.0.tgz", - "integrity": "sha512-JXDycchgbOI+7T/VKmFWnAIn042LLScK1fNkmNunb0jz5q5aPGCAybx2bTo7X5t31Jkj9OsxKNb/vZPDPWufCg==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.8.3.tgz", + "integrity": "sha512-VPSHJF/PW9zrPVCdQ94/YOI2lFfJVlaiAeQveJN2nlPVMivgvXkuFJyfe42GbZqm+qlnRjH9B4WbY9rCZz9miw==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.6", @@ -14352,9 +14362,9 @@ } }, "rc-calendar": { - "version": "9.10.10", - "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.10.10.tgz", - "integrity": "sha512-WFnxpXGzIt2cPCJjFmrju/w2jZHAO9jW3JSDZovaJuBtVciu1p8brL6PSjWCo4flD3jVurL9LO8tJwgajELj2w==", + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.0.tgz", + "integrity": "sha512-jmyiSG2QWIwB6Po2PySwB+kwpodWMxLVIJ0G2VJKu3jPQL0hNbsV47U28bhQzHkm5o0B3rJ3Tm+lk2VLcKbkaA==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14366,9 +14376,9 @@ } }, "rc-cascader": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.1.tgz", - "integrity": "sha512-JED1iOLpj1+uob+0Asd4zwhhMRp3gLs2iYOY2/0OsdEsPc8Qj6TUwj8+isVtqyXiwGWG3vo8XgO6KCM/i7ZFqQ==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.4.tgz", + "integrity": "sha512-CeFQJIMzY7x++uPqlx4Xl/cH8iTs8nRoW522+DLb21kdL5kWqKlK+3iHXExoxcAymjwo5ScIiXi+NY4m8Pgq9w==", "requires": { "array-tree-filter": "^2.1.0", "prop-types": "^15.5.8", @@ -14380,20 +14390,20 @@ } }, "rc-checkbox": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.6.tgz", - "integrity": "sha512-+VxQbt2Cwe1PxCvwosrAYXT6EQeGwrbLJB2K+IPGCSRPCKnk9zcub/0eW8A4kxjyyfh60PkwsAUZ7qmB31OmRA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.7.tgz", + "integrity": "sha512-8L+0XuucUOMUM6F/7qH+hnQpEHPZfW1Um02lUHEVdpZNor5mC0Fj4x8GvTtwcM1pAl5tD3I6lHYD8cE1W8RZJw==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", "prop-types": "15.x", - "rc-util": "^4.0.4" + "react-lifecycles-compat": "^3.0.4" } }, "rc-collapse": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.10.3.tgz", - "integrity": "sha512-uGZpSwTnKw9lZ4ODTqU3u4d6OcdAG0uB6lwSRNDISVdsDX8oMXULULqvFyM8UrgOkQFqU6klch78hyVE8+gFfA==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.11.3.tgz", + "integrity": "sha512-yECQX2iDPWnKcVi3Wz5bomZuJ2u+wv+kGxuKo2GIRz7Brh9jkGQz5ElghCV1jqDGnzy8GIRxxHHSwlSgdxdUog==", "requires": { "classnames": "2.x", "css-animation": "1.x", @@ -14404,9 +14414,9 @@ } }, "rc-dialog": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.3.0.tgz", - "integrity": "sha512-YLQHqZuU0cO02LUwhCsCCtvSw24SKLrT4DkNHCNGGcH9YpZP/IOFaH4zVUmXGEQiwyt0D1f3volHthMCKzLzMg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.4.1.tgz", + "integrity": "sha512-vvVVP7AUjxs2AEGL5GUr6BjfVzaiBV5RoiPYchCDqHmf8n7xTrfsACAhZ2Vezj6mtl2446zhxoGvhxNpyCyX7A==", "requires": { "babel-runtime": "6.x", "rc-animate": "2.x", @@ -14414,9 +14424,9 @@ } }, "rc-drawer": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-1.7.7.tgz", - "integrity": "sha512-7dESNkClYdWGSdBdwcfeOz6DUCqzrW44QT013fsTBJIiWNLSLgDV5KoHKXG8VTJWU4mBn7M5Lqgyr94CRZcxGA==", + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-1.9.9.tgz", + "integrity": "sha512-4oG0okZ7JhOTnGHRkxhOO1yb1U13v5ocns+40xmfogdD+oVNTKHIamCU1cKVVcMQYWpUCn8aYbawY2JuuGN/pA==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14437,9 +14447,9 @@ } }, "rc-editor-core": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.9.tgz", - "integrity": "sha512-fGTkTm96Kil/i9n5a3JwAzJcl2TkfjO1r1WBWf6NIOxXiJXpC3Lajkf3j6E5K7iz5AW0QRaSGnNQFBrwvXKKWA==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.10.tgz", + "integrity": "sha512-T3aHpeMCIYA1sdAI7ynHHjXy5fqp83uPlD68ovZ0oClTSc3tbHmyCxXlA+Ti4YgmcpCYv7avF6a+TIbAka53kw==", "requires": { "babel-runtime": "^6.26.0", "classnames": "^2.2.5", @@ -14451,24 +14461,24 @@ } }, "rc-editor-mention": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.12.tgz", - "integrity": "sha512-cPm2rQ7P+hXaKMsO0ajVv08QlTDcSPVtw8/lVr9D+QzQKRPChCqLw9rVGOa4YGYTeS3gVe8lBfLr8a9JKFk3gA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.13.tgz", + "integrity": "sha512-3AOmGir91Fi2ogfRRaXLtqlNuIwQpvla7oUnGHS1+3eo7b+fUp5IlKcagqtwUBB5oDNofoySXkLBxzWvSYNp/Q==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.5", "dom-scroll-into-view": "^1.2.0", "draft-js": "~0.10.0", - "immutable": "^3.7.4", + "immutable": "~3.7.4", "prop-types": "^15.5.8", "rc-animate": "^2.3.0", "rc-editor-core": "~0.8.3" } }, "rc-form": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.2.tgz", - "integrity": "sha512-1UeBuKBH9V5W9KxE48ecGAj5//kSt6F+AHB2vBxGRy1cZL+A5L9cKfI3HwsFpRa/ty6vaUAlGfq2xytQqN8enA==", + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/rc-form/-/rc-form-2.4.6.tgz", + "integrity": "sha512-yv+G1X0lJODswtrbrsa5bkicwk8NoIQmsOADYTzGlzOtvlwsdSLS02YEBONSi9tWTACgwFLY0ifERN6CJFF9dg==", "requires": { "async-validator": "~1.8.5", "babel-runtime": "6.x", @@ -14490,22 +14500,35 @@ } }, "rc-input-number": { - "version": "4.3.9", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.3.9.tgz", - "integrity": "sha512-u2ioYqAwHIbDpp6sUEIOv8kqQw8e7VfTR6Kn+wJYff7TBA3Zw2Ql9I4DQniuLXglCJzDiHqG1OR5v3kN3GrD4w==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.4.5.tgz", + "integrity": "sha512-Dt20e8Ylc/N/6oXiPUlwDVdx3fz7W5umUOa4z5pBuWFG7NPlBVXRWkq7+nbnTyaK24UxN67PVpmD3+Omo+QRZQ==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.0", - "is-negative-zero": "^2.0.0", "prop-types": "^15.5.7", "rc-util": "^4.5.1", "rmc-feedback": "^2.0.0" } }, + "rc-mentions": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.3.1.tgz", + "integrity": "sha512-fa5dN3IMTahJfAga1nmma9OymK/ZBV/MZfV11h4kjDmCAVETv5EbAlV0mn6Y+JajvXS6n/XFoPUSF+nwK/AeWw==", + "requires": { + "@ant-design/create-react-context": "^0.2.4", + "babel-runtime": "^6.23.0", + "classnames": "^2.2.6", + "rc-menu": "^7.4.22", + "rc-trigger": "^2.6.2", + "rc-util": "^4.6.0", + "react-lifecycles-compat": "^3.0.4" + } + }, "rc-menu": { - "version": "7.4.21", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.4.21.tgz", - "integrity": "sha512-TfcwybKLuw2WhEkplYH7iFMGlDbH6KhPcd+gv5J2oLQcgiGeUECzyOWSVaFRRlkpB7g2eNzXbha/AXN/Xyzvnw==", + "version": "7.4.23", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-7.4.23.tgz", + "integrity": "sha512-d0pUMN0Zr3GCFxNpas8p7AUTeX8viItUOQXku4AsyX82ZzUz79HgGul2Nk17BIFTtLzqdB7/NT6WVb5PAOOILw==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14533,11 +14556,12 @@ } }, "rc-pagination": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.17.8.tgz", - "integrity": "sha512-duEV+K/b/nZNGr943+TMCEcY4xWkjAkpKW0Vr7fSR8wQk0DY7aTJC+k+vjl4X2EzEmPXqy85hibzpsO9vydKAw==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.1.tgz", + "integrity": "sha512-EC2sxfKo1+R34fDN8EQgFiJn0Z6SKef4O0FizoqV3IomPczSikoarxL1RrHzqeGNsfg7JbUYaux5fQdmUAlPnA==", "requires": { "babel-runtime": "6.x", + "classnames": "^2.2.6", "prop-types": "^15.5.7", "react-lifecycles-compat": "^3.0.4" } @@ -14563,9 +14587,9 @@ } }, "rc-select": { - "version": "8.8.4", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-8.8.4.tgz", - "integrity": "sha512-3ylsjhiUtEN4Tg6/ddg1wG0FXSmT/67LT2/KF8azaG6x/1sMNmSxoyi1nxVoFdmkCO5luDA5F1xCHCOxGuEj3A==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.1.5.tgz", + "integrity": "sha512-P2QDl5xSdrYuvODnwZIKxhBv2AzfsuFNfaoXjRsPTlQvOjLMCGYgyRzZ4xdUy1IAc1yER6LV+g7e4N9Qc+3DDQ==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", @@ -14582,9 +14606,9 @@ } }, "rc-slider": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.6.6.tgz", - "integrity": "sha512-byfnq1LbBFyZ0HURWo22sjeiKIxLyzSnIiNUsUf6SWu1ZhQe/Qt24JnE/ZJsqKoUirXxlX+d577ptfAybZHm+Q==", + "version": "8.6.13", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.6.13.tgz", + "integrity": "sha512-fCUe8pPn8n9pq1ARX44nN2nzJoATtna4x/PdskUrxIvZXN8ja7HuceN/hq6kokZjo3FBD2B1yMZvZh6oi68l6Q==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14596,9 +14620,9 @@ } }, "rc-steps": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.3.1.tgz", - "integrity": "sha512-LGzmPYS9ETePo+6YbHlFukCdcKppeBZXO49ZxewaC7Cba00q0zrMXlexquZ4fm+9iz0IkpzwgmenvjsVWCmGOw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.4.1.tgz", + "integrity": "sha512-zdeOFmFqiXlXCQyHet1qrDDbGKZ7OQTrlzn8DP5N6M/WqN7HaYoUDy1fZ+NY2htL5WzzVFQpDRKzjiOiHaSqgw==", "requires": { "babel-runtime": "^6.23.0", "classnames": "^2.2.3", @@ -14617,9 +14641,9 @@ } }, "rc-table": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.4.3.tgz", - "integrity": "sha512-4/f7mS87EtNxM2vhIaA7I1J8hPZ5OiOQwmjac7RJTmGOFVA8PJDGwEipeyU/eC9RM7f3v4Lc+a05KCfIbRU4tg==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.6.7.tgz", + "integrity": "sha512-NC6kaHl6q/Eed0THGVSFLfc0xRcctiVEv63oDCrpYRTJPCTfG9q5APDLzwh44dKDAfXHt2JCJ5QtRJH8zaM2IQ==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14644,9 +14668,9 @@ } }, "rc-tabs": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.6.1.tgz", - "integrity": "sha512-3/Ip9yCEERFFvCjU0ZoQqvn6unMo0XOQESygNLq1DyOAYRcukpq8Q28awpXWqh8l8NBcyw1sVfrs6SZN/zmAKg==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.6.4.tgz", + "integrity": "sha512-l4PoDSShNJ6pWGuR1UcUgvee48b3Qu1jgMEaD1hH3Rc+mqysoO7hA9AQ1YywkIy34afGTTejAWDSIFZ0lmg08g==", "requires": { "babel-runtime": "6.x", "classnames": "2.x", @@ -14656,6 +14680,7 @@ "raf": "^3.4.1", "rc-hammerjs": "~0.6.0", "rc-util": "^4.0.4", + "resize-observer-polyfill": "^1.5.1", "warning": "^3.0.0" }, "dependencies": { @@ -14670,13 +14695,14 @@ } }, "rc-time-picker": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.6.2.tgz", - "integrity": "sha512-SyGEVXO0ImeG2mz+7fkVmDoVM0+OrX6uYGpKYijNr/lAah7c5p310ZR6fVrblXOl4TpqVnfWR67RMJ3twAyM7w==", + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.6.6.tgz", + "integrity": "sha512-NVeJuxWjg9eJ0+jcCCT2dxVY2OBYxOrjsgu8ly0lk9IUJ8lwjS6JU+OibHRPJPew3Smfz88dz7GQRdBE7BcnRA==", "requires": { "classnames": "2.x", "moment": "2.x", "prop-types": "^15.5.8", + "raf": "^3.4.1", "rc-trigger": "^2.2.0" } }, @@ -14691,54 +14717,30 @@ } }, "rc-tree": { - "version": "1.14.10", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-1.14.10.tgz", - "integrity": "sha512-iOn7+SpWzM4OQoF/7wJeFiuRpBGJ3ndTe6YVGnfIhsWqDd7S6a7z0anDQcBpPsW/PvisjNDXr4zKchZvx+0iCA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.0.tgz", + "integrity": "sha512-DyHG/W9rW8cYfBrqVrZUep5yt30scyBuYvFnGrU32bh1DUj8GKqOcdoRBaIiOBYurmIiJ02rq6BeBbvVtVp0mw==", "requires": { "babel-runtime": "^6.23.0", "classnames": "2.x", "prop-types": "^15.5.8", - "rc-animate": "^3.0.0-rc.5", + "rc-animate": "^2.6.0", "rc-util": "^4.5.1", "react-lifecycles-compat": "^3.0.4", - "warning": "^3.0.0" - }, - "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "requires": { - "loose-envify": "^1.0.0" - } - } + "warning": "^4.0.3" } }, "rc-tree-select": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.5.4.tgz", - "integrity": "sha512-7PVC3SV8X02cTZ9+VtNLM5dpYdIbB/xe6N2MVKFnc2YNgMx76sm+Fk2OrgbgicIK/lWAPkKTxnwvNk5PKR4a1g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.1.tgz", + "integrity": "sha512-AfJQC1ZzaeH+Onmx84TtVLUL2guBZe7exA8XSfj1RRB1doDbYGTtybzpP3CEw/tuSftSRnz+iPt+iaxRTrgXRw==", "requires": { "classnames": "^2.2.1", + "dom-scroll-into-view": "^1.2.1", "prop-types": "^15.5.8", "raf": "^3.4.0", - "rc-animate": "^3.0.0-rc.4", - "rc-tree": "~1.14.3", + "rc-animate": "^2.8.2", + "rc-tree": "~2.0.0", "rc-trigger": "^3.0.0-rc.2", "rc-util": "^4.5.0", "react-lifecycles-compat": "^3.0.4", @@ -14746,19 +14748,28 @@ "warning": "^4.0.1" }, "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" + "rc-tree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.0.0.tgz", + "integrity": "sha512-DAT/jsbnFbHqG9Df9OaVG93CAVtTsJVnJiwKX+wqsG8TChpty3s6QX3zJZ+gBgjkq4ikLbu1kuFJtX63EKhSAA==", + "requires": { + "babel-runtime": "^6.23.0", + "classnames": "2.x", + "prop-types": "^15.5.8", + "rc-animate": "^2.6.0", + "rc-util": "^4.5.1", + "react-lifecycles-compat": "^3.0.4", + "warning": "^3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + } } }, "rc-trigger": { @@ -14773,14 +14784,31 @@ "rc-align": "^2.4.1", "rc-animate": "^3.0.0-rc.1", "rc-util": "^4.4.0" + }, + "dependencies": { + "rc-animate": { + "version": "3.0.0-rc.6", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", + "integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.5", + "component-classes": "^1.2.6", + "fbjs": "^0.8.16", + "prop-types": "15.x", + "raf": "^3.4.0", + "rc-util": "^4.5.0", + "react-lifecycles-compat": "^3.0.4" + } + } } } } }, "rc-trigger": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.2.tgz", - "integrity": "sha512-op4xCu95/gdHVaysyxxiYxbY+Z+UcIBSUY9nQfLqm1FlitdtnAN+owD5iMPfnnsRXntgcQ5+RdYKNUFQT5DjzA==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.3.tgz", + "integrity": "sha512-wcYFTdWBcHjK+Wu72sLzpKttKBqJpFoIv7Ho6AnAjjsJZlxi+MpHrQs9ozRM3Q9G1M87BSYYrORGSgx5HpGI1w==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.6", @@ -14791,9 +14819,9 @@ } }, "rc-upload": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.6.3.tgz", - "integrity": "sha512-wM57UH/EEqW2/EcWz5nwnU07d4LHDHjBgxRin2Q56TW9JcFVnaQVq/JHycVFumsgSFV5CZfNW8PBROsKT9VFMw==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-2.6.7.tgz", + "integrity": "sha512-i6roYvM31ue50r0w/MbxOdbbkZHqpJLT29JyjQC2W5i/7w0/lZJkWEmj/DG5WRRJCnVfIiKmXp2437oXnUFNuw==", "requires": { "babel-runtime": "6.x", "classnames": "^2.2.5", @@ -14907,15 +14935,14 @@ } }, "react-slick": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.23.2.tgz", - "integrity": "sha512-fM6DXX7+22eOcYE9cgaXUfioZL/Zw6fwS6aPMDBt0kLHl4H4fFNEbp4JsJQdEWMLUNFtUytNcvd9KRml22Tp5w==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.24.0.tgz", + "integrity": "sha512-Pvo0B74ohumQdYOf0qP+pdQpj9iUbAav7+2qiF3uTc5XeQp/Y/cnIeDBM2tB3txthfSe05jKIqLMJTS6qVvt5g==", "requires": { "classnames": "^2.2.5", "enquire.js": "^2.1.6", "json2mq": "^0.2.0", "lodash.debounce": "^4.0.8", - "prettier": "^1.14.3", "resize-observer-polyfill": "^1.5.0" } }, @@ -16025,9 +16052,9 @@ "integrity": "sha1-QV9CcC1z2BAzApLMXuhurhoRoXA=" }, "shallow-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.1.0.tgz", - "integrity": "sha512-0SW1nWo1hnabO62SEeHsl8nmTVVEzguVWZCj5gaQrgWAxz/BaCja4OWdJBWLVPDxdtE/WU7c98uUCCXyPHSCvw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.0.tgz", + "integrity": "sha512-Z21pVxR4cXsfwpMKMhCEIO1PCi5sp7KEp+CmOpBQ+E8GpHwKOw2sEzk7sgblM3d/j4z4gakoWEoPcjK0VJQogA==" }, "shallowequal": { "version": "1.1.0", @@ -16049,7 +16076,7 @@ "dependencies": { "minimist": { "version": "0.0.5", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz", "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=" } } @@ -16537,7 +16564,7 @@ }, "split": { "version": "0.2.10", - "resolved": "http://registry.npmjs.org/split/-/split-0.2.10.tgz", + "resolved": "https://registry.npmjs.org/split/-/split-0.2.10.tgz", "integrity": "sha1-Zwl8YB1pfOE2j0GPBs0gHPBSGlc=", "requires": { "through": "2" @@ -16895,7 +16922,7 @@ "dependencies": { "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -17029,7 +17056,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -17591,6 +17618,11 @@ "to-array-buffer": "^3.0.0" } }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, "topojson-client": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-2.1.0.tgz", @@ -17739,9 +17771,9 @@ } }, "ua-parser-js": { - "version": "0.7.19", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", - "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" + "version": "0.7.20", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", + "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==" }, "uglify-js": { "version": "2.8.29", diff --git a/package.json b/package.json index 9d3d2ced7d..d3ba2b2e4f 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "angular-ui-bootstrap": "^2.5.0", "angular-vs-repeat": "^1.1.7", "angular2react": "^3.0.2", - "antd": "^3.12.3", + "antd": "^3.19.7", "bootstrap": "^3.3.7", "brace": "^0.11.0", "chroma-js": "^1.3.6", From 7efcd39163469e1e16deb1b78b0f61d19cd51635 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 27 Jun 2019 13:00:03 -0300 Subject: [PATCH 05/39] Cleanup and DateRangeParameter --- client/app/components/DateRangeInput.jsx | 14 ++- .../components/EditDateParameterDialog.jsx | 104 ------------------ client/app/components/ParameterValueInput.jsx | 53 +-------- .../parameters/DateRangeParameter.jsx | 87 +++++++++++++++ .../parameters/DateRangeParameter.less | 16 +++ .../components/parameters/DynamicButton.jsx | 56 ++++++++++ .../components/parameters/DynamicButton.less | 33 ++++++ client/app/services/query.js | 2 +- 8 files changed, 212 insertions(+), 153 deletions(-) delete mode 100644 client/app/components/EditDateParameterDialog.jsx create mode 100644 client/app/components/parameters/DateRangeParameter.jsx create mode 100644 client/app/components/parameters/DateRangeParameter.less create mode 100644 client/app/components/parameters/DynamicButton.jsx create mode 100644 client/app/components/parameters/DynamicButton.less diff --git a/client/app/components/DateRangeInput.jsx b/client/app/components/DateRangeInput.jsx index 3961e252dc..db91a0b87a 100644 --- a/client/app/components/DateRangeInput.jsx +++ b/client/app/components/DateRangeInput.jsx @@ -9,15 +9,23 @@ import { Moment } from '@/components/proptypes'; const { RangePicker } = DatePicker; export function DateRangeInput({ + defaultValue, value, onSelect, className, + hideValue, ...props }) { const format = clientConfig.dateFormat || 'YYYY-MM-DD'; const additionalAttributes = {}; + if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { + additionalAttributes.defaultValue = defaultValue; + } if (isArray(value) && value[0].isValid() && value[1].isValid()) { - additionalAttributes.defaultValue = value; + additionalAttributes.value = value; + } + if (hideValue) { + additionalAttributes.value = null; } return ( {}, className: '', + hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/EditDateParameterDialog.jsx b/client/app/components/EditDateParameterDialog.jsx deleted file mode 100644 index e4aec4dac3..0000000000 --- a/client/app/components/EditDateParameterDialog.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { findIndex } from 'lodash'; -import InputNumber from 'antd/lib/input-number'; -import Form from 'antd/lib/form'; -import Modal from 'antd/lib/modal'; -import Radio from 'antd/lib/radio'; -import { wrap as wrapDialog, DialogPropType } from '@/components/DialogWrapper'; - -const DATE_INTERVAL_OPTIONS = [ - { name: 'Last week', value: 'd_last_week' }, - { name: 'Last month', value: 'd_last_month' }, - { name: 'Last year', value: 'd_last_year' }, - { name: 'Last 7 days', value: 'd_last_7_days' }, -]; - -class EditDateParameterDialog extends React.Component { - static propTypes = { - dialog: DialogPropType.isRequired, - defaultValue: PropTypes.any, // eslint-disable-line react/forbid-prop-types - }; - - static defaultProps = { - defaultValue: null, - }; - - state = { - currentOption: 0, - }; - - formItemProps = { - labelCol: { span: 5 }, - wrapperCol: { span: 16 }, - }; - - constructor(props) { - super(props); - const currentOption = findIndex(DATE_INTERVAL_OPTIONS, v => v.value === props.defaultValue); - this.state = { - currentOption: currentOption === -1 ? 'static' : currentOption, - }; - } - - getValue = () => { - const { currentOption } = this.state; - switch (currentOption) { - case 'static': - return null; - default: - return DATE_INTERVAL_OPTIONS[currentOption]; - } - } - - onChange = (e) => { - this.setState({ currentOption: e.target.value }); - } - - onOk = () => { - this.props.dialog.close(this.getValue()); - } - - renderCustomOptions() { - return ( - - year(s) - month(s) - day(s) - - ); - } - - render() { - const { dialog } = this.props; - const radioStyle = { - display: 'block', - height: '30px', - lineHeight: '30px', - }; - return ( - -
- - - - Static value - - {DATE_INTERVAL_OPTIONS.map((option, key) => ( - - {option.name} - - ))} - - Custom - - - - {this.state.currentOption === 'custom' && this.renderCustomOptions()} -
-
- ); - } -} - -export default wrapDialog(EditDateParameterDialog); diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index 4a58e97b16..181957d8e0 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -6,12 +6,10 @@ import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; import InputNumber from 'antd/lib/input-number'; import Icon from 'antd/lib/icon'; -import Tag from 'antd/lib/tag'; import Tooltip from 'antd/lib/tooltip'; -import EditDateParameterDialog from '@/components/EditDateParameterDialog'; -import { defer, isFunction, includes } from 'lodash'; +import DateRangeParameter from '@/components/parameters/DateRangeParameter'; +import { defer, isFunction } from 'lodash'; import { DateInput } from './DateInput'; -import { DateRangeInput } from './DateRangeInput'; import { DateTimeInput } from './DateTimeInput'; import { DateTimeRangeInput } from './DateTimeRangeInput'; import { QueryBasedParameterInput } from './QueryBasedParameterInput'; @@ -45,27 +43,9 @@ export class ParameterValueInput extends React.Component { constructor(props) { super(props); - this.state = { - value: props.value, - hasDynamicDateTime: !!(props.parameter && props.parameter.hasDynamicValue), - }; + this.state = { value: props.value }; } - openDateParameterDialog = (e) => { - e.stopPropagation(); - - const { onSelect, parameter } = this.props; - EditDateParameterDialog.showModal({ defaultValue: parameter.value }).result - .then((datePeriod) => { - if (datePeriod) { - onSelect(datePeriod.value); - } else { - onSelect(parameter.getValue()); - } - this.setState({ hasDynamicDateTime: parameter.hasDynamicValue }); - }); - }; - renderApplyButton() { const { onSelect } = this.props; const { value } = this.state; @@ -136,8 +116,6 @@ export class ParameterValueInput extends React.Component { value={value} onSelect={onSelect} withSeconds - suffixIcon={this.renderDynamicOptionButton()} - allowClear={false} /> ); } @@ -149,35 +127,22 @@ export class ParameterValueInput extends React.Component { className={this.props.className} value={value} onSelect={onSelect} - suffixIcon={this.renderDynamicOptionButton()} - allowClear={false} /> ); } renderDateRangeInput() { - const { value, onSelect } = this.props; + const { value, parameter, onSelect } = this.props; return ( - ); } - renderDynamicDateRangeTag() { - const { parameter } = this.props; - return ( -
- {parameter.dynamicValue.name} - {this.renderDynamicOptionButton()} -
- ); - } - renderEnumInput() { const { value, onSelect, enumOptions } = this.props; const enumOptionsArray = enumOptions.split('\n').filter(v => v !== ''); @@ -270,12 +235,6 @@ export class ParameterValueInput extends React.Component { render() { const { type } = this.props; - const isDateRangeType = includes(['datetime-range-with-seconds', 'datetime-range', 'date-range'], type); - - if (this.state.hasDynamicDateTime && isDateRangeType) { - return this.renderDynamicDateRangeTag(); - } - switch (type) { case 'datetime-with-seconds': return this.renderDateTimeWithSecondsInput(); case 'datetime-local': return this.renderDateTimeInput(); diff --git a/client/app/components/parameters/DateRangeParameter.jsx b/client/app/components/parameters/DateRangeParameter.jsx new file mode 100644 index 0000000000..e3b3170c8a --- /dev/null +++ b/client/app/components/parameters/DateRangeParameter.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { DYNAMIC_DATE_RANGES } from '@/services/query'; +import { DateRangeInput } from '@/components/DateRangeInput'; +import DynamicButton from '@/components/parameters/DynamicButton'; + +import './DateRangeParameter.less'; + +const DYNAMIC_OPTIONS = [ + { name: 'Static value', value: 'static' }, + { name: 'Last week', + value: 'd_last_week', + label: () => DYNAMIC_DATE_RANGES.last_week.value()[0].format('MMM D') + ' - ' + + DYNAMIC_DATE_RANGES.last_week.value()[1].format('MMM D') }, + { name: 'Last month', value: 'd_last_month', label: () => DYNAMIC_DATE_RANGES.last_month.value()[0].format('MMMM') }, + { name: 'Last year', value: 'd_last_year', label: () => DYNAMIC_DATE_RANGES.last_year.value()[0].format('YYYY') }, + { name: 'Last 7 days', + value: 'd_last_7_days', + label: () => DYNAMIC_DATE_RANGES.last_7_days.value()[0].format('MMM D') + ' - Today' }, +]; + +export default class DateRangeParameter extends React.Component { + static propTypes = { + className: PropTypes.string, + value: PropTypes.any, // eslint-disable-line react/forbid-prop-types + parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types + onSelect: PropTypes.func, + }; + + static defaultProps = { + className: '', + value: null, + parameter: null, + onSelect: () => {}, + }; + + constructor(props) { + super(props); + this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; + } + + onDynamicValueSelect = (dynamicValue) => { + const { onSelect, parameter } = this.props; + if (dynamicValue.value === 'static') { + this.setState({ dynamicValue: false }); + onSelect(parameter.getValue()); + } else { + this.setState({ dynamicValue: true }); + onSelect(dynamicValue.value); + } + }; + + onSelect = (value) => { + const { onSelect } = this.props; + this.setState({ dynamicValue: false }, () => onSelect(value)); + }; + + render() { + const { value, parameter, className } = this.props; + const { dynamicValue } = this.state; + + const additionalAttributes = {}; + + if (dynamicValue) { + additionalAttributes.placeholder = [parameter.dynamicValue && parameter.dynamicValue.name]; + additionalAttributes.hideValue = true; + } + + return ( + + )} + allowClear={false} + {...additionalAttributes} + /> + ); + } +} diff --git a/client/app/components/parameters/DateRangeParameter.less b/client/app/components/parameters/DateRangeParameter.less new file mode 100644 index 0000000000..f78b1800e5 --- /dev/null +++ b/client/app/components/parameters/DateRangeParameter.less @@ -0,0 +1,16 @@ +.dynamic-value { + & ::placeholder, & .dynamic-icon { + color: #1890ff !important + } + + .ant-calendar-range-picker-separator, + .ant-calendar-range-picker-input:not(:first-child) { + display: none; + } +} + +.redash-datepicker { + .ant-calendar-picker-clear { + right: 35px; + } +} diff --git a/client/app/components/parameters/DynamicButton.jsx b/client/app/components/parameters/DynamicButton.jsx new file mode 100644 index 0000000000..a62813bf2d --- /dev/null +++ b/client/app/components/parameters/DynamicButton.jsx @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { isFunction, get } from 'lodash'; +import Dropdown from 'antd/lib/dropdown'; +import Icon from 'antd/lib/icon'; +import Menu from 'antd/lib/menu'; + +import './DynamicButton.less'; + +export default function DynamicButton({ options, onSelect, enabled }) { + const menu = ( + onSelect(get(options, key))} + > + {options.map((option, index) => ( + // eslint-disable-next-line react/no-array-index-key + + {option.name} {option.label && ( + {isFunction(option.label) ? option.label() : option.label} + )} + + ))} + + ); + + return ( + e.stopPropagation()}> + + )} + /> + + ); +} + +DynamicButton.propTypes = { + options: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types + onSelect: PropTypes.func, + enabled: PropTypes.bool, +}; + +DynamicButton.defaultProps = { + options: [], + onSelect: () => {}, + enabled: false, +}; diff --git a/client/app/components/parameters/DynamicButton.less b/client/app/components/parameters/DynamicButton.less new file mode 100644 index 0000000000..755c9c18a5 --- /dev/null +++ b/client/app/components/parameters/DynamicButton.less @@ -0,0 +1,33 @@ + + +.dynamic-button { + position: absolute !important; + right: 1px; + top: 0; + + button { + border: none; + padding: 0; + box-shadow: none; + background-color: transparent !important; + } + + &::after { + content: ""; + position: absolute; + width: 1px; + height: 17px; + left: 0; + top: 8px; + border-left: 1px dotted rgba(0, 0, 0, 0.12); + } +} + +.dynamic-menu { + width: 187px; + + em { + color: #ccc; + font-size: 11px; + } +} diff --git a/client/app/services/query.js b/client/app/services/query.js index a6b0387c4c..3002b3f3ce 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -25,7 +25,7 @@ const DATETIME_FORMATS = { const DYNAMIC_DATE_PREFIX = 'd_'; -const DYNAMIC_DATE_RANGES = { +export const DYNAMIC_DATE_RANGES = { last_week: { name: 'Last week', value: () => [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')], From 050eb616d06bfaef098251d1d5b07af204754eb9 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 27 Jun 2019 17:02:52 -0300 Subject: [PATCH 06/39] Dynamic DateTimeRange --- client/app/components/DateTimeRangeInput.jsx | 27 ++++++----- client/app/components/ParameterValueInput.jsx | 28 +++-------- .../DateRangeParameter.jsx | 46 ++++++++++++++++--- .../DynamicButton.jsx | 0 .../DynamicButton.less | 0 .../DynamicParameters.less} | 2 + client/app/services/query.js | 8 ++++ 7 files changed, 71 insertions(+), 40 deletions(-) rename client/app/components/{parameters => dynamic-parameters}/DateRangeParameter.jsx (66%) rename client/app/components/{parameters => dynamic-parameters}/DynamicButton.jsx (100%) rename client/app/components/{parameters => dynamic-parameters}/DynamicButton.less (100%) rename client/app/components/{parameters/DateRangeParameter.less => dynamic-parameters/DynamicParameters.less} (91%) diff --git a/client/app/components/DateTimeRangeInput.jsx b/client/app/components/DateTimeRangeInput.jsx index fc7ec37bf2..023d1e6b8d 100644 --- a/client/app/components/DateTimeRangeInput.jsx +++ b/client/app/components/DateTimeRangeInput.jsx @@ -1,5 +1,5 @@ import { isArray } from 'lodash'; -import React, { useRef } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { react2angular } from 'react2angular'; import DatePicker from 'antd/lib/date-picker'; @@ -9,51 +9,54 @@ import { Moment } from '@/components/proptypes'; const { RangePicker } = DatePicker; export function DateTimeRangeInput({ + defaultValue, value, withSeconds, onSelect, className, + hideValue, ...props }) { const format = (clientConfig.dateFormat || 'YYYY-MM-DD') + (withSeconds ? ' HH:mm:ss' : ' HH:mm'); const additionalAttributes = {}; + if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { + additionalAttributes.defaultValue = defaultValue; + } if (isArray(value) && value[0].isValid() && value[1].isValid()) { - additionalAttributes.defaultValue = value; + additionalAttributes.value = value; + } + if (hideValue) { + additionalAttributes.value = null; } - const currentValueRef = useRef(additionalAttributes.defaultValue); return ( { currentValueRef.current = newValue; }} - onOpenChange={(status) => { - const currentValue = currentValueRef.current; - if (!status) { // on close picker - if (isArray(currentValue) && currentValue[0].isValid() && currentValue[1].isValid()) { - onSelect(currentValue); - } - } - }} + onChange={onSelect} {...props} /> ); } DateTimeRangeInput.propTypes = { + defaultValue: PropTypes.arrayOf(Moment), value: PropTypes.arrayOf(Moment), withSeconds: PropTypes.bool, onSelect: PropTypes.func, className: PropTypes.string, + hideValue: PropTypes.bool, }; DateTimeRangeInput.defaultProps = { + defaultValue: null, value: null, withSeconds: false, onSelect: () => {}, className: '', + hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index 181957d8e0..93df6f2e24 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -5,9 +5,7 @@ import Button from 'antd/lib/button'; import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; import InputNumber from 'antd/lib/input-number'; -import Icon from 'antd/lib/icon'; -import Tooltip from 'antd/lib/tooltip'; -import DateRangeParameter from '@/components/parameters/DateRangeParameter'; +import DateRangeParameter from '@/components/dynamic-parameters/DateRangeParameter'; import { defer, isFunction } from 'lodash'; import { DateInput } from './DateInput'; import { DateTimeInput } from './DateTimeInput'; @@ -61,19 +59,6 @@ export class ParameterValueInput extends React.Component { ); } - renderDynamicOptionButton() { - return ( - - - - ); - } - renderDateTimeWithSecondsInput() { const { value, onSelect } = this.props; return ( @@ -131,10 +116,11 @@ export class ParameterValueInput extends React.Component { ); } - renderDateRangeInput() { - const { value, parameter, onSelect } = this.props; + renderDateRangeParameter() { + const { type, value, parameter, onSelect } = this.props; return ( DYNAMIC_DATE_RANGES.last_week.value()[0].format('MMM D') + ' - ' + @@ -20,8 +21,19 @@ const DYNAMIC_OPTIONS = [ label: () => DYNAMIC_DATE_RANGES.last_7_days.value()[0].format('MMM D') + ' - Today' }, ]; +const DYNAMIC_DATETIME_OPTIONS = [ + { name: 'Today', + value: 'd_today', + label: () => DYNAMIC_DATE_RANGES.today.value()[0].format('MMM D') }, + { name: 'Yesterday', + value: 'd_yesterday', + label: () => DYNAMIC_DATE_RANGES.yesterday.value()[0].format('MMM D') }, + ...DYNAMIC_DATE_OPTIONS, +]; + export default class DateRangeParameter extends React.Component { static propTypes = { + type: PropTypes.string, className: PropTypes.string, value: PropTypes.any, // eslint-disable-line react/forbid-prop-types parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types @@ -29,6 +41,7 @@ export default class DateRangeParameter extends React.Component { }; static defaultProps = { + type: '', className: '', value: null, parameter: null, @@ -40,6 +53,16 @@ export default class DateRangeParameter extends React.Component { this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; } + dynamicOptions = () => { + const isDateTimeRange = includes(this.props.type, 'datetime-range'); + const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; + + return [ + { name: 'Static value', value: 'static' }, + ...options, + ]; + } + onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue.value === 'static') { @@ -57,24 +80,33 @@ export default class DateRangeParameter extends React.Component { }; render() { - const { value, parameter, className } = this.props; + const { type, value, parameter, className } = this.props; const { dynamicValue } = this.state; + const isDateTime = includes(type, 'datetime-range'); const additionalAttributes = {}; + let DateRangeComponent = DateRangeInput; + if (isDateTime) { + DateRangeComponent = DateTimeRangeInput; + if (includes(type, 'with-seconds')) { + additionalAttributes.withSeconds = true; + } + } + if (dynamicValue) { additionalAttributes.placeholder = [parameter.dynamicValue && parameter.dynamicValue.name]; additionalAttributes.hideValue = true; } return ( - diff --git a/client/app/components/parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx similarity index 100% rename from client/app/components/parameters/DynamicButton.jsx rename to client/app/components/dynamic-parameters/DynamicButton.jsx diff --git a/client/app/components/parameters/DynamicButton.less b/client/app/components/dynamic-parameters/DynamicButton.less similarity index 100% rename from client/app/components/parameters/DynamicButton.less rename to client/app/components/dynamic-parameters/DynamicButton.less diff --git a/client/app/components/parameters/DateRangeParameter.less b/client/app/components/dynamic-parameters/DynamicParameters.less similarity index 91% rename from client/app/components/parameters/DateRangeParameter.less rename to client/app/components/dynamic-parameters/DynamicParameters.less index f78b1800e5..0dca09c237 100644 --- a/client/app/components/parameters/DateRangeParameter.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -10,6 +10,8 @@ } .redash-datepicker { + width: auto !important; + .ant-calendar-picker-clear { right: 35px; } diff --git a/client/app/services/query.js b/client/app/services/query.js index 3002b3f3ce..f0b44ecf76 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -26,6 +26,14 @@ const DATETIME_FORMATS = { const DYNAMIC_DATE_PREFIX = 'd_'; export const DYNAMIC_DATE_RANGES = { + today: { + name: 'Today', + value: () => [moment().startOf('day'), moment().endOf('day')], + }, + yesterday: { + name: 'Yesterday', + value: () => [moment().subtract(1, 'day').startOf('day'), moment().subtract(1, 'day').endOf('day')], + }, last_week: { name: 'Last week', value: () => [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')], From 6af60919f31521b8f9e81462595df1b702d9ab14 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 27 Jun 2019 18:42:43 -0300 Subject: [PATCH 07/39] Add Dynamic options to Date Parameters --- client/app/components/DateInput.jsx | 16 ++- client/app/components/DateTimeInput.jsx | 29 +++--- client/app/components/ParameterValueInput.jsx | 64 ++---------- .../dynamic-parameters/DateParameter.jsx | 97 +++++++++++++++++++ .../dynamic-parameters/DateRangeParameter.jsx | 4 +- .../dynamic-parameters/DynamicButton.less | 2 - client/app/services/query.js | 47 +++++++-- 7 files changed, 178 insertions(+), 81 deletions(-) create mode 100644 client/app/components/dynamic-parameters/DateParameter.jsx diff --git a/client/app/components/DateInput.jsx b/client/app/components/DateInput.jsx index 733c3b669c..05b9978b56 100644 --- a/client/app/components/DateInput.jsx +++ b/client/app/components/DateInput.jsx @@ -6,14 +6,23 @@ import { clientConfig } from '@/services/auth'; import { Moment } from '@/components/proptypes'; export function DateInput({ + defaultValue, value, onSelect, className, + hideValue, + ...props }) { const format = clientConfig.dateFormat || 'YYYY-MM-DD'; const additionalAttributes = {}; + if (defaultValue && defaultValue.isValid()) { + additionalAttributes.defaultValue = defaultValue; + } if (value && value.isValid()) { - additionalAttributes.defaultValue = value; + additionalAttributes.value = value; + } + if (hideValue) { + additionalAttributes.value = null; } return ( ); } DateInput.propTypes = { + defaultValue: Moment, value: Moment, onSelect: PropTypes.func, className: PropTypes.string, + hideValue: PropTypes.bool, }; DateInput.defaultProps = { + defaultValue: null, value: null, onSelect: () => {}, className: '', + hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/DateTimeInput.jsx b/client/app/components/DateTimeInput.jsx index 7f185fef0b..4ea8c2d5ae 100644 --- a/client/app/components/DateTimeInput.jsx +++ b/client/app/components/DateTimeInput.jsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import { react2angular } from 'react2angular'; import DatePicker from 'antd/lib/date-picker'; @@ -6,18 +6,26 @@ import { clientConfig } from '@/services/auth'; import { Moment } from '@/components/proptypes'; export function DateTimeInput({ + defaultValue, value, withSeconds, onSelect, className, + hideValue, + ...props }) { const format = (clientConfig.dateFormat || 'YYYY-MM-DD') + (withSeconds ? ' HH:mm:ss' : ' HH:mm'); const additionalAttributes = {}; + if (defaultValue && defaultValue.isValid()) { + additionalAttributes.defaultValue = defaultValue; + } if (value && value.isValid()) { - additionalAttributes.defaultValue = value; + additionalAttributes.value = value; + } + if (hideValue) { + additionalAttributes.value = null; } - const currentValueRef = useRef(additionalAttributes.defaultValue); return ( { currentValueRef.current = newValue; }} - onOpenChange={(status) => { - const currentValue = currentValueRef.current; - if (!status) { // on close picker - if (currentValue && currentValue.isValid()) { - onSelect(currentValue); - } - } - }} + onChange={onSelect} + {...props} /> ); } DateTimeInput.propTypes = { + defaultValue: Moment, value: Moment, withSeconds: PropTypes.bool, onSelect: PropTypes.func, className: PropTypes.string, + hideValue: PropTypes.bool, }; DateTimeInput.defaultProps = { + defaultValue: null, value: null, withSeconds: false, onSelect: () => {}, className: '', + hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index 93df6f2e24..d0073e2dd5 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -5,11 +5,9 @@ import Button from 'antd/lib/button'; import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; import InputNumber from 'antd/lib/input-number'; +import DateParameter from '@/components/dynamic-parameters/DateParameter'; import DateRangeParameter from '@/components/dynamic-parameters/DateRangeParameter'; import { defer, isFunction } from 'lodash'; -import { DateInput } from './DateInput'; -import { DateTimeInput } from './DateTimeInput'; -import { DateTimeRangeInput } from './DateTimeRangeInput'; import { QueryBasedParameterInput } from './QueryBasedParameterInput'; import './ParameterValueInput.less'; @@ -59,58 +57,14 @@ export class ParameterValueInput extends React.Component { ); } - renderDateTimeWithSecondsInput() { - const { value, onSelect } = this.props; - return ( - - ); - } - - renderDateTimeInput() { - const { value, onSelect } = this.props; - return ( - - ); - } - - renderDateInput() { - const { value, onSelect } = this.props; - return ( - - ); - } - - renderDateTimeRangeWithSecondsInput() { - const { value, onSelect } = this.props; - return ( - - ); - } - - renderDateTimeRangeInput() { - const { value, onSelect } = this.props; + renderDateParameter() { + const { type, value, parameter, onSelect } = this.props; return ( - ); @@ -222,9 +176,9 @@ export class ParameterValueInput extends React.Component { render() { const { type } = this.props; switch (type) { - case 'datetime-with-seconds': return this.renderDateTimeWithSecondsInput(); - case 'datetime-local': return this.renderDateTimeInput(); - case 'date': return this.renderDateInput(); + case 'datetime-with-seconds': return this.renderDateParameter(); + case 'datetime-local': return this.renderDateParameter(); + case 'date': return this.renderDateParameter(); case 'datetime-range-with-seconds': return this.renderDateRangeParameter(); case 'datetime-range': return this.renderDateRangeParameter(); case 'date-range': return this.renderDateRangeParameter(); diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx new file mode 100644 index 0000000000..fe987156f7 --- /dev/null +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -0,0 +1,97 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { includes } from 'lodash'; +import { DYNAMIC_DATES } from '@/services/query'; +import { DateInput } from '@/components/DateInput'; +import { DateTimeInput } from '@/components/DateTimeInput'; +import DynamicButton from '@/components/dynamic-parameters/DynamicButton'; + +import './DynamicParameters.less'; + +const DYNAMIC_DATE_OPTIONS = [ + { name: 'Static value', value: 'static' }, + { name: 'Today/Now', + value: 'd_now', + label: () => DYNAMIC_DATES.now.value().format('MMM D') }, + { name: 'Yesterday', + value: 'd_yesterday', + label: () => DYNAMIC_DATES.yesterday.value().format('MMM D') }, +]; + +export default class DateParameter extends React.Component { + static propTypes = { + type: PropTypes.string, + className: PropTypes.string, + value: PropTypes.any, // eslint-disable-line react/forbid-prop-types + parameter: PropTypes.any, // eslint-disable-line react/forbid-prop-types + onSelect: PropTypes.func, + }; + + static defaultProps = { + type: '', + className: '', + value: null, + parameter: null, + onSelect: () => {}, + }; + + constructor(props) { + super(props); + this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; + } + + onDynamicValueSelect = (dynamicValue) => { + const { onSelect, parameter } = this.props; + if (dynamicValue.value === 'static') { + this.setState({ dynamicValue: false }); + onSelect(parameter.getValue()); + } else { + this.setState({ dynamicValue: true }); + onSelect(dynamicValue.value); + } + }; + + onSelect = (value) => { + const { onSelect } = this.props; + this.setState({ dynamicValue: false }, () => onSelect(value)); + }; + + render() { + const { type, value, parameter, className } = this.props; + const { dynamicValue } = this.state; + const isDateTime = includes(type, 'datetime'); + + const additionalAttributes = {}; + + let DateComponent = DateInput; + if (isDateTime) { + DateComponent = DateTimeInput; + if (includes(type, 'with-seconds')) { + additionalAttributes.withSeconds = true; + } + } + + if (dynamicValue) { + additionalAttributes.placeholder = parameter.dynamicValue && parameter.dynamicValue.name; + additionalAttributes.hideValue = true; + } + + return ( + + )} + allowClear={false} + {...additionalAttributes} + /> + ); + } +} diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index d32ebeb848..3566cc4efe 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -82,12 +82,12 @@ export default class DateRangeParameter extends React.Component { render() { const { type, value, parameter, className } = this.props; const { dynamicValue } = this.state; - const isDateTime = includes(type, 'datetime-range'); + const isDateTimeRange = includes(type, 'datetime-range'); const additionalAttributes = {}; let DateRangeComponent = DateRangeInput; - if (isDateTime) { + if (isDateTimeRange) { DateRangeComponent = DateTimeRangeInput; if (includes(type, 'with-seconds')) { additionalAttributes.withSeconds = true; diff --git a/client/app/components/dynamic-parameters/DynamicButton.less b/client/app/components/dynamic-parameters/DynamicButton.less index 755c9c18a5..e1eaffacc6 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.less +++ b/client/app/components/dynamic-parameters/DynamicButton.less @@ -1,5 +1,3 @@ - - .dynamic-button { position: absolute !important; right: 1px; diff --git a/client/app/services/query.js b/client/app/services/query.js index f0b44ecf76..1a1e7b7294 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -4,7 +4,7 @@ import Mustache from 'mustache'; import { zipObject, isEmpty, map, filter, includes, union, uniq, has, isNull, isUndefined, isArray, isObject, identity, extend, each, - startsWith, + startsWith, invoke, } from 'lodash'; Mustache.escape = identity; // do not html-escape values @@ -52,6 +52,17 @@ export const DYNAMIC_DATE_RANGES = { }, }; +export const DYNAMIC_DATES = { + now: { + name: 'Today/Now', + value: () => moment(), + }, + yesterday: { + name: 'Yesterday', + value: () => moment().subtract(1, 'day'), + }, +}; + function isDynamicValue(value) { return startsWith(value, DYNAMIC_DATE_PREFIX); } @@ -118,11 +129,12 @@ export class Parameter { } get hasDynamicValue() { - return isDynamicValue(this.value); + return (isDateParameter(this.type) || isDateRangeParameter(this.type)) && isDynamicValue(this.value); } get dynamicValue() { - return this.hasDynamicValue ? DYNAMIC_DATE_RANGES[this.value.substring(DYNAMIC_DATE_PREFIX.length)] : null; + const DYNAMIC_VALUES = isDateParameter(this.type) ? DYNAMIC_DATES : DYNAMIC_DATE_RANGES; + return this.hasDynamicValue ? DYNAMIC_VALUES[this.value.substring(DYNAMIC_DATE_PREFIX.length)] : null; } getValue() { @@ -132,7 +144,7 @@ export class Parameter { static getValue(param) { const { value, type, useCurrentDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); - if (isDateRangeParameter(type) && startsWith(value, DYNAMIC_DATE_PREFIX)) { + if (isDateRangeParameter(type) && isDynamicValue(value)) { const dynamicValue = value.substring(DYNAMIC_DATE_PREFIX.length); if (DYNAMIC_DATE_RANGES[dynamicValue]) { const dateRange = DYNAMIC_DATE_RANGES[dynamicValue].value(); @@ -143,6 +155,15 @@ export class Parameter { } return null; } + + if (isDateParameter(type) && isDynamicValue(value)) { + const dynamicValue = value.substring(DYNAMIC_DATE_PREFIX.length); + if (DYNAMIC_DATES[dynamicValue]) { + return DYNAMIC_DATES[dynamicValue].value().format(DATETIME_FORMATS[type]); + } + return null; + } + if (isEmptyValue) { if ( includes(['date', 'datetime-local', 'datetime-with-seconds'], type) && @@ -177,7 +198,7 @@ export class Parameter { this.$$value = value; } } else if (isDynamicValue(value)) { - const dynamicValue = DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)].value(); + const dynamicValue = invoke(DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)], 'value'); if (dynamicValue) { this.value = value; this.$$value = [dynamicValue[0], dynamicValue[1]]; @@ -187,10 +208,18 @@ export class Parameter { this.value = null; this.$$value = null; - value = moment(value); - if (value.isValid()) { - this.value = value.format(DATETIME_FORMATS[this.type]); - this.$$value = value; + if (isDynamicValue(value)) { + const dynamicValue = invoke(DYNAMIC_DATES[value.substring(DYNAMIC_DATE_PREFIX.length)], 'value'); + if (dynamicValue) { + this.value = value; + this.$$value = dynamicValue; + } + } else { + value = moment(value); + if (value.isValid()) { + this.value = value.format(DATETIME_FORMATS[this.type]); + this.$$value = value; + } } } else if (this.type === 'number') { this.value = value; From 7df5aadbc6e852dda43bbf8a2e8c56a9b27872b0 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 30 Jun 2019 19:55:20 -0300 Subject: [PATCH 08/39] UI refinements --- client/app/assets/less/ant.less | 1 + .../dynamic-parameters/DateParameter.jsx | 4 ++-- .../dynamic-parameters/DateRangeParameter.jsx | 16 ++++------------ .../dynamic-parameters/DynamicButton.jsx | 18 +++++++++++++++--- .../dynamic-parameters/DynamicButton.less | 9 +++++++-- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/client/app/assets/less/ant.less b/client/app/assets/less/ant.less index 508a1e3660..36b6c437a1 100644 --- a/client/app/assets/less/ant.less +++ b/client/app/assets/less/ant.less @@ -35,6 +35,7 @@ @import "~antd/lib/notification/style/index"; @import "~antd/lib/collapse/style/index"; @import "~antd/lib/progress/style/index"; +@import "~antd/lib/typography/style/index"; @import 'inc/ant-variables'; // Increase z-indexes to avoid conflicts with some other libraries (e.g. Plotly) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index fe987156f7..ad565ddc59 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -10,7 +10,6 @@ import DynamicButton from '@/components/dynamic-parameters/DynamicButton'; import './DynamicParameters.less'; const DYNAMIC_DATE_OPTIONS = [ - { name: 'Static value', value: 'static' }, { name: 'Today/Now', value: 'd_now', label: () => DYNAMIC_DATES.now.value().format('MMM D') }, @@ -43,7 +42,7 @@ export default class DateParameter extends React.Component { onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; - if (dynamicValue.value === 'static') { + if (dynamicValue === 'static') { this.setState({ dynamicValue: false }); onSelect(parameter.getValue()); } else { @@ -85,6 +84,7 @@ export default class DateParameter extends React.Component { suffixIcon={( diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 3566cc4efe..87073eb79c 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -53,19 +53,9 @@ export default class DateRangeParameter extends React.Component { this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; } - dynamicOptions = () => { - const isDateTimeRange = includes(this.props.type, 'datetime-range'); - const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; - - return [ - { name: 'Static value', value: 'static' }, - ...options, - ]; - } - onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; - if (dynamicValue.value === 'static') { + if (dynamicValue === 'static') { this.setState({ dynamicValue: false }); onSelect(parameter.getValue()); } else { @@ -83,6 +73,7 @@ export default class DateRangeParameter extends React.Component { const { type, value, parameter, className } = this.props; const { dynamicValue } = this.state; const isDateTimeRange = includes(type, 'datetime-range'); + const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; const additionalAttributes = {}; @@ -106,7 +97,8 @@ export default class DateRangeParameter extends React.Component { onSelect={this.onSelect} suffixIcon={( diff --git a/client/app/components/dynamic-parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx index a62813bf2d..e1325faf57 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.jsx +++ b/client/app/components/dynamic-parameters/DynamicButton.jsx @@ -1,17 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { isFunction, get } from 'lodash'; +import { isFunction, get, findIndex } from 'lodash'; import Dropdown from 'antd/lib/dropdown'; import Icon from 'antd/lib/icon'; import Menu from 'antd/lib/menu'; +import Typography from 'antd/lib/typography'; import './DynamicButton.less'; -export default function DynamicButton({ options, onSelect, enabled }) { +const { Text } = Typography; + +export default function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { const menu = ( onSelect(get(options, key))} + onClick={({ key }) => onSelect(get(options, key, 'static'))} + selectedKeys={[`${findIndex(options, { value: selectedDynamicValue })}`]} > {options.map((option, index) => ( // eslint-disable-next-line react/no-array-index-key @@ -21,6 +25,12 @@ export default function DynamicButton({ options, onSelect, enabled }) { )} ))} + {enabled && } + {enabled && ( + + Back to Static Value + + )} ); @@ -45,12 +55,14 @@ export default function DynamicButton({ options, onSelect, enabled }) { DynamicButton.propTypes = { options: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types + selectedDynamicValue: PropTypes.string, onSelect: PropTypes.func, enabled: PropTypes.bool, }; DynamicButton.defaultProps = { options: [], + selectedDynamicValue: null, onSelect: () => {}, enabled: false, }; diff --git a/client/app/components/dynamic-parameters/DynamicButton.less b/client/app/components/dynamic-parameters/DynamicButton.less index e1eaffacc6..4bff173af4 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.less +++ b/client/app/components/dynamic-parameters/DynamicButton.less @@ -1,8 +1,13 @@ .dynamic-button { + height: 100%; position: absolute !important; right: 1px; top: 0; + .ant-dropdown-trigger { + height: 100%; + } + button { border: none; padding: 0; @@ -10,11 +15,11 @@ background-color: transparent !important; } - &::after { + &:after { content: ""; position: absolute; width: 1px; - height: 17px; + height: 19px; left: 0; top: 8px; border-left: 1px dotted rgba(0, 0, 0, 0.12); From ad8d03f6cdcba392c7f1e420b1fbe4f57ee8960e Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 1 Jul 2019 09:51:07 -0300 Subject: [PATCH 09/39] Add getDynamicValue function --- client/app/services/query.js | 39 ++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/client/app/services/query.js b/client/app/services/query.js index 1a1e7b7294..516b065a8d 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -4,7 +4,7 @@ import Mustache from 'mustache'; import { zipObject, isEmpty, map, filter, includes, union, uniq, has, isNull, isUndefined, isArray, isObject, identity, extend, each, - startsWith, invoke, + startsWith, } from 'lodash'; Mustache.escape = identity; // do not html-escape values @@ -94,6 +94,16 @@ function isDateRangeParameter(paramType) { return includes(['date-range', 'datetime-range', 'datetime-range-with-seconds'], paramType); } +function getDynamicValue(value, paramType) { + if (isDateParameter(paramType) && isDynamicValue(value)) { + return DYNAMIC_DATES[value.substring(DYNAMIC_DATE_PREFIX.length)]; + } + if (isDateRangeParameter(paramType) && isDynamicValue(value)) { + return DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)]; + } + return null; +} + export class Parameter { constructor(parameter, parentQueryId) { this.title = parameter.title; @@ -133,8 +143,7 @@ export class Parameter { } get dynamicValue() { - const DYNAMIC_VALUES = isDateParameter(this.type) ? DYNAMIC_DATES : DYNAMIC_DATE_RANGES; - return this.hasDynamicValue ? DYNAMIC_VALUES[this.value.substring(DYNAMIC_DATE_PREFIX.length)] : null; + return getDynamicValue(this.value, this.type); } getValue() { @@ -144,10 +153,10 @@ export class Parameter { static getValue(param) { const { value, type, useCurrentDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); - if (isDateRangeParameter(type) && isDynamicValue(value)) { - const dynamicValue = value.substring(DYNAMIC_DATE_PREFIX.length); - if (DYNAMIC_DATE_RANGES[dynamicValue]) { - const dateRange = DYNAMIC_DATE_RANGES[dynamicValue].value(); + if (isDateRangeParameter(type) && param.hasDynamicValue) { + const dynamicValue = param.dynamicValue; + if (dynamicValue) { + const dateRange = dynamicValue.value(); return { start: dateRange[0].format(DATETIME_FORMATS[type]), end: dateRange[1].format(DATETIME_FORMATS[type]), @@ -156,10 +165,10 @@ export class Parameter { return null; } - if (isDateParameter(type) && isDynamicValue(value)) { - const dynamicValue = value.substring(DYNAMIC_DATE_PREFIX.length); - if (DYNAMIC_DATES[dynamicValue]) { - return DYNAMIC_DATES[dynamicValue].value().format(DATETIME_FORMATS[type]); + if (isDateParameter(type) && param.hasDynamicValue) { + const dynamicValue = param.dynamicValue; + if (dynamicValue) { + return dynamicValue.value().format(DATETIME_FORMATS[type]); } return null; } @@ -198,10 +207,10 @@ export class Parameter { this.$$value = value; } } else if (isDynamicValue(value)) { - const dynamicValue = invoke(DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)], 'value'); + const dynamicValue = getDynamicValue(value, this.type); if (dynamicValue) { this.value = value; - this.$$value = [dynamicValue[0], dynamicValue[1]]; + this.$$value = [dynamicValue.value()[0], dynamicValue.value()[1]]; } } } else if (isDateParameter(this.type)) { @@ -209,10 +218,10 @@ export class Parameter { this.$$value = null; if (isDynamicValue(value)) { - const dynamicValue = invoke(DYNAMIC_DATES[value.substring(DYNAMIC_DATE_PREFIX.length)], 'value'); + const dynamicValue = getDynamicValue(value, this.type); if (dynamicValue) { this.value = value; - this.$$value = dynamicValue; + this.$$value = dynamicValue.value(); } } else { value = moment(value); From 8044d18b7c1da2f323174694da2106e2afdf0e53 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 1 Jul 2019 10:26:45 -0300 Subject: [PATCH 10/39] Add 'This' options and prevent text clipping --- .../dynamic-parameters/DateRangeParameter.jsx | 6 ++++++ .../dynamic-parameters/DynamicParameters.less | 5 +++++ client/app/services/query.js | 12 ++++++++++++ 3 files changed, 23 insertions(+) diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 87073eb79c..474c0396c4 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -10,6 +10,12 @@ import DynamicButton from '@/components/dynamic-parameters/DynamicButton'; import './DynamicParameters.less'; const DYNAMIC_DATE_OPTIONS = [ + { name: 'This week', + value: 'd_this_week', + label: () => DYNAMIC_DATE_RANGES.this_week.value()[0].format('MMM D') + ' - ' + + DYNAMIC_DATE_RANGES.this_week.value()[1].format('MMM D') }, + { name: 'This month', value: 'd_this_month', label: () => DYNAMIC_DATE_RANGES.this_month.value()[0].format('MMMM') }, + { name: 'This year', value: 'd_this_year', label: () => DYNAMIC_DATE_RANGES.this_year.value()[0].format('YYYY') }, { name: 'Last week', value: 'd_last_week', label: () => DYNAMIC_DATE_RANGES.last_week.value()[0].format('MMM D') + ' - ' + diff --git a/client/app/components/dynamic-parameters/DynamicParameters.less b/client/app/components/dynamic-parameters/DynamicParameters.less index 0dca09c237..2f0ddc8707 100644 --- a/client/app/components/dynamic-parameters/DynamicParameters.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -3,6 +3,11 @@ color: #1890ff !important } + .ant-calendar-range-picker-input { + width: 100%; + text-align: left; + } + .ant-calendar-range-picker-separator, .ant-calendar-range-picker-input:not(:first-child) { display: none; diff --git a/client/app/services/query.js b/client/app/services/query.js index 516b065a8d..52e6ea43cb 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -34,6 +34,18 @@ export const DYNAMIC_DATE_RANGES = { name: 'Yesterday', value: () => [moment().subtract(1, 'day').startOf('day'), moment().subtract(1, 'day').endOf('day')], }, + this_week: { + name: 'This week', + value: () => [moment().startOf('week'), moment().endOf('week')], + }, + this_month: { + name: 'This month', + value: () => [moment().startOf('month'), moment().endOf('month')], + }, + this_year: { + name: 'This year', + value: () => [moment().startOf('year'), moment().endOf('year')], + }, last_week: { name: 'Last week', value: () => [moment().subtract(1, 'week').startOf('week'), moment().subtract(1, 'week').endOf('week')], From f3c013e20548ba52e0111a0f8aea685293ff2273 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 1 Jul 2019 11:30:47 -0300 Subject: [PATCH 11/39] Make allowClear available --- client/app/components/DateInput.jsx | 10 ++-------- client/app/components/DateRangeInput.jsx | 10 ++-------- client/app/components/DateTimeInput.jsx | 10 ++-------- client/app/components/DateTimeRangeInput.jsx | 10 ++-------- .../components/dynamic-parameters/DateParameter.jsx | 4 +--- .../dynamic-parameters/DateRangeParameter.jsx | 4 +--- 6 files changed, 10 insertions(+), 38 deletions(-) diff --git a/client/app/components/DateInput.jsx b/client/app/components/DateInput.jsx index 05b9978b56..5e47a64394 100644 --- a/client/app/components/DateInput.jsx +++ b/client/app/components/DateInput.jsx @@ -10,7 +10,6 @@ export function DateInput({ value, onSelect, className, - hideValue, ...props }) { const format = clientConfig.dateFormat || 'YYYY-MM-DD'; @@ -18,12 +17,9 @@ export function DateInput({ if (defaultValue && defaultValue.isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value && value.isValid()) { + if (value !== undefined) { additionalAttributes.value = value; } - if (hideValue) { - additionalAttributes.value = null; - } return ( {}, className: '', - hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/DateRangeInput.jsx b/client/app/components/DateRangeInput.jsx index db91a0b87a..1cd6c76eea 100644 --- a/client/app/components/DateRangeInput.jsx +++ b/client/app/components/DateRangeInput.jsx @@ -13,7 +13,6 @@ export function DateRangeInput({ value, onSelect, className, - hideValue, ...props }) { const format = clientConfig.dateFormat || 'YYYY-MM-DD'; @@ -21,12 +20,9 @@ export function DateRangeInput({ if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (isArray(value) && value[0].isValid() && value[1].isValid()) { + if (value !== undefined) { additionalAttributes.value = value; } - if (hideValue) { - additionalAttributes.value = null; - } return ( {}, className: '', - hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/DateTimeInput.jsx b/client/app/components/DateTimeInput.jsx index 4ea8c2d5ae..f8b119bfc2 100644 --- a/client/app/components/DateTimeInput.jsx +++ b/client/app/components/DateTimeInput.jsx @@ -11,7 +11,6 @@ export function DateTimeInput({ withSeconds, onSelect, className, - hideValue, ...props }) { const format = (clientConfig.dateFormat || 'YYYY-MM-DD') + @@ -20,12 +19,9 @@ export function DateTimeInput({ if (defaultValue && defaultValue.isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value && value.isValid()) { + if (value !== undefined) { additionalAttributes.value = value; } - if (hideValue) { - additionalAttributes.value = null; - } return ( {}, className: '', - hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/DateTimeRangeInput.jsx b/client/app/components/DateTimeRangeInput.jsx index 023d1e6b8d..38f26aa490 100644 --- a/client/app/components/DateTimeRangeInput.jsx +++ b/client/app/components/DateTimeRangeInput.jsx @@ -14,7 +14,6 @@ export function DateTimeRangeInput({ withSeconds, onSelect, className, - hideValue, ...props }) { const format = (clientConfig.dateFormat || 'YYYY-MM-DD') + @@ -23,12 +22,9 @@ export function DateTimeRangeInput({ if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (isArray(value) && value[0].isValid() && value[1].isValid()) { + if (value !== undefined) { additionalAttributes.value = value; } - if (hideValue) { - additionalAttributes.value = null; - } return ( {}, className: '', - hideValue: false, }; export default function init(ngModule) { diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index ad565ddc59..49839a3fe3 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -73,13 +73,12 @@ export default class DateParameter extends React.Component { if (dynamicValue) { additionalAttributes.placeholder = parameter.dynamicValue && parameter.dynamicValue.name; - additionalAttributes.hideValue = true; } return ( )} - allowClear={false} {...additionalAttributes} /> ); diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 474c0396c4..559ed66429 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -93,13 +93,12 @@ export default class DateRangeParameter extends React.Component { if (dynamicValue) { additionalAttributes.placeholder = [parameter.dynamicValue && parameter.dynamicValue.name]; - additionalAttributes.hideValue = true; } return ( )} - allowClear={false} {...additionalAttributes} /> ); From e5981c4e639a946a3bf521d5a3bd5b91661d3c84 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 1 Jul 2019 11:31:02 -0300 Subject: [PATCH 12/39] Update ScheduleDialog snapshot --- .../__snapshots__/ScheduleDialog.test.js.snap | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/client/app/components/queries/__snapshots__/ScheduleDialog.test.js.snap b/client/app/components/queries/__snapshots__/ScheduleDialog.test.js.snap index ffdf31b3af..2108b9fccb 100644 --- a/client/app/components/queries/__snapshots__/ScheduleDialog.test.js.snap +++ b/client/app/components/queries/__snapshots__/ScheduleDialog.test.js.snap @@ -74,7 +74,6 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "1 Day 22:15" Set "click", ] } - showArrow={true} showSearch={false} tabIndex={0} tags={false} @@ -312,6 +311,7 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "1 Day 22:15" Set className="" data-icon="down" fill="currentColor" + focusable="false" height="1em" key="svg-down" viewBox="64 64 896 896" @@ -533,7 +533,6 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "1 Day 22:15" Set popup={ Date: Tue, 2 Jul 2019 17:29:33 -0300 Subject: [PATCH 13/39] Add some protections and separate Date/DateRange --- .../dynamic-parameters/DateParameter.jsx | 27 +++--- .../dynamic-parameters/DateRangeParameter.jsx | 33 ++++--- .../dynamic-parameters/DynamicParameters.less | 18 ++-- client/app/services/query.js | 86 ++++++++++++------- 4 files changed, 101 insertions(+), 63 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index 49839a3fe3..391642eb5d 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import moment from 'moment'; import { includes } from 'lodash'; import { DYNAMIC_DATES } from '@/services/query'; import { DateInput } from '@/components/DateInput'; @@ -37,28 +38,28 @@ export default class DateParameter extends React.Component { constructor(props) { super(props); - this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; + this.state = { hasDynamicValue: !!(props.parameter && props.parameter.hasDynamicDate) }; } onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - this.setState({ dynamicValue: false }); + this.setState({ hasDynamicValue: false }); onSelect(parameter.getValue()); } else { - this.setState({ dynamicValue: true }); + this.setState({ hasDynamicValue: true }); onSelect(dynamicValue.value); } }; onSelect = (value) => { const { onSelect } = this.props; - this.setState({ dynamicValue: false }, () => onSelect(value)); + this.setState({ hasDynamicValue: false }, () => onSelect(value)); }; render() { const { type, value, parameter, className } = this.props; - const { dynamicValue } = this.state; + const { hasDynamicValue } = this.state; const isDateTime = includes(type, 'datetime'); const additionalAttributes = {}; @@ -71,20 +72,24 @@ export default class DateParameter extends React.Component { } } - if (dynamicValue) { - additionalAttributes.placeholder = parameter.dynamicValue && parameter.dynamicValue.name; + if (moment.isMoment(value)) { + additionalAttributes.value = value; + } + + if (hasDynamicValue) { + additionalAttributes.placeholder = parameter.dynamicDate && parameter.dynamicDate.name; + additionalAttributes.value = null; } return ( )} diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 559ed66429..e6debbd9d7 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { includes } from 'lodash'; +import moment from 'moment'; +import { includes, isArray, isString } from 'lodash'; import { DYNAMIC_DATE_RANGES } from '@/services/query'; import { DateRangeInput } from '@/components/DateRangeInput'; import { DateTimeRangeInput } from '@/components/DateTimeRangeInput'; @@ -37,6 +38,10 @@ const DYNAMIC_DATETIME_OPTIONS = [ ...DYNAMIC_DATE_OPTIONS, ]; +function isValidDateRangeValue(value) { + return isArray(value) && value.length === 2 && moment.isMoment(value[0]) && moment.isMoment(value[1]); +} + export default class DateRangeParameter extends React.Component { static propTypes = { type: PropTypes.string, @@ -56,28 +61,28 @@ export default class DateRangeParameter extends React.Component { constructor(props) { super(props); - this.state = { dynamicValue: !!(props.parameter && props.parameter.hasDynamicValue) }; + this.state = { hasDynamicValue: !!(props.parameter && props.parameter.hasDynamicDateRange) }; } onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - this.setState({ dynamicValue: false }); + this.setState({ hasDynamicValue: false }); onSelect(parameter.getValue()); } else { - this.setState({ dynamicValue: true }); + this.setState({ hasDynamicValue: true }); onSelect(dynamicValue.value); } }; onSelect = (value) => { const { onSelect } = this.props; - this.setState({ dynamicValue: false }, () => onSelect(value)); + this.setState({ hasDynamicValue: false }, () => onSelect(value)); }; render() { const { type, value, parameter, className } = this.props; - const { dynamicValue } = this.state; + const { hasDynamicValue } = this.state; const isDateTimeRange = includes(type, 'datetime-range'); const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; @@ -91,20 +96,24 @@ export default class DateRangeParameter extends React.Component { } } - if (dynamicValue) { - additionalAttributes.placeholder = [parameter.dynamicValue && parameter.dynamicValue.name]; + if (isValidDateRangeValue(value)) { + additionalAttributes.value = value; + } + + if (hasDynamicValue) { + additionalAttributes.placeholder = [parameter.dynamicDateRange && parameter.dynamicDateRange.name]; + additionalAttributes.value = null; } return ( )} diff --git a/client/app/components/dynamic-parameters/DynamicParameters.less b/client/app/components/dynamic-parameters/DynamicParameters.less index 2f0ddc8707..abb4d15c65 100644 --- a/client/app/components/dynamic-parameters/DynamicParameters.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -3,14 +3,16 @@ color: #1890ff !important } - .ant-calendar-range-picker-input { - width: 100%; - text-align: left; - } - - .ant-calendar-range-picker-separator, - .ant-calendar-range-picker-input:not(:first-child) { - display: none; + &.hide-end-value { + .ant-calendar-range-picker-input { + width: 100%; + text-align: left; + } + + .ant-calendar-range-picker-separator, + .ant-calendar-range-picker-input:not(:first-child) { + display: none; + } } } diff --git a/client/app/services/query.js b/client/app/services/query.js index 52e6ea43cb..d5d0d7e179 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -23,7 +23,7 @@ const DATETIME_FORMATS = { 'datetime-range-with-seconds': 'YYYY-MM-DD HH:mm:ss', }; -const DYNAMIC_DATE_PREFIX = 'd_'; +const DYNAMIC_PREFIX = 'd_'; export const DYNAMIC_DATE_RANGES = { today: { @@ -75,10 +75,6 @@ export const DYNAMIC_DATES = { }, }; -function isDynamicValue(value) { - return startsWith(value, DYNAMIC_DATE_PREFIX); -} - function normalizeNumericValue(value, defaultValue = null) { const result = parseFloat(value); return isFinite(result) ? result : defaultValue; @@ -106,14 +102,32 @@ function isDateRangeParameter(paramType) { return includes(['date-range', 'datetime-range', 'datetime-range-with-seconds'], paramType); } -function getDynamicValue(value, paramType) { - if (isDateParameter(paramType) && isDynamicValue(value)) { - return DYNAMIC_DATES[value.substring(DYNAMIC_DATE_PREFIX.length)]; +function isDynamicDate(value) { + if (!startsWith(value, DYNAMIC_PREFIX)) { + return false; + } + return !!DYNAMIC_DATES[value.substring(DYNAMIC_PREFIX.length)]; +} + +function isDynamicDateRange(value) { + if (!startsWith(value, DYNAMIC_PREFIX)) { + return false; } - if (isDateRangeParameter(paramType) && isDynamicValue(value)) { - return DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_DATE_PREFIX.length)]; + return !!DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)]; +} + +function getDynamicDate(value) { + if (!isDynamicDate(value)) { + return null; } - return null; + return DYNAMIC_DATES[value.substring(DYNAMIC_PREFIX.length)]; +} + +function getDynamicDateRange(value) { + if (!isDynamicDateRange(value)) { + return null; + } + return DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)]; } export class Parameter { @@ -150,12 +164,20 @@ export class Parameter { return isNull(this.getValue()); } - get hasDynamicValue() { - return (isDateParameter(this.type) || isDateRangeParameter(this.type)) && isDynamicValue(this.value); + get hasDynamicDate() { + return isDateParameter(this.type) && isDynamicDate(this.value); + } + + get dynamicDate() { + return getDynamicDate(this.value); } - get dynamicValue() { - return getDynamicValue(this.value, this.type); + get hasDynamicDateRange() { + return isDateRangeParameter(this.type) && isDynamicDateRange(this.value); + } + + get dynamicDateRange() { + return getDynamicDateRange(this.value); } getValue() { @@ -165,10 +187,10 @@ export class Parameter { static getValue(param) { const { value, type, useCurrentDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); - if (isDateRangeParameter(type) && param.hasDynamicValue) { - const dynamicValue = param.dynamicValue; - if (dynamicValue) { - const dateRange = dynamicValue.value(); + if (param.hasDynamicDateRange) { + const { dynamicDateRange } = param; + if (dynamicDateRange) { + const dateRange = dynamicDateRange.value(); return { start: dateRange[0].format(DATETIME_FORMATS[type]), end: dateRange[1].format(DATETIME_FORMATS[type]), @@ -177,10 +199,10 @@ export class Parameter { return null; } - if (isDateParameter(type) && param.hasDynamicValue) { - const dynamicValue = param.dynamicValue; - if (dynamicValue) { - return dynamicValue.value().format(DATETIME_FORMATS[type]); + if (param.hasDynamicDate) { + const dynamicDate = param.dynamicDate; + if (dynamicDate) { + return dynamicDate.value().format(DATETIME_FORMATS[type]); } return null; } @@ -218,22 +240,22 @@ export class Parameter { }; this.$$value = value; } - } else if (isDynamicValue(value)) { - const dynamicValue = getDynamicValue(value, this.type); - if (dynamicValue) { + } else if (isDynamicDateRange(value)) { + const dynamicDateRange = getDynamicDateRange(value, this.type); + if (dynamicDateRange) { this.value = value; - this.$$value = [dynamicValue.value()[0], dynamicValue.value()[1]]; + this.$$value = [dynamicDateRange.value()[0], dynamicDateRange.value()[1]]; } } } else if (isDateParameter(this.type)) { this.value = null; this.$$value = null; - if (isDynamicValue(value)) { - const dynamicValue = getDynamicValue(value, this.type); - if (dynamicValue) { + if (isDynamicDate(value)) { + const dynamicDate = getDynamicDate(value); + if (dynamicDate) { this.value = value; - this.$$value = dynamicValue.value(); + this.$$value = dynamicDate.value(); } } else { value = moment(value); @@ -297,7 +319,7 @@ export class Parameter { const key = `${prefix}${this.name}`; const keyStart = `${prefix}${this.name}.start`; const keyEnd = `${prefix}${this.name}.end`; - if (has(query, key) && isDynamicValue(query[key])) { + if (has(query, key)) { this.setValue(query[key]); } else if (has(query, keyStart) && has(query, keyEnd)) { this.setValue([query[keyStart], query[keyEnd]]); From b75598985b527a34f4d88f80397d20524b0adcb7 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 2 Jul 2019 20:41:05 -0300 Subject: [PATCH 14/39] Accept null values on date or daterange parameters --- client/app/components/dynamic-parameters/DateParameter.jsx | 2 +- client/app/components/dynamic-parameters/DateRangeParameter.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index 391642eb5d..60c0c80b24 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -72,7 +72,7 @@ export default class DateParameter extends React.Component { } } - if (moment.isMoment(value)) { + if (moment.isMoment(value) || value === null) { additionalAttributes.value = value; } diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index e6debbd9d7..4eace9007f 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -96,7 +96,7 @@ export default class DateRangeParameter extends React.Component { } } - if (isValidDateRangeValue(value)) { + if (isValidDateRangeValue(value) || value === null) { additionalAttributes.value = value; } From ca7f481100048850f50ca9a209e1bf68bda4ebd6 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 8 Jul 2019 11:06:24 -0300 Subject: [PATCH 15/39] Handle undefined values on Moment propType --- client/app/components/proptypes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/app/components/proptypes.js b/client/app/components/proptypes.js index 05b585904d..70c96e7a14 100644 --- a/client/app/components/proptypes.js +++ b/client/app/components/proptypes.js @@ -86,8 +86,8 @@ export const UserProfile = PropTypes.shape({ function checkMoment(isRequired, props, propName, componentName) { const value = props[propName]; - const isRequiredValid = isRequired && (value !== null); - const isOptionalValid = !isRequired && ((value === null) || moment.isMoment(value)); + const isRequiredValid = isRequired && (value !== null && value !== undefined) && moment.isMoment(value); + const isOptionalValid = !isRequired && ((value === null || value === undefined) || moment.isMoment(value)); if (!isRequiredValid && !isOptionalValid) { return new Error('Prop `' + propName + '` supplied to `' + componentName + '` should be a Moment.js instance.'); } From 5933a4ef6b596c8a3f7b4b6468de7d937c652f83 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 11 Jul 2019 12:27:58 -0300 Subject: [PATCH 16/39] Move export to end of files --- client/app/components/dynamic-parameters/DateParameter.jsx | 4 +++- .../app/components/dynamic-parameters/DateRangeParameter.jsx | 4 +++- client/app/components/dynamic-parameters/DynamicButton.jsx | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index 60c0c80b24..d9d295fa7c 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -19,7 +19,7 @@ const DYNAMIC_DATE_OPTIONS = [ label: () => DYNAMIC_DATES.yesterday.value().format('MMM D') }, ]; -export default class DateParameter extends React.Component { +class DateParameter extends React.Component { static propTypes = { type: PropTypes.string, className: PropTypes.string, @@ -98,3 +98,5 @@ export default class DateParameter extends React.Component { ); } } + +export default DateParameter; diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 4eace9007f..6cf90761aa 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -42,7 +42,7 @@ function isValidDateRangeValue(value) { return isArray(value) && value.length === 2 && moment.isMoment(value[0]) && moment.isMoment(value[1]); } -export default class DateRangeParameter extends React.Component { +class DateRangeParameter extends React.Component { static propTypes = { type: PropTypes.string, className: PropTypes.string, @@ -122,3 +122,5 @@ export default class DateRangeParameter extends React.Component { ); } } + +export default DateRangeParameter; diff --git a/client/app/components/dynamic-parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx index e1325faf57..d82fbaa19a 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.jsx +++ b/client/app/components/dynamic-parameters/DynamicButton.jsx @@ -10,7 +10,7 @@ import './DynamicButton.less'; const { Text } = Typography; -export default function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { +function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { const menu = ( {}, enabled: false, }; + +export default DynamicButton; From 89a3e7f543c7eb5aa39ae7c1339d942e2ce333b7 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 16 Jul 2019 14:34:13 -0300 Subject: [PATCH 17/39] Remove Today/Now option --- .../components/EditParameterSettingsDialog.jsx | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/client/app/components/EditParameterSettingsDialog.jsx b/client/app/components/EditParameterSettingsDialog.jsx index 1805f9ed6c..af3c742aaf 100644 --- a/client/app/components/EditParameterSettingsDialog.jsx +++ b/client/app/components/EditParameterSettingsDialog.jsx @@ -1,10 +1,9 @@ -import { includes, startsWith, words, capitalize, clone, isNull } from 'lodash'; +import { includes, words, capitalize, clone, isNull } from 'lodash'; import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import Modal from 'antd/lib/modal'; import Form from 'antd/lib/form'; -import Checkbox from 'antd/lib/checkbox'; import Button from 'antd/lib/button'; import Select from 'antd/lib/select'; import Input from 'antd/lib/input'; @@ -20,10 +19,6 @@ function getDefaultTitle(text) { return capitalize(words(text).join(' ')); // humanize } -function isTypeDate(type) { - return startsWith(type, 'date') && !isTypeDateRange(type); -} - function isTypeDateRange(type) { return /-range/.test(type); } @@ -172,17 +167,6 @@ function EditParameterSettingsDialog(props) { - {isTypeDate(param.type) && ( - - setParam({ ...param, useCurrentDateTime: e.target.checked })} - data-test="UseCurrentDateTimeCheckbox" - > - Default to Today/Now if no other value is set - - - )} {param.type === 'enum' && ( Date: Wed, 17 Jul 2019 14:43:24 -0300 Subject: [PATCH 18/39] Update with Apply Changes --- client/app/components/ParameterValueInput.jsx | 6 ++- .../dynamic-parameters/DateParameter.jsx | 27 ++++------- .../dynamic-parameters/DateRangeParameter.jsx | 45 +++++++------------ client/app/services/query.js | 16 +++---- 4 files changed, 37 insertions(+), 57 deletions(-) diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index bb5da98a8d..a3e772f925 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -57,7 +57,8 @@ export class ParameterValueInput extends React.Component { } renderDateParameter() { - const { type, value, parameter } = this.props; + const { type, parameter } = this.props; + const { value } = this.state; return ( DYNAMIC_DATES.now.value().format('MMM D') }, + label: () => getDynamicDate('d_now').value().format('MMM D') }, { name: 'Yesterday', value: 'd_yesterday', - label: () => DYNAMIC_DATES.yesterday.value().format('MMM D') }, + label: () => getDynamicDate('d_yesterday').value().format('MMM D') }, ]; class DateParameter extends React.Component { @@ -36,30 +36,18 @@ class DateParameter extends React.Component { onSelect: () => {}, }; - constructor(props) { - super(props); - this.state = { hasDynamicValue: !!(props.parameter && props.parameter.hasDynamicDate) }; - } - onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - this.setState({ hasDynamicValue: false }); onSelect(parameter.getValue()); } else { - this.setState({ hasDynamicValue: true }); onSelect(dynamicValue.value); } }; - onSelect = (value) => { - const { onSelect } = this.props; - this.setState({ hasDynamicValue: false }, () => onSelect(value)); - }; - render() { - const { type, value, parameter, className } = this.props; - const { hasDynamicValue } = this.state; + const { type, value, parameter, className, onSelect } = this.props; + const hasDynamicValue = isDynamicDate(value); const isDateTime = includes(type, 'datetime'); const additionalAttributes = {}; @@ -77,14 +65,15 @@ class DateParameter extends React.Component { } if (hasDynamicValue) { - additionalAttributes.placeholder = parameter.dynamicDate && parameter.dynamicDate.name; + const dynamicDate = getDynamicDate(value); + additionalAttributes.placeholder = dynamicDate && dynamicDate.name; additionalAttributes.value = null; } return ( DYNAMIC_DATE_RANGES.this_week.value()[0].format('MMM D') + ' - ' + - DYNAMIC_DATE_RANGES.this_week.value()[1].format('MMM D') }, - { name: 'This month', value: 'd_this_month', label: () => DYNAMIC_DATE_RANGES.this_month.value()[0].format('MMMM') }, - { name: 'This year', value: 'd_this_year', label: () => DYNAMIC_DATE_RANGES.this_year.value()[0].format('YYYY') }, + label: () => getDynamicDateRange('d_this_week').value()[0].format('MMM D') + ' - ' + + getDynamicDateRange('d_this_week').value()[1].format('MMM D') }, + { name: 'This month', value: 'd_this_month', label: () => getDynamicDateRange('d_this_month').value()[0].format('MMMM') }, + { name: 'This year', value: 'd_this_year', label: () => getDynamicDateRange('d_this_year').value()[0].format('YYYY') }, { name: 'Last week', value: 'd_last_week', - label: () => DYNAMIC_DATE_RANGES.last_week.value()[0].format('MMM D') + ' - ' + - DYNAMIC_DATE_RANGES.last_week.value()[1].format('MMM D') }, - { name: 'Last month', value: 'd_last_month', label: () => DYNAMIC_DATE_RANGES.last_month.value()[0].format('MMMM') }, - { name: 'Last year', value: 'd_last_year', label: () => DYNAMIC_DATE_RANGES.last_year.value()[0].format('YYYY') }, + label: () => getDynamicDateRange('d_last_week').value()[0].format('MMM D') + ' - ' + + getDynamicDateRange('d_last_week').value()[1].format('MMM D') }, + { name: 'Last month', value: 'd_last_month', label: () => getDynamicDateRange('d_last_month').value()[0].format('MMMM') }, + { name: 'Last year', value: 'd_last_year', label: () => getDynamicDateRange('d_last_year').value()[0].format('YYYY') }, { name: 'Last 7 days', value: 'd_last_7_days', - label: () => DYNAMIC_DATE_RANGES.last_7_days.value()[0].format('MMM D') + ' - Today' }, + label: () => getDynamicDateRange('d_last_7_days').value()[0].format('MMM D') + ' - Today' }, ]; const DYNAMIC_DATETIME_OPTIONS = [ { name: 'Today', value: 'd_today', - label: () => DYNAMIC_DATE_RANGES.today.value()[0].format('MMM D') }, + label: () => getDynamicDateRange('d_today').value()[0].format('MMM D') }, { name: 'Yesterday', value: 'd_yesterday', - label: () => DYNAMIC_DATE_RANGES.yesterday.value()[0].format('MMM D') }, + label: () => getDynamicDateRange('d_yesterday').value()[0].format('MMM D') }, ...DYNAMIC_DATE_OPTIONS, ]; @@ -59,31 +59,19 @@ class DateRangeParameter extends React.Component { onSelect: () => {}, }; - constructor(props) { - super(props); - this.state = { hasDynamicValue: !!(props.parameter && props.parameter.hasDynamicDateRange) }; - } - onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - this.setState({ hasDynamicValue: false }); onSelect(parameter.getValue()); } else { - this.setState({ hasDynamicValue: true }); onSelect(dynamicValue.value); } }; - onSelect = (value) => { - const { onSelect } = this.props; - this.setState({ hasDynamicValue: false }, () => onSelect(value)); - }; - render() { - const { type, value, parameter, className } = this.props; - const { hasDynamicValue } = this.state; + const { type, value, parameter, onSelect, className } = this.props; const isDateTimeRange = includes(type, 'datetime-range'); + const hasDynamicValue = isDynamicDateRange(value); const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; const additionalAttributes = {}; @@ -101,14 +89,15 @@ class DateRangeParameter extends React.Component { } if (hasDynamicValue) { - additionalAttributes.placeholder = [parameter.dynamicDateRange && parameter.dynamicDateRange.name]; + const dynamicDateRange = getDynamicDateRange(value); + additionalAttributes.placeholder = [dynamicDateRange && dynamicDateRange.name]; additionalAttributes.value = null; } return ( [moment().startOf('day'), moment().endOf('day')], @@ -64,7 +64,7 @@ export const DYNAMIC_DATE_RANGES = { }, }; -export const DYNAMIC_DATES = { +const DYNAMIC_DATES = { now: { name: 'Today/Now', value: () => moment(), @@ -102,28 +102,28 @@ function isDateRangeParameter(paramType) { return includes(['date-range', 'datetime-range', 'datetime-range-with-seconds'], paramType); } -function isDynamicDate(value) { +export function isDynamicDate(value) { if (!startsWith(value, DYNAMIC_PREFIX)) { return false; } return !!DYNAMIC_DATES[value.substring(DYNAMIC_PREFIX.length)]; } -function isDynamicDateRange(value) { +export function isDynamicDateRange(value) { if (!startsWith(value, DYNAMIC_PREFIX)) { return false; } return !!DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)]; } -function getDynamicDate(value) { +export function getDynamicDate(value) { if (!isDynamicDate(value)) { return null; } return DYNAMIC_DATES[value.substring(DYNAMIC_PREFIX.length)]; } -function getDynamicDateRange(value) { +export function getDynamicDateRange(value) { if (!isDynamicDateRange(value)) { return null; } @@ -244,7 +244,7 @@ export class Parameter { const dynamicDateRange = getDynamicDateRange(value, this.type); if (dynamicDateRange) { this.value = value; - this.$$value = [dynamicDateRange.value()[0], dynamicDateRange.value()[1]]; + this.$$value = value; } } } else if (isDateParameter(this.type)) { @@ -255,7 +255,7 @@ export class Parameter { const dynamicDate = getDynamicDate(value); if (dynamicDate) { this.value = value; - this.$$value = dynamicDate.value(); + this.$$value = value; } } else { value = moment(value); From e4f58965dcff7034346e9cb6324ab518bad57942 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 17 Jul 2019 14:56:13 -0300 Subject: [PATCH 19/39] Show name instead of value for dynamic values --- client/app/components/ParameterMappingInput.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/app/components/ParameterMappingInput.jsx b/client/app/components/ParameterMappingInput.jsx index ad455b8a6b..590cb2404e 100644 --- a/client/app/components/ParameterMappingInput.jsx +++ b/client/app/components/ParameterMappingInput.jsx @@ -536,7 +536,16 @@ export class ParameterMappingListInput extends React.Component { param = param.clone().setValue(mapping.value); } - const value = Parameter.getValue(param); + let value = Parameter.getValue(param); + + // in case of dynamic value display the name instead of value + if (param.hasDynamicDate) { + value = param.dynamicDate.name; + } + if (param.hasDynamicDateRange) { + value = param.dynamicDateRange.name; + } + return this.getStringValue(value); } From 80d61d71e56fd462474401972a3aac5b55688bc9 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 17 Jul 2019 14:57:47 -0300 Subject: [PATCH 20/39] Add comment about supporting useCurrentDateTime --- client/app/services/query.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/app/services/query.js b/client/app/services/query.js index 3a05ee3089..edd4bcdaa5 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -208,6 +208,7 @@ export class Parameter { } if (isEmptyValue) { + // keep support for existing useCurentDateTime (not available in UI) if ( includes(['date', 'datetime-local', 'datetime-with-seconds'], type) && useCurrentDateTime From 1ef0d0de650c067b7e77028a562da5b1ec8b99da Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 17 Jul 2019 18:23:02 -0300 Subject: [PATCH 21/39] Cypress Tests: Date Parameters --- .../dynamic-parameters/DynamicButton.jsx | 2 + .../integration/query/parameter_spec.js | 84 ++++++++++++------- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/client/app/components/dynamic-parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx index d82fbaa19a..b0ab0668ea 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.jsx +++ b/client/app/components/dynamic-parameters/DynamicButton.jsx @@ -16,6 +16,7 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { className="dynamic-menu" onClick={({ key }) => onSelect(get(options, key, 'static'))} selectedKeys={[`${findIndex(options, { value: selectedDynamicValue })}`]} + data-test="DynamicButtonMenu" > {options.map((option, index) => ( // eslint-disable-next-line react/no-array-index-key @@ -48,6 +49,7 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { className="dynamic-icon" /> )} + data-test="DynamicButton" /> ); diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index 9b4a8b8584..571b0701b0 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -152,6 +152,17 @@ describe('Parameter', () => { }); describe('Date Parameter', () => { + const selectCalendarDate = (date) => { + cy.getByTestId('ParameterName-test-parameter') + .find('input') + .click(); + + cy.get('.ant-calendar-date-panel') + .contains('.ant-calendar-date', date) + .click() + .click(); // workaround for datepicker display bug + }; + beforeEach(() => { const queryData = { name: 'Date Parameter', @@ -170,46 +181,47 @@ describe('Parameter', () => { ParameterSettings-test-parameter ParameterTypeSelect DateParameterTypeOption - UseCurrentDateTimeCheckbox SaveParameterSettings `); const now = new Date(); now.setDate(1); - cy.clock(now); + cy.wrap(now.getTime()).as('now'); + cy.clock(now.getTime()); }); afterEach(() => { cy.clock().then(clock => clock.restore()); }); - it('updates the results after selecting a date', () => { - cy.getByTestId('ParameterName-test-parameter') - .find('input') + it('updates the results after selecting a date', function () { + selectCalendarDate('15'); + + cy.getByTestId('ParameterApplyButton') .click(); - cy.get('.ant-calendar-date-panel') - .contains('.ant-calendar-date', '15') + cy.getByTestId('DynamicTable') + .should('contain', Cypress.moment(this.now).format('15/MM/YY')); + }); + + it('allows picking a dynamic date', function () { + cy.getByTestId('DynamicButton') .click() - .click(); // workaround for datepicker display bug + .click(); + + cy.getByTestId('DynamicButtonMenu') + .contains('Today/Now') + .click(); cy.getByTestId('ParameterApplyButton') .click(); cy.getByTestId('DynamicTable') - .should('contain', Cypress.moment().format('15/MM/YY')); + .should('contain', Cypress.moment(this.now).format('DD/MM/YY')); }); it('sets dirty state when edited', () => { - expectDirtyStateChange(() => { - cy.getByTestId('ParameterName-test-parameter') - .find('input') - .click(); - - cy.get('.ant-calendar-date-panel') - .contains('.ant-calendar-date', '15') - .click(); - }); + expectDirtyStateChange(() => selectCalendarDate('15')); }); }); @@ -232,12 +244,12 @@ describe('Parameter', () => { ParameterSettings-test-parameter ParameterTypeSelect DateTimeParameterTypeOption - UseCurrentDateTimeCheckbox SaveParameterSettings `); const now = new Date(); now.setDate(1); + cy.wrap(now.getTime()).as('now'); cy.clock(now.getTime()); }); @@ -245,7 +257,7 @@ describe('Parameter', () => { cy.clock().then(clock => clock.restore()); }); - it('updates the results after selecting a date and clicking in ok', () => { + it('updates the results after selecting a date and clicking in ok', function () { cy.getByTestId('ParameterName-test-parameter') .find('input') .as('Input') @@ -265,14 +277,11 @@ describe('Parameter', () => { cy.getByTestId('ParameterApplyButton') .click(); - cy.get('@Input').then(($input) => { - const now = Cypress.moment($input.val(), 'DD/MM/YY HH:mm'); - cy.getByTestId('DynamicTable') - .should('contain', now.format('YYYY-MM-15 HH:mm')); - }); + cy.getByTestId('DynamicTable') + .should('contain', Cypress.moment(this.now).format('YYYY-MM-15 HH:mm')); }); - it('shows the current datetime after clicking in Now', () => { + it('shows the current datetime after clicking in Now', function () { cy.getByTestId('ParameterName-test-parameter') .find('input') .as('Input') @@ -286,11 +295,24 @@ describe('Parameter', () => { cy.getByTestId('ParameterApplyButton') .click(); - cy.get('@Input').then(($input) => { - const now = Cypress.moment($input.val(), 'DD/MM/YY HH:mm'); - cy.getByTestId('DynamicTable') - .should('contain', now.format('YYYY-MM-01 HH:mm')); - }); + cy.getByTestId('DynamicTable') + .should('contain', Cypress.moment(this.now).format('YYYY-MM-DD HH:mm')); + }); + + it('allows picking a dynamic date', function () { + cy.getByTestId('DynamicButton') + .click() + .click(); + + cy.getByTestId('DynamicButtonMenu') + .contains('Today/Now') + .click(); + + cy.getByTestId('ParameterApplyButton') + .click(); + + cy.getByTestId('DynamicTable') + .should('contain', Cypress.moment(this.now).format('YYYY-MM-DD HH:mm')); }); it('sets dirty state when edited', () => { From 8d7255fb3c1c5408612127a4813e9976000de582 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 17 Jul 2019 18:50:12 -0300 Subject: [PATCH 22/39] Cypress Tests: Date Range Parameters --- .../EditParameterSettingsDialog.jsx | 2 +- .../integration/query/parameter_spec.js | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/client/app/components/EditParameterSettingsDialog.jsx b/client/app/components/EditParameterSettingsDialog.jsx index af3c742aaf..503e5ae477 100644 --- a/client/app/components/EditParameterSettingsDialog.jsx +++ b/client/app/components/EditParameterSettingsDialog.jsx @@ -162,7 +162,7 @@ function EditParameterSettingsDialog(props) { - + diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index 571b0701b0..2b66fdb71f 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -328,6 +328,88 @@ describe('Parameter', () => { }); }); + describe('Date Range Parameter', () => { + const selectCalendarDateRange = (startDate, endDate) => { + cy.getByTestId('ParameterName-test-parameter') + .find('input') + .first() + .click(); + + cy.get('.ant-calendar-date-panel') + .contains('.ant-calendar-date', startDate) + .click(); + + cy.get('.ant-calendar-date-panel') + .contains('.ant-calendar-date', endDate) + .click() + .click(); // workaround for datepicker display bug + }; + + beforeEach(() => { + const queryData = { + name: 'Date Range Parameter', + query: "SELECT '{{test-parameter.start}} - {{test-parameter.end}}' AS parameter", + options: { + parameters: [ + { name: 'test-parameter', title: 'Test Parameter', type: 'daterange' }, + ], + }, + }; + + createQuery(queryData, false) + .then(({ id }) => cy.visit(`/queries/${id}/source`)); + + cy.clickThrough(` + ParameterSettings-test-parameter + ParameterTypeSelect + DateRangeParameterTypeOption + SaveParameterSettings + `); + + const now = new Date(); + now.setDate(1); + cy.wrap(now.getTime()).as('now'); + cy.clock(now.getTime()); + }); + + afterEach(() => { + cy.clock().then(clock => clock.restore()); + }); + + it('updates the results after selecting a date range', function () { + selectCalendarDateRange('15', '20'); + + cy.getByTestId('ParameterApplyButton') + .click(); + + const now = Cypress.moment(this.now); + cy.getByTestId('DynamicTable') + .should('contain', now.format('YYYY-MM-15') + ' - ' + now.format('YYYY-MM-20')); + }); + + it('allows picking a dynamic date range', function () { + cy.getByTestId('DynamicButton') + .click() + .click(); + + cy.getByTestId('DynamicButtonMenu') + .contains('Last month') + .click(); + + cy.getByTestId('ParameterApplyButton') + .click(); + + const lastMonth = Cypress.moment(this.now).subtract(1, 'month'); + cy.getByTestId('DynamicTable') + .should('contain', lastMonth.startOf('month').format('YYYY-MM-DD') + ' - ' + + lastMonth.endOf('month').format('YYYY-MM-DD')); + }); + + it('sets dirty state when edited', () => { + expectDirtyStateChange(() => selectCalendarDateRange('15', '20')); + }); + }); + describe('Apply Changes', () => { const expectAppliedChanges = (apply) => { cy.getByTestId('ParameterName-test-parameter-1') From cf42e97ee9c0b060441675a47bf09052490a34d4 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 17 Jul 2019 19:44:19 -0300 Subject: [PATCH 23/39] Don't put null params in the url --- client/app/components/parameters.js | 1 + client/app/services/query.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/client/app/components/parameters.js b/client/app/components/parameters.js index 0dc8a87e99..b7d5fe112f 100644 --- a/client/app/components/parameters.js +++ b/client/app/components/parameters.js @@ -49,6 +49,7 @@ function ParametersDirective($location, KeyboardShortcuts) { scope.parameters.forEach((param) => { extend(params, param.toUrlParams()); }); + Object.keys(params).forEach(key => params[key] == null && delete params[key]); $location.search(params); }, true, diff --git a/client/app/services/query.js b/client/app/services/query.js index edd4bcdaa5..2dbd863d65 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -470,6 +470,7 @@ class Parameters { } const params = Object.assign(...this.get().map(p => p.toUrlParams())); + Object.keys(params).forEach(key => params[key] == null && delete params[key]); return Object .keys(params) .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`) @@ -719,6 +720,7 @@ function QueryResource( extend(params, param.toUrlParams()); }); } + Object.keys(params).forEach(key => params[key] == null && delete params[key]); params = map(params, (value, name) => `${encodeURIComponent(name)}=${encodeURIComponent(value)}`).join('&'); if (params !== '') { From 02e740f0e80f94dab987c695f89a9d25af18b6ab Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 11:08:26 -0300 Subject: [PATCH 24/39] Add workaround comments to Cypress tests Co-Authored-By: Ran Byron --- client/cypress/integration/query/parameter_spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index 2b66fdb71f..c7bbd993c0 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -207,7 +207,7 @@ describe('Parameter', () => { it('allows picking a dynamic date', function () { cy.getByTestId('DynamicButton') .click() - .click(); + .click(); // workaround for datepicker display bug cy.getByTestId('DynamicButtonMenu') .contains('Today/Now') @@ -302,7 +302,7 @@ describe('Parameter', () => { it('allows picking a dynamic date', function () { cy.getByTestId('DynamicButton') .click() - .click(); + .click(); // workaround for datepicker display bug cy.getByTestId('DynamicButtonMenu') .contains('Today/Now') From e77b9c410bfaf9416e9e5dca8e47c4b7e5b63b30 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 13:14:33 -0300 Subject: [PATCH 25/39] Fix Dynamic Value as default for global parameters --- client/app/services/dashboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/services/dashboard.js b/client/app/services/dashboard.js index 398f96cf47..7cab5b20bb 100644 --- a/client/app/services/dashboard.js +++ b/client/app/services/dashboard.js @@ -210,7 +210,7 @@ function DashboardService($resource, $http, $location, currentUser) { } }); return _.values(_.each(globalParams, (param) => { - param.setValue(param.getValue()); // apply global param value to all locals + param.setValue(param.value); // apply global param value to all locals param.fromUrlParams(queryParams); // try to initialize from url (may do nothing) })); }; From f23540b41f28e63bbdc521ff83f7938f569fe519 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 15:07:57 -0300 Subject: [PATCH 26/39] Update Back to Static Value --- client/app/components/dynamic-parameters/DateRangeParameter.jsx | 2 +- client/app/components/dynamic-parameters/DynamicButton.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index da0867b25d..f8bf980a62 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -62,7 +62,7 @@ class DateRangeParameter extends React.Component { onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - onSelect(parameter.getValue()); + onSelect([moment(parameter.getValue().start), moment(parameter.getValue().end)]); } else { onSelect(dynamicValue.value); } diff --git a/client/app/components/dynamic-parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx index b0ab0668ea..5394d7297c 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.jsx +++ b/client/app/components/dynamic-parameters/DynamicButton.jsx @@ -29,7 +29,7 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { {enabled && } {enabled && ( - Back to Static Value + Back to Static Value )} From f9dda5ac3b301841eb35fdeb45ffa138a1cebda1 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 15:13:52 -0300 Subject: [PATCH 27/39] Add isValid to value on Date and DateRange inputs --- client/app/components/DateInput.jsx | 2 +- client/app/components/DateRangeInput.jsx | 2 +- client/app/components/DateTimeInput.jsx | 2 +- client/app/components/DateTimeRangeInput.jsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/app/components/DateInput.jsx b/client/app/components/DateInput.jsx index 5e47a64394..aeae70a35c 100644 --- a/client/app/components/DateInput.jsx +++ b/client/app/components/DateInput.jsx @@ -17,7 +17,7 @@ export function DateInput({ if (defaultValue && defaultValue.isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value !== undefined) { + if (value === null || (value && value.isValid())) { additionalAttributes.value = value; } return ( diff --git a/client/app/components/DateRangeInput.jsx b/client/app/components/DateRangeInput.jsx index 1cd6c76eea..cc67c2ef80 100644 --- a/client/app/components/DateRangeInput.jsx +++ b/client/app/components/DateRangeInput.jsx @@ -20,7 +20,7 @@ export function DateRangeInput({ if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value !== undefined) { + if (value === null || (isArray(value) && value[0].isValid() && value[1].isValid())) { additionalAttributes.value = value; } return ( diff --git a/client/app/components/DateTimeInput.jsx b/client/app/components/DateTimeInput.jsx index f8b119bfc2..db06a0dc48 100644 --- a/client/app/components/DateTimeInput.jsx +++ b/client/app/components/DateTimeInput.jsx @@ -19,7 +19,7 @@ export function DateTimeInput({ if (defaultValue && defaultValue.isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value !== undefined) { + if (value === null || (value && value.isValid())) { additionalAttributes.value = value; } return ( diff --git a/client/app/components/DateTimeRangeInput.jsx b/client/app/components/DateTimeRangeInput.jsx index 38f26aa490..0263409268 100644 --- a/client/app/components/DateTimeRangeInput.jsx +++ b/client/app/components/DateTimeRangeInput.jsx @@ -22,7 +22,7 @@ export function DateTimeRangeInput({ if (isArray(defaultValue) && defaultValue[0].isValid() && defaultValue[1].isValid()) { additionalAttributes.defaultValue = defaultValue; } - if (value !== undefined) { + if (value === null || (isArray(value) && value[0].isValid() && value[1].isValid())) { additionalAttributes.value = value; } return ( From 1f45ad01cac945d1b9c5f3095de026aeecff41da Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 15:23:16 -0300 Subject: [PATCH 28/39] CR suggestions --- .../app/components/ParameterMappingInput.jsx | 7 +-- client/app/components/ParameterValueInput.jsx | 8 ++-- client/app/services/query.js | 44 ++++++++++--------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/client/app/components/ParameterMappingInput.jsx b/client/app/components/ParameterMappingInput.jsx index 590cb2404e..fe8e82b901 100644 --- a/client/app/components/ParameterMappingInput.jsx +++ b/client/app/components/ParameterMappingInput.jsx @@ -539,11 +539,8 @@ export class ParameterMappingListInput extends React.Component { let value = Parameter.getValue(param); // in case of dynamic value display the name instead of value - if (param.hasDynamicDate) { - value = param.dynamicDate.name; - } - if (param.hasDynamicDateRange) { - value = param.dynamicDateRange.name; + if (param.hasDynamicValue) { + value = param.dynamicValue.name; } return this.getStringValue(value); diff --git a/client/app/components/ParameterValueInput.jsx b/client/app/components/ParameterValueInput.jsx index a3e772f925..615e0e6abd 100644 --- a/client/app/components/ParameterValueInput.jsx +++ b/client/app/components/ParameterValueInput.jsx @@ -147,11 +147,11 @@ export class ParameterValueInput extends React.Component { renderInput() { const { type } = this.props; switch (type) { - case 'datetime-with-seconds': return this.renderDateParameter(); - case 'datetime-local': return this.renderDateParameter(); + case 'datetime-with-seconds': + case 'datetime-local': case 'date': return this.renderDateParameter(); - case 'datetime-range-with-seconds': return this.renderDateRangeParameter(); - case 'datetime-range': return this.renderDateRangeParameter(); + case 'datetime-range-with-seconds': + case 'datetime-range': case 'date-range': return this.renderDateRangeParameter(); case 'enum': return this.renderEnumInput(); case 'query': return this.renderQueryBasedInput(); diff --git a/client/app/services/query.js b/client/app/services/query.js index 2dbd863d65..1819765d9e 100644 --- a/client/app/services/query.js +++ b/client/app/services/query.js @@ -164,20 +164,24 @@ export class Parameter { return isNull(this.getValue()); } - get hasDynamicDate() { - return isDateParameter(this.type) && isDynamicDate(this.value); - } - - get dynamicDate() { - return getDynamicDate(this.value); - } - - get hasDynamicDateRange() { - return isDateRangeParameter(this.type) && isDynamicDateRange(this.value); + get hasDynamicValue() { + if (isDateParameter(this.type)) { + return isDynamicDate(this.value); + } + if (isDateRangeParameter(this.type)) { + return isDynamicDateRange(this.value); + } + return false; } - get dynamicDateRange() { - return getDynamicDateRange(this.value); + get dynamicValue() { + if (isDateParameter(this.type)) { + return getDynamicDate(this.value); + } + if (isDateRangeParameter(this.type)) { + return getDynamicDateRange(this.value); + } + return false; } getValue() { @@ -187,10 +191,10 @@ export class Parameter { static getValue(param) { const { value, type, useCurrentDateTime } = param; const isEmptyValue = isNull(value) || isUndefined(value) || (value === ''); - if (param.hasDynamicDateRange) { - const { dynamicDateRange } = param; - if (dynamicDateRange) { - const dateRange = dynamicDateRange.value(); + if (isDateRangeParameter(type) && param.hasDynamicValue) { + const { dynamicValue } = param; + if (dynamicValue) { + const dateRange = dynamicValue.value(); return { start: dateRange[0].format(DATETIME_FORMATS[type]), end: dateRange[1].format(DATETIME_FORMATS[type]), @@ -199,10 +203,10 @@ export class Parameter { return null; } - if (param.hasDynamicDate) { - const dynamicDate = param.dynamicDate; - if (dynamicDate) { - return dynamicDate.value().format(DATETIME_FORMATS[type]); + if (isDateParameter(type) && param.hasDynamicValue) { + const { dynamicValue } = param; + if (dynamicValue) { + return dynamicValue.value().format(DATETIME_FORMATS[type]); } return null; } From b81b74fc22c2d6b285b4b0721927757db635bf07 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 15:41:24 -0300 Subject: [PATCH 29/39] Fix Back to Static Value for Dates --- client/app/components/dynamic-parameters/DateParameter.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index 5823110cd5..68e927b960 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -39,7 +39,7 @@ class DateParameter extends React.Component { onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - onSelect(parameter.getValue()); + onSelect(moment(parameter.getValue())); } else { onSelect(dynamicValue.value); } From 7b8bc5a7b7a33ee20b33d07aef5ec3fc4e44e6ac Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 15:41:33 -0300 Subject: [PATCH 30/39] Update Dynamic Value Styling --- client/app/components/dynamic-parameters/DynamicButton.jsx | 2 +- .../components/dynamic-parameters/DynamicParameters.less | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/app/components/dynamic-parameters/DynamicButton.jsx b/client/app/components/dynamic-parameters/DynamicButton.jsx index 5394d7297c..a013fa21cb 100644 --- a/client/app/components/dynamic-parameters/DynamicButton.jsx +++ b/client/app/components/dynamic-parameters/DynamicButton.jsx @@ -45,7 +45,7 @@ function DynamicButton({ options, selectedDynamicValue, onSelect, enabled }) { icon={( )} diff --git a/client/app/components/dynamic-parameters/DynamicParameters.less b/client/app/components/dynamic-parameters/DynamicParameters.less index abb4d15c65..ccd6fb8e86 100644 --- a/client/app/components/dynamic-parameters/DynamicParameters.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -1,6 +1,8 @@ +@import '../../assets/less/inc/variables'; + .dynamic-value { - & ::placeholder, & .dynamic-icon { - color: #1890ff !important + & ::placeholder { + color: @text-color !important; } &.hide-end-value { From ccb1e78e675d6873b0af2adc912379b4ff557941 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Thu, 18 Jul 2019 20:49:26 -0300 Subject: [PATCH 31/39] Fix failing Date tests --- .../integration/query/parameter_spec.js | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index c7bbd993c0..23deaff320 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -175,14 +175,11 @@ describe('Parameter', () => { }; createQuery(queryData, false) - .then(({ id }) => cy.visit(`/queries/${id}/source`)); + .then(({ id }) => cy.visit(`/queries/${id}`)); - cy.clickThrough(` - ParameterSettings-test-parameter - ParameterTypeSelect - DateParameterTypeOption - SaveParameterSettings - `); + // make sure parameter is loaded, otherwise cy.clock won't work + cy.getByTestId('ParameterApplyButton') + .should('exist'); const now = new Date(); now.setDate(1); @@ -238,14 +235,11 @@ describe('Parameter', () => { }; createQuery(queryData, false) - .then(({ id }) => cy.visit(`/queries/${id}/source`)); + .then(({ id }) => cy.visit(`/queries/${id}`)); - cy.clickThrough(` - ParameterSettings-test-parameter - ParameterTypeSelect - DateTimeParameterTypeOption - SaveParameterSettings - `); + // make sure parameter is loaded, otherwise cy.clock won't work + cy.getByTestId('ParameterApplyButton') + .should('exist'); const now = new Date(); now.setDate(1); From b7dea346567925bce4ebec048a18d0af03e13fc0 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Sun, 21 Jul 2019 11:24:13 -0300 Subject: [PATCH 32/39] Fix selectedDynamicValue --- client/app/components/dynamic-parameters/DateParameter.jsx | 4 ++-- .../components/dynamic-parameters/DateRangeParameter.jsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index 68e927b960..d1e3d44a7f 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -46,7 +46,7 @@ class DateParameter extends React.Component { }; render() { - const { type, value, parameter, className, onSelect } = this.props; + const { type, value, className, onSelect } = this.props; const hasDynamicValue = isDynamicDate(value); const isDateTime = includes(type, 'datetime'); @@ -77,7 +77,7 @@ class DateParameter extends React.Component { suffixIcon={( diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index f8bf980a62..adceb3bfa8 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import moment from 'moment'; -import { includes, isArray, isString } from 'lodash'; +import { includes, isArray } from 'lodash'; import { isDynamicDateRange, getDynamicDateRange } from '@/services/query'; import { DateRangeInput } from '@/components/DateRangeInput'; import { DateTimeRangeInput } from '@/components/DateTimeRangeInput'; @@ -69,7 +69,7 @@ class DateRangeParameter extends React.Component { }; render() { - const { type, value, parameter, onSelect, className } = this.props; + const { type, value, onSelect, className } = this.props; const isDateTimeRange = includes(type, 'datetime-range'); const hasDynamicValue = isDynamicDateRange(value); const options = isDateTimeRange ? DYNAMIC_DATETIME_OPTIONS : DYNAMIC_DATE_OPTIONS; @@ -101,7 +101,7 @@ class DateRangeParameter extends React.Component { suffixIcon={( From 34ee589479ed959c9f2f0a3c20fd45b03cd1d877 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Mon, 22 Jul 2019 14:30:53 -0300 Subject: [PATCH 33/39] Parameter spec: Remove date range clickThrough --- client/cypress/integration/query/parameter_spec.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index a85a3809af..7764982545 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -345,7 +345,7 @@ describe('Parameter', () => { query: "SELECT '{{test-parameter.start}} - {{test-parameter.end}}' AS parameter", options: { parameters: [ - { name: 'test-parameter', title: 'Test Parameter', type: 'daterange' }, + { name: 'test-parameter', title: 'Test Parameter', type: 'date-range' }, ], }, }; @@ -353,13 +353,6 @@ describe('Parameter', () => { createQuery(queryData, false) .then(({ id }) => cy.visit(`/queries/${id}/source`)); - cy.clickThrough(` - ParameterSettings-test-parameter - ParameterTypeSelect - DateRangeParameterTypeOption - SaveParameterSettings - `); - const now = new Date(); now.setDate(1); cy.wrap(now.getTime()).as('now'); From 794fde73db37b856f182cc0d1034f67909a8e0e7 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 23 Jul 2019 13:08:26 -0300 Subject: [PATCH 34/39] Add transition --- .../dynamic-parameters/DateRangeParameter.jsx | 2 +- .../dynamic-parameters/DynamicParameters.less | 43 +++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index adceb3bfa8..60f4ab1330 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -96,7 +96,7 @@ class DateRangeParameter extends React.Component { return ( Date: Tue, 23 Jul 2019 13:31:28 -0300 Subject: [PATCH 35/39] Fix failing Cypress tests --- client/cypress/integration/query/parameter_spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/cypress/integration/query/parameter_spec.js b/client/cypress/integration/query/parameter_spec.js index 7764982545..86362f01f3 100644 --- a/client/cypress/integration/query/parameter_spec.js +++ b/client/cypress/integration/query/parameter_spec.js @@ -353,6 +353,10 @@ describe('Parameter', () => { createQuery(queryData, false) .then(({ id }) => cy.visit(`/queries/${id}/source`)); + // make sure parameter is loaded, otherwise cy.clock won't work + cy.getByTestId('ParameterName-test-parameter') + .should('exist'); + const now = new Date(); now.setDate(1); cy.wrap(now.getTime()).as('now'); From 44a0ca9ab3ebf0c4952d349de4fb9542bc2a7424 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 23 Jul 2019 14:11:54 -0300 Subject: [PATCH 36/39] Back with 'width: auto' --- client/app/components/dynamic-parameters/DynamicParameters.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/app/components/dynamic-parameters/DynamicParameters.less b/client/app/components/dynamic-parameters/DynamicParameters.less index 2cd36c9585..80a6d07416 100644 --- a/client/app/components/dynamic-parameters/DynamicParameters.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -1,6 +1,8 @@ @import '../../assets/less/inc/variables'; .redash-datepicker { + width: auto !important; + .ant-calendar-picker-clear { right: 35px; } From 16bed9c781cbf5f4da620ff07fe3d28816ee63c4 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 23 Jul 2019 14:28:45 -0300 Subject: [PATCH 37/39] Check value is valid on Back to Static value --- .../app/components/dynamic-parameters/DateParameter.jsx | 7 ++++++- .../components/dynamic-parameters/DateRangeParameter.jsx | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateParameter.jsx b/client/app/components/dynamic-parameters/DateParameter.jsx index d1e3d44a7f..f9b8d25f2c 100644 --- a/client/app/components/dynamic-parameters/DateParameter.jsx +++ b/client/app/components/dynamic-parameters/DateParameter.jsx @@ -39,7 +39,12 @@ class DateParameter extends React.Component { onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - onSelect(moment(parameter.getValue())); + const parameterValue = parameter.getValue(); + if (parameterValue) { + onSelect(moment(parameterValue)); + } else { + onSelect(null); + } } else { onSelect(dynamicValue.value); } diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 60f4ab1330..98ff953a26 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import moment from 'moment'; -import { includes, isArray } from 'lodash'; +import { includes, isArray, isObject } from 'lodash'; import { isDynamicDateRange, getDynamicDateRange } from '@/services/query'; import { DateRangeInput } from '@/components/DateRangeInput'; import { DateTimeRangeInput } from '@/components/DateTimeRangeInput'; @@ -62,7 +62,12 @@ class DateRangeParameter extends React.Component { onDynamicValueSelect = (dynamicValue) => { const { onSelect, parameter } = this.props; if (dynamicValue === 'static') { - onSelect([moment(parameter.getValue().start), moment(parameter.getValue().end)]); + const parameterValue = parameter.getValue(); + if (isObject(parameterValue) && parameterValue.start && parameterValue.end) { + onSelect([moment(parameterValue.start), moment(parameterValue.end)]); + } else { + onSelect(null); + } } else { onSelect(dynamicValue.value); } From 9a7881a0dd2bbd5caae806956b4e46af0798297b Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Wed, 24 Jul 2019 14:24:39 -0300 Subject: [PATCH 38/39] CR --- .../dynamic-parameters/DateRangeParameter.jsx | 7 +++++++ .../dynamic-parameters/DynamicParameters.less | 11 ++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 98ff953a26..0ef0371d41 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -38,6 +38,12 @@ const DYNAMIC_DATETIME_OPTIONS = [ ...DYNAMIC_DATE_OPTIONS, ]; +const widthByType = { + 'date-range': 270, + 'datetime-range': 320, + 'datetime-range-with-seconds': 370, +}; + function isValidDateRangeValue(value) { return isArray(value) && value.length === 2 && moment.isMoment(value[0]) && moment.isMoment(value[1]); } @@ -103,6 +109,7 @@ class DateRangeParameter extends React.Component { Date: Thu, 25 Jul 2019 12:01:05 -0300 Subject: [PATCH 39/39] Update Date Range width --- .../components/dynamic-parameters/DateRangeParameter.jsx | 6 +++--- .../components/dynamic-parameters/DynamicParameters.less | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/app/components/dynamic-parameters/DateRangeParameter.jsx b/client/app/components/dynamic-parameters/DateRangeParameter.jsx index 0ef0371d41..77f63e24c2 100644 --- a/client/app/components/dynamic-parameters/DateRangeParameter.jsx +++ b/client/app/components/dynamic-parameters/DateRangeParameter.jsx @@ -39,9 +39,9 @@ const DYNAMIC_DATETIME_OPTIONS = [ ]; const widthByType = { - 'date-range': 270, - 'datetime-range': 320, - 'datetime-range-with-seconds': 370, + 'date-range': 294, + 'datetime-range': 352, + 'datetime-range-with-seconds': 382, }; function isValidDateRangeValue(value) { diff --git a/client/app/components/dynamic-parameters/DynamicParameters.less b/client/app/components/dynamic-parameters/DynamicParameters.less index 4e34c0b0c7..7a6a56d443 100644 --- a/client/app/components/dynamic-parameters/DynamicParameters.less +++ b/client/app/components/dynamic-parameters/DynamicParameters.less @@ -3,6 +3,7 @@ .redash-datepicker { .ant-calendar-picker-clear { right: 35px; + background: transparent; } &.date-range-input {