client/app/services/parameters/DateRangeParameter.js (193 lines of code) (raw):

import { startsWith, has, includes, findKey, values, isObject, isArray } from "lodash"; import moment from "moment"; import PropTypes from "prop-types"; import Parameter from "./Parameter"; const DATETIME_FORMATS = { "date-range": "YYYY-MM-DD", "datetime-range": "YYYY-MM-DD HH:mm", "datetime-range-with-seconds": "YYYY-MM-DD HH:mm:ss", }; const DYNAMIC_PREFIX = "d_"; 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"), ], }, 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"), ], }, 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()], }, last_14_days: { name: "Last 14 days", value: () => [moment().subtract(14, "days"), moment()], }, last_30_days: { name: "Last 30 days", value: () => [moment().subtract(30, "days"), moment()], }, last_60_days: { name: "Last 60 days", value: () => [moment().subtract(60, "days"), moment()], }, last_90_days: { name: "Last 90 days", value: () => [moment().subtract(90, "days"), moment()], }, last_12_months: { name: "Last 12 months", value: () => [moment().subtract(12, "months"), moment()], }, }; export const DynamicDateRangeType = PropTypes.oneOf(values(DYNAMIC_DATE_RANGES)); export function isDynamicDateRangeString(value) { if (!startsWith(value, DYNAMIC_PREFIX)) { return false; } return !!DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)]; } export function isDynamicDateRange(value) { return includes(DYNAMIC_DATE_RANGES, value); } export function getDynamicDateRangeFromString(value) { if (!isDynamicDateRangeString(value)) { return null; } return DYNAMIC_DATE_RANGES[value.substring(DYNAMIC_PREFIX.length)]; } class DateRangeParameter extends Parameter { constructor(parameter, parentQueryId) { super(parameter, parentQueryId); this.setValue(parameter.value); } get hasDynamicValue() { return isDynamicDateRange(this.normalizedValue); } // eslint-disable-next-line class-methods-use-this normalizeValue(value) { if (isDynamicDateRangeString(value)) { return getDynamicDateRangeFromString(value); } if (isDynamicDateRange(value)) { return value; } if (isObject(value) && !isArray(value)) { value = [value.start, value.end]; } if (isArray(value) && value.length === 2) { value = [moment(value[0]), moment(value[1])]; if (value[0].isValid() && value[1].isValid()) { return value; } } return null; } setValue(value) { const normalizedValue = this.normalizeValue(value); if (isDynamicDateRange(normalizedValue)) { this.value = DYNAMIC_PREFIX + findKey(DYNAMIC_DATE_RANGES, normalizedValue); } else if (isArray(normalizedValue)) { this.value = { start: normalizedValue[0].format(DATETIME_FORMATS[this.type]), end: normalizedValue[1].format(DATETIME_FORMATS[this.type]), }; } else { this.value = normalizedValue; } this.$$value = normalizedValue; this.updateLocals(); this.clearPendingValue(); return this; } getExecutionValue() { if (this.hasDynamicValue) { const format = date => date.format(DATETIME_FORMATS[this.type]); const [start, end] = this.normalizedValue.value().map(format); return { start, end }; } return this.value; } toUrlParams() { const prefix = this.urlPrefix; if (isObject(this.value) && this.value.start && this.value.end) { return { [`${prefix}${this.name}`]: `${this.value.start}--${this.value.end}`, }; } return super.toUrlParams(); } fromUrlParams(query) { const prefix = this.urlPrefix; const key = `${prefix}${this.name}`; // backward compatibility const keyStart = `${prefix}${this.name}.start`; const keyEnd = `${prefix}${this.name}.end`; if (has(query, key)) { const dates = query[key].split("--"); if (dates.length === 2) { this.setValue(dates); } else { this.setValue(query[key]); } } else if (has(query, keyStart) && has(query, keyEnd)) { this.setValue([query[keyStart], query[keyEnd]]); } } toQueryTextFragment() { return `{{ ${this.name}.start }} {{ ${this.name}.end }}`; } } export default DateRangeParameter;