You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by yo...@apache.org on 2021/01/29 05:36:56 UTC

[superset] branch master updated: 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.

yongjiezhao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 642a76f  fix(explore): time picker can not be switched between now and specific (#12793)
642a76f is described below

commit 642a76f6ccaa9c2cd6b54460cf5672e1e3917f27
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}`;
 };