-
Notifications
You must be signed in to change notification settings - Fork 367
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upcoming: [M3-7614] - Placement Groups Create/Rename Drawers (#10106)
* Initial commit: setting up the pieces * Form conditionals * Finalize create drawer * Save work * Cleanup after rebase * Cleanup after rebase * Save progress * Cleanup and invalidation * cleanup issue with deps * Tests * moar covering * cleanup * cleanup 2 * Add drawer to empty state * Added changeset: Placement Groups Create/Rename Drawers * Replace enum * Feedback * implement hook for reusability * Feedback * Moar Feedback * Moooaaaar Feedback
- Loading branch information
1 parent
9781197
commit 3937bc7
Showing
23 changed files
with
724 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
packages/manager/.changeset/pr-10106-upcoming-features-1706544198124.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@linode/manager": Upcoming Features | ||
--- | ||
|
||
Placement Groups Create/Rename Drawers ([#10106](https://github.com/linode/manager/pull/10106)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
packages/manager/src/features/PlacementGroups/PlacementGroupsCreateDrawer.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { fireEvent } from '@testing-library/react'; | ||
import * as React from 'react'; | ||
|
||
import { renderWithTheme } from 'src/utilities/testHelpers'; | ||
|
||
import { PlacementGroupsCreateDrawer } from './PlacementGroupsCreateDrawer'; | ||
|
||
const commonProps = { | ||
onClose: vi.fn(), | ||
onPlacementGroupCreated: vi.fn(), | ||
open: true, | ||
}; | ||
|
||
describe('PlacementGroupsCreateDrawer', () => { | ||
it('should render and have its fields enabled', () => { | ||
const { getByLabelText } = renderWithTheme( | ||
<PlacementGroupsCreateDrawer | ||
numberOfPlacementGroupsCreated={0} | ||
{...commonProps} | ||
/> | ||
); | ||
|
||
expect(getByLabelText('Label')).toBeEnabled(); | ||
expect(getByLabelText('Region')).toBeEnabled(); | ||
expect(getByLabelText('Affinity Type')).toBeEnabled(); | ||
}); | ||
|
||
it('Affinity Type select should have the correct options', async () => { | ||
const { getByPlaceholderText, getByText } = renderWithTheme( | ||
<PlacementGroupsCreateDrawer | ||
numberOfPlacementGroupsCreated={0} | ||
{...commonProps} | ||
/> | ||
); | ||
|
||
const inputElement = getByPlaceholderText('Select an Affinity Type'); | ||
fireEvent.focus(inputElement); | ||
|
||
fireEvent.change(inputElement, { target: { value: 'Affinity' } }); | ||
expect(getByText('Affinity')).toBeInTheDocument(); | ||
|
||
fireEvent.change(inputElement, { target: { value: 'Anti-affinity' } }); | ||
expect(getByText('Anti-affinity')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should disable the submit button when the number of placement groups created is >= to the max', () => { | ||
const { getByTestId } = renderWithTheme( | ||
<PlacementGroupsCreateDrawer | ||
numberOfPlacementGroupsCreated={5} | ||
{...commonProps} | ||
/> | ||
); | ||
|
||
expect(getByTestId('submit')).toHaveAttribute('aria-disabled', 'true'); | ||
}); | ||
|
||
it('should populate the region select with the selected region prop', () => { | ||
const { getByLabelText } = renderWithTheme( | ||
<PlacementGroupsCreateDrawer | ||
numberOfPlacementGroupsCreated={0} | ||
selectedRegionId="us-east" | ||
{...commonProps} | ||
/> | ||
); | ||
|
||
expect(getByLabelText('Region')).toHaveValue('Newark, NJ (us-east)'); | ||
}); | ||
}); |
133 changes: 133 additions & 0 deletions
133
packages/manager/src/features/PlacementGroups/PlacementGroupsCreateDrawer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { createPlacementGroupSchema } from '@linode/validation'; | ||
import { useFormik } from 'formik'; | ||
import { useSnackbar } from 'notistack'; | ||
import * as React from 'react'; | ||
import { useQueryClient } from 'react-query'; | ||
|
||
import { Drawer } from 'src/components/Drawer'; | ||
import { useFormValidateOnChange } from 'src/hooks/useFormValidateOnChange'; | ||
import { queryKey as placementGroupQueryKey } from 'src/queries/placementGroups'; | ||
import { useCreatePlacementGroup } from 'src/queries/placementGroups'; | ||
import { useRegionsQuery } from 'src/queries/regions'; | ||
import { getErrorMap } from 'src/utilities/errorUtils'; | ||
import { | ||
handleFieldErrors, | ||
handleGeneralErrors, | ||
} from 'src/utilities/formikErrorUtils'; | ||
|
||
import { PlacementGroupsDrawerContent } from './PlacementGroupsDrawerContent'; | ||
import { MAX_NUMBER_OF_PLACEMENT_GROUPS } from './constants'; | ||
|
||
import type { | ||
PlacementGroupDrawerFormikProps, | ||
PlacementGroupsCreateDrawerProps, | ||
} from './types'; | ||
|
||
export const PlacementGroupsCreateDrawer = ( | ||
props: PlacementGroupsCreateDrawerProps | ||
) => { | ||
const { | ||
numberOfPlacementGroupsCreated, | ||
onClose, | ||
onPlacementGroupCreated, | ||
open, | ||
selectedRegionId, | ||
} = props; | ||
const queryClient = useQueryClient(); | ||
const { data: regions } = useRegionsQuery(); | ||
const { mutateAsync } = useCreatePlacementGroup(); | ||
const { enqueueSnackbar } = useSnackbar(); | ||
const { | ||
hasFormBeenSubmitted, | ||
setHasFormBeenSubmitted, | ||
} = useFormValidateOnChange(); | ||
|
||
const { | ||
errors, | ||
handleBlur, | ||
handleChange, | ||
handleSubmit, | ||
isSubmitting, | ||
resetForm, | ||
setFieldValue, | ||
status, | ||
values, | ||
...rest | ||
} = useFormik({ | ||
enableReinitialize: true, | ||
initialValues: { | ||
affinity_type: '' as PlacementGroupDrawerFormikProps['affinity_type'], | ||
label: '', | ||
region: selectedRegionId ?? '', | ||
}, | ||
onSubmit( | ||
values: PlacementGroupDrawerFormikProps, | ||
{ setErrors, setStatus, setSubmitting } | ||
) { | ||
setHasFormBeenSubmitted(false); | ||
setStatus(undefined); | ||
setErrors({}); | ||
const payload = { ...values }; | ||
|
||
mutateAsync(payload) | ||
.then((response) => { | ||
setSubmitting(false); | ||
queryClient.invalidateQueries([placementGroupQueryKey]); | ||
|
||
enqueueSnackbar( | ||
`Placement Group ${payload.label} successfully created`, | ||
{ | ||
variant: 'success', | ||
} | ||
); | ||
|
||
if (onPlacementGroupCreated) { | ||
onPlacementGroupCreated(response); | ||
} | ||
onClose(); | ||
}) | ||
.catch((err) => { | ||
const mapErrorToStatus = () => | ||
setStatus({ generalError: getErrorMap([], err).none }); | ||
|
||
setSubmitting(false); | ||
handleFieldErrors(setErrors, err); | ||
handleGeneralErrors( | ||
mapErrorToStatus, | ||
err, | ||
'Error creating Placement Group.' | ||
); | ||
}); | ||
}, | ||
validateOnBlur: false, | ||
validateOnChange: hasFormBeenSubmitted, | ||
validationSchema: createPlacementGroupSchema, | ||
}); | ||
|
||
return ( | ||
<Drawer onClose={onClose} open={open} title="Create Placement Group"> | ||
<PlacementGroupsDrawerContent | ||
formik={{ | ||
errors, | ||
handleBlur, | ||
handleChange, | ||
handleSubmit, | ||
isSubmitting, | ||
resetForm, | ||
setFieldValue, | ||
status, | ||
values, | ||
...rest, | ||
}} | ||
maxNumberOfPlacementGroups={MAX_NUMBER_OF_PLACEMENT_GROUPS} | ||
mode="create" | ||
numberOfPlacementGroupsCreated={numberOfPlacementGroupsCreated} | ||
onClose={onClose} | ||
open={open} | ||
regions={regions ?? []} | ||
selectedRegionId={selectedRegionId} | ||
setHasFormBeenSubmitted={setHasFormBeenSubmitted} | ||
/> | ||
</Drawer> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.