You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2021/01/29 14:25:54 UTC
[superset] 16/18: fix(explore): time picker can not be switched
between now and specific (#12793)
This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch 1.0
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 926fdce42559f2e41f5f7830b948f1c329aa09de
Author: Yongjie Zhao <yo...@gmail.com>
AuthorDate: Fri Jan 29 13:35:57 2021 +0800
fix(explore): time picker can not be switched between now and specific (#12793)
* fix(explore): time picker can not be switched between now and specifc
* fix linting
* fix type
* fix UT
---
.../components/DateFilterControl/utils_spec.ts | 298 +++++++++++++++++++++
.../DateFilterControl/frame/CustomFrame.tsx | 18 +-
.../components/controls/DateFilterControl/types.ts | 2 +-
.../components/controls/DateFilterControl/utils.ts | 36 ++-
4 files changed, 334 insertions(+), 20 deletions(-)
diff --git a/superset-frontend/spec/javascripts/explore/components/DateFilterControl/utils_spec.ts b/superset-frontend/spec/javascripts/explore/components/DateFilterControl/utils_spec.ts
new file mode 100644
index 0000000..d44b08d
--- /dev/null
+++ b/superset-frontend/spec/javascripts/explore/components/DateFilterControl/utils_spec.ts
@@ -0,0 +1,298 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {
+ customTimeRangeEncode,
+ customTimeRangeDecode,
+} from 'src/explore/components/controls/DateFilterControl/utils';
+
+describe('Custom TimeRange', () => {
+ describe('customTimeRangeEncode', () => {
+ it('1) specific : specific', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: '2021-01-20T00:00:00',
+ sinceMode: 'specific',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'specific',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual('2021-01-20T00:00:00 : 2021-01-27T00:00:00');
+ });
+
+ it('2) specific : relative', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: '2021-01-20T00:00:00',
+ sinceMode: 'specific',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-20T00:00:00',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual(
+ '2021-01-20T00:00:00 : DATEADD(DATETIME("2021-01-20T00:00:00"), 7, day)',
+ );
+ });
+
+ it('3) now : relative', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: 'now',
+ sinceMode: 'now',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'now',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual('now : DATEADD(DATETIME("now"), 7, day)');
+ });
+
+ it('4) today : relative', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: 'today',
+ sinceMode: 'today',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'today',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual('today : DATEADD(DATETIME("today"), 7, day)');
+ });
+
+ it('5) relative : specific', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: '2021-01-27T00:00:00',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'specific',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual(
+ 'DATEADD(DATETIME("2021-01-27T00:00:00"), -7, day) : 2021-01-27T00:00:00',
+ );
+ });
+
+ it('6) relative : now', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: 'now',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'now',
+ untilMode: 'now',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual('DATEADD(DATETIME("now"), -7, day) : now');
+ });
+
+ it('7) relative : today', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: 'today',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'today',
+ untilMode: 'today',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual('DATEADD(DATETIME("today"), -7, day) : today');
+ });
+
+ it('8) relative : relative (now)', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: 'now',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'now',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ }),
+ ).toEqual(
+ 'DATEADD(DATETIME("now"), -7, day) : DATEADD(DATETIME("now"), 7, day)',
+ );
+ });
+
+ it('9) relative : relative (date/time)', () => {
+ expect(
+ customTimeRangeEncode({
+ sinceDatetime: '2021-01-27T00:00:00',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'specific',
+ anchorValue: '2021-01-27T00:00:00',
+ }),
+ ).toEqual(
+ 'DATEADD(DATETIME("2021-01-27T00:00:00"), -7, day) : DATEADD(DATETIME("2021-01-27T00:00:00"), 7, day)',
+ );
+ });
+ });
+
+ describe('customTimeRangeDecode', () => {
+ it('1) specific : specific', () => {
+ expect(
+ customTimeRangeDecode('2021-01-20T00:00:00 : 2021-01-27T00:00:00'),
+ ).toEqual({
+ customRange: {
+ sinceDatetime: '2021-01-20T00:00:00',
+ sinceMode: 'specific',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'specific',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ },
+ matchedFlag: true,
+ });
+ });
+
+ it('2) specific : relative', () => {
+ expect(
+ customTimeRangeDecode(
+ '2021-01-20T00:00:00 : DATEADD(DATETIME("2021-01-20T00:00:00"), 7, day)',
+ ),
+ ).toEqual({
+ customRange: {
+ sinceDatetime: '2021-01-20T00:00:00',
+ sinceMode: 'specific',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-20T00:00:00',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ },
+ matchedFlag: true,
+ });
+ });
+
+ it('3) relative : specific', () => {
+ expect(
+ customTimeRangeDecode(
+ 'DATEADD(DATETIME("2021-01-27T00:00:00"), -7, day) : 2021-01-27T00:00:00',
+ ),
+ ).toEqual({
+ customRange: {
+ sinceDatetime: '2021-01-27T00:00:00',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'specific',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ },
+ matchedFlag: true,
+ });
+ });
+
+ it('4) relative : relative (now)', () => {
+ expect(
+ customTimeRangeDecode(
+ 'DATEADD(DATETIME("now"), -7, day) : DATEADD(DATETIME("now"), 7, day)',
+ ),
+ ).toEqual({
+ customRange: {
+ sinceDatetime: 'now',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: 'now',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'now',
+ anchorValue: 'now',
+ },
+ matchedFlag: true,
+ });
+ });
+
+ it('5) relative : relative (date/time)', () => {
+ expect(
+ customTimeRangeDecode(
+ 'DATEADD(DATETIME("2021-01-27T00:00:00"), -7, day) : DATEADD(DATETIME("2021-01-27T00:00:00"), 7, day)',
+ ),
+ ).toEqual({
+ customRange: {
+ sinceDatetime: '2021-01-27T00:00:00',
+ sinceMode: 'relative',
+ sinceGrain: 'day',
+ sinceGrainValue: -7,
+ untilDatetime: '2021-01-27T00:00:00',
+ untilMode: 'relative',
+ untilGrain: 'day',
+ untilGrainValue: 7,
+ anchorMode: 'specific',
+ anchorValue: '2021-01-27T00:00:00',
+ },
+ matchedFlag: true,
+ });
+ });
+ });
+});
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/frame/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/frame/CustomFrame.tsx
index 3f15873..08045ee 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/frame/CustomFrame.tsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/frame/CustomFrame.tsx
@@ -18,7 +18,7 @@
*/
import React from 'react';
import { t } from '@superset-ui/core';
-import moment, { Moment } from 'moment';
+import { Moment } from 'moment';
import { isInteger } from 'lodash';
import {
Col,
@@ -36,23 +36,17 @@ import {
MOMENT_FORMAT,
MIDNIGHT,
} from '../constants';
-import { customTimeRangeDecode, customTimeRangeEncode } from '../utils';
+import {
+ customTimeRangeDecode,
+ customTimeRangeEncode,
+ dttmToMoment,
+} from '../utils';
import {
CustomRangeKey,
SelectOptionType,
FrameComponentProps,
} from '../types';
-const dttmToMoment = (dttm: string): Moment => {
- if (dttm === 'now') {
- return moment().utc().startOf('second');
- }
- if (dttm === 'today') {
- return moment().utc().startOf('day');
- }
- return moment(dttm);
-};
-
export function CustomFrame(props: FrameComponentProps) {
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
if (!matchedFlag) {
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
index 1d400de..0fcdfca 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
@@ -57,7 +57,7 @@ export type CustomRangeType = {
sinceDatetime: string;
sinceGrain: DateTimeGrainType;
sinceGrainValue: number;
- untilMode: 'specific' | 'relative' | 'now' | 'today';
+ untilMode: DateTimeModeType;
untilDatetime: string;
untilGrain: DateTimeGrainType;
untilGrainValue: number;
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils.ts
index 0cdf64e..4deb81b 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils.ts
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import moment, { Moment } from 'moment';
import { SEPARATOR } from 'src/explore/dateFilterUtils';
import {
CustomRangeDecodeType,
@@ -23,7 +24,7 @@ import {
DateTimeGrainType,
DateTimeModeType,
} from './types';
-import { SEVEN_DAYS_AGO, MIDNIGHT } from './constants';
+import { SEVEN_DAYS_AGO, MIDNIGHT, MOMENT_FORMAT } from './constants';
/**
* RegExp to test a string for a full ISO 8601 Date
@@ -60,6 +61,19 @@ const defaultCustomRange: CustomRangeType = {
};
const SPECIFIC_MODE = ['specific', 'today', 'now'];
+export const dttmToMoment = (dttm: string): Moment => {
+ if (dttm === 'now') {
+ return moment().utc().startOf('second');
+ }
+ if (dttm === 'today') {
+ return moment().utc().startOf('day');
+ }
+ return moment(dttm);
+};
+
+export const dttmToString = (dttm: string): string =>
+ dttmToMoment(dttm).format(MOMENT_FORMAT);
+
export const customTimeRangeDecode = (
timeRange: string,
): CustomRangeDecodeType => {
@@ -104,6 +118,7 @@ export const customTimeRangeDecode = (
...defaultCustomRange,
sinceGrain: grain as DateTimeGrainType,
sinceGrainValue: parseInt(grainValue, 10),
+ sinceDatetime: dttm,
untilDatetime: dttm,
sinceMode: 'relative',
untilMode,
@@ -129,6 +144,7 @@ export const customTimeRangeDecode = (
untilGrain: grain as DateTimeGrainType,
untilGrainValue: parseInt(grainValue, 10),
sinceDatetime: dttm,
+ untilDatetime: dttm,
untilMode: 'relative',
sinceMode,
},
@@ -150,8 +166,10 @@ export const customTimeRangeDecode = (
...defaultCustomRange,
sinceGrain: sinceGrain as DateTimeGrainType,
sinceGrainValue: parseInt(sinceGrainValue, 10),
+ sinceDatetime: sinceDttm,
untilGrain: untilGrain as DateTimeGrainType,
untilGrainValue: parseInt(untilGrainValue, 10),
+ untilDatetime: untileDttm,
anchorValue: sinceDttm,
sinceMode: 'relative',
untilMode: 'relative',
@@ -183,31 +201,35 @@ export const customTimeRangeEncode = (customRange: CustomRangeType): string => {
} = { ...customRange };
// specific : specific
if (SPECIFIC_MODE.includes(sinceMode) && SPECIFIC_MODE.includes(untilMode)) {
- const since = sinceMode === 'specific' ? sinceDatetime : sinceMode;
- const until = untilMode === 'specific' ? untilDatetime : untilMode;
+ const since =
+ sinceMode === 'specific' ? dttmToString(sinceDatetime) : sinceMode;
+ const until =
+ untilMode === 'specific' ? dttmToString(untilDatetime) : untilMode;
return `${since} : ${until}`;
}
// specific : relative
if (SPECIFIC_MODE.includes(sinceMode) && untilMode === 'relative') {
- const since = sinceMode === 'specific' ? sinceDatetime : sinceMode;
+ const since =
+ sinceMode === 'specific' ? dttmToString(sinceDatetime) : sinceMode;
const until = `DATEADD(DATETIME("${since}"), ${untilGrainValue}, ${untilGrain})`;
return `${since} : ${until}`;
}
// relative : specific
if (sinceMode === 'relative' && SPECIFIC_MODE.includes(untilMode)) {
- const until = untilMode === 'specific' ? untilDatetime : untilMode;
+ const until =
+ untilMode === 'specific' ? dttmToString(untilDatetime) : untilMode;
const since = `DATEADD(DATETIME("${until}"), ${-Math.abs(
sinceGrainValue,
- )}, ${sinceGrain})`; // eslint-disable-line
+ )}, ${sinceGrain})`;
return `${since} : ${until}`;
}
// relative : relative
const since = `DATEADD(DATETIME("${anchorValue}"), ${-Math.abs(
sinceGrainValue,
- )}, ${sinceGrain})`; // eslint-disable-line
+ )}, ${sinceGrain})`;
const until = `DATEADD(DATETIME("${anchorValue}"), ${untilGrainValue}, ${untilGrain})`;
return `${since} : ${until}`;
};