-
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.
feat: [M3-8560] - NodeBalancer Configurations - Support Linodes with …
…Multiple Private IPs (#11069) * initial work to support multiple private ipv4s on a Linode * fix style bug * clean up validation and utils * add changeset * add more detailed changesets * feedback @hkhalil-akamai * clean `LinodeSelect` extra props --------- Co-authored-by: Banks Nussman <banks@nussman.us>
- Loading branch information
1 parent
150d2e5
commit 60a1925
Showing
16 changed files
with
204 additions
and
165 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@linode/manager": Fixed | ||
--- | ||
|
||
Support Linodes with multiple private IPs in NodeBalancer configurations ([#11069](https://github.com/linode/manager/pull/11069)) |
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
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
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
170 changes: 88 additions & 82 deletions
170
packages/manager/src/features/NodeBalancers/ConfigNodeIPSelect.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 |
---|---|---|
@@ -1,96 +1,102 @@ | ||
import { Box } from '@mui/material'; | ||
import * as React from 'react'; | ||
import React from 'react'; | ||
|
||
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; | ||
import { SelectedIcon } from 'src/components/Autocomplete/Autocomplete.styles'; | ||
import { LinodeSelect } from 'src/features/Linodes/LinodeSelect/LinodeSelect'; | ||
import { privateIPRegex } from 'src/utilities/ipUtils'; | ||
import { Box } from 'src/components/Box'; | ||
import { Stack } from 'src/components/Stack'; | ||
import { Typography } from 'src/components/Typography'; | ||
import { useAllLinodesQuery } from 'src/queries/linodes/linodes'; | ||
|
||
import type { Linode } from '@linode/api-v4/lib/linodes'; | ||
import type { TextFieldProps } from 'src/components/TextField'; | ||
import { getPrivateIPOptions } from './ConfigNodeIPSelect.utils'; | ||
|
||
interface ConfigNodeIPSelectProps { | ||
interface Props { | ||
/** | ||
* Disables the select | ||
*/ | ||
disabled?: boolean; | ||
errorText?: string; | ||
/** | ||
* Validation error text | ||
*/ | ||
errorText: string | undefined; | ||
/** | ||
* Function that is called when the select's value changes | ||
*/ | ||
handleChange: (nodeIndex: number, ipAddress: null | string) => void; | ||
/** | ||
* Override the default input `id` for the select | ||
*/ | ||
inputId?: string; | ||
nodeAddress?: string; | ||
/** | ||
* The selected private IP address | ||
*/ | ||
nodeAddress: string | undefined; | ||
/** | ||
* The index of the config node in state | ||
*/ | ||
nodeIndex: number; | ||
selectedRegion?: string; | ||
textfieldProps: Omit<TextFieldProps, 'label'>; | ||
/** | ||
* The region for which to load Linodes and to show private IPs | ||
* @note IPs won't load until a region is passed | ||
*/ | ||
region: string | undefined; | ||
} | ||
|
||
export const ConfigNodeIPSelect = React.memo( | ||
(props: ConfigNodeIPSelectProps) => { | ||
const { | ||
handleChange: _handleChange, | ||
inputId, | ||
nodeAddress, | ||
nodeIndex, | ||
} = props; | ||
|
||
const handleChange = (linode: Linode | null) => { | ||
if (!linode) { | ||
_handleChange(nodeIndex, null); | ||
} | ||
export const ConfigNodeIPSelect = React.memo((props: Props) => { | ||
const { | ||
disabled, | ||
errorText, | ||
handleChange, | ||
inputId, | ||
nodeAddress, | ||
nodeIndex, | ||
region, | ||
} = props; | ||
|
||
const thisLinodesPrivateIP = linode?.ipv4.find((ipv4) => | ||
ipv4.match(privateIPRegex) | ||
); | ||
const { data: linodes, error, isLoading } = useAllLinodesQuery( | ||
{}, | ||
{ region }, | ||
region !== undefined | ||
); | ||
|
||
if (!thisLinodesPrivateIP) { | ||
return; | ||
} | ||
const options = getPrivateIPOptions(linodes); | ||
|
||
/** | ||
* we can be sure the selection has a private IP because of the | ||
* filterCondition prop in the render method below | ||
*/ | ||
_handleChange(nodeIndex, thisLinodesPrivateIP); | ||
}; | ||
|
||
return ( | ||
<LinodeSelect | ||
noOptionsMessage={`No options - please ensure you have at least 1 Linode | ||
with a private IP located in the selected region.`} | ||
optionsFilter={(linode) => { | ||
/** | ||
* if the Linode doesn't have an private IP OR if the Linode | ||
* is in a different region that the NodeBalancer, don't show it | ||
* in the select dropdown | ||
*/ | ||
return ( | ||
!!linode.ipv4.find((eachIP) => eachIP.match(privateIPRegex)) && | ||
linode.region === props.selectedRegion | ||
); | ||
}} | ||
renderOption={(linode, selected) => ( | ||
<> | ||
<Box | ||
sx={{ | ||
flexGrow: 1, | ||
}} | ||
> | ||
<strong> | ||
{linode.ipv4.find((eachIP) => eachIP.match(privateIPRegex))} | ||
</strong> | ||
<div>{linode.label}</div> | ||
</Box> | ||
<SelectedIcon visible={selected} /> | ||
</> | ||
)} | ||
renderOptionLabel={(linode) => | ||
linode.ipv4.find((eachIP) => eachIP.match(privateIPRegex)) ?? '' | ||
} | ||
clearable | ||
disabled={props.disabled} | ||
errorText={props.errorText} | ||
id={inputId} | ||
label="IP Address" | ||
noMarginTop | ||
onSelectionChange={handleChange} | ||
placeholder="Enter IP Address" | ||
value={(linode) => linode.ipv4.some((ip) => ip === nodeAddress)} | ||
/> | ||
); | ||
} | ||
); | ||
return ( | ||
<Autocomplete | ||
renderOption={(props, option, { selected }) => ( | ||
<li {...props} key={props.key}> | ||
<Box | ||
alignItems="center" | ||
display="flex" | ||
flexDirection="row" | ||
gap={1} | ||
justifyContent="space-between" | ||
width="100%" | ||
> | ||
<Stack> | ||
<Typography | ||
color="inherit" | ||
fontFamily={(theme) => theme.font.bold} | ||
> | ||
{option.label} | ||
</Typography> | ||
<Typography color="inherit">{option.linode.label}</Typography> | ||
</Stack> | ||
{selected && <SelectedIcon visible />} | ||
</Box> | ||
</li> | ||
)} | ||
disabled={disabled} | ||
errorText={errorText ?? error?.[0].reason} | ||
id={inputId} | ||
label="IP Address" | ||
loading={isLoading} | ||
noMarginTop | ||
noOptionsText="No options - please ensure you have at least 1 Linode with a private IP located in the selected region." | ||
onChange={(e, value) => handleChange(nodeIndex, value?.label ?? null)} | ||
options={options} | ||
placeholder="Enter IP Address" | ||
value={options.find((o) => o.label === nodeAddress) ?? null} | ||
/> | ||
); | ||
}); |
Oops, something went wrong.