mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site): set spend today range to end of day (#26992)
Selecting Today in the AI spend usage date range picker sent an end date rounded to the next hour, which made refreshed usage pages show stale partial-day data. This lets the shared date range picker keep its existing next-hour default for template insights while the spend usage and drill-in pickers request an end-of-day boundary for Today. Closes https://linear.app/codercom/issue/CODAGT-751/date-range-picker-uses-end-of-hour-for-today Generated by Coder Agents.
This commit is contained in:
@@ -21,6 +21,7 @@ import { useAuthenticated } from "#/hooks/useAuthenticated";
|
||||
import { usePaginatedQuery } from "#/hooks/usePaginatedQuery";
|
||||
import { RequirePermission } from "#/modules/permissions/RequirePermission";
|
||||
import { SpendPageView } from "./SpendPageView";
|
||||
import { toExclusiveEndOfDayDateRange } from "./utils/dateRange";
|
||||
|
||||
const startDateSearchParam = "startDate";
|
||||
const endDateSearchParam = "endDate";
|
||||
@@ -132,11 +133,13 @@ const SpendPage: FC<SpendPageProps> = ({ now }) => {
|
||||
};
|
||||
|
||||
const onDateRangeChange = (value: DateRangeValue) => {
|
||||
const nextDateRange = toExclusiveEndOfDayDateRange(value);
|
||||
|
||||
setSearchParams(
|
||||
(prev) => {
|
||||
const next = new URLSearchParams(prev);
|
||||
next.set(startDateSearchParam, value.startDate.toISOString());
|
||||
next.set(endDateSearchParam, value.endDate.toISOString());
|
||||
next.set(startDateSearchParam, nextDateRange.startDate.toISOString());
|
||||
next.set(endDateSearchParam, nextDateRange.endDate.toISOString());
|
||||
next.delete("page");
|
||||
return next;
|
||||
},
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { formatUsageDateRange, toInclusiveDateRange } from "./dateRange";
|
||||
import {
|
||||
formatUsageDateRange,
|
||||
toExclusiveEndOfDayDateRange,
|
||||
toInclusiveDateRange,
|
||||
} from "./dateRange";
|
||||
|
||||
describe("toExclusiveEndOfDayDateRange", () => {
|
||||
it("moves a non-midnight end date to the next midnight", () => {
|
||||
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
|
||||
const endDate = new Date(2025, 5, 8, 14, 30, 0, 0);
|
||||
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
|
||||
expect(result.endDate).toEqual(new Date(2025, 5, 9, 0, 0, 0, 0));
|
||||
});
|
||||
|
||||
it("returns unchanged when the end date is already midnight", () => {
|
||||
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
|
||||
const endDate = new Date(2025, 5, 8, 0, 0, 0, 0);
|
||||
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
|
||||
expect(result.endDate).toBe(endDate);
|
||||
});
|
||||
|
||||
it("preserves startDate", () => {
|
||||
const startDate = new Date(2025, 5, 1, 0, 0, 0, 0);
|
||||
const endDate = new Date(2025, 5, 8, 14, 30, 0, 0);
|
||||
const result = toExclusiveEndOfDayDateRange({ startDate, endDate });
|
||||
expect(result.startDate).toBe(startDate);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toInclusiveDateRange", () => {
|
||||
it("subtracts 1ms when endDateIsExclusive is true and end date is midnight", () => {
|
||||
|
||||
@@ -16,6 +16,19 @@ function isMidnight(date: Date): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export function toExclusiveEndOfDayDateRange(
|
||||
dateRange: DateRangeValue,
|
||||
): DateRangeValue {
|
||||
if (isMidnight(dateRange.endDate)) {
|
||||
return dateRange;
|
||||
}
|
||||
|
||||
return {
|
||||
startDate: dateRange.startDate,
|
||||
endDate: dayjs(dateRange.endDate).startOf("day").add(1, "day").toDate(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user picks an explicit date range whose end boundary is
|
||||
* midnight of the following day, adjust it by −1 ms so the
|
||||
|
||||
Reference in New Issue
Block a user