Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

Improve VLANSelect component behavior when creating a new VLAN ([#12380](https://github.com/linode/manager/pull/12380))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Add region filtering for VLANSelect in AddInterface form ([#12380](https://github.com/linode/manager/pull/12380))
53 changes: 37 additions & 16 deletions packages/manager/src/components/VLANSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export const VLANSelect = (props: Props) => {
// If the value gets cleared, make sure the TextField's value also gets cleared.
setInputValue('');
}
if (value && !inputValue) {
setInputValue(value);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);

Expand Down Expand Up @@ -108,27 +111,31 @@ export const VLANSelect = (props: Props) => {
option === newVlanPlaceholder ? `Create "${inputValue}"` : option.label
}
helperText={helperText}
inputValue={selectedVLAN ? selectedVLAN.label : inputValue}
isOptionEqualToValue={(option1, options2) =>
option1.label === options2.label
inputValue={selectedVLAN && !open ? selectedVLAN.label : inputValue}
isOptionEqualToValue={(option1, option2) =>
option1.label === option2.label
}
label="VLAN"
ListboxProps={{
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ListboxProps is deprecated - moved to slotProps.listbox

onScroll: (event: React.SyntheticEvent) => {
const listboxNode = event.currentTarget;
if (
listboxNode.scrollTop + listboxNode.clientHeight >=
listboxNode.scrollHeight &&
hasNextPage
) {
fetchNextPage();
}
},
}}
loading={isFetching}
noMarginTop
noOptionsText="You have no VLANs in this region. Type to create one."
onBlur={onBlur}
onBlur={() => {
if (inputValue !== value) {
if (vlans.length === 1 && onChange) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should just stick with one behavior (clear on blur or keep value) instead of conditional behavior

// if input value has changed and there is only one option, select that input value
// this handles the case where users expect the new VLAN to be selected onBlur if the only option that exists is to create it
onChange(inputValue);
} else {
// otherwise, if there are multiple options: if we didn't explicitly select the new input value, keep the old value
// if there is no pre-existing value selected, this clears the textfield
setInputValue(value ?? '');
}
}

if (onBlur) {
onBlur();
}
}}
onChange={(event, value) => {
if (onChange) {
onChange(value?.label ?? null);
Expand All @@ -151,6 +158,20 @@ export const VLANSelect = (props: Props) => {
open={open}
options={vlans}
placeholder="Create or select a VLAN"
slotProps={{
listbox: {
onScroll: (event: React.SyntheticEvent) => {
const listboxNode = event.currentTarget;
if (
listboxNode.scrollTop + listboxNode.clientHeight >=
listboxNode.scrollHeight &&
hasNextPage
) {
fetchNextPage();
}
},
},
}}
sx={sx}
value={selectedVLAN}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ export const AddInterfaceForm = (props: Props) => {
)}
<InterfaceType />
{selectedInterfacePurpose === 'public' && <PublicInterface />}
{selectedInterfacePurpose === 'vlan' && <VLANInterface />}
{selectedInterfacePurpose === 'vlan' && (
<VLANInterface regionId={regionId} />
)}
{selectedInterfacePurpose === 'vpc' && (
<VPCInterface regionId={regionId} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { VLANSelect } from 'src/components/VLANSelect';

import type { CreateInterfaceFormValues } from '../utilities';

export const VLANInterface = () => {
interface Props {
regionId: string;
}

export const VLANInterface = ({ regionId }: Props) => {
const { control } = useFormContext<CreateInterfaceFormValues>();

return (
Expand All @@ -17,6 +21,7 @@ export const VLANInterface = () => {
render={({ field, fieldState }) => (
<VLANSelect
errorText={fieldState.error?.message}
filter={{ region: regionId }}
onChange={field.onChange}
value={field.value ?? null}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/mocks/serverHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,7 @@ export const handlers = [
return HttpResponse.json(volume);
}),
http.get('*/vlans', () => {
const vlans = VLANFactory.buildList(2);
const vlans = VLANFactory.buildList(30);
return HttpResponse.json(makeResourcePage(vlans));
}),
http.get('*/profile/preferences', () => {
Expand Down