diff --git a/static/app/components/codecov/datePicker/datePicker.spec.tsx b/static/app/components/codecov/datePicker/datePicker.spec.tsx
index 20f173cba17b37..16154d66b455b9 100644
--- a/static/app/components/codecov/datePicker/datePicker.spec.tsx
+++ b/static/app/components/codecov/datePicker/datePicker.spec.tsx
@@ -1,152 +1,53 @@
-import {initializeOrg} from 'sentry-test/initializeOrg';
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
-import {initializeUrlState} from 'sentry/actionCreators/pageFilters';
+import CodecovQueryParamsProvider from 'sentry/components/codecov/container/codecovParamsProvider';
import {DatePicker} from 'sentry/components/codecov/datePicker/datePicker';
-import OrganizationStore from 'sentry/stores/organizationStore';
-import PageFiltersStore from 'sentry/stores/pageFiltersStore';
-
-const {organization, router} = initializeOrg({
- router: {
- location: {
- query: {},
- pathname: '/codecov/tests',
- },
- params: {},
- },
-});
describe('DatePicker', function () {
- beforeEach(() => {
- PageFiltersStore.init();
- OrganizationStore.init();
-
- OrganizationStore.onUpdate(organization, {replace: true});
- PageFiltersStore.onInitializeUrlState(
+ it('can change period', async function () {
+ const {router} = render(
+
+
+ ,
{
- projects: [],
- environments: [],
- datetime: {
- period: '7d',
- start: null,
- end: null,
- utc: false,
+ initialRouterConfig: {
+ location: {
+ pathname: '/codecov/tests',
+ query: {codecovPeriod: '7d'},
+ },
},
- },
- new Set(['datetime'])
+ }
);
- });
-
- it('can change period', async function () {
- render(, {
- router,
- deprecatedRouterMocks: true,
- });
await userEvent.click(screen.getByRole('button', {name: '7D', expanded: false}));
await userEvent.click(screen.getByRole('option', {name: 'Last 30 days'}));
+ expect(router.location.search).toBe('?codecovPeriod=30d');
+
expect(
screen.getByRole('button', {name: '30D', expanded: false})
).toBeInTheDocument();
- expect(router.push).toHaveBeenCalledWith(
- expect.objectContaining({query: {statsPeriod: '30d'}})
- );
- expect(PageFiltersStore.getState()).toEqual({
- isReady: true,
- shouldPersist: true,
- desyncedFilters: new Set(),
- pinnedFilters: new Set(['datetime']),
- selection: {
- datetime: {
- period: '30d',
- end: null,
- start: null,
- utc: false,
- },
- environments: [],
- projects: [],
- },
- });
});
- it('adjusts period if invalid', async function () {
- PageFiltersStore.reset();
- PageFiltersStore.onInitializeUrlState(
+ it('displays invalid button for invalid values', async function () {
+ render(
+
+
+ ,
{
- projects: [],
- environments: [],
- datetime: {
- period: '123d',
- start: null,
- end: null,
- utc: false,
+ initialRouterConfig: {
+ location: {
+ pathname: '/codecov/tests',
+ query: {codecovPeriod: '123Dd12'},
+ },
},
- },
- new Set(['datetime'])
+ }
);
- render(, {
- router,
- deprecatedRouterMocks: true,
+ const button = await screen.findByRole('button', {
+ name: 'Invalid Period',
+ expanded: false,
});
-
- // Confirm selection changed to default Codecov period
- const button = await screen.findByRole('button', {name: '24H', expanded: false});
expect(button).toBeInTheDocument();
- expect(router.push).toHaveBeenCalledWith(
- expect.objectContaining({query: {statsPeriod: '24h'}})
- );
- expect(PageFiltersStore.getState()).toEqual({
- isReady: true,
- shouldPersist: true,
- desyncedFilters: new Set(),
- pinnedFilters: new Set(['datetime']),
- selection: {
- datetime: {
- period: '24h',
- end: null,
- start: null,
- utc: false,
- },
- environments: [],
- projects: [],
- },
- });
- });
-
- it('displays a desynced state message', async function () {
- const {organization: desyncOrganization, router: desyncRouter} = initializeOrg({
- router: {
- location: {
- query: {statsPeriod: '7d'},
- pathname: '/codecov/test',
- },
- params: {},
- },
- });
-
- PageFiltersStore.reset();
- initializeUrlState({
- memberProjects: [],
- nonMemberProjects: [],
- organization: desyncOrganization,
- queryParams: {statsPeriod: '30d'},
- router: desyncRouter,
- shouldEnforceSingleProject: false,
- });
-
- render(, {
- router: desyncRouter,
- organization: desyncOrganization,
- deprecatedRouterMocks: true,
- });
-
- await userEvent.click(screen.getByRole('button', {name: '30D', expanded: false}));
- expect(screen.getByText('Filters Updated')).toBeInTheDocument();
- expect(
- screen.getByRole('button', {name: 'Restore Previous Values'})
- ).toBeInTheDocument();
- expect(screen.getByRole('button', {name: 'Got It'})).toBeInTheDocument();
});
});
diff --git a/static/app/components/codecov/datePicker/datePicker.tsx b/static/app/components/codecov/datePicker/datePicker.tsx
index 7cb3c716302caa..475f61eb9d816c 100644
--- a/static/app/components/codecov/datePicker/datePicker.tsx
+++ b/static/app/components/codecov/datePicker/datePicker.tsx
@@ -1,64 +1,23 @@
-import {useEffect} from 'react';
+import {useSearchParams} from 'react-router-dom';
-import {updateDateTime} from 'sentry/actionCreators/pageFilters';
-import type {DateSelectorProps} from 'sentry/components/codecov/datePicker/dateSelector';
+import {useCodecovContext} from 'sentry/components/codecov/context/codecovContext';
import {DateSelector} from 'sentry/components/codecov/datePicker/dateSelector';
-import {isValidCodecovRelativePeriod} from 'sentry/components/codecov/utils';
-import {DesyncedFilterMessage} from 'sentry/components/organizations/pageFilters/desyncedFilter';
-import {t} from 'sentry/locale';
-import usePageFilters from 'sentry/utils/usePageFilters';
-import useRouter from 'sentry/utils/useRouter';
-const CODECOV_DEFAULT_RELATIVE_PERIOD = '24h';
-export const CODECOV_DEFAULT_RELATIVE_PERIODS = {
- '24h': t('Last 24 hours'),
- '7d': t('Last 7 days'),
- '30d': t('Last 30 days'),
-};
-
-interface DatePickerProps
- extends Partial>> {}
-
-export function DatePicker({
- onChange,
- menuTitle,
- menuWidth,
- triggerProps = {},
- ...selectProps
-}: DatePickerProps) {
- const router = useRouter();
- const {selection, desyncedFilters} = usePageFilters();
- const desynced = desyncedFilters.has('datetime');
- const period = selection.datetime?.period;
-
- // Adjusts to valid Codecov relative period since Codecov only accepts a subset of dates other components accept, defined in CODECOV_DEFAULT_RELATIVE_PERIODS
- useEffect(() => {
- if (!isValidCodecovRelativePeriod(period)) {
- const newTimePeriod = {period: CODECOV_DEFAULT_RELATIVE_PERIOD};
- updateDateTime(newTimePeriod, router, {
- save: true,
- });
- }
- }, [period, router]);
+export function DatePicker() {
+ const {codecovPeriod} = useCodecovContext();
+ const [searchParams, setSearchParams] = useSearchParams();
return (
{
- const {relative} = timePeriodUpdate;
- const newTimePeriod = {period: relative};
-
- onChange?.(timePeriodUpdate);
- updateDateTime(newTimePeriod, router, {
- save: true,
- });
+ relativeDate={codecovPeriod}
+ onChange={newCodecovPeriod => {
+ const currentParams = Object.fromEntries(searchParams.entries());
+ const updatedParams = {
+ ...currentParams,
+ codecovPeriod: newCodecovPeriod,
+ };
+ setSearchParams(updatedParams);
}}
- menuTitle={menuTitle ?? t('Filter Time Range')}
- menuWidth={(menuWidth ?? desynced) ? '22em' : undefined}
- menuBody={desynced && }
- triggerProps={triggerProps}
/>
);
}
diff --git a/static/app/components/codecov/datePicker/dateSelector.spec.tsx b/static/app/components/codecov/datePicker/dateSelector.spec.tsx
index f2a0be2fa9b87a..55b8e4b853bf20 100644
--- a/static/app/components/codecov/datePicker/dateSelector.spec.tsx
+++ b/static/app/components/codecov/datePicker/dateSelector.spec.tsx
@@ -4,12 +4,12 @@ import {DateSelector} from 'sentry/components/codecov/datePicker/dateSelector';
describe('DateSelector', function () {
it('renders when given relative period', async function () {
- render();
+ render( {}} />);
expect(await screen.findByRole('button', {name: '7D'})).toBeInTheDocument();
});
it('renders when given an invalid relative period', async function () {
- render();
+ render( {}} />);
expect(
await screen.findByRole('button', {name: 'Invalid Period'})
).toBeInTheDocument();
diff --git a/static/app/components/codecov/datePicker/dateSelector.tsx b/static/app/components/codecov/datePicker/dateSelector.tsx
index 87fa5def7c4f88..b0325c5b45eb5f 100644
--- a/static/app/components/codecov/datePicker/dateSelector.tsx
+++ b/static/app/components/codecov/datePicker/dateSelector.tsx
@@ -1,136 +1,87 @@
-import {useCallback} from 'react';
+import {useCallback, useMemo} from 'react';
import styled from '@emotion/styled';
import type {SelectOption, SingleSelectProps} from 'sentry/components/core/compactSelect';
import {CompactSelect} from 'sentry/components/core/compactSelect';
-import type {Item} from 'sentry/components/dropdownAutoComplete/types';
import DropdownButton from 'sentry/components/dropdownButton';
-import HookOrDefault from 'sentry/components/hookOrDefault';
-import {DesyncedFilterIndicator} from 'sentry/components/organizations/pageFilters/desyncedFilter';
-import SelectorItems from 'sentry/components/timeRangeSelector/selectorItems';
-import {
- getArbitraryRelativePeriod,
- getSortedRelativePeriods,
-} from 'sentry/components/timeRangeSelector/utils';
+import {getArbitraryRelativePeriod} from 'sentry/components/timeRangeSelector/utils';
import {t} from 'sentry/locale';
-import {parsePeriodToHours} from 'sentry/utils/duration/parsePeriodToHours';
-import {CODECOV_DEFAULT_RELATIVE_PERIODS} from './datePicker';
-
-const SelectorItemsHook = HookOrDefault({
- hookName: 'component:header-selector-items',
- defaultComponent: SelectorItems,
-});
-
-type ChangeData = {
- relative: string | null;
+export const CODECOV_DEFAULT_RELATIVE_PERIODS = {
+ '24h': t('Last 24 hours'),
+ '7d': t('Last 7 days'),
+ '30d': t('Last 30 days'),
};
-export interface DateSelectorProps
- extends Omit<
- SingleSelectProps,
- 'disableSearchFilter' | 'onChange' | 'onClose' | 'options' | 'value'
- > {
+export interface DateSelectorProps {
+ onChange: (data: string) => void;
/**
- * Whether the current value is out of sync with the stored persistent value.
+ * Relative date value
*/
- desynced?: boolean;
+ relativeDate?: string | null;
/**
- * Custom width value for relative compact select
+ * Optional trigger for the assignee selector. If nothing passed in,
+ * the default trigger will be used
*/
- menuWidth?: string;
- onChange?: (data: ChangeData) => void;
- onClose?: () => void;
- /**
- * Relative date value
- */
- relative?: string | null;
+ trigger?: (
+ props: Omit, 'children'>,
+ isOpen: boolean
+ ) => React.ReactNode;
}
-export function DateSelector({
- relative,
- onChange,
- onClose,
- trigger,
- menuWidth,
- desynced,
- ...selectProps
-}: DateSelectorProps) {
- const getOptions = useCallback((items: Item[]): Array> => {
- return items.map((item: Item): SelectOption => {
- return {
- value: item.value,
- label: {item.label},
- textValue: item.searchKey,
- };
- });
- }, []);
-
+export function DateSelector({relativeDate, onChange, trigger}: DateSelectorProps) {
const handleChange = useCallback['onChange']>>(
- option => {
- onChange?.({relative: option.value});
+ newSelectedPeriod => {
+ onChange(newSelectedPeriod.value);
},
[onChange]
);
- // Currently selected relative period
- const arbitraryRelativePeriods = getArbitraryRelativePeriod(relative);
- // Periods from default relative periods object
- const restrictedDefaultPeriods = Object.fromEntries(
- Object.entries(CODECOV_DEFAULT_RELATIVE_PERIODS).filter(([period]) =>
- parsePeriodToHours(period)
- )
- );
- const defaultRelativePeriods = {
- ...restrictedDefaultPeriods,
- ...arbitraryRelativePeriods,
- };
+ const options = useMemo((): Array> => {
+ const currentAndDefaultCodecovPeriods = {
+ ...getArbitraryRelativePeriod(relativeDate),
+ ...CODECOV_DEFAULT_RELATIVE_PERIODS,
+ };
+
+ return Object.entries(currentAndDefaultCodecovPeriods).map(
+ ([key, value]): SelectOption => {
+ return {
+ value: key,
+ label: {value},
+ textValue: value,
+ };
+ }
+ );
+ }, [relativeDate]);
return (
- handleChange({value})}
- >
- {items => (
- {
- onClose?.();
- }}
- trigger={
- trigger ??
- ((triggerProps, isOpen) => {
- const defaultLabel = items.some(item => item.value === relative)
- ? relative?.toUpperCase()
- : t('Invalid Period');
+ {
+ const defaultLabel = options.some(item => item.value === relativeDate)
+ ? relativeDate?.toUpperCase()
+ : t('Invalid Period');
- return (
-
-
-
- {selectProps.triggerLabel ?? defaultLabel}
-
- {desynced && }
-
-
- );
- })
- }
- />
- )}
-
+ return (
+
+
+ {defaultLabel}
+
+
+ );
+ })
+ }
+ />
);
}
diff --git a/static/app/components/codecov/utils.spec.tsx b/static/app/components/codecov/utils.spec.tsx
deleted file mode 100644
index 187470d6f4bf1e..00000000000000
--- a/static/app/components/codecov/utils.spec.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import {isValidCodecovRelativePeriod} from 'sentry/components/codecov/utils';
-
-describe('isValidCodecovRelativePeriod', function () {
- it('returns false for null relative periods', function () {
- const period = null;
- expect(isValidCodecovRelativePeriod(period)).toBe(false);
- });
- it('returns false for periods not belonging to the Codecov default relative periods', function () {
- const period = '123d';
- expect(isValidCodecovRelativePeriod(period)).toBe(false);
- });
- it('returns true for a valid relative period', function () {
- const period = '7d';
- expect(isValidCodecovRelativePeriod(period)).toBe(true);
- });
-});
diff --git a/static/app/components/codecov/utils.tsx b/static/app/components/codecov/utils.tsx
deleted file mode 100644
index 9c82455c27c47d..00000000000000
--- a/static/app/components/codecov/utils.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {CODECOV_DEFAULT_RELATIVE_PERIODS} from './datePicker/datePicker';
-
-// Date Picker Utils Start
-
-/**
- * Determines if a period is valid for a Codecov DatePicker component. A period is invalid if
- * it is null or if it doesn't belong to the list of Codecov default relative periods.
- */
-export function isValidCodecovRelativePeriod(period: string | null): boolean {
- if (period === null) {
- return false;
- }
-
- if (!Object.hasOwn(CODECOV_DEFAULT_RELATIVE_PERIODS, period)) {
- return false;
- }
-
- return true;
-}
-
-// Date Picker Utils End
diff --git a/static/app/views/codecov/tests/tests.tsx b/static/app/views/codecov/tests/tests.tsx
index a32b07038ae1ab..e8572905e79b83 100644
--- a/static/app/views/codecov/tests/tests.tsx
+++ b/static/app/views/codecov/tests/tests.tsx
@@ -1,10 +1,9 @@
import styled from '@emotion/styled';
-import CodecovProvider from 'sentry/components/codecov/container/codecovParamsProvider';
+import CodecovQueryParamsProvider from 'sentry/components/codecov/container/codecovParamsProvider';
import {DatePicker} from 'sentry/components/codecov/datePicker/datePicker';
import {RepoPicker} from 'sentry/components/codecov/repoPicker/repoPicker';
import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
-import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
import {space} from 'sentry/styles/space';
import {decodeSorts} from 'sentry/utils/queryString';
import {useLocation} from 'sentry/utils/useLocation';
@@ -15,13 +14,6 @@ import TestAnalyticsTable, {
isAValidSort,
} from 'sentry/views/codecov/tests/testAnalyticsTable/testAnalyticsTable';
-const DEFAULT_CODECOV_DATETIME_SELECTION = {
- start: null,
- end: null,
- utc: false,
- period: '24h',
-};
-
// TODO: Sorting will only work once this is connected to the API
const fakeApiResponse = {
data: [
@@ -66,18 +58,12 @@ export default function TestsPage() {
return (
Test Analytics
-
+
-
-
-
-
-
+
{/* TODO: Conditionally show these if the branch we're in is the main branch */}