Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [M3-8985] - High performance volume indicator #11400

Merged
merged 8 commits into from
Dec 16, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Upcoming Features
---

New `Block Storage Performance B1` linode capability ([#11400](https://github.com/linode/manager/pull/11400))
7 changes: 5 additions & 2 deletions packages/api-v4/src/linodes/types.ts
mjac0bs marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface Linode {
id: number;
alerts: LinodeAlerts;
backups: LinodeBackups;
capabilities?: LinodeCapabilities[]; // @TODO BSE: Remove optionality once BSE is fully rolled out
Copy link
Member

@bnussman-akamai bnussman-akamai Dec 13, 2024

Choose a reason for hiding this comment

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

I went ahead and pushed f80e9e9 to improve some types. I also removed the optionality here.

@dwiley-akamai @hkhalil-akamai Do you guys think this change is okay? From what I can see, capabilities is fully rolled out

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we should be good to go with that. I'll circle back to review other instances as part of M3-8405

capabilities: LinodeCapabilities[];
created: string;
disk_encryption?: EncryptionStatus; // @TODO LDE: Remove optionality once LDE is fully rolled out
region: string;
Expand Down Expand Up @@ -55,7 +55,10 @@ export interface LinodeBackups {
last_successful: string | null;
}

export type LinodeCapabilities = 'Block Storage Encryption' | 'SMTP Enabled';
export type LinodeCapabilities =
| 'Block Storage Encryption'
| 'SMTP Enabled'
| 'Block Storage Performance B1';

export type Window =
| 'Scheduling'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

High performance volume indicator ([#11400](https://github.com/linode/manager/pull/11400))
4 changes: 4 additions & 0 deletions packages/manager/src/__data__/linodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const linode1: Linode = {
window: 'W2',
},
},
capabilities: [],
created: '2017-12-07T19:12:58',
group: 'active',
hypervisor: 'kvm',
Expand Down Expand Up @@ -65,6 +66,7 @@ export const linode2: Linode = {
window: 'Scheduling',
},
},
capabilities: [],
created: '2018-02-22T16:11:07',
group: 'inactive',
hypervisor: 'kvm',
Expand Down Expand Up @@ -114,6 +116,7 @@ export const linode3: Linode = {
window: 'Scheduling',
},
},
capabilities: [],
created: '2018-02-22T16:11:07',
group: 'inactive',
hypervisor: 'kvm',
Expand Down Expand Up @@ -163,6 +166,7 @@ export const linode4: Linode = {
window: 'Scheduling',
},
},
capabilities: [],
created: '2018-02-22T16:11:07',
group: 'inactive',
hypervisor: 'kvm',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { IconButton, Tooltip } from '@linode/ui';
import BoltIcon from '@mui/icons-material/Bolt';
import React from 'react';

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

interface Props {
linodeCapabilities: LinodeCapabilities[];
}

export function HighPerformanceVolumeIcon({ linodeCapabilities }: Props) {
const isHighPerformanceVolume = !!linodeCapabilities?.includes(
'Block Storage Performance B1'
);

if (!isHighPerformanceVolume) {
return null;
}

return (
<Tooltip title="High Performance">
<IconButton
sx={{
border: '1px solid',
borderRadius: '50%',
padding: 0,
}}
>
<BoltIcon sx={{ fontSize: 12 }} />
</IconButton>
</Tooltip>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const LinodeEntityDetail = (props: Props) => {
ipv6={trimmedIPv6}
isLKELinode={Boolean(linode.lke_cluster_id)}
isVPCOnlyLinode={isVPCOnlyLinode}
linodeCapabilities={linode.capabilities}
linodeId={linode.id}
linodeIsInDistributedRegion={linodeIsInDistributedRegion}
linodeLabel={linode.label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import { usePreferences } from 'src/queries/profile/preferences';
import { useProfile } from 'src/queries/profile/profile';
import { pluralize } from 'src/utilities/pluralize';

import { encryptionStatusTestId } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import { EncryptedStatus } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import { encryptionStatusTestId } from '../Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodeTable';
import { HighPerformanceVolumeIcon } from './HighPerformanceVolumeIcon';
import {
StyledBodyGrid,
StyledColumnLabelGrid,
Expand All @@ -41,6 +42,7 @@ import type {
EncryptionStatus,
Interface,
Linode,
LinodeCapabilities,
} from '@linode/api-v4/lib/linodes/types';
import type { Subnet } from '@linode/api-v4/lib/vpcs';
import type { TypographyProps } from '@linode/ui';
Expand All @@ -66,6 +68,7 @@ export interface BodyProps {
ipv6: Linode['ipv6'];
isLKELinode: boolean; // indicates whether linode belongs to an LKE cluster
isVPCOnlyLinode: boolean;
linodeCapabilities: LinodeCapabilities[];
linodeId: number;
linodeIsInDistributedRegion: boolean;
linodeLabel: string;
Expand All @@ -85,6 +88,7 @@ export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {
ipv6,
isLKELinode,
isVPCOnlyLinode,
linodeCapabilities,
linodeId,
linodeIsInDistributedRegion,
linodeLabel,
Expand Down Expand Up @@ -151,9 +155,23 @@ export const LinodeEntityDetailBody = React.memo((props: BodyProps) => {
<Typography>{gbRAM} GB RAM</Typography>
</Grid>
<Grid lg={6} sm={12} xs={6}>
<Typography>
{pluralize('Volume', 'Volumes', numVolumes)}
</Typography>
<Box
sx={(theme) => ({
alignItems: 'center',
display: 'flex',
gap: theme.spacing(),
})}
>
<Typography>
{pluralize('Volume', 'Volumes', numVolumes)}
</Typography>

{numVolumes > 0 && (
<HighPerformanceVolumeIcon
linodeCapabilities={linodeCapabilities}
/>
)}
</Box>
</Grid>
{isDiskEncryptionFeatureEnabled && encryptionStatus && (
<Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export const LinodeVolumes = () => {
}
isDetailsPageRow
key={volume.id}
linodeCapabilities={linode?.capabilities}
volume={volume}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('LinodeRow', () => {
}}
alerts={linode.alerts}
backups={linode.backups}
capabilities={linode.capabilities}
created={linode.created}
group={linode.group}
hypervisor={linode.hypervisor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ListView = (props: RenderLinodesProps) => {
}}
alerts={linode.alerts}
backups={linode.backups}
capabilities={linode.capabilities}
created={linode.created}
group={linode.group}
hypervisor={linode.hypervisor}
Expand Down
20 changes: 20 additions & 0 deletions packages/manager/src/features/Volumes/VolumeTableRow.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as React from 'react';

Expand Down Expand Up @@ -174,4 +175,23 @@ describe('Volume table row - for linodes detail page', () => {
// Make sure there is a detach button
expect(getByText('Detach'));
});

it('should show a high performance icon tooltip if Linode has the capability', async () => {
const { getByLabelText, getByText } = await renderWithThemeAndRouter(
wrapWithTableBody(
<VolumeTableRow
handlers={handlers}
isDetailsPageRow
linodeCapabilities={['Block Storage Performance B1']}
volume={attachedVolume}
/>
)
);

const highPerformanceIcon = getByLabelText('High Performance');

expect(highPerformanceIcon).toBeVisible();
await userEvent.click(highPerformanceIcon);
await waitFor(() => expect(getByText('High Performance')).toBeVisible());
});
});
21 changes: 19 additions & 2 deletions packages/manager/src/features/Volumes/VolumeTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useNotificationsQuery } from 'src/queries/account/notifications';
import { useInProgressEvents } from 'src/queries/events/events';
import { useRegionsQuery } from 'src/queries/regions/regions';

import { HighPerformanceVolumeIcon } from '../Linodes/HighPerformanceVolumeIcon';
import {
getDerivedVolumeStatusFromStatusAndEvent,
getEventProgress,
Expand All @@ -20,7 +21,7 @@ import {
import { VolumesActionMenu } from './VolumesActionMenu';

import type { ActionHandlers } from './VolumesActionMenu';
import type { Volume } from '@linode/api-v4';
import type { LinodeCapabilities, Volume } from '@linode/api-v4';

export const useStyles = makeStyles()({
volumePath: {
Expand All @@ -33,6 +34,7 @@ interface Props {
handlers: ActionHandlers;
isBlockStorageEncryptionFeatureEnabled?: boolean;
isDetailsPageRow?: boolean;
linodeCapabilities?: LinodeCapabilities[];
volume: Volume;
}

Expand All @@ -42,6 +44,7 @@ export const VolumeTableRow = React.memo((props: Props) => {
handlers,
isBlockStorageEncryptionFeatureEnabled,
isDetailsPageRow,
linodeCapabilities,
volume,
} = props;

Expand Down Expand Up @@ -115,7 +118,21 @@ export const VolumeTableRow = React.memo((props: Props) => {
wrap: 'nowrap',
}}
>
{volume.label}
<Box
sx={(theme) => ({
alignItems: 'center',
display: 'flex',
gap: theme.spacing(),
})}
>
{volume.label}
{linodeCapabilities && (
<HighPerformanceVolumeIcon
linodeCapabilities={linodeCapabilities}
/>
)}
</Box>

{isEligibleForUpgradeToNVMe && (
<Chip
clickable
Expand Down
4 changes: 3 additions & 1 deletion packages/manager/src/mocks/presets/crud/seeds/linodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ export const linodesSeeder: MockSeeder = {
const count = seedsCountMap[linodesSeeder.id] ?? 0;
const linodeSeeds = seedWithUniqueIds<'linodes'>({
dbEntities: await mswDB.getAll('linodes'),
seedEntities: linodeFactory.buildList(count),
seedEntities: linodeFactory.buildList(count, {
capabilities: ['Block Storage Performance B1'],
}),
});

const configs: [number, Config][] = linodeSeeds.map((linodeSeed) => {
Expand Down
Loading