Skip to content

Commit

Permalink
Wizard: Swap kernel name input with drop down
Browse files Browse the repository at this point in the history
This replaces the kernel name input with a static drop down populated with valid values.
  • Loading branch information
regexowl committed Jan 9, 2025
1 parent 2516e14 commit 0a309fd
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 88 deletions.
9 changes: 1 addition & 8 deletions src/Components/CreateImageWizard/CreateImageWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
useDetailsValidation,
useRegistrationValidation,
useHostnameValidation,
useKernelValidation,
} from './utilities/useValidation';
import {
isAwsAccountIdValid,
Expand Down Expand Up @@ -222,8 +221,6 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
const fileSystemValidation = useFilesystemValidation();
// Hostname
const hostnameValidation = useHostnameValidation();
// Kernel
const kernelValidation = useKernelValidation();
// Firstboot
const firstBootValidation = useFirstBootValidation();
// Details
Expand Down Expand Up @@ -511,12 +508,8 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
key="wizard-kernel"
navItem={customStatusNavItem}
isHidden={!isKernelEnabled}
status={kernelValidation.disabledNext ? 'error' : 'default'}
footer={
<CustomWizardFooter
disableNext={kernelValidation.disabledNext}
optional={true}
/>
<CustomWizardFooter disableNext={false} optional={true} />
}
>
<KernelStep />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,86 @@
import React from 'react';
import React, { useState } from 'react';

import { FormGroup } from '@patternfly/react-core';
import {
MenuToggle,
MenuToggleElement,
Select,
SelectList,
SelectOption,
} from '@patternfly/react-core/dist/esm';

import { useAppDispatch, useAppSelector } from '../../../../../store/hooks';
import {
changeKernelName,
selectKernel,
} from '../../../../../store/wizardSlice';
import { useKernelValidation } from '../../../utilities/useValidation';
import { HookValidatedInput } from '../../../ValidatedTextInput';

const kernelOptions = ['kernel', 'kernel-debug'];

const KernelName = () => {
const dispatch = useAppDispatch();
const kernel = useAppSelector(selectKernel);

const stepValidation = useKernelValidation();
const [isOpen, setIsOpen] = useState(false);

const onToggle = () => {
setIsOpen(!isOpen);
};

const onSelect = (_event: React.MouseEvent, value: string) => {
if (value === 'default') {
dispatch(changeKernelName(''));
} else {
dispatch(changeKernelName(value));
}
setIsOpen(false);
};

const handleChange = (e: React.FormEvent, value: string) => {
dispatch(changeKernelName(value));
const defaultOption = () => {
return (
<SelectOption key="default" value="default">
Default kernel package
</SelectOption>
);
};

const prepareSelectOptions = () => {
const kernelSelectOptions = kernelOptions.map((option) => (
<SelectOption key={option} value={option}>
{option}
</SelectOption>
));

if (kernel.name) {
return [defaultOption()].concat(kernelSelectOptions);
} else return kernelSelectOptions;
};

const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
ref={toggleRef}
onClick={onToggle}
isExpanded={isOpen}
isFullWidth
data-testid="kernel-name-dropdown"
>
{kernel.name}
</MenuToggle>
);

return (
<FormGroup isRequired={false} label="Name">
<HookValidatedInput
ariaLabel="kernel input"
value={kernel.name}
onChange={handleChange}
placeholder="Add a kernel name"
stepValidation={stepValidation}
fieldName="kernel"
/>
<Select
isScrollable
isOpen={isOpen}
selected={kernel.name}
onSelect={onSelect}
onOpenChange={onToggle}
toggle={toggle}
shouldFocusFirstItemOnOpen={false}
>
<SelectList>{prepareSelectOptions()}</SelectList>
</Select>
</FormGroup>
);
};
Expand Down
18 changes: 0 additions & 18 deletions src/Components/CreateImageWizard/utilities/useValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
selectActivationKey,
selectRegistrationType,
selectHostname,
selectKernel,
} from '../../../store/wizardSlice';
import {
getDuplicateMountPoints,
Expand All @@ -28,7 +27,6 @@ import {
isMountpointMinSizeValid,
isSnapshotValid,
isHostnameValid,
isKernelNameValid,
} from '../validators';

export type StepValidation = {
Expand All @@ -43,15 +41,13 @@ export function useIsBlueprintValid(): boolean {
const filesystem = useFilesystemValidation();
const snapshot = useSnapshotValidation();
const hostname = useHostnameValidation();
const kernel = useKernelValidation();
const firstBoot = useFirstBootValidation();
const details = useDetailsValidation();
return (
!registration.disabledNext &&
!filesystem.disabledNext &&
!snapshot.disabledNext &&
!hostname.disabledNext &&
!kernel.disabledNext &&
!firstBoot.disabledNext &&
!details.disabledNext
);
Expand Down Expand Up @@ -159,20 +155,6 @@ export function useHostnameValidation(): StepValidation {
return { errors: {}, disabledNext: false };
}

export function useKernelValidation(): StepValidation {
const kernel = useAppSelector(selectKernel);

if (!isKernelNameValid(kernel.name)) {
return {
errors: {
kernel: 'Invalid kernel name',
},
disabledNext: true,
};
}
return { errors: {}, disabledNext: false };
}

export function useDetailsValidation(): StepValidation {
const name = useAppSelector(selectBlueprintName);
const description = useAppSelector(selectBlueprintDescription);
Expand Down
11 changes: 0 additions & 11 deletions src/Components/CreateImageWizard/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,3 @@ export const isHostnameValid = (hostname: string) => {
)
);
};

export const isKernelNameValid = (kernelName: string) => {
if (!kernelName) {
return true;
}

return (
kernelName.length < 65 &&
/^[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(kernelName)
);
};
62 changes: 25 additions & 37 deletions src/test/Components/CreateImageWizard/steps/Kernel/Kernel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
clickBack,
clickNext,
enterBlueprintName,
getNextButton,
interceptBlueprintRequest,
openAndDismissSaveAndBuildModal,
verifyCancelButton,
Expand Down Expand Up @@ -44,20 +43,13 @@ const goToReviewStep = async () => {
await clickNext(); // Review
};

const enterKernelName = async (kernelName: string) => {
const selectKernelName = async (kernelName: string) => {
const user = userEvent.setup();
const kernelNameInput = await screen.findByPlaceholderText(
/Add a kernel name/i
);
await waitFor(() => user.type(kernelNameInput, kernelName));
};
const kernelNameDropdown = await screen.findByTestId('kernel-name-dropdown');
await waitFor(() => user.click(kernelNameDropdown));

const clearKernelName = async () => {
const user = userEvent.setup();
const kernelNameInput = await screen.findByPlaceholderText(
/Add a kernel name/i
);
await waitFor(() => user.clear(kernelNameInput));
const kernelOption = await screen.findByText(kernelName);
await waitFor(() => user.click(kernelOption));
};

describe('Step Kernel', () => {
Expand Down Expand Up @@ -87,38 +79,17 @@ describe('Step Kernel', () => {
await goToKernelStep();
await verifyCancelButton(router);
});

test('validation works', async () => {
await renderCreateMode();
await goToKernelStep();

// with empty kernel name input
const nextButton = await getNextButton();
expect(nextButton).toBeEnabled();

// invalid name
await enterKernelName('INVALID/NAME');
expect(nextButton).toBeDisabled();
await clickNext(); // dummy click to blur and render error (doesn't render when pristine)
await screen.findByText(/Invalid kernel name/);

// valid name
await clearKernelName();
await enterKernelName('valid-kernel-name');
expect(nextButton).toBeEnabled();
expect(screen.queryByText(/Invalid kernel name/)).not.toBeInTheDocument();
});
});

describe('Kernel request generated correctly', () => {
beforeEach(async () => {
vi.clearAllMocks();
});

test('with valid kernel name', async () => {
test('with kernel name', async () => {
await renderCreateMode();
await goToKernelStep();
await enterKernelName('kernel-name');
await selectKernelName('kernel-debug');
await goToReviewStep();
// informational modal pops up in the first test only as it's tied
// to a 'imageBuilder.saveAndBuildModalSeen' variable in localStorage
Expand All @@ -129,7 +100,7 @@ describe('Kernel request generated correctly', () => {
...blueprintRequest,
customizations: {
kernel: {
name: 'kernel-name',
name: 'kernel-debug',
},
},
};
Expand All @@ -138,6 +109,23 @@ describe('Kernel request generated correctly', () => {
expect(receivedRequest).toEqual(expectedRequest);
});
});

test('when unselecting kernel name', async () => {
await renderCreateMode();
await goToKernelStep();
await selectKernelName('kernel-debug');
await selectKernelName('Default kernel package');
await goToReviewStep();
const receivedRequest = await interceptBlueprintRequest(CREATE_BLUEPRINT);

const expectedRequest = {
...blueprintRequest,
};

await waitFor(() => {
expect(receivedRequest).toEqual(expectedRequest);
});
});
});

// TO DO 'Kernel step' -> 'revisit step button on Review works'
Expand Down

0 comments on commit 0a309fd

Please sign in to comment.