diff --git a/packages/api-v4/.changeset/pr-13269-added-1768236376323.md b/packages/api-v4/.changeset/pr-13269-added-1768236376323.md new file mode 100644 index 00000000000..53800260763 --- /dev/null +++ b/packages/api-v4/.changeset/pr-13269-added-1768236376323.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Added +--- + +`Maintenance Policy` to Linode Capabilities ([#13269](https://github.com/linode/manager/pull/13269)) diff --git a/packages/api-v4/src/linodes/types.ts b/packages/api-v4/src/linodes/types.ts index 04e915b48ad..79b35707a30 100644 --- a/packages/api-v4/src/linodes/types.ts +++ b/packages/api-v4/src/linodes/types.ts @@ -46,7 +46,13 @@ export interface Linode { label: string; lke_cluster_id: null | number; locks: LockType[]; - maintenance_policy?: MaintenancePolicySlug; + /** + * The maintenance policy configured for this Linode. + * + * Will be `null` if the Maintenance Policy feature is not enabled or the Linode's + * region does not support maintenance policies. + */ + maintenance_policy: MaintenancePolicySlug | null; placement_group: LinodePlacementGroupPayload | null; region: string; site_type: RegionSite; @@ -75,6 +81,7 @@ export interface LinodeBackups { export type LinodeCapabilities = | 'Block Storage Encryption' | 'Block Storage Performance B1' + | 'Maintenance Policy' | 'SMTP Enabled'; export type Window = diff --git a/packages/manager/.changeset/pr-13269-fixed-1768236332373.md b/packages/manager/.changeset/pr-13269-fixed-1768236332373.md new file mode 100644 index 00000000000..9210bb5e2b6 --- /dev/null +++ b/packages/manager/.changeset/pr-13269-fixed-1768236332373.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +Only show Maintenance Policy for Linodes that actually have a Maintenance Policy ([#13269](https://github.com/linode/manager/pull/13269)) diff --git a/packages/manager/src/features/Linodes/LinodeEntityDetail.test.tsx b/packages/manager/src/features/Linodes/LinodeEntityDetail.test.tsx index f0a63b78eff..0f7d2aba767 100644 --- a/packages/manager/src/features/Linodes/LinodeEntityDetail.test.tsx +++ b/packages/manager/src/features/Linodes/LinodeEntityDetail.test.tsx @@ -336,6 +336,63 @@ describe('Linode Entity Detail', () => { expect(await findByTestId('linode-encryption-status')).toBeVisible(); }); + + it('should display the Linode maintenance policy if it supports it and the flag is on', async () => { + const linode = linodeFactory.build({ + maintenance_policy: 'linode/power_off_on', + capabilities: ['Maintenance Policy'], + }); + + server.use( + http.get('*/linode/instances/:linodeId', () => { + return HttpResponse.json(linode); + }) + ); + + const { findByText, getByText } = renderWithTheme( + , + { + flags: { + vmHostMaintenance: { enabled: true, beta: false, new: false }, + }, + } + ); + + expect( + await findByText('Maintenance Policy', { exact: false }) + ).toBeVisible(); + + expect(getByText('Power Off / Power On')).toBeVisible(); + }); + + it('should not display a maintenance policy if the linode does not have one', async () => { + const linode = linodeFactory.build({ + maintenance_policy: null, + capabilities: [], + }); + + server.use( + http.get('*/linode/instances/:linodeId', () => { + return HttpResponse.json(linode); + }) + ); + + const { findByText, queryByText } = renderWithTheme( + , + { + flags: { + vmHostMaintenance: { enabled: true, beta: false, new: false }, + }, + } + ); + + // Ensure the Linode is loaded + await findByText(linode.ipv4[0]); + + expect( + queryByText('Maintenance Policy', { exact: false }) + ).not.toBeInTheDocument(); + }); }); describe('getSubnetsString function', () => { diff --git a/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx b/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx index 3fde42e8fd0..2b1e855ac65 100644 --- a/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx +++ b/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx @@ -154,6 +154,7 @@ export const LinodeEntityDetail = (props: Props) => { image={linode.image ?? 'Unknown Image'} imageVendor={imageVendor} isSummaryView={isSummaryView} + linodeCapabilities={linode.capabilities} linodeId={linode.id} linodeLabel={linode.label} linodeMaintenancePolicySet={ diff --git a/packages/manager/src/features/Linodes/LinodeEntityDetailHeader.tsx b/packages/manager/src/features/Linodes/LinodeEntityDetailHeader.tsx index 1d078e796a5..49f1aa82335 100644 --- a/packages/manager/src/features/Linodes/LinodeEntityDetailHeader.tsx +++ b/packages/manager/src/features/Linodes/LinodeEntityDetailHeader.tsx @@ -15,11 +15,7 @@ import { LinodeEntityDetailHeaderMaintenancePolicy } from './LinodeEntityDetailH import { getLinodeIconStatus } from './LinodesLanding/utils'; import type { LinodeHandlers } from './LinodesLanding/LinodesLanding'; -import type { - Config, - LinodeBackups, - MaintenancePolicySlug, -} from '@linode/api-v4'; +import type { Config, LinodeBackups, LinodeCapabilities } from '@linode/api-v4'; import type { Linode, LinodeType } from '@linode/api-v4/lib/linodes/types'; import type { TypographyProps } from '@linode/ui'; import type { LinodeMaintenance } from 'src/utilities/linodes'; @@ -45,9 +41,10 @@ export interface HeaderProps { image: string; imageVendor: null | string; isSummaryView?: boolean; + linodeCapabilities: LinodeCapabilities[]; linodeId: number; linodeLabel: string; - linodeMaintenancePolicySet: MaintenancePolicySlug | undefined; + linodeMaintenancePolicySet: Linode['maintenance_policy']; linodeRegionDisplay: string; linodeStatus: Linode['status']; maintenance: LinodeMaintenance | null; @@ -76,6 +73,7 @@ export const LinodeEntityDetailHeader = ( linodeLabel, linodeRegionDisplay, linodeStatus, + linodeCapabilities, linodeMaintenancePolicySet, maintenance, openNotificationMenu, @@ -87,6 +85,10 @@ export const LinodeEntityDetailHeader = ( const { isVMHostMaintenanceEnabled } = useVMHostMaintenanceEnabled(); + const showMaintenancePolicy = + isVMHostMaintenanceEnabled && + linodeCapabilities.includes('Maintenance Policy'); + const isRunning = linodeStatus === 'running'; const isRebootNeeded = React.useMemo( @@ -157,7 +159,7 @@ export const LinodeEntityDetailHeader = ( text={VPC_REBOOT_MESSAGE} /> )} - {isVMHostMaintenanceEnabled && ( + {showMaintenancePolicy && (