diff --git a/playwright/Basic/imageMode.spec.ts b/playwright/Basic/imageMode.spec.ts
index 3199d2f9c3..6e5c6c4674 100644
--- a/playwright/Basic/imageMode.spec.ts
+++ b/playwright/Basic/imageMode.spec.ts
@@ -81,7 +81,7 @@ test('Image mode blueprint create, edit, export, import', async ({
).toBeHidden();
// but the guest image is
await expect(
- frame.getByRole('radio', { name: 'Virtualization' }),
+ frame.getByRole('radio', { name: /^Virtualization/ }),
).toBeVisible();
imageSourceDropdown = frame.getByRole('button', {
@@ -119,7 +119,7 @@ test('Image mode blueprint create, edit, export, import', async ({
frame.getByRole('radio', { name: 'Microsoft Azure' }),
).toBeVisible();
- await frame.getByRole('radio', { name: 'Virtualization' }).click();
+ await frame.getByRole('radio', { name: /^Virtualization/ }).click();
});
await test.step('Create blueprint', async () => {
@@ -146,10 +146,10 @@ test('Image mode blueprint create, edit, export, import', async ({
).toBeVisible();
await expect(
- frame.getByRole('radio', { name: 'Virtualization' }),
+ frame.getByRole('radio', { name: /^Virtualization/ }),
).toBeVisible();
await expect(
- frame.getByRole('radio', { name: 'Virtualization' }),
+ frame.getByRole('radio', { name: /^Virtualization/ }),
).toBeChecked();
});
@@ -187,7 +187,7 @@ test('Image mode blueprint create, edit, export, import', async ({
await expect(importedImageMode).toHaveAttribute('aria-pressed', 'true');
// Export doesn't include image_requests, so image types must be re-selected
- await frame.getByRole('radio', { name: 'Virtualization' }).click();
+ await frame.getByRole('radio', { name: /^Virtualization/ }).click();
// Change the name to avoid "name already exists" conflict
await frame
diff --git a/playwright/BootTests/ImageMode/ImageMode.boot.ts b/playwright/BootTests/ImageMode/ImageMode.boot.ts
index 497c82a8a9..0d38bef8db 100644
--- a/playwright/BootTests/ImageMode/ImageMode.boot.ts
+++ b/playwright/BootTests/ImageMode/ImageMode.boot.ts
@@ -72,7 +72,7 @@ test('Image mode boot integration test', async ({ page, cleanup }) => {
await rhelSourceOption.click();
// In image mode, arch is determined by the image source, so we only select the target
- await frame.getByRole('radio', { name: 'Virtualization' }).click();
+ await frame.getByRole('radio', { name: /^Virtualization/ }).click();
});
await test.step('Create blueprint', async () => {
diff --git a/playwright/Cockpit/cockpit.spec.ts b/playwright/Cockpit/cockpit.spec.ts
index 6ba31d6a9f..765cc9aa09 100644
--- a/playwright/Cockpit/cockpit.spec.ts
+++ b/playwright/Cockpit/cockpit.spec.ts
@@ -92,7 +92,7 @@ test('Cockpit AWS cloud upload', async ({ page, cleanup }) => {
await expect(
frame.getByRole('heading', { name: 'Base settings' }),
).toBeVisible();
- await frame.getByRole('checkbox', { name: /amazon web services/i }).click();
+ await frame.getByRole('radio', { name: /amazon web services/i }).click();
await registerLater(frame);
await frame.getByRole('button', { name: 'Review image' }).click();
await frame.getByRole('button', { name: 'Back', exact: true }).click();
diff --git a/playwright/Customizations/Filesystem.spec.ts b/playwright/Customizations/Filesystem.spec.ts
index 3744806470..203fed7dc7 100644
--- a/playwright/Customizations/Filesystem.spec.ts
+++ b/playwright/Customizations/Filesystem.spec.ts
@@ -261,18 +261,7 @@ test('Filesystem configuration is hidden for ISO target only', async ({
await fillInDetails(frame, blueprintName);
await test.step('Select only ISO target', async () => {
- await fillInImageOutput(frame);
- const imageInstallerCheckbox = frame.getByRole('checkbox', {
- name: /bare metal installer/i,
- });
- await imageInstallerCheckbox.click();
-
- const guestImageCheckbox = frame.getByRole('checkbox', {
- name: /virtualization guest image/i,
- });
- if (await guestImageCheckbox.isChecked()) {
- await guestImageCheckbox.click();
- }
+ await fillInImageOutput(frame, 'iso');
});
await test.step('Verify filesystem configuration is not available', async () => {
@@ -284,48 +273,3 @@ test('Filesystem configuration is hidden for ISO target only', async ({
).toBeHidden();
});
});
-
-test('Filesystem configuration is available for ISO and other target', async ({
- page,
- cleanup,
-}) => {
- const blueprintName = 'test-' + crypto.randomUUID();
- cleanup.add(() => deleteBlueprint(page, blueprintName));
-
- await ensureAuthenticated(page);
- await navigateToLandingPage(page);
- const frame = ibFrame(page);
- await openWizard(frame);
- await fillInDetails(frame, blueprintName);
-
- await test.step('Select ISO and guest image targets', async () => {
- await fillInImageOutput(frame);
- const imageInstallerCheckbox = frame.getByRole('checkbox', {
- name: /bare metal installer/i,
- });
- await imageInstallerCheckbox.click();
-
- const guestImageCheckbox = frame.getByRole('checkbox', {
- name: /virtualization guest image/i,
- });
- if (!(await guestImageCheckbox.isChecked())) {
- await guestImageCheckbox.click();
- }
- });
-
- await test.step('Verify manual partitioning is available', async () => {
- await registerLater(frame);
- await frame.getByRole('button', { name: /Advanced settings/ }).click();
-
- await frame
- .getByRole('button', { name: /Automatic partitioning/i })
- .click();
- await frame
- .getByRole('option', { name: /Basic filesystem partitioning/i })
- .click();
-
- await expect(
- frame.getByRole('button', { name: /Basic filesystem partitioning/i }),
- ).toBeVisible();
- });
-});
diff --git a/playwright/Customizations/OpenSCAP.spec.ts b/playwright/Customizations/OpenSCAP.spec.ts
index 4fddf4ecbb..9c81c9ceb8 100644
--- a/playwright/Customizations/OpenSCAP.spec.ts
+++ b/playwright/Customizations/OpenSCAP.spec.ts
@@ -47,14 +47,9 @@ test('Create a blueprint with OpenSCAP customization', async ({
await fillInDetails(frame, blueprintName);
});
- await test.step('WSL + Installer shows WSL is not supported', async () => {
- await fillInImageOutput(frame, 'wsl', 'rhel9');
- await frame.getByRole('checkbox', { name: 'Bare metal installer' }).click();
+ await test.step('Select target and register later', async () => {
+ await fillInImageOutput(frame, 'qcow2', 'rhel9');
await registerLater(frame);
-
- await expect(
- frame.getByText('WSL: customization is not supported'),
- ).toBeVisible();
});
await test.step('Select a CIS profile then switch to None', async () => {
diff --git a/playwright/Customizations/TargetEnvironments/Azure.spec.ts b/playwright/Customizations/TargetEnvironments/Azure.spec.ts
index 0c5bcd77c3..ba6955170e 100644
--- a/playwright/Customizations/TargetEnvironments/Azure.spec.ts
+++ b/playwright/Customizations/TargetEnvironments/Azure.spec.ts
@@ -164,20 +164,16 @@ test('Deselecting Azure removes its config from the blueprint', async ({
.fill(RESOURCE_GROUP);
});
- await test.step('Go back and deselect Azure', async () => {
+ await test.step('Go back and select a different target', async () => {
await frame.getByRole('button', { name: 'Base settings' }).click();
- await selectTarget(frame, 'azure');
+ await frame.getByRole('radio', { name: /^Virtualization/i }).click();
await expect(
- frame.getByRole('checkbox', { name: 'Microsoft Azure' }),
+ frame.getByRole('radio', { name: 'Microsoft Azure' }),
).not.toBeChecked();
});
- await test.step('Select Guest Image and continue', async () => {
- await frame.getByRole('checkbox', { name: /Virtualization/i }).click();
- });
-
await test.step('Navigate to review and verify no Azure details', async () => {
await registerLater(frame);
await frame.getByRole('button', { name: 'Review image' }).click();
diff --git a/playwright/Import/Import.spec.ts b/playwright/Import/Import.spec.ts
index f56cbd2423..e5aceaf5e3 100644
--- a/playwright/Import/Import.spec.ts
+++ b/playwright/Import/Import.spec.ts
@@ -46,7 +46,7 @@ test('Import a blueprint with invalid customization', async ({
});
await test.step('Select Virtualization and register later', async () => {
- await frame.getByRole('checkbox', { name: 'Virtualization' }).click();
+ await frame.getByRole('radio', { name: /^Virtualization/ }).click();
await registerLater(frame);
});
diff --git a/playwright/helpers/navHelpers.ts b/playwright/helpers/navHelpers.ts
index 67a5ff89af..3023f3dd67 100644
--- a/playwright/helpers/navHelpers.ts
+++ b/playwright/helpers/navHelpers.ts
@@ -43,7 +43,7 @@ export const fillInImageOutput = async (
if (target) {
await selectTarget(page, target);
} else {
- await page.getByRole('checkbox', { name: 'Virtualization' }).click();
+ await page.getByRole('radio', { name: /^Virtualization/ }).click();
}
};
diff --git a/playwright/helpers/targetChooser.ts b/playwright/helpers/targetChooser.ts
index 138c62cc12..7c03457364 100644
--- a/playwright/helpers/targetChooser.ts
+++ b/playwright/helpers/targetChooser.ts
@@ -13,30 +13,30 @@ export const selectTarget = async (
*/
switch (target) {
case 'qcow2':
- await page.getByRole('checkbox', { name: 'Virtualization' }).click();
+ await page.getByRole('radio', { name: /^Virtualization/ }).click();
break;
case 'iso':
- await page.getByRole('checkbox', { name: 'Bare metal' }).click();
+ await page.getByRole('radio', { name: 'Bare metal' }).click();
break;
case 'wsl':
await page
- .getByRole('checkbox', { name: 'Windows Subsystem for Linux' })
+ .getByRole('radio', { name: 'Windows Subsystem for Linux' })
.click();
break;
case 'ova':
await page
- .getByRole('checkbox', {
+ .getByRole('radio', {
name: 'VMware vSphere - Open virtualization format',
})
.click();
break;
case 'vmdk':
await page
- .getByRole('checkbox', { name: 'VMware vSphere - Virtual disk' })
+ .getByRole('radio', { name: 'VMware vSphere - Virtual disk' })
.click();
break;
case 'azure':
- await page.getByRole('checkbox', { name: /Microsoft Azure/ }).click();
+ await page.getByRole('radio', { name: /Microsoft Azure/ }).click();
break;
}
};
diff --git a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx
index cef5535840..cac32074c6 100644
--- a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx
+++ b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironment.tsx
@@ -33,6 +33,7 @@ import {
selectIsOnlyNetworkInstallerSelected,
selectIsoPayloadReference,
selectIsOtherEnvironmentSelected,
+ selectUseSingleTarget,
} from '@/store/slices/wizard';
import Aws from './Aws';
@@ -75,6 +76,7 @@ const TargetEnvironment = () => {
const isOtherEnvironmentSelected = useAppSelector(
selectIsOtherEnvironmentSelected,
);
+ const useSingleTarget = useAppSelector(selectUseSingleTarget);
const forceShowErrors = useAppSelector(selectForceShowErrors);
const { restrictions } = useCustomizationRestrictions({
@@ -196,7 +198,7 @@ const TargetEnvironment = () => {
fieldId='target-environments'
>
- {isImageMode
+ {isImageMode || useSingleTarget
? 'Select a target environment.'
: 'Select one or more target environments.'}
diff --git a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironmentOption.tsx b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironmentOption.tsx
index 2c6b6277a7..3e3659a879 100644
--- a/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironmentOption.tsx
+++ b/src/Components/CreateImageWizard/steps/ImageOutput/components/TargetEnvironmentOption.tsx
@@ -12,6 +12,7 @@ import {
removeImageType,
selectImageTypes,
selectIsImageMode,
+ selectUseSingleTarget,
type SupportedImageTypes,
} from '@/store/slices/wizard';
@@ -33,21 +34,27 @@ const TargetEnvironmentOption = ({
const dispatch = useAppDispatch();
const environments = useAppSelector(selectImageTypes);
const isImageMode = useAppSelector(selectIsImageMode);
+ const useSingleTarget = useAppSelector(selectUseSingleTarget);
const isChecked = environments.includes(environment);
+ const reinitializeCloudProvider = (env: SupportedImageTypes) => {
+ switch (env) {
+ case 'aws':
+ dispatch(reinitializeAws());
+ break;
+ case 'azure':
+ dispatch(reinitializeAzure());
+ break;
+ case 'gcp':
+ dispatch(reinitializeGcp());
+ break;
+ }
+ };
+
const handleToggle = () => {
if (isChecked) {
- switch (environment) {
- case 'aws':
- dispatch(reinitializeAws());
- break;
- case 'azure':
- dispatch(reinitializeAzure());
- break;
- case 'gcp':
- dispatch(reinitializeGcp());
- }
+ reinitializeCloudProvider(environment);
dispatch(removeImageType(environment));
} else {
dispatch(addImageType(environment));
@@ -55,10 +62,15 @@ const TargetEnvironmentOption = ({
};
const handleSelect = () => {
+ for (const prev of environments) {
+ if (prev !== environment) {
+ reinitializeCloudProvider(prev);
+ }
+ }
dispatch(changeImageTypes([environment]));
};
- if (isImageMode) {
+ if (isImageMode || useSingleTarget) {
return (
{
fetchMock.resetMocks();
});
+const multiTargetOverrides: WizardStateOverrides = {
+ output: {
+ ...initialState.output,
+ initialImageTypeCount: 2,
+ },
+};
+
describe('TargetEnvironment', () => {
describe('Rendering', () => {
test('renders target environment form group', async () => {
@@ -44,30 +55,30 @@ describe('TargetEnvironment', () => {
).toBeInTheDocument();
});
- test('shows public cloud targets for x86_64', async () => {
+ test('shows public cloud targets as radios in create mode', async () => {
renderTargetEnvironment();
expect(
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i }),
+ await screen.findByRole('radio', { name: /Amazon Web Services/i }),
).toBeInTheDocument();
expect(
- screen.getByRole('checkbox', { name: /Google Cloud/i }),
+ screen.getByRole('radio', { name: /Google Cloud/i }),
).toBeInTheDocument();
expect(
- screen.getByRole('checkbox', { name: /Microsoft Azure/i }),
+ screen.getByRole('radio', { name: /Microsoft Azure/i }),
).toBeInTheDocument();
});
- test('shows other target options', async () => {
+ test('shows other target options as radios in create mode', async () => {
renderTargetEnvironment();
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i });
+ await screen.findByRole('radio', { name: /Amazon Web Services/i });
expect(
- screen.getByRole('checkbox', { name: /Virtualization guest image/i }),
+ screen.getByRole('radio', { name: /Virtualization.*Guest image/i }),
).toBeInTheDocument();
expect(
- screen.getByRole('checkbox', { name: /Bare metal installer/i }),
+ screen.getByRole('radio', { name: /Bare metal.*Installer/i }),
).toBeInTheDocument();
});
@@ -81,61 +92,63 @@ describe('TargetEnvironment', () => {
});
});
- describe('Target selection', () => {
- test('clicking AWS checkbox properly adds and removes aws from image types', async () => {
+ describe('Single-target selection (create mode)', () => {
+ test('selecting a radio adds the target to image types', async () => {
const user = createUser();
const { store } = renderTargetEnvironment();
- await clickTargetCheckbox(user, /Amazon Web Services/i);
- expect(selectImageTypes(store.getState())).toContain('aws');
-
- await clickTargetCheckbox(user, /Amazon Web Services/i);
- expect(selectImageTypes(store.getState())).not.toContain('aws');
+ await clickTargetRadio(user, /Amazon Web Services/i);
+ expect(selectImageTypes(store.getState())).toEqual(['aws']);
});
- test('clicking Google Cloud checkbox adds gcp to image types', async () => {
+ test('selecting a different radio replaces the previous selection', async () => {
const user = createUser();
const { store } = renderTargetEnvironment();
- await clickTargetCheckbox(user, /Google Cloud/i);
+ await clickTargetRadio(user, /Amazon Web Services/i);
+ expect(selectImageTypes(store.getState())).toEqual(['aws']);
- expect(selectImageTypes(store.getState())).toContain('gcp');
+ await clickTargetRadio(user, /Google Cloud/i);
+ expect(selectImageTypes(store.getState())).toEqual(['gcp']);
});
- test('clicking Azure checkbox adds azure to image types', async () => {
+ test('radio shows checked state when selected', async () => {
const user = createUser();
- const { store } = renderTargetEnvironment();
+ renderTargetEnvironment();
- await clickTargetCheckbox(user, /Microsoft Azure/i);
+ const radio = await screen.findByRole('radio', {
+ name: /Amazon Web Services/i,
+ });
- expect(selectImageTypes(store.getState())).toContain('azure');
- });
+ await clickTargetRadio(user, /Amazon Web Services/i);
- test('clicking guest image checkbox properly addd and removes guest-image from image types', async () => {
- const user = createUser();
- const { store } = renderTargetEnvironment();
+ expect(radio).toBeChecked();
+ });
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i });
- await clickTargetCheckbox(user, /Virtualization guest image/i);
- expect(selectImageTypes(store.getState())).toContain('guest-image');
+ test('shows singular helper text', async () => {
+ renderTargetEnvironment();
- await clickTargetCheckbox(user, /Virtualization guest image/i);
- expect(selectImageTypes(store.getState())).not.toContain('guest-image');
+ expect(
+ await screen.findByText('Select a target environment.'),
+ ).toBeInTheDocument();
});
+ });
- test('clicking bare metal checkbox adds image-installer to image types', async () => {
- const user = createUser();
- const { store } = renderTargetEnvironment();
-
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i });
- await clickTargetCheckbox(user, /Bare metal installer/i);
+ describe('Multi-target selection (edit with multiple targets)', () => {
+ test('renders checkboxes when initialImageTypeCount > 1', async () => {
+ renderTargetEnvironment(multiTargetOverrides);
- expect(selectImageTypes(store.getState())).toContain('image-installer');
+ expect(
+ await screen.findByRole('checkbox', {
+ name: /Amazon Web Services checkbox/i,
+ }),
+ ).toBeInTheDocument();
+ expect(screen.queryAllByRole('radio')).toHaveLength(0);
});
test('can select multiple targets', async () => {
const user = createUser();
- const { store } = renderTargetEnvironment();
+ const { store } = renderTargetEnvironment(multiTargetOverrides);
await clickTargetCheckbox(user, /Amazon Web Services/i);
await clickTargetCheckbox(user, /Google Cloud/i);
@@ -146,21 +159,63 @@ describe('TargetEnvironment', () => {
expect(imageTypes).toContain('gcp');
expect(imageTypes).toContain('guest-image');
});
- });
- describe('Visual state', () => {
- test('checkbox shows checked state when selected', async () => {
+ test('clicking a checkbox toggles the target', async () => {
const user = createUser();
- renderTargetEnvironment();
+ const { store } = renderTargetEnvironment(multiTargetOverrides);
+
+ await clickTargetCheckbox(user, /Amazon Web Services/i);
+ expect(selectImageTypes(store.getState())).toContain('aws');
+
+ await clickTargetCheckbox(user, /Amazon Web Services/i);
+ expect(selectImageTypes(store.getState())).not.toContain('aws');
+ });
+
+ test('shows plural helper text', async () => {
+ renderTargetEnvironment(multiTargetOverrides);
+
+ expect(
+ await screen.findByText('Select one or more target environments.'),
+ ).toBeInTheDocument();
+ });
+
+ test('still shows checkboxes after unchecking down to one target', async () => {
+ const user = createUser();
+ renderTargetEnvironment({
+ output: {
+ ...initialState.output,
+ imageTypes: ['aws', 'gcp', 'guest-image'],
+ initialImageTypeCount: 3,
+ },
+ });
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i });
- const checkbox = screen.getByRole('checkbox', {
- name: /Virtualization guest image/i,
+ await screen.findByRole('checkbox', {
+ name: /Amazon Web Services checkbox/i,
});
- await clickTargetCheckbox(user, /Virtualization guest image/i);
+ await clickTargetCheckbox(user, /Amazon Web Services/i);
+ await clickTargetCheckbox(user, /Google Cloud/i);
- expect(checkbox).toBeChecked();
+ expect(
+ screen.getByRole('checkbox', {
+ name: /Virtualization guest image checkbox/i,
+ }),
+ ).toBeInTheDocument();
+ });
+
+ test('renders radios when editing a single-target blueprint', async () => {
+ renderTargetEnvironment({
+ output: {
+ ...initialState.output,
+ imageTypes: ['aws'],
+ initialImageTypeCount: 1,
+ },
+ });
+
+ expect(
+ await screen.findByRole('radio', { name: /Amazon Web Services/i }),
+ ).toBeInTheDocument();
+ expect(screen.queryAllByRole('checkbox')).toHaveLength(0);
});
});
@@ -178,16 +233,23 @@ describe('TargetEnvironment', () => {
output: {
...initialState.output,
imageTypes: ['network-installer'],
+ initialImageTypeCount: 2,
},
});
- await screen.findByRole('checkbox', { name: /Network installer/i });
+ await screen.findByRole('checkbox', {
+ name: /Network installer checkbox/i,
+ });
expect(
- screen.getByRole('checkbox', { name: /Virtualization guest image/i }),
+ screen.getByRole('checkbox', {
+ name: /Virtualization guest image checkbox/i,
+ }),
).toBeDisabled();
expect(
- screen.getByRole('checkbox', { name: /Bare metal installer/i }),
+ screen.getByRole('checkbox', {
+ name: /Bare metal installer checkbox/i,
+ }),
).toBeDisabled();
});
@@ -196,6 +258,7 @@ describe('TargetEnvironment', () => {
output: {
...initialState.output,
imageTypes: ['network-installer'],
+ initialImageTypeCount: 2,
},
});
@@ -211,21 +274,27 @@ describe('TargetEnvironment', () => {
output: {
...initialState.output,
imageTypes: ['guest-image'],
+ initialImageTypeCount: 2,
},
});
const networkInstallerCheckbox = await screen.findByRole('checkbox', {
- name: /Network installer/i,
+ name: /Network installer checkbox/i,
});
expect(networkInstallerCheckbox).toBeDisabled();
});
test('network installer checkbox is enabled when no other targets selected', async () => {
- renderTargetEnvironment();
+ renderTargetEnvironment({
+ output: {
+ ...initialState.output,
+ initialImageTypeCount: 2,
+ },
+ });
const networkInstallerCheckbox = await screen.findByRole('checkbox', {
- name: /Network installer/i,
+ name: /Network installer checkbox/i,
});
expect(networkInstallerCheckbox).toBeEnabled();
diff --git a/src/Components/CreateImageWizard/steps/ImageOutput/tests/helpers.tsx b/src/Components/CreateImageWizard/steps/ImageOutput/tests/helpers.tsx
index f93401a2ea..9157026d0e 100644
--- a/src/Components/CreateImageWizard/steps/ImageOutput/tests/helpers.tsx
+++ b/src/Components/CreateImageWizard/steps/ImageOutput/tests/helpers.tsx
@@ -106,6 +106,14 @@ export const clickTargetCheckbox = async (
const checkbox = await screen.findByRole('checkbox', { name: checkboxLabel });
await clickWithWait(user, checkbox);
};
+
+export const clickTargetRadio = async (
+ user: UserEventInstance,
+ radioLabel: RegExp | string,
+) => {
+ const radio = await screen.findByRole('radio', { name: radioLabel });
+ await clickWithWait(user, radio);
+};
// BlueprintMode render function (uses on-premise store)
export const renderBlueprintMode = (
wizardStateOverrides: WizardStateOverrides = {},
diff --git a/src/Components/CreateImageWizard/tests/CreateMode.test.tsx b/src/Components/CreateImageWizard/tests/CreateMode.test.tsx
index 0bdbf3c693..565b59ff65 100644
--- a/src/Components/CreateImageWizard/tests/CreateMode.test.tsx
+++ b/src/Components/CreateImageWizard/tests/CreateMode.test.tsx
@@ -3,7 +3,7 @@ import { vi } from 'vitest';
import { composeHandlers, createArchitecturesHandler } from '@/test/testUtils';
-import { renderCreateMode, testCheckbox } from './helpers';
+import { renderCreateMode, testRadio } from './helpers';
import {
createDefaultFetchHandler,
fetchMock,
@@ -76,7 +76,7 @@ describe('Keyboard accessibility', () => {
fetchMock.disableMocks();
});
- test('target environment checkboxes are keyboard selectable', async () => {
+ test('target environment radios are keyboard selectable', async () => {
await renderCreateMode();
await waitFor(() =>
@@ -87,14 +87,8 @@ describe('Keyboard accessibility', () => {
).not.toBeInTheDocument(),
);
- await testCheckbox(
- await screen.findByRole('checkbox', { name: /Amazon Web Services/i }),
- );
- await testCheckbox(
- await screen.findByRole('checkbox', { name: /Google Cloud/i }),
- );
- await testCheckbox(
- await screen.findByRole('checkbox', { name: /Microsoft Azure/i }),
+ await testRadio(
+ await screen.findByRole('radio', { name: /Amazon Web Services/i }),
);
});
});
diff --git a/src/Components/CreateImageWizard/tests/helpers.tsx b/src/Components/CreateImageWizard/tests/helpers.tsx
index d559dee536..4641ecb0e9 100644
--- a/src/Components/CreateImageWizard/tests/helpers.tsx
+++ b/src/Components/CreateImageWizard/tests/helpers.tsx
@@ -147,19 +147,19 @@ export const renderImportMode = async (
});
};
-export const testCheckbox = async (checkbox: HTMLElement) => {
+export const testRadio = async (radio: HTMLElement) => {
const user = createUser();
- checkbox.focus();
+ radio.focus();
await keyboardWithWait(user, ' ');
- expect(checkbox).toBeChecked();
+ expect(radio).toBeChecked();
};
export const selectGuestImage = async (user: UserEventInstance) => {
await clickWithWait(
user,
- await screen.findByRole('checkbox', {
- name: /virtualization guest image/i,
+ await screen.findByRole('radio', {
+ name: /virtualization.*guest image/i,
}),
);
};
diff --git a/src/store/slices/wizard/output/parsers.ts b/src/store/slices/wizard/output/parsers.ts
index d0e7ea0be5..413cc0f7ee 100644
--- a/src/store/slices/wizard/output/parsers.ts
+++ b/src/store/slices/wizard/output/parsers.ts
@@ -69,12 +69,16 @@ const parseImageSourceType = ({ bootc }: RequestLike): ImageSourceType => {
return 'official';
};
-export const parseOutputFromRequest = (request: RequestLike): OutputSlice => ({
- architecture: parseArchitecture(request),
- distribution: parseDistribution(request),
- imageTypes: parseImageTypes(request),
- imageSource: parseImageSource(request),
- imageSourceType: parseImageSourceType(request),
- isoPayloadReference: parseIsoPayloadRef(request),
- bootcDistributions: [],
-});
+export const parseOutputFromRequest = (request: RequestLike): OutputSlice => {
+ const imageTypes = parseImageTypes(request);
+ return {
+ architecture: parseArchitecture(request),
+ distribution: parseDistribution(request),
+ imageTypes,
+ imageSource: parseImageSource(request),
+ imageSourceType: parseImageSourceType(request),
+ isoPayloadReference: parseIsoPayloadRef(request),
+ bootcDistributions: [],
+ initialImageTypeCount: imageTypes.length,
+ };
+};
diff --git a/src/store/slices/wizard/output/selectors.ts b/src/store/slices/wizard/output/selectors.ts
index 8b4650a5d5..76b0fecb8e 100644
--- a/src/store/slices/wizard/output/selectors.ts
+++ b/src/store/slices/wizard/output/selectors.ts
@@ -49,6 +49,15 @@ export const selectIsOfficialImage = createSelector(
(imageSource) => !!imageSource && isKnownImageRef(imageSource),
);
+export const selectInitialImageTypeCount = (state: RootState) => {
+ return state.wizard.output.initialImageTypeCount;
+};
+
+export const selectUseSingleTarget = createSelector(
+ selectInitialImageTypeCount,
+ (initialCount) => initialCount <= 1,
+);
+
export const selectImageSourceFilter = createSelector(
selectIsOnPremise,
selectImageSource,
diff --git a/src/store/slices/wizard/output/state.ts b/src/store/slices/wizard/output/state.ts
index 724da67d6b..d7bf66bcc8 100644
--- a/src/store/slices/wizard/output/state.ts
+++ b/src/store/slices/wizard/output/state.ts
@@ -8,4 +8,5 @@ export const initialState: OutputSlice = {
distribution: RHEL_10,
imageSourceType: 'official',
imageTypes: [],
+ initialImageTypeCount: 0,
};
diff --git a/src/store/slices/wizard/output/tests/parsers.test.ts b/src/store/slices/wizard/output/tests/parsers.test.ts
index 46307e8f82..8f1d360446 100644
--- a/src/store/slices/wizard/output/tests/parsers.test.ts
+++ b/src/store/slices/wizard/output/tests/parsers.test.ts
@@ -64,6 +64,7 @@ describe('parseOutputFromRequest', () => {
isoPayloadReference: undefined,
imageTypes: ['guest-image'],
bootcDistributions: [],
+ initialImageTypeCount: 1,
});
});
diff --git a/src/store/slices/wizard/output/types.ts b/src/store/slices/wizard/output/types.ts
index 7a457b7b92..5f39d590a1 100644
--- a/src/store/slices/wizard/output/types.ts
+++ b/src/store/slices/wizard/output/types.ts
@@ -36,4 +36,5 @@ export type OutputSlice = {
architecture: ImageRequest['architecture'];
distribution: Distributions;
imageTypes: SupportedImageTypes[];
+ initialImageTypeCount: number;
};