feat(CalendarFrame): adding previous calendar quarter (#31889)

Co-authored-by: Diego Pucci <diegopucci.me@gmail.com>
This commit is contained in:
Alexandru Soare 2025-01-22 18:54:29 +02:00 committed by GitHub
parent b74da7963b
commit e4e07eef5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 139 additions and 2 deletions

View File

@ -39,11 +39,16 @@ export const GlobalStyles = () => (
.echarts-tooltip[style*='visibility: hidden'] {
display: none !important;
}
// Ant Design is applying inline z-index styles causing troubles
// TODO: Remove z-indexes when Ant Design is fully upgraded to v5
// Prefer vanilla Ant Design z-indexes that should work out of the box
.ant-popover,
.antd5-dropdown,
.ant-dropdown,
.ant-select-dropdown {
z-index: ${theme.zIndex.max};
.ant-select-dropdown,
.antd5-modal-wrap,
.antd5-modal-mask {
z-index: ${theme.zIndex.max} !important;
}
// TODO: Remove when buttons have been upgraded to Ant Design 5.

View File

@ -0,0 +1,90 @@
/**
* 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 { render, screen, fireEvent } from 'spec/helpers/testing-library';
import { CalendarFrame } from '../components/CalendarFrame';
import { PreviousCalendarWeek, PreviousCalendarQuarter } from '../types';
import { CALENDAR_RANGE_OPTIONS } from '../utils/constants';
describe('CalendarFrame', () => {
it('calls onChange with PreviousCalendarWeek if value is not in CALENDAR_RANGE_SET', () => {
const mockOnChange = jest.fn();
render(<CalendarFrame onChange={mockOnChange} value="invalid-value" />);
expect(mockOnChange).toHaveBeenCalledWith(PreviousCalendarWeek);
});
it('renders null if value is not in CALENDAR_RANGE_SET', () => {
render(<CalendarFrame onChange={jest.fn()} value="invalid-value" />);
expect(
screen.queryByText('Configure Time Range: Previous...'),
).not.toBeInTheDocument();
});
it('renders the correct number of radio options', () => {
render(<CalendarFrame onChange={jest.fn()} value={PreviousCalendarWeek} />);
const radios = screen.getAllByRole('radio');
expect(radios).toHaveLength(CALENDAR_RANGE_OPTIONS.length);
CALENDAR_RANGE_OPTIONS.forEach(option => {
expect(screen.getByText(option.label)).toBeInTheDocument();
});
});
it('calls onChange with the correct value when a radio button is selected', () => {
const mockOnChange = jest.fn();
render(
<CalendarFrame
onChange={mockOnChange}
value={CALENDAR_RANGE_OPTIONS[0].value}
/>,
);
const secondOption = CALENDAR_RANGE_OPTIONS[1];
const radio = screen.getByLabelText(secondOption.label);
fireEvent.click(radio);
expect(mockOnChange).toHaveBeenCalledWith(secondOption.value);
});
it('renders the section title correctly', () => {
render(
<CalendarFrame
onChange={jest.fn()}
value={CALENDAR_RANGE_OPTIONS[0].value}
/>,
);
expect(
screen.getByText('Configure Time Range: Previous...'),
).toBeInTheDocument();
});
it('ensures the third option is PreviousCalendarQuarter', () => {
render(
<CalendarFrame
onChange={jest.fn()}
value={CALENDAR_RANGE_OPTIONS[0].value}
/>,
);
const thirdOption = CALENDAR_RANGE_OPTIONS[2];
expect(thirdOption.value).toBe(PreviousCalendarQuarter);
expect(screen.getByLabelText(thirdOption.label)).toBeInTheDocument();
});
});

View File

@ -80,10 +80,12 @@ export type CommonRangeType =
export const PreviousCalendarWeek = 'previous calendar week';
export const PreviousCalendarMonth = 'previous calendar month';
export const PreviousCalendarQuarter = 'previous calendar quarter';
export const PreviousCalendarYear = 'previous calendar year';
export type CalendarRangeType =
| typeof PreviousCalendarWeek
| typeof PreviousCalendarMonth
| typeof PreviousCalendarQuarter
| typeof PreviousCalendarYear;
export const CurrentDay = 'Current day';

View File

@ -21,6 +21,7 @@ import {
SelectOptionType,
PreviousCalendarWeek,
PreviousCalendarMonth,
PreviousCalendarQuarter,
PreviousCalendarYear,
CommonRangeType,
CalendarRangeType,
@ -56,6 +57,7 @@ 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: PreviousCalendarQuarter, label: t('previous calendar quarter') },
{ value: PreviousCalendarYear, label: t('previous calendar year') },
];
export const CALENDAR_RANGE_VALUES_SET = new Set(
@ -119,6 +121,7 @@ export const COMMON_RANGE_SET: Set<CommonRangeType> = new Set([
export const CALENDAR_RANGE_SET: Set<CalendarRangeType> = new Set([
PreviousCalendarWeek,
PreviousCalendarMonth,
PreviousCalendarQuarter,
PreviousCalendarYear,
]);

View File

@ -369,6 +369,15 @@ 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, MONTH), MONTH) : DATETRUNC(DATETIME('today'), MONTH)" # pylint: disable=line-too-long,useless-suppression # noqa: E501
if (
time_range
and time_range.startswith("previous calendar quarter")
and separator not in time_range
):
time_range = (
"DATETRUNC(DATEADD(DATETIME('today'), -1, QUARTER), QUARTER) : "
"DATETRUNC(DATETIME('today'), QUARTER)" # pylint: disable=line-too-long,useless-suppression # noqa: E501
)
if (
time_range
and time_range.startswith("previous calendar year")

View File

@ -19,6 +19,7 @@ from datetime import date, datetime, timedelta
from typing import Optional
from unittest.mock import Mock, patch
import freezegun
import pytest
from dateutil.relativedelta import relativedelta
@ -316,6 +317,33 @@ def test_get_since_until_instant_time_comparison_enabled() -> None:
assert result == expected
def test_previous_calendar_quarter():
with freezegun.freeze_time("2023-01-15"):
result = get_since_until("previous calendar quarter")
expected = (datetime(2022, 10, 1), datetime(2023, 1, 1))
assert result == expected
with freezegun.freeze_time("2023, 4, 15"):
result = get_since_until("previous calendar quarter")
expected = (datetime(2023, 1, 1), datetime(2023, 4, 1))
assert result == expected
with freezegun.freeze_time("2023, 8, 15"):
result = get_since_until("previous calendar quarter")
expected = (datetime(2023, 4, 1), datetime(2023, 7, 1))
assert result == expected
with freezegun.freeze_time("2023, 10, 15"):
result = get_since_until("previous calendar quarter")
expected = (datetime(2023, 7, 1), datetime(2023, 10, 1))
assert result == expected
with freezegun.freeze_time("2024, 1, 1"):
result = get_since_until("previous calendar quarter")
expected = (datetime(2023, 10, 1), datetime(2024, 1, 1))
assert result == expected
@patch("superset.utils.date_parser.parse_human_datetime", mock_parse_human_datetime)
def test_datetime_eval() -> None:
result = datetime_eval("datetime('now')")