From 04822f64b2dfa0b420a3c637467801f121ce4875 Mon Sep 17 00:00:00 2001 From: Artur Pata Date: Mon, 4 Nov 2024 11:23:36 +0200 Subject: [PATCH] Limit maximum date to today in calendars (#4746) * Limit maximum date to today in calendars * Add test * Make calendar max dates sensitive to site timezone --- assets/jest.config.json | 1 - .../js/dashboard/date-range-calendar.test.tsx | 81 +++++++++++++++++++ assets/js/dashboard/datepicker.tsx | 14 ++-- assets/js/dashboard/query-time-periods.ts | 7 +- assets/js/dashboard/util/date.test.ts | 15 ++++ assets/package.json | 2 +- assets/test-utils/set-fixed-timezone.ts | 13 --- 7 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 assets/js/dashboard/date-range-calendar.test.tsx delete mode 100644 assets/test-utils/set-fixed-timezone.ts diff --git a/assets/jest.config.json b/assets/jest.config.json index 540d9ec36dd0..37c13e8d4113 100644 --- a/assets/jest.config.json +++ b/assets/jest.config.json @@ -6,7 +6,6 @@ "globals": { "BUILD_EXTRA": true }, - "setupFiles": ["/test-utils/set-fixed-timezone.ts"], "setupFilesAfterEnv": [ "/test-utils/extend-expect.ts", "/test-utils/reset-state.ts" diff --git a/assets/js/dashboard/date-range-calendar.test.tsx b/assets/js/dashboard/date-range-calendar.test.tsx new file mode 100644 index 000000000000..0511d963279d --- /dev/null +++ b/assets/js/dashboard/date-range-calendar.test.tsx @@ -0,0 +1,81 @@ +/** @format */ + +import React from 'react' +import { render, screen } from '@testing-library/react' +import { DateRangeCalendar } from './date-range-calendar' +import userEvent from '@testing-library/user-event' + +test('renders with default dates in view, respects max and min dates', async () => { + const onCloseWithNoSelection = jest.fn() + const onCloseWithSelection = jest.fn() + const handlers = { onCloseWithNoSelection, onCloseWithSelection } + + render( + + ) + + const days = await screen.queryAllByLabelText(/, 2024/) + + expect( + days.map((d) => [d.getAttribute('aria-label'), d.getAttribute('class')]) + ).toEqual([ + ['September 1, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 2, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 3, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 4, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 5, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 6, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 7, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 8, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 9, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 10, 2024', 'flatpickr-day'], + ['September 11, 2024', 'flatpickr-day'], + ['September 12, 2024', 'flatpickr-day selected startRange'], + ['September 13, 2024', 'flatpickr-day inRange'], + ['September 14, 2024', 'flatpickr-day inRange'], + ['September 15, 2024', 'flatpickr-day inRange'], + ['September 16, 2024', 'flatpickr-day inRange'], + ['September 17, 2024', 'flatpickr-day inRange'], + ['September 18, 2024', 'flatpickr-day inRange'], + ['September 19, 2024', 'flatpickr-day selected endRange'], + ['September 20, 2024', 'flatpickr-day'], + ['September 21, 2024', 'flatpickr-day'], + ['September 22, 2024', 'flatpickr-day'], + ['September 23, 2024', 'flatpickr-day'], + ['September 24, 2024', 'flatpickr-day'], + ['September 25, 2024', 'flatpickr-day'], + ['September 26, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 27, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 28, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 29, 2024', 'flatpickr-day flatpickr-disabled'], + ['September 30, 2024', 'flatpickr-day flatpickr-disabled'], + ['October 1, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 2, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 3, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 4, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 5, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 6, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 7, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 8, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 9, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 10, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 11, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'], + ['October 12, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'] + ]) + + const newStart = await screen.getByLabelText('September 20, 2024') + await userEvent.click(newStart) + const newEnd = await screen.getByLabelText('September 25, 2024') + await userEvent.click(newEnd) + + expect(onCloseWithSelection).toHaveBeenCalledTimes(1) + expect(onCloseWithSelection).toHaveBeenLastCalledWith([ + new Date('2024-09-20'), + new Date('2024-09-25') + ]) +}) diff --git a/assets/js/dashboard/datepicker.tsx b/assets/js/dashboard/datepicker.tsx index dbed663dda7a..956cc3fd564a 100644 --- a/assets/js/dashboard/datepicker.tsx +++ b/assets/js/dashboard/datepicker.tsx @@ -1,6 +1,6 @@ /* @format */ import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react' -import { formatDateRange, formatISO } from './util/date' +import { formatDateRange, formatISO, nowForSite } from './util/date' import { shiftQueryPeriod, getDateForShiftedPeriod, @@ -317,14 +317,16 @@ export default function QueryPeriodPicker() { () => getCompareLinkItem({ site, query }), [site, query] ) - const groups = useMemo(() => { + + const datePeriodGroups = useMemo(() => { const groups = getDatePeriodGroups(site) // add Custom Range link to the last group groups[groups.length - 1].push(customRangeLink) + if (COMPARISON_DISABLED_PERIODS.includes(query.period)) { return groups } - // maybe ass Compare link as another group to the very end + // maybe add Compare link as another group to the very end return groups.concat([[compareLink]]) }, [site, query, customRangeLink, compareLink]) @@ -357,7 +359,7 @@ export default function QueryPeriodPicker() { }} > {menuVisible === 'datemenu' && ( - + )} {menuVisible === 'datemenu-calendar' && ( - {groups + {datePeriodGroups .concat([[last6MonthsLinkItem]]) .flatMap((group) => group diff --git a/assets/js/dashboard/query-time-periods.ts b/assets/js/dashboard/query-time-periods.ts index 59f94ec8e522..ea59be8fe4b4 100644 --- a/assets/js/dashboard/query-time-periods.ts +++ b/assets/js/dashboard/query-time-periods.ts @@ -398,7 +398,12 @@ export const getDatePeriodGroups = ( export const last6MonthsLinkItem: LinkItem = [ ['Last 6 months', 'S'], { - search: (s) => ({ ...s, period: QueryPeriod['6mo'], keybindHint: 'S' }), + search: (s) => ({ + ...s, + ...clearedDateSearch, + period: QueryPeriod['6mo'], + keybindHint: 'S' + }), isActive: ({ query }) => query.period === QueryPeriod['6mo'] } ] diff --git a/assets/js/dashboard/util/date.test.ts b/assets/js/dashboard/util/date.test.ts index 98624162ec81..99a2085fa70f 100644 --- a/assets/js/dashboard/util/date.test.ts +++ b/assets/js/dashboard/util/date.test.ts @@ -4,6 +4,21 @@ import { formatISO, nowForSite, shiftMonths, yesterday } from './date' jest.useFakeTimers() +describe(`${nowForSite.name} and ${formatISO.name}`, () => { + /* prettier-ignore */ + const cases = [ + [ 'Los Angeles/America', -3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-01' ], + [ 'Sydney/Australia', 3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-02' ] + ] + test.each(cases)( + 'in timezone of %s (offset %p) at %s, today is %s', + (_tz, offset, utcTime, expectedToday) => { + jest.setSystemTime(new Date(utcTime)) + expect(formatISO(nowForSite({ offset }))).toEqual(expectedToday) + } + ) +}) + /* prettier-ignore */ const dstChangeOverDayEstonia = [ // system time today yesterday today-2mo today+2mo today-12mo offset diff --git a/assets/package.json b/assets/package.json index 4e9078d5ee82..09ca12902bb5 100644 --- a/assets/package.json +++ b/assets/package.json @@ -3,7 +3,7 @@ "version": "1.4.0", "license": "AGPL-3.0-or-later", "scripts": { - "test": "jest", + "test": "TZ=UTC jest", "format": "prettier --write", "check-format": "prettier --check **/*.{js,css,ts,tsx} --require-pragma", "eslint": "eslint js/**", diff --git a/assets/test-utils/set-fixed-timezone.ts b/assets/test-utils/set-fixed-timezone.ts deleted file mode 100644 index 42da38697fe1..000000000000 --- a/assets/test-utils/set-fixed-timezone.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @format - */ - -/** - * @returns sets a fixed timezone for the test process, - * otherwise test runs on different servers and machines may be inconsistent - */ -function setFixedTimezone() { - process.env.TZ = 'UTC' -} - -setFixedTimezone()