Skip to content

Commit

Permalink
upcoming: [M3-7993] - PlacementGroups Select optimizations & cleanup (#…
Browse files Browse the repository at this point in the history
…10455)

* Initial commit - save work

* optimize queries

* Cleanup and and create flow v2

* Fix type error in create linode flow v2

* fixing all the types

* Cleanup

* Moar Cleanup

* Added changeset: PlacementGroups Select optimizations & cleanup

* Copy update

* Feedback @carrillo-erik
  • Loading branch information
abailly-akamai committed May 14, 2024
1 parent 013dc2b commit a1e1213
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 98 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

PlacementGroups Select optimizations & cleanup ([#10455](https://github.com/linode/manager/pull/10455))
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('Tags list', () => {
value: ['tag1', 'tag2'].map((tag) => ({ label: tag, value: tag })),
}}
handlePlacementGroupChange={handlePlacementGroupChange}
selectedPlacementGroupId={null}
/>
);

Expand Down Expand Up @@ -53,6 +54,7 @@ describe('Tags list', () => {
})),
}}
handlePlacementGroupChange={handlePlacementGroupChange}
selectedPlacementGroupId={null}
/>
);

Expand All @@ -69,6 +71,7 @@ describe('Tags list', () => {
value: '',
}}
handlePlacementGroupChange={handlePlacementGroupChange}
selectedPlacementGroupId={null}
/>
);
expect(queryByLabelText(TAG_LABEL)).not.toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import type { PlacementGroup } from '@linode/api-v4';

interface DetailsPanelProps {
error?: string;
handlePlacementGroupChange: (selected: PlacementGroup) => void;
handlePlacementGroupChange: (selected: PlacementGroup | null) => void;
labelFieldProps?: TextFieldProps;
selectedPlacementGroupId: null | number;
selectedRegionId?: string;
tagsInputProps?: TagsInputProps;
}
Expand All @@ -24,6 +25,7 @@ export const DetailsPanel = (props: DetailsPanelProps) => {
error,
handlePlacementGroupChange,
labelFieldProps,
selectedPlacementGroupId,
selectedRegionId,
tagsInputProps,
} = props;
Expand Down Expand Up @@ -62,6 +64,7 @@ export const DetailsPanel = (props: DetailsPanelProps) => {
{isPlacementGroupsEnabled && (
<PlacementGroupsDetailPanel
handlePlacementGroupChange={handlePlacementGroupChange}
selectedPlacementGroupId={selectedPlacementGroupId}
selectedRegionId={selectedRegionId}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ import { PlacementGroupsSelect } from './PlacementGroupsSelect';
import type { PlacementGroupsSelectProps } from './PlacementGroupsSelect';

const props: PlacementGroupsSelectProps = {
errorText: '',
handlePlacementGroupChange: vi.fn(),
id: '',
label: 'Placement Groups in Atlanta, GA (us-southeast)',
noOptionsMessage: '',
selectedPlacementGroup: null,
selectedPlacementGroupId: null,
selectedRegion: regionFactory.build({ id: 'us-southeast' }),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,52 @@ import type { PlacementGroup, Region } from '@linode/api-v4';
import type { SxProps } from '@mui/system';

export interface PlacementGroupsSelectProps {
clearOnBlur?: boolean;
clearable?: boolean;
defaultValue?: PlacementGroup;
/**
* If true, the component will be disabled.
*/
disabled?: boolean;
errorText?: string;
handlePlacementGroupChange: (selected: PlacementGroup) => void;
id?: string;
/**
* A callback to execute when the selected Placement Group changes.
* The selection is handled by a parent component.
*/
handlePlacementGroupChange: (selected: PlacementGroup | null) => void;
/**
* The label for the TextField component.
*/
label: string;
/**
* If true, the component will display a loading spinner. (usually when fetching data)
*/
loading?: boolean;
/**
* The message to display when there are no options available.
*/
noOptionsMessage?: string;
onBlur?: (e: React.FocusEvent) => void;
selectedPlacementGroup: PlacementGroup | null;
selectedRegion?: Region;
/**
* The ID of the selected Placement Group.
*/
selectedPlacementGroupId: null | number;
/**
* We want to pass the full region object here so we can check if the selected Placement Group is at capacity.
*/
selectedRegion: Region | undefined;
/**
* Any additional styles to apply to the root element.
*/
sx?: SxProps;
/**
* Any additional props to pass to the TextField component.
*/
textFieldProps?: Partial<TextFieldProps>;
}

export const PlacementGroupsSelect = (props: PlacementGroupsSelectProps) => {
const {
clearOnBlur,
clearable = true,
defaultValue,
disabled,
errorText,
handlePlacementGroupChange,
id,
label,
loading,
noOptionsMessage,
onBlur,
selectedPlacementGroup,
selectedPlacementGroupId,
selectedRegion,
sx,
...textFieldProps
Expand All @@ -51,8 +66,15 @@ export const PlacementGroupsSelect = (props: PlacementGroupsSelectProps) => {
const {
data: placementGroups,
error,
isFetching,
isLoading,
} = useAllPlacementGroupsQuery(Boolean(selectedRegion?.id));
} = useAllPlacementGroupsQuery({
enabled: Boolean(selectedRegion?.id),
// Placement Group selection is always dependent on a selected region.
filter: {
region: selectedRegion?.id,
},
});

const isDisabledPlacementGroup = (
selectedPlacementGroup: PlacementGroup,
Expand All @@ -68,26 +90,18 @@ export const PlacementGroupsSelect = (props: PlacementGroupsSelectProps) => {
});
};

if (!placementGroups) {
return null;
}

const placementGroupsOptions: PlacementGroup[] = placementGroups.filter(
(placementGroup) => placementGroup.region === selectedRegion?.id
);

const selection =
placementGroupsOptions.find(
(placementGroup) => placementGroup.id === selectedPlacementGroup?.id
placementGroups?.find(
(placementGroup) => placementGroup.id === selectedPlacementGroupId
) ?? null;

return (
<Autocomplete
noOptionsText={
noOptionsMessage ?? getDefaultNoOptionsMessage(error, isLoading)
}
onChange={(_, selectedOption: PlacementGroup) => {
handlePlacementGroupChange(selectedOption);
onChange={(_, selectedOption) => {
handlePlacementGroupChange(selectedOption ?? null);
}}
renderOption={(props, option, { selected }) => {
return (
Expand All @@ -101,18 +115,14 @@ export const PlacementGroupsSelect = (props: PlacementGroupsSelectProps) => {
/>
);
}}
clearOnBlur={clearOnBlur}
clearOnBlur={true}
data-testid="placement-groups-select"
defaultValue={defaultValue}
disableClearable={!clearable}
disabled={Boolean(!selectedRegion?.id) || disabled}
errorText={errorText}
errorText={error?.[0]?.reason}
getOptionLabel={(placementGroup: PlacementGroup) => placementGroup.label}
id={id}
label={label}
loading={isLoading || loading}
onBlur={onBlur}
options={placementGroupsOptions ?? []}
loading={isFetching}
options={placementGroups ?? []}
placeholder="None"
sx={sx}
value={selection}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ export const PlacementGroupPanel = () => {
return (
<PlacementGroupsDetailPanel
handlePlacementGroupChange={(placementGroup) =>
field.onChange(placementGroup.id)
field.onChange(placementGroup?.id)
}
selectedPlacementGroupId={field.value ?? null}
selectedRegionId={regionId}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export interface LinodeCreateProps {
handleAgreementChange: () => void;
handleFirewallChange: (firewallId: number) => void;
handleIPv4RangesForVPC: (ranges: ExtendedIP[]) => void;
handlePlacementGroupChange: (placementGroup: PlacementGroup) => void;
handlePlacementGroupChange: (placementGroup: PlacementGroup | null) => void;
handleShowApiAwarenessModal: () => void;
handleSubmitForm: HandleSubmit;
handleSubnetChange: (subnetId: number) => void;
Expand Down Expand Up @@ -656,6 +656,9 @@ export class LinodeCreate extends React.PureComponent<
onChange: (e) => updateLabel(e.target.value),
value: label || '',
}}
selectedPlacementGroupId={
this.props.placementGroupSelection?.id ?? null
}
tagsInputProps={
this.props.createType !== 'fromLinode'
? tagsInputProps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ class LinodeCreateContainer extends React.PureComponent<CombinedProps, State> {
imageDisplayInfo={this.getImageInfo()}
ipamAddress={this.state.vlanIPAMAddress}
label={this.generateLabel()}
placementGroupSelection={this.state.placementGroupSelection}
regionDisplayInfo={this.getRegionInfo()}
regionsData={regionsData}
resetCreationState={this.clearCreationState}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RegionSelect } from 'src/components/RegionSelect/RegionSelect';
import { sxEdgeIcon } from 'src/components/RegionSelect/RegionSelect.styles';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { Typography } from 'src/components/Typography';
import { NO_PLACEMENT_GROUPS_IN_SELECTED_REGION_MESSAGE } from 'src/features/PlacementGroups/constants';
import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';
import { useFlags } from 'src/hooks/useFlags';
import { useRegionsQuery } from 'src/queries/regions/regions';
Expand Down Expand Up @@ -208,8 +209,8 @@ export const ConfigureForm = React.memo((props: Props) => {
disabled={isPlacementGroupSelectDisabled}
key={selectedRegion}
label={placementGroupSelectLabel}
noOptionsMessage="There are no Placement Groups in this region."
selectedPlacementGroup={selectedPlacementGroup}
noOptionsMessage={NO_PLACEMENT_GROUPS_IN_SELECTED_REGION_MESSAGE}
selectedPlacementGroupId={selectedPlacementGroup?.id ?? null}
selectedRegion={newRegion}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const PlacementGroupsAssignLinodesDrawer = (
const {
data: allPlacementGroups,
error: allPlacementGroupsError,
} = useAllPlacementGroupsQuery();
} = useAllPlacementGroupsQuery({});
const { enqueueSnackbar } = useSnackbar();

// We display a notice and disable inputs in case the user reaches this drawer somehow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ export const PlacementGroupsCreateDrawer = (
selectedRegionId,
} = props;
const { data: regions } = useRegionsQuery();
const { data: allPlacementGroups } = useAllPlacementGroupsQuery();
const { data: allPlacementGroupsInRegion } = useAllPlacementGroupsQuery({
enabled: Boolean(selectedRegionId),
filter: {
region: selectedRegionId,
},
});
const { error, mutateAsync } = useCreatePlacementGroup();
const { enqueueSnackbar } = useSnackbar();
const {
Expand Down Expand Up @@ -183,7 +188,7 @@ export const PlacementGroupsCreateDrawer = (
handleDisabledRegion={(region) => {
const isRegionAtCapacity = hasRegionReachedPlacementGroupCapacity(
{
allPlacementGroups,
allPlacementGroups: allPlacementGroupsInRegion,
region,
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PlacementGroupsDetailPanel } from './PlacementGroupsDetailPanel';

const defaultProps = {
handlePlacementGroupChange: vi.fn(),
selectedPlacementGroupId: null,
};

const queryMocks = vi.hoisted(() => ({
Expand Down
Loading

0 comments on commit a1e1213

Please sign in to comment.