Skip to content

Commit f0b3e18

Browse files
authored
Merge pull request #2821 from Faakhir30/feat/new-chart-stories
Frontend: Add stories for chart componenets
2 parents ebe3ae6 + dd236ce commit f0b3e18

22 files changed

+1619
-91
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import { Meta, StoryFn } from '@storybook/react';
2+
import { KubeMetrics } from '../../../lib/k8s/cluster';
3+
import Node from '../../../lib/k8s/node';
4+
import Pod from '../../../lib/k8s/pod';
5+
import { CircularChartProps } from '../../common/Resource/CircularChart';
6+
import { CpuCircularChart, MemoryCircularChart } from './ResourceCharts';
7+
8+
interface ResourceCircularChartProps {
9+
chart_props: CircularChartProps;
10+
resource: 'memory' | 'cpu';
11+
}
12+
13+
const Template1: StoryFn<ResourceCircularChartProps> = (args: ResourceCircularChartProps) => {
14+
if (args.resource === 'memory') {
15+
return <MemoryCircularChart {...args.chart_props} />;
16+
} else {
17+
return <CpuCircularChart {...args.chart_props} />;
18+
}
19+
};
20+
21+
const meta: Meta = {
22+
title: 'Cluster/ResourceCharts',
23+
component: Template1,
24+
decorators: [Story => <Story />],
25+
};
26+
27+
export default meta;
28+
29+
// Base objects for mock data
30+
const baseNodeData = {
31+
kind: 'Node',
32+
apiVersion: 'v1',
33+
metadata: {
34+
uid: '1',
35+
resourceVersion: '1',
36+
creationTimestamp: '2021-01-01T00:00:00Z',
37+
namespace: 'default',
38+
},
39+
spec: {
40+
podCIDR: '10.244.0.0/24',
41+
taints: [],
42+
},
43+
status: {
44+
capacity: {
45+
cpu: '2', // 2 CPU cores
46+
memory: '8Gi', // 8GB memory
47+
ephemeralStorage: '100Gi',
48+
hugepages_1Gi: '0',
49+
hugepages_2Mi: '0',
50+
pods: '110',
51+
},
52+
conditions: [
53+
{
54+
type: 'Ready',
55+
status: 'True',
56+
lastHeartbeatTime: '2021-01-01T00:00:00Z',
57+
lastTransitionTime: '2021-01-01T00:00:00Z',
58+
message: 'Node is ready',
59+
reason: 'KubeletReady',
60+
},
61+
],
62+
},
63+
};
64+
65+
const basePodData = {
66+
kind: 'Pod',
67+
apiVersion: 'v1',
68+
metadata: {
69+
uid: '1',
70+
resourceVersion: '1',
71+
creationTimestamp: '2021-01-01T00:00:00Z',
72+
namespace: 'default',
73+
},
74+
spec: {
75+
containers: [],
76+
nodeName: 'node-1',
77+
},
78+
status: {
79+
phase: 'Running',
80+
conditions: [
81+
{
82+
type: 'Ready',
83+
status: 'True',
84+
lastTransitionTime: '2021-01-01T00:00:00Z',
85+
lastProbeTime: '2021-01-01T00:00:00Z',
86+
message: 'Pod is ready',
87+
reason: 'PodReady',
88+
},
89+
],
90+
containerStatuses: [],
91+
startTime: '2021-01-01T00:00:00Z',
92+
},
93+
};
94+
95+
// Mock data
96+
const mockNode = new Node({
97+
...baseNodeData,
98+
metadata: {
99+
...baseNodeData.metadata,
100+
name: 'node-1',
101+
},
102+
});
103+
104+
const mockNodeMetrics: KubeMetrics = {
105+
metadata: {
106+
name: 'node-1',
107+
uid: '1',
108+
resourceVersion: '1',
109+
creationTimestamp: '2021-01-01T00:00:00Z',
110+
namespace: 'default',
111+
},
112+
usage: {
113+
cpu: '500m', // 0.5 CPU
114+
memory: '2Gi', // 2GB memory
115+
},
116+
status: {
117+
capacity: {
118+
cpu: '2',
119+
memory: '8Gi',
120+
},
121+
},
122+
};
123+
124+
const mockPod = new Pod({
125+
...basePodData,
126+
metadata: {
127+
...basePodData.metadata,
128+
name: 'pod-1',
129+
},
130+
});
131+
132+
const mockPodMetrics: KubeMetrics = {
133+
metadata: {
134+
name: 'pod-1',
135+
uid: '1',
136+
resourceVersion: '1',
137+
creationTimestamp: '2021-01-01T00:00:00Z',
138+
namespace: 'default',
139+
},
140+
usage: {
141+
cpu: '200m', // 0.2 CPU
142+
memory: '500Mi', // 500MB memory
143+
},
144+
status: {
145+
capacity: {
146+
cpu: '1',
147+
memory: '1Gi',
148+
},
149+
},
150+
};
151+
152+
// Memory Chart Stories
153+
export const MemoryChartWithMetrics = Template1.bind({});
154+
MemoryChartWithMetrics.args = {
155+
chart_props: {
156+
items: [mockNode],
157+
itemsMetrics: [mockNodeMetrics],
158+
noMetrics: false,
159+
},
160+
resource: 'memory',
161+
};
162+
163+
export const MemoryChartNoMetrics = Template1.bind({});
164+
MemoryChartNoMetrics.args = {
165+
chart_props: {
166+
items: [mockNode],
167+
itemsMetrics: null,
168+
noMetrics: true,
169+
},
170+
resource: 'memory',
171+
};
172+
173+
export const MemoryChartPod = Template1.bind({});
174+
MemoryChartPod.args = {
175+
chart_props: {
176+
items: [mockPod],
177+
itemsMetrics: [mockPodMetrics],
178+
noMetrics: false,
179+
},
180+
resource: 'memory',
181+
};
182+
183+
// CPU Chart Stories
184+
export const CpuChartWithMetrics = Template1.bind({});
185+
CpuChartWithMetrics.args = {
186+
chart_props: {
187+
items: [mockNode],
188+
itemsMetrics: [mockNodeMetrics],
189+
noMetrics: false,
190+
},
191+
resource: 'cpu',
192+
};
193+
194+
export const CpuChartNoMetrics = Template1.bind({});
195+
CpuChartNoMetrics.args = {
196+
chart_props: {
197+
items: [mockNode],
198+
itemsMetrics: null,
199+
noMetrics: true,
200+
},
201+
resource: 'cpu',
202+
};
203+
204+
export const CpuChartPod = Template1.bind({});
205+
CpuChartPod.args = {
206+
chart_props: {
207+
items: [mockPod],
208+
itemsMetrics: [mockPodMetrics],
209+
noMetrics: false,
210+
},
211+
resource: 'cpu',
212+
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import '../../../i18n/config';
2+
import { useTranslation } from 'react-i18next';
3+
import { KubeMetrics } from '../../../lib/k8s/cluster';
4+
import Node from '../../../lib/k8s/node';
5+
import Pod from '../../../lib/k8s/pod';
6+
import { parseCpu, parseRam, TO_GB, TO_ONE_CPU } from '../../../lib/units';
7+
import ResourceCircularChart, {
8+
CircularChartProps as ResourceCircularChartProps,
9+
} from '../../common/Resource/CircularChart';
10+
11+
export function MemoryCircularChart(props: ResourceCircularChartProps) {
12+
const { noMetrics } = props;
13+
const { t } = useTranslation(['translation', 'glossary']);
14+
15+
function memoryUsedGetter(item: KubeMetrics) {
16+
return parseRam(item.usage.memory) / TO_GB;
17+
}
18+
19+
function memoryAvailableGetter(item: Node | Pod) {
20+
return parseRam(item.status?.capacity?.memory) / TO_GB;
21+
}
22+
23+
function getLegend(used: number, available: number) {
24+
if (available === 0 || available === -1) {
25+
return '';
26+
}
27+
28+
const availableLabel = `${available.toFixed(2)} GB`;
29+
if (noMetrics) {
30+
return availableLabel;
31+
}
32+
33+
return `${used.toFixed(2)} / ${availableLabel}`;
34+
}
35+
36+
return (
37+
<ResourceCircularChart
38+
getLegend={getLegend}
39+
resourceUsedGetter={memoryUsedGetter}
40+
resourceAvailableGetter={memoryAvailableGetter}
41+
title={noMetrics ? t('glossary|Memory') : t('translation|Memory Usage')}
42+
{...props}
43+
/>
44+
);
45+
}
46+
47+
export function CpuCircularChart(props: ResourceCircularChartProps) {
48+
const { noMetrics } = props;
49+
const { t } = useTranslation(['translation', 'glossary']);
50+
51+
function cpuUsedGetter(item: KubeMetrics) {
52+
return parseCpu(item.usage.cpu) / TO_ONE_CPU;
53+
}
54+
55+
function cpuAvailableGetter(item: Node | Pod) {
56+
return parseCpu(item.status?.capacity?.cpu) / TO_ONE_CPU;
57+
}
58+
59+
function getLegend(used: number, available: number) {
60+
if (available === 0 || available === -1) {
61+
return '';
62+
}
63+
64+
const availableLabel = t('translation|{{ available }} units', { available });
65+
if (noMetrics) {
66+
return availableLabel;
67+
}
68+
69+
return `${used.toFixed(2)} / ${availableLabel}`;
70+
}
71+
72+
return (
73+
<ResourceCircularChart
74+
getLegend={getLegend}
75+
resourceUsedGetter={cpuUsedGetter}
76+
resourceAvailableGetter={cpuAvailableGetter}
77+
title={noMetrics ? t('glossary|CPU') : t('translation|CPU Usage')}
78+
{...props}
79+
/>
80+
);
81+
}

0 commit comments

Comments
 (0)