Skip to content

Commit

Permalink
feat: [M3-8985] - High performance volume indicator (#11400)
Browse files Browse the repository at this point in the history
* feat: [M3-8985] - High performance volume indicator added.

* Added changeset: High performance volume indicator added.

* Added changeset: New `Block Storage Performance B1` linode capability

* feat: [M3-8985] - Comments resolved.

* improve prop optionality

* Use ui package components and keep tooltip styling consistent

* Update changesets for Upcoming Features

* Small fix.

---------

Co-authored-by: Banks Nussman <banks@nussman.us>
Co-authored-by: mjac0bs <mjacobs@akamai.com>
  • Loading branch information
3 people authored Dec 16, 2024
1 parent 456b923 commit b703190
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 9 deletions.
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
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
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
26 changes: 22 additions & 4 deletions packages/manager/src/features/Linodes/LinodeEntityDetailBody.tsx
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

0 comments on commit b703190

Please sign in to comment.