Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Upcoming Features
---

Update Linode Config types for Linode Interfaces ([#11727](https://github.com/linode/manager/pull/11727))
6 changes: 3 additions & 3 deletions packages/api-v4/src/linodes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ export interface Config {
created: string;
updated: string;
initrd: string | null;
// If a Linode is using the new Linode Interfaces, this field will no longer be present.
interfaces?: Interface[];
// If a Linode is using new Linode Interfaces, the interfaces in the Config object will be returned as null.
interfaces: Interface[] | null;
}

// ----------------------------------------------------------
Expand Down Expand Up @@ -430,7 +430,7 @@ export interface LinodeConfigCreationData {
updatedb_disabled: boolean;
distro: boolean;
modules_dep: boolean;
network: boolean;
network?: boolean;
devtmpfs_automount: boolean;
};
root_device: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Hide Networking sections from Linode Configurations page for Linodes with new interfaces ([#11727](https://github.com/linode/manager/pull/11727))
2 changes: 1 addition & 1 deletion packages/manager/cypress/support/intercepts/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,6 @@ export const mockCreateLinodeConfigInterfaces = (
return cy.intercept(
'POST',
apiMatcher(`linode/instances/${linodeId}/configs/${config.id}/interfaces`),
config.interfaces
config.interfaces ?? undefined
);
};
4 changes: 2 additions & 2 deletions packages/manager/src/factories/linodeConfigs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Config } from '@linode/api-v4/lib/linodes/types';
import Factory from 'src/factories/factoryProxy';

import {
LinodeConfigInterfaceFactory,
LinodeConfigInterfaceFactoryWithVPC,
} from 'src/factories/linodeConfigInterfaceFactory';

import type { Config } from '@linode/api-v4';

const generateRandomId = () => Math.floor(Math.random() * 10000);

const publicInterface = LinodeConfigInterfaceFactory.build({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import {
Config,
Devices,
DiskDevice,
VolumeDevice,
} from '@linode/api-v4/lib/linodes';
import { styled } from '@mui/material/styles';
import * as React from 'react';

import { TableCell } from 'src/components/TableCell';
import { TableRow } from 'src/components/TableRow';
import { API_MAX_PAGE_SIZE } from 'src/constants';
import { useAllLinodeDisksQuery } from 'src/queries/linodes/disks';
import { useLinodeKernelQuery } from 'src/queries/linodes/linodes';
import {
useLinodeKernelQuery,
useLinodeQuery,
} from 'src/queries/linodes/linodes';
import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes';

import { InterfaceListItem } from './InterfaceListItem';
import { ConfigActionMenu } from './LinodeConfigActionMenu';

import type {
Config,
Devices,
DiskDevice,
VolumeDevice,
} from '@linode/api-v4/lib/linodes';

interface Props {
config: Config;
linodeId: number;
Expand All @@ -27,20 +31,22 @@ interface Props {
}

export const isDiskDevice = (
device: VolumeDevice | DiskDevice
device: DiskDevice | VolumeDevice
): device is DiskDevice => {
return 'disk_id' in device;
};

const isVolumeDevice = (
device: VolumeDevice | DiskDevice
device: DiskDevice | VolumeDevice
): device is VolumeDevice => {
return 'volume_id' in device;
};

export const ConfigRow = React.memo((props: Props) => {
const { config, linodeId, onBoot, onDelete, onEdit, readOnly } = props;

const { data: linode } = useLinodeQuery(linodeId);

const { data: kernel } = useLinodeKernelQuery(config.kernel);

const { data: disks } = useAllLinodeDisksQuery(linodeId);
Expand Down Expand Up @@ -110,9 +116,11 @@ export const ConfigRow = React.memo((props: Props) => {
{config.label} – {kernel?.label ?? config.kernel}
</TableCell>
<TableCell>{deviceLabels}</TableCell>
<TableCell>
{interfaces.length > 0 ? InterfaceList : defaultInterfaceLabel}
</TableCell>
{linode?.interface_generation !== 'linode' && (
<TableCell>
{interfaces.length > 0 ? InterfaceList : defaultInterfaceLabel}
</TableCell>
)}
<StyledTableCell>
<ConfigActionMenu
config={config}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import {
LinodeConfigInterfaceFactory,
linodeConfigFactory,
linodeFactory,
} from 'src/factories';
import {
LINODE_UNREACHABLE_HELPER_TEXT,
Expand All @@ -12,11 +13,32 @@ import {
import 'src/mocks/testServer';
import { renderWithTheme } from 'src/utilities/testHelpers';

import { unrecommendedConfigNoticeSelector } from './LinodeConfigDialog';
import { LinodeConfigDialog, padList } from './LinodeConfigDialog';
import { unrecommendedConfigNoticeSelector } from './LinodeConfigDialog';

import type { MemoryLimit } from './LinodeConfigDialog';

const queryMocks = vi.hoisted(() => ({
useFlags: vi.fn().mockReturnValue({}),
useLinodeQuery: vi.fn().mockReturnValue({}),
}));

vi.mock('src/queries/linodes/linodes', async () => {
const actual = await vi.importActual('src/queries/linodes/linodes');
return {
...actual,
useLinodeQuery: queryMocks.useLinodeQuery,
};
});

vi.mock('src/hooks/useFlags', () => {
const actual = vi.importActual('src/hooks/useFlags');
return {
...actual,
useFlags: queryMocks.useFlags,
};
});

describe('LinodeConfigDialog', () => {
describe('padInterface helper method', () => {
it('should return a list of the correct length unchanged', () => {
Expand Down Expand Up @@ -171,4 +193,37 @@ describe('LinodeConfigDialog', () => {
await findByDisplayValue('VPC');
await findByDisplayValue('Public Internet');
});

it('should hide the Network Interfaces section if Linode uses new interfaces', () => {
const props = {
isReadOnly: false,
linodeId: 1,
onClose: vi.fn(),
};

const linode = linodeFactory.build({ interface_generation: 'linode' });

queryMocks.useLinodeQuery.mockReturnValue({
data: linode,
});

queryMocks.useFlags.mockReturnValue({
linodeInterfaces: { enabled: true },
});

const { queryByLabelText } = renderWithTheme(
<LinodeConfigDialog
config={linodeConfigFactory.build({ interfaces: null })}
open={true}
{...props}
/>
);

expect(
queryByLabelText('Primary Interface (Default Route)')
).not.toBeInTheDocument();
expect(queryByLabelText('eth0')).not.toBeInTheDocument();
expect(queryByLabelText('eth1')).not.toBeInTheDocument();
expect(queryByLabelText('eth2')).not.toBeInTheDocument();
});
});
Loading