diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
index edfcf9b2383bd..e5ef553267969 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
@@ -53,6 +53,7 @@ import {
AdvancedFrame,
DateLabel,
} from './components';
+import { CurrentCalendarFrame } from './components/CurrentCalendarFrame';
const StyledRangeType = styled(Select)`
width: 272px;
@@ -201,6 +202,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
if (
guessedFrame === 'Common' ||
guessedFrame === 'Calendar' ||
+ guessedFrame === 'Current' ||
guessedFrame === 'No filter'
) {
setActualTimeRange(value);
@@ -296,6 +298,12 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
{frame === 'Calendar' && (
)}
+ {frame === 'Current' && (
+
+ )}
{frame === 'Advanced' && (
)}
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CurrentCalendarFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CurrentCalendarFrame.tsx
new file mode 100644
index 0000000000000..78fcacf5c05f9
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CurrentCalendarFrame.tsx
@@ -0,0 +1,65 @@
+/**
+ * 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 React, { useEffect } from 'react';
+import { t } from '@superset-ui/core';
+import { Radio } from 'src/components/Radio';
+import {
+ CURRENT_RANGE_OPTIONS,
+ CURRENT_CALENDAR_RANGE_SET,
+} from 'src/explore/components/controls/DateFilterControl/utils';
+import { CurrentRangeType, CurrentWeek, FrameComponentProps } from '../types';
+
+export function CurrentCalendarFrame({ onChange, value }: FrameComponentProps) {
+ useEffect(() => {
+ if (!CURRENT_CALENDAR_RANGE_SET.has(value as CurrentRangeType)) {
+ onChange(CurrentWeek);
+ }
+ }, [value]);
+
+ if (!CURRENT_CALENDAR_RANGE_SET.has(value as CurrentRangeType)) {
+ return null;
+ }
+
+ return (
+ <>
+
+ {t('Configure Time Range: Current...')}
+
+ {
+ let newValue = e.target.value;
+ // Sanitization: Trim whitespace
+ newValue = newValue.trim();
+ // Validation: Check if the value is non-empty
+ if (newValue === '') {
+ return;
+ }
+ onChange(newValue);
+ }}
+ >
+ {CURRENT_RANGE_OPTIONS.map(({ value, label }) => (
+
+ {label}
+
+ ))}
+
+ >
+ );
+}
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
index 0d46ee7a97d19..29449c74d3462 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
@@ -18,6 +18,7 @@
*/
export { CommonFrame } from './CommonFrame';
export { CalendarFrame } from './CalendarFrame';
+export { CurrentCalendarFrame } from './CurrentCalendarFrame';
export { CustomFrame } from './CustomFrame';
export { AdvancedFrame } from './AdvancedFrame';
export { DateLabel } from './DateLabel';
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/tests/CurrentCalendarFrame.test.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/CurrentCalendarFrame.test.tsx
new file mode 100644
index 0000000000000..ae33aa119ee3f
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/tests/CurrentCalendarFrame.test.tsx
@@ -0,0 +1,37 @@
+/**
+ * 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 React from 'react';
+import { render } from '@testing-library/react';
+import '@testing-library/jest-dom/extend-expect'; // For advanced DOM assertions
+import { CurrentCalendarFrame } from '../components/CurrentCalendarFrame';
+import { CurrentWeek } from '../types';
+
+const mockOnChange = jest.fn();
+
+test('calls onChange(CurrentWeek) when value is invalid', () => {
+ render();
+ expect(mockOnChange).toHaveBeenCalledWith(CurrentWeek);
+});
+
+test('returns null if value is not a valid CurrentRangeType', () => {
+ const { container } = render(
+ ,
+ );
+ expect(container.childNodes.length).toBe(0);
+});
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
index ce5e8127698cb..7062b4858065b 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts
@@ -24,6 +24,7 @@ export type SelectOptionType = {
export type FrameType =
| 'Common'
| 'Calendar'
+ | 'Current'
| 'Custom'
| 'Advanced'
| 'No filter';
@@ -85,6 +86,18 @@ export type CalendarRangeType =
| typeof PreviousCalendarMonth
| typeof PreviousCalendarYear;
+export const CurrentDay = 'Current day';
+export const CurrentWeek = 'Current week';
+export const CurrentMonth = 'Current month';
+export const CurrentYear = 'Current year';
+export const CurrentQuarter = 'Current quarter';
+export type CurrentRangeType =
+ | typeof CurrentDay
+ | typeof CurrentWeek
+ | typeof CurrentMonth
+ | typeof CurrentQuarter
+ | typeof CurrentYear;
+
export type FrameComponentProps = {
onChange: (timeRange: string) => void;
value: string;
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts
index ddd9bf2e5836a..cad7a0e816230 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts
@@ -25,11 +25,18 @@ import {
PreviousCalendarYear,
CommonRangeType,
CalendarRangeType,
+ CurrentRangeType,
+ CurrentWeek,
+ CurrentMonth,
+ CurrentYear,
+ CurrentQuarter,
+ CurrentDay,
} from 'src/explore/components/controls/DateFilterControl/types';
export const FRAME_OPTIONS: SelectOptionType[] = [
{ value: 'Common', label: t('Last') },
{ value: 'Calendar', label: t('Previous') },
+ { value: 'Current', label: t('Current') },
{ value: 'Custom', label: t('Custom') },
{ value: 'Advanced', label: t('Advanced') },
{ value: 'No filter', label: t('No filter') },
@@ -48,16 +55,24 @@ export const COMMON_RANGE_VALUES_SET = new Set(
export const CALENDAR_RANGE_OPTIONS: SelectOptionType[] = [
{ value: PreviousCalendarWeek, label: t('previous calendar week') },
- {
- value: PreviousCalendarMonth,
- label: t('previous calendar month'),
- },
+ { value: PreviousCalendarMonth, label: t('previous calendar month') },
{ value: PreviousCalendarYear, label: t('previous calendar year') },
];
export const CALENDAR_RANGE_VALUES_SET = new Set(
CALENDAR_RANGE_OPTIONS.map(({ value }) => value),
);
+export const CURRENT_RANGE_OPTIONS: SelectOptionType[] = [
+ { value: CurrentDay, label: t('Current day') },
+ { value: CurrentWeek, label: t('Current week') },
+ { value: CurrentMonth, label: t('Current month') },
+ { value: CurrentQuarter, label: t('Current quarter') },
+ { value: CurrentYear, label: t('Current year') },
+];
+export const CURRENT_RANGE_VALUES_SET = new Set(
+ CURRENT_RANGE_OPTIONS.map(({ value }) => value),
+);
+
const GRAIN_OPTIONS = [
{ value: 'second', label: (rel: string) => t('Seconds %s', rel) },
{ value: 'minute', label: (rel: string) => t('Minutes %s', rel) },
@@ -107,6 +122,14 @@ export const CALENDAR_RANGE_SET: Set = new Set([
PreviousCalendarYear,
]);
+export const CURRENT_CALENDAR_RANGE_SET: Set = new Set([
+ CurrentDay,
+ CurrentWeek,
+ CurrentMonth,
+ CurrentQuarter,
+ CurrentYear,
+]);
+
export const MOMENT_FORMAT = 'YYYY-MM-DD[T]HH:mm:ss';
export const SEVEN_DAYS_AGO = moment()
.utc()
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
index 4be932e34ab22..835492e40bc6c 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/dateFilterUtils.ts
@@ -21,6 +21,7 @@ import { useSelector } from 'react-redux';
import {
COMMON_RANGE_VALUES_SET,
CALENDAR_RANGE_VALUES_SET,
+ CURRENT_RANGE_VALUES_SET,
customTimeRangeDecode,
} from '.';
import { FrameType } from '../types';
@@ -32,6 +33,9 @@ export const guessFrame = (timeRange: string): FrameType => {
if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) {
return 'Calendar';
}
+ if (CURRENT_RANGE_VALUES_SET.has(timeRange)) {
+ return 'Current';
+ }
if (timeRange === NO_TIME_RANGE) {
return 'No filter';
}
diff --git a/superset/utils/date_parser.py b/superset/utils/date_parser.py
index bffe50c6242c3..a3736b0ab0200 100644
--- a/superset/utils/date_parser.py
+++ b/superset/utils/date_parser.py
@@ -207,6 +207,36 @@ def get_since_until( # pylint: disable=too-many-arguments,too-many-locals,too-m
and separator not in time_range
):
time_range = "DATETRUNC(DATEADD(DATETIME('today'), -1, YEAR), YEAR) : DATETRUNC(DATETIME('today'), YEAR)" # pylint: disable=line-too-long,useless-suppression
+ if (
+ time_range
+ and time_range.startswith("Current day")
+ and separator not in time_range
+ ):
+ time_range = "DATETRUNC(DATEADD(DATETIME('today'), 0, DAY), DAY) : DATETRUNC(DATEADD(DATETIME('today'), 1, DAY), DAY)" # pylint: disable=line-too-long,useless-suppression
+ if (
+ time_range
+ and time_range.startswith("Current week")
+ and separator not in time_range
+ ):
+ time_range = "DATETRUNC(DATEADD(DATETIME('today'), 0, WEEK), WEEK) : DATETRUNC(DATEADD(DATETIME('today'), 1, WEEK), WEEK)" # pylint: disable=line-too-long,useless-suppression
+ if (
+ time_range
+ and time_range.startswith("Current month")
+ and separator not in time_range
+ ):
+ time_range = "DATETRUNC(DATEADD(DATETIME('today'), 0, MONTH), MONTH) : DATETRUNC(DATEADD(DATETIME('today'), 1, MONTH), MONTH)" # pylint: disable=line-too-long,useless-suppression
+ if (
+ time_range
+ and time_range.startswith("Current quarter")
+ and separator not in time_range
+ ):
+ time_range = "DATETRUNC(DATEADD(DATETIME('today'), 0, QUARTER), QUARTER) : DATETRUNC(DATEADD(DATETIME('today'), 1, QUARTER), QUARTER)" # pylint: disable=line-too-long,useless-suppression
+ if (
+ time_range
+ and time_range.startswith("Current year")
+ and separator not in time_range
+ ):
+ time_range = "DATETRUNC(DATEADD(DATETIME('today'), 0, YEAR), YEAR) : DATETRUNC(DATEADD(DATETIME('today'), 1, YEAR), YEAR)" # pylint: disable=line-too-long,useless-suppression
if time_range and separator in time_range:
time_range_lookup = [
diff --git a/tests/unit_tests/utils/date_parser_tests.py b/tests/unit_tests/utils/date_parser_tests.py
index e007c17e829c5..a5a3f8b0ac926 100644
--- a/tests/unit_tests/utils/date_parser_tests.py
+++ b/tests/unit_tests/utils/date_parser_tests.py
@@ -160,6 +160,26 @@ def test_get_since_until() -> None:
expected = datetime(2015, 1, 1, 0, 0, 0), datetime(2016, 1, 1, 0, 0, 0)
assert result == expected
+ result = get_since_until("Current day")
+ expected = datetime(2016, 11, 7, 0, 0, 0), datetime(2016, 11, 8, 0, 0, 0)
+ assert result == expected
+
+ result = get_since_until("Current week")
+ expected = datetime(2016, 11, 7, 0, 0, 0), datetime(2016, 11, 14, 0, 0, 0)
+ assert result == expected
+
+ result = get_since_until("Current month")
+ expected = datetime(2016, 11, 1, 0, 0, 0), datetime(2016, 12, 1, 0, 0, 0)
+ assert result == expected
+
+ result = get_since_until("Current quarter")
+ expected = datetime(2016, 10, 1, 0, 0, 0), datetime(2017, 1, 1, 0, 0, 0)
+ assert result == expected
+
+ result = get_since_until("Current year")
+ expected = expected = datetime(2016, 1, 1, 0, 0, 0), datetime(2017, 1, 1, 0, 0, 0)
+ assert result == expected
+
# Tests for our new instant_time_comparison logic and Feature Flag off
result = get_since_until(
time_range="2000-01-01T00:00:00 : 2018-01-01T00:00:00",