diff --git a/src/__tests__/CompareResults/Retrigger.test.tsx b/src/__tests__/CompareResults/Retrigger.test.tsx
index 302972e45..fc3a1511e 100644
--- a/src/__tests__/CompareResults/Retrigger.test.tsx
+++ b/src/__tests__/CompareResults/Retrigger.test.tsx
@@ -127,6 +127,25 @@ describe('Retrigger', () => {
mockedGetLocationOrigin.mockImplementation(() => 'http://localhost:3000');
});
+ async function openRetriggerConfigModal(
+ compareResult: typeof result = result,
+ ) {
+ setUpUserCredentials();
+ render();
+
+ const openModalButton = await screen.findByRole('button', {
+ name: 'retrigger jobs',
+ });
+
+ const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
+ await user.click(openModalButton);
+
+ return {
+ baseSelect: await screen.findByLabelText('Base'),
+ newSelect: await screen.findByLabelText('New'),
+ };
+ }
+
it('should display Sign In modal when there are no credentials', async () => {
render();
@@ -267,6 +286,47 @@ describe('Retrigger', () => {
expect(new MockedHooks().triggerHook).toHaveBeenCalled();
});
+
+ it('should disable the Base dropdown when there are no base retriggerable jobs', async () => {
+ const { baseSelect, newSelect } = await openRetriggerConfigModal({
+ ...result,
+ base_retriggerable_job_ids: [],
+ });
+
+ // MUI Select uses a combobox div with aria-disabled rather than native disabled.
+ expect(baseSelect).toHaveAttribute('aria-disabled', 'true');
+ expect(baseSelect).toHaveTextContent('0');
+ expect(newSelect).not.toHaveAttribute('aria-disabled', 'true');
+ expect(newSelect).toHaveTextContent('5');
+ expect(screen.getByRole('button', { name: 'Retrigger' })).toBeEnabled();
+ });
+
+ it('should disable the New dropdown when there are no new retriggerable jobs', async () => {
+ const { baseSelect, newSelect } = await openRetriggerConfigModal({
+ ...result,
+ new_retriggerable_job_ids: [],
+ });
+
+ expect(baseSelect).not.toHaveAttribute('aria-disabled', 'true');
+ expect(baseSelect).toHaveTextContent('5');
+ expect(newSelect).toHaveAttribute('aria-disabled', 'true');
+ expect(newSelect).toHaveTextContent('0');
+ expect(screen.getByRole('button', { name: 'Retrigger' })).toBeEnabled();
+ });
+
+ it('should disable both dropdowns when there are no retriggerable jobs', async () => {
+ const { baseSelect, newSelect } = await openRetriggerConfigModal({
+ ...result,
+ base_retriggerable_job_ids: [],
+ new_retriggerable_job_ids: [],
+ });
+
+ expect(baseSelect).toHaveAttribute('aria-disabled', 'true');
+ expect(baseSelect).toHaveTextContent('0');
+ expect(newSelect).toHaveAttribute('aria-disabled', 'true');
+ expect(newSelect).toHaveTextContent('0');
+ expect(screen.getByRole('button', { name: 'Retrigger' })).toBeDisabled();
+ });
});
describe('Retrigger in Subtests view', () => {
diff --git a/src/components/CompareResults/Retrigger/RetriggerButton.tsx b/src/components/CompareResults/Retrigger/RetriggerButton.tsx
index 520be1425..7c4f5bc96 100644
--- a/src/components/CompareResults/Retrigger/RetriggerButton.tsx
+++ b/src/components/CompareResults/Retrigger/RetriggerButton.tsx
@@ -210,6 +210,8 @@ export function RetriggerButton({ result, variant }: RetriggerButtonProps) {
open={status === 'retrigger-modal'}
onClose={() => setStatus('pending')}
onRetriggerClick={onRetriggerConfirm}
+ hasBaseJobs={baseRetriggerableJobIds.length > 0}
+ hasNewJobs={newRetriggerableJobIds.length > 0}
/>
>
);
diff --git a/src/components/CompareResults/Retrigger/RetriggerConfigModal.tsx b/src/components/CompareResults/Retrigger/RetriggerConfigModal.tsx
index 32220adb2..569be654d 100644
--- a/src/components/CompareResults/Retrigger/RetriggerConfigModal.tsx
+++ b/src/components/CompareResults/Retrigger/RetriggerConfigModal.tsx
@@ -16,17 +16,24 @@ const retriggerStrings = Strings.components.retrigger.config;
function RetriggerCountSelect({
prefix,
label,
+ disabled = false,
}: {
prefix: string;
label: string;
+ disabled?: boolean;
}) {
return (
-
+
{label}
+ {/*
+ defaultValue is safe here because CenteredModal unmounts when closed,
+ so the select remounts with a fresh default each time the modal opens.
+ FormControl's disabled state is passed to Select via context.
+ */}