Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: [M3-8777] - Refactor CreateCluster component to use react-hook-form #11581

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from

Conversation

hasyed-akamai
Copy link
Contributor

@hasyed-akamai hasyed-akamai commented Jan 29, 2025

Description 📝

This PR refactors the CreateCluster component to use react-hook-form for form state management. It also removes the MultipleIPInput components for cleaner code.

Changes 🔄

  • Used React Hook Form for better state management

Target release date 🗓️

N/A

Verification steps

  • Check if the CreateCluster component's functionality is unaffected by the changes
Author Checklists

As an Author, to speed up the review process, I considered 🤔

👀 Doing a self review
❔ Our contribution guidelines
🤏 Splitting feature into small PRs
➕ Adding a changeset
🧪 Providing/improving test coverage
🔐 Removing all sensitive information from the code and PR description
🚩 Using a feature flag to protect the release
👣 Providing comprehensive reproduction steps
📑 Providing or updating our documentation
🕛 Scheduling a pair reviewing session
📱 Providing mobile support
♿ Providing accessibility support


  • I have read and considered all applicable items listed above.

As an Author, before moving this PR from Draft to Open, I confirmed ✅

  • All unit tests are passing
  • TypeScript compilation succeeded without errors
  • Code passes all linting rules

@hasyed-akamai hasyed-akamai marked this pull request as ready for review February 6, 2025 12:14
@hasyed-akamai hasyed-akamai requested review from a team as code owners February 6, 2025 12:14
@hasyed-akamai hasyed-akamai requested review from jdamore-linode, hana-akamai and harsh-akamai and removed request for a team February 6, 2025 12:14
Copy link

github-actions bot commented Feb 12, 2025

Coverage Report:
Base Coverage: 80.07%
Current Coverage: 80.03%

Comment on lines -261 to +260
cy.findAllByRole('alert').should('have.length', 1);
cy.get(notices.limitedAvailability).should('be.visible');
cy.findAllByRole('alert').should('have.length', 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the alert and limited availability notice the same thing?

Comment on lines -446 to +439
cy.get('[data-qa-plan-row="gpu-2 Ada"]').should(
'have.attr',
'disabled'
);
cy.get('[data-qa-plan-row="gpu-2 Ada"]').should('be.visible');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the context for this change? It seems like this PR is a refactor, so I'm a bit confused as to why some test cases are changing

@linode-gh-bot
Copy link
Collaborator

Cloud Manager UI test results

🔺 2 failing tests on test run #17 ↗︎

❌ Failing✅ Passing↪️ Skipped🕐 Duration
2 Failing498 Passing2 Skipped114m 31s

Details

Failing Tests
SpecTest
smoke-community-stackscripts.spec.tsCommunity Stackscripts integration tests » pagination works with infinite scrolling
smoke-community-stackscripts.spec.tsCommunity Stackscripts integration tests » deploys a new linode as expected

Troubleshooting

Use this command to re-run the failing tests:

yarn cy:run -s "cypress/e2e/core/stackscripts/smoke-community-stackscripts.spec.ts"

Comment on lines +61 to +84
React.useEffect(() => {
if (enableControlPlaneACL) {
if (
(!ipv4Addresses || ipv4Addresses.length === 0) &&
!ipv4Fields.length
) {
appendIPv4('');
}
if (
(!ipv6Addresses || ipv6Addresses.length === 0) &&
!ipv6Fields.length
) {
appendIPv6('');
}
}
}, [
enableControlPlaneACL,
ipv4Addresses,
ipv6Addresses,
ipv4Fields,
ipv6Fields,
appendIPv4,
appendIPv6,
]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this here using a useEffect, can we just do this in the initialValues function of useForm?

Comment on lines 66 to 68
const [version, setVersion] = React.useState<string | undefined>();
const [errors, setErrors] = React.useState<APIError[] | undefined>();
const [submitting, setSubmitting] = React.useState<boolean>(false);
const [hasAgreed, setAgreed] = React.useState<boolean>(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to use react-hook-form, it should ideally manage all of the form's state. All of of these states should be removed

Comment on lines +119 to +122
React.useEffect(() => {
if (versions.length > 0) {
setVersion(getLatestVersion(versions).value);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than using a useEffect, we should probably use an async defaultValues function for this form's useForm that sets version to the latest version.

It would look something very roughly like this:

const {
  control,
  getValues,
  handleSubmit,
  setValue,
  watch,
} = useForm<CreateKubeClusterPayload>({
  async defaultValues() {
    const versions = await queryClient.ensureQueryData(kubernetesQueries.versions)
    
    return {
      k8s_version: getLatestVersion(versions)
    };
  },
});

scrollErrorIntoViewV2(formContainerRef);
return;
}
const createCluster = (formData: any) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const createCluster = (formData: any) => {
const createCluster = (formData: CreateKubeClusterPayload) => {

@@ -301,208 +286,306 @@ export const CreateCluster = () => {
isSelectedRegionEligibleForPlan,
} = plansNoticesUtils({
regionsData,
selectedRegionID: selectedRegion?.id,
selectedRegionID: '',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to pass the selected region ID?

Comment on lines +297 to +303
handleClusterTypeSelection={handleClusterTypeSelection}
selectedTier={selectedTier}
/>
</>
)}
<Divider sx={{ marginTop: 4 }} />
<StyledFieldWithDocsStack>
<Stack>
<RegionSelect
currentCapability={
isLkeEnterpriseLAFeatureEnabled &&
selectedTier === 'enterprise'
? 'Kubernetes Enterprise'
: 'Kubernetes'
}
textFieldProps={{
helperText: <RegionHelperText mb={2} />,
helperTextPosition: 'top',
}}
tooltipText={
isLkeEnterpriseLAFeatureEnabled &&
selectedTier === 'enterprise'
? 'Only regions that support Kubernetes Enterprise are listed.'
: undefined
}
disableClearable
errorText={errorMap.region}
onChange={(e, region) => setSelectedRegion(region)}
regions={regionsData}
value={selectedRegion?.id}
/>
</Stack>
<StyledDocsLinkContainer
sx={(theme) => ({ marginTop: theme.spacing(2) })}
>
<DocsLink
href="https://www.linode.com/pricing"
label={DOCS_LINK_LABEL_DC_PRICING}
/>
</StyledDocsLinkContainer>
</StyledFieldWithDocsStack>
<Divider sx={{ marginTop: 4 }} />
<Autocomplete
onChange={(_, selected) => {
setVersion(selected?.value);
}}
disableClearable={!!version}
errorText={errorMap.k8s_version}
label="Kubernetes Version"
loading={isLoadingVersions}
options={versions}
placeholder={' '}
value={versions.find((v) => v.value === version) ?? null}
/>
{showAPL && (
<>
<Divider sx={{ marginTop: 4 }} />
<StyledFieldWithDocsStack>
<Stack>
<ApplicationPlatform
setAPL={setApl_enabled}
setHighAvailability={setHighAvailability}
/>
</Stack>
</StyledFieldWithDocsStack>
</>
)}
<Divider sx={{ marginTop: showAPL ? 1 : 4 }} />
{showHighAvailability && selectedTier !== 'enterprise' && (
<Box data-testid="ha-control-plane">
<HAControlPlane
highAvailabilityPrice={
isErrorKubernetesTypes || !highAvailabilityPrice
? UNKNOWN_PRICE
: highAvailabilityPrice
}
isAPLEnabled={apl_enabled}
isErrorKubernetesTypes={isErrorKubernetesTypes}
isLoadingKubernetesTypes={isLoadingKubernetesTypes}
selectedRegionId={selectedRegion?.id}
setHighAvailability={setHighAvailability}
/>
</Box>
)}
{showControlPlaneACL && (
<>
{selectedTier !== 'enterprise' && <Divider />}
<ControlPlaneACLPane
handleIPv4Change={(newIpV4Addr: ExtendedIP[]) => {
setIPv4Addr(newIpV4Addr);
}}
handleIPv6Change={(newIpV6Addr: ExtendedIP[]) => {
setIPv6Addr(newIpV6Addr);
}}
enableControlPlaneACL={controlPlaneACL}
errorText={errorMap.control_plane}
ipV4Addr={ipV4Addr}
ipV6Addr={ipV6Addr}
setControlPlaneACL={setControlPlaneACL}
<form onSubmit={onSubmit}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be cleaned up to be something like

  return (
    <form onSubmit={handleSubmit(createCluster)}>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants