Skip to content

Commit

Permalink
upcoming: [M3-7300] - Replace Linode details Analytics tab with Recha…
Browse files Browse the repository at this point in the history
…rts (#10037)

## Description 📝
Replace Linode details Analytics charts with Recharts

- CPU % chart
- Disk I/O chart
- Network Transfer charts (IPv4 & IPv6)

## Changes  🔄
List any change relevant to the reviewer.
- Updated UI charts for the Linode details Analytics tab
- Added custom legend logic to AreaChart
- Migrate MetricDisplay styles to styled components

## How to test 🧪

### Prerequisites
(How to setup test environment)
- Have a Linode that's been running for a while

### Verification steps 
(How to verify changes)
- Go to a Linode's details page. On the Analytics tab, verify the updated UI and that there are no regressions in the graph, units, functionality, etc.
  - Note: X and Y axis labels will not match exactly but the graph data is still the same
  • Loading branch information
hana-akamai authored Jan 16, 2024
1 parent 9774383 commit 395b91d
Show file tree
Hide file tree
Showing 19 changed files with 748 additions and 271 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Replace Linode details Analytics tab with Recharts ([#10037](https://github.com/linode/manager/pull/10037))
47 changes: 44 additions & 3 deletions packages/manager/src/components/AreaChart/AreaChart.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import React from 'react';

import { tooltipValueFormatter } from 'src/components/AreaChart/utils';
import { getMetrics } from 'src/utilities/statMetrics';

import { AreaChart } from './AreaChart';
import { timeData } from './utils';
import { customLegendData, timeData } from './utils';

import type { Meta, StoryObj } from '@storybook/react';
import type { Meta, StoryFn, StoryObj } from '@storybook/react';

const meta: Meta<typeof AreaChart> = {
component: AreaChart,
decorators: [
(Story: StoryFn) => (
<div style={{ marginTop: '2em' }}>
<Story />
</div>
),
],
title: 'Components/Graphs/AreaChart',
};

Expand All @@ -24,7 +34,38 @@ export const Default: Story = {
],
ariaLabel: 'Network Transfer History Graph',
data: timeData,
height: 190,
height: 300,
showLegend: true,
timezone: 'UTC',
unit: ` Kb/s`,
xAxis: {
tickFormat: 'LLL dd',
tickGap: 30,
},
},
render: (args) => <AreaChart {...args} />,
};

export const CustomLegend: Story = {
args: {
areas: [
{
color: '#1CB35C',
dataKey: 'Public Outbound Traffic',
},
],
ariaLabel: 'Network Transfer History Graph',
data: timeData,
height: 360,
legendRows: [
{
data: getMetrics(customLegendData),
format: (value: number) => tooltipValueFormatter(value, ' Kb/s'),
legendColor: 'lightGreen',
legendTitle: 'Public Outbound Traffic',
},
],
showLegend: true,
timezone: 'UTC',
unit: ` Kb/s`,
xAxis: {
Expand Down
34 changes: 33 additions & 1 deletion packages/manager/src/components/AreaChart/AreaChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
} from 'recharts';

import { AccessibleAreaChart } from 'src/components/AreaChart/AccessibleAreaChart';
import { MetricsDisplayRow } from 'src/components/LineGraph/MetricsDisplay';
import MetricsDisplay from 'src/components/LineGraph/MetricsDisplay';
import { Paper } from 'src/components/Paper';
import { StyledBottomLegend } from 'src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel';

import { tooltipLabelFormatter, tooltipValueFormatter } from './utils';

Expand All @@ -34,6 +37,7 @@ interface AreaChartProps {
ariaLabel: string;
data: any;
height: number;
legendRows?: Omit<MetricsDisplayRow[], 'handleLegendClick'>;
showLegend?: boolean;
timezone: string;
unit: string;
Expand All @@ -56,6 +60,7 @@ export const AreaChart = (props: AreaChartProps) => {
ariaLabel,
data,
height,
legendRows,
showLegend,
timezone,
unit,
Expand Down Expand Up @@ -100,6 +105,25 @@ export const AreaChart = (props: AreaChartProps) => {
return null;
};

const CustomLegend = () => {
if (legendRows) {
const legendRowsWithClickHandler = legendRows.map((legendRow) => ({
...legendRow,
handleLegendClick: () => handleLegendClick(legendRow.legendTitle),
}));

return (
<StyledBottomLegend>
<MetricsDisplay
hiddenRows={activeSeries}
rows={legendRowsWithClickHandler}
/>
</StyledBottomLegend>
);
}
return null;
};

const accessibleDataKeys = areas.map((area) => area.dataKey);

return (
Expand Down Expand Up @@ -132,7 +156,7 @@ export const AreaChart = (props: AreaChartProps) => {
}}
content={<CustomTooltip />}
/>
{showLegend && (
{showLegend && !legendRows && (
<Legend
formatter={(value) => (
<span style={{ color: theme.color.label, cursor: 'pointer' }}>
Expand All @@ -146,6 +170,14 @@ export const AreaChart = (props: AreaChartProps) => {
onClick={(props) => handleLegendClick(props.dataKey)}
/>
)}
{showLegend && legendRows && (
<Legend
wrapperStyle={{
left: 20,
}}
content={<CustomLegend />}
/>
)}
{areas.map(({ color, dataKey }) => (
<Area
dataKey={dataKey}
Expand Down
29 changes: 29 additions & 0 deletions packages/manager/src/components/AreaChart/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
interface TimeData {
timestamp: number;
}

export interface CPUTimeData extends TimeData {
'CPU %': number;
}

export interface DiskIOTimeData extends TimeData {
'I/O Rate': number;
'Swap Rate': number;
}

export interface NetworkTimeData extends TimeData {
'Private In': number;
'Private Out': number;
'Public In': number;
'Public Out': number;
}

export interface LinodeNetworkTimeData extends TimeData {
'Public Outbound Traffic': number;
}

export interface NodeBalancerConnectionsTimeData extends TimeData {
Connections: number;
}

export type Point = [number, number];
157 changes: 144 additions & 13 deletions packages/manager/src/components/AreaChart/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@ import { DateTime } from 'luxon';

import { roundTo } from 'src/utilities/roundTo';

export const timeData = [
import { LinodeNetworkTimeData } from './types';

export const getAccessibleTimestamp = (timestamp: number, timezone: string) =>
DateTime.fromMillis(timestamp, { zone: timezone }).toLocaleString(
DateTime.DATETIME_SHORT
);

export const tooltipLabelFormatter = (timestamp: number, timezone: string) =>
DateTime.fromMillis(timestamp, { zone: timezone }).toLocaleString(
DateTime.DATETIME_MED
);

export const tooltipValueFormatter = (value: number, unit: string) =>
`${roundTo(value)}${unit}`;

export const timeData: LinodeNetworkTimeData[] = [
{
'Public Outbound Traffic': 5.434939999999999,
timestamp: 1703304000000,
Expand Down Expand Up @@ -509,15 +524,131 @@ export const timeData = [
},
];

export const getAccessibleTimestamp = (timestamp: number, timezone: string) =>
DateTime.fromMillis(timestamp, { zone: timezone }).toLocaleString(
DateTime.DATETIME_SHORT
);

export const tooltipLabelFormatter = (timestamp: number, timezone: string) =>
DateTime.fromMillis(timestamp, { zone: timezone }).toLocaleString(
DateTime.DATETIME_MED
);

export const tooltipValueFormatter = (value: number, unit: string) =>
`${roundTo(value)}${unit}`;
export const customLegendData = [
[1703304000000, 5.434939999999999],
[1703311200000, 5.48299],
[1703318400000, 5.65558],
[1703325600000, 4.76884],
[1703332800000, 6.4184399999999995],
[1703340000000, 5.62116],
[1703347200000, 5.07858],
[1703354400000, 5.00401],
[1703361600000, 6.556310000000001],
[1703368800000, 5.0976300000000005],
[1703376000000, 4.8704],
[1703383200000, 5.489439999999999],
[1703390400000, 4.55057],
[1703397600000, 5.61529],
[1703404800000, 5.217],
[1703412000000, 5.11331],
[1703419200000, 5.46411],
[1703426400000, 4.7774399999999995],
[1703433600000, 5.02865],
[1703440800000, 6.32617],
[1703448000000, 4.93639],
[1703455200000, 5.915970000000001],
[1703462400000, 5.27855],
[1703469600000, 4.93147],
[1703476800000, 5.0265699999999995],
[1703484000000, 4.87472],
[1703491200000, 4.92317],
[1703498400000, 5.582979999999999],
[1703505600000, 4.59687],
[1703512800000, 5.0703000000000005],
[1703520000000, 5.48172],
[1703527200000, 5.71833],
[1703534400000, 5.80666],
[1703541600000, 7.650729999999999],
[1703548800000, 6.09863],
[1703556000000, 4.88399],
[1703563200000, 6.38346],
[1703570400000, 5.52181],
[1703577600000, 6.409890000000001],
[1703584800000, 6.24504],
[1703592000000, 6.706390000000001],
[1703599200000, 6.55377],
[1703606400000, 5.45406],
[1703613600000, 5.48203],
[1703620800000, 6.31843],
[1703628000000, 5.257149999999999],
[1703635200000, 5.693689999999999],
[1703642400000, 6.15741],
[1703649600000, 6.1616],
[1703656800000, 5.59863],
[1703664000000, 5.09122],
[1703671200000, 5.93977],
[1703678400000, 5.08668],
[1703685600000, 6.441350000000001],
[1703692800000, 5.36822],
[1703700000000, 28.10246],
[1703707200000, 5.84647],
[1703714400000, 5.9009],
[1703721600000, 5.97372],
[1703728800000, 7.28458],
[1703736000000, 6.96537],
[1703743200000, 4.5504],
[1703750400000, 4.5921],
[1703757600000, 6.516850000000001],
[1703764800000, 5.257359999999999],
[1703772000000, 5.79805],
[1703779200000, 5.2665],
[1703786400000, 6.34178],
[1703793600000, 5.37263],
[1703800800000, 6.46444],
[1703808000000, 5.16033],
[1703815200000, 4.85757],
[1703822400000, 6.5664299999999995],
[1703829600000, 6.73556],
[1703836800000, 5.29416],
[1703844000000, 5.54825],
[1703851200000, 5.0805],
[1703858400000, 6.29611],
[1703865600000, 5.98415],
[1703872800000, 6.11128],
[1703880000000, 6.23872],
[1703887200000, 5.773029999999999],
[1703894400000, 6.229100000000001],
[1703901600000, 7.26283],
[1703908800000, 4.83416],
[1703916000000, 6.2334700000000005],
[1703923200000, 5.019939999999999],
[1703930400000, 5.516310000000001],
[1703937600000, 6.84012],
[1703944800000, 4.83355],
[1703952000000, 5.28805],
[1703959200000, 5.223],
[1703966400000, 5.01722],
[1703973600000, 4.8092299999999994],
[1703980800000, 5.91444],
[1703988000000, 5.9965399999999995],
[1703995200000, 5.3739799999999995],
[1704002400000, 5.932720000000001],
[1704009600000, 5.38283],
[1704016800000, 6.44168],
[1704024000000, 4.90296],
[1704031200000, 4.883109999999999],
[1704038400000, 5.21804],
[1704045600000, 5.63115],
[1704052800000, 6.74491],
[1704060000000, 5.04914],
[1704067200000, 5.44395],
[1704074400000, 4.781350000000001],
[1704081600000, 5.3388100000000005],
[1704088800000, 5.9689499999999995],
[1704096000000, 5.15655],
[1704103200000, 6.12438],
[1704110400000, 4.669560000000001],
[1704117600000, 4.63611],
[1704124800000, 5.66633],
[1704132000000, 5.86619],
[1704139200000, 5.7318500000000006],
[1704146400000, 5.75463],
[1704153600000, 5.652810000000001],
[1704160800000, 5.0788400000000005],
[1704168000000, 6.32605],
[1704175200000, 9.19674],
[1704182400000, 10.7236],
[1704189600000, 11.021540000000002],
[1704196800000, 8.08084],
[1704204000000, 5.6375],
];
Loading

0 comments on commit 395b91d

Please sign in to comment.