Skip to content

Commit 83c6fc2

Browse files
committed
Plugins: Charts Example: Add failed pods resource chart to overview page.
Signed-off-by: Faakhir30 <[email protected]>
1 parent 59699ef commit 83c6fc2

File tree

16 files changed

+35881
-15
lines changed

16 files changed

+35881
-15
lines changed

Diff for: frontend/src/components/cluster/Overview.tsx

+36-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Event from '../../lib/k8s/event';
77
import Node from '../../lib/k8s/node';
88
import Pod from '../../lib/k8s/pod';
99
import { useFilterFunc } from '../../lib/util';
10+
import { OverviewChart } from '../../redux/overviewChartsSlice';
11+
import { useTypedSelector } from '../../redux/reducers/reducers';
1012
import { DateLabel, Link, PageGrid, StatusLabel } from '../common';
1113
import Empty from '../common/EmptyContent';
1214
import ResourceListView from '../common/Resource/ResourceListView';
@@ -22,34 +24,54 @@ import {
2224

2325
export default function Overview() {
2426
const { t } = useTranslation(['translation']);
25-
2627
const [pods] = Pod.useList();
2728
const [nodes] = Node.useList();
28-
2929
const [nodeMetrics, metricsError] = Node.useMetrics();
30+
const chartProcessors = useTypedSelector(state => state.overviewCharts.processors);
3031

3132
const noMetrics = metricsError?.status === 404;
3233
const noPermissions = metricsError?.status === 403;
3334

35+
// Process the default charts through any registered processors
36+
const defaultCharts: OverviewChart[] = [
37+
{
38+
id: 'cpu',
39+
component: () => (
40+
<CpuCircularChart items={nodes} itemsMetrics={nodeMetrics} noMetrics={noMetrics} />
41+
),
42+
},
43+
{
44+
id: 'memory',
45+
component: () => (
46+
<MemoryCircularChart items={nodes} itemsMetrics={nodeMetrics} noMetrics={noMetrics} />
47+
),
48+
},
49+
{
50+
id: 'pods',
51+
component: () => <PodsStatusCircleChart items={pods} />,
52+
},
53+
{
54+
id: 'nodes',
55+
component: () => <NodesStatusCircleChart items={nodes} />,
56+
},
57+
];
58+
const charts = chartProcessors.reduce(
59+
(currentCharts, p) => p.processor(currentCharts),
60+
defaultCharts
61+
);
62+
3463
return (
3564
<PageGrid>
3665
<SectionBox title={t('translation|Overview')} py={2} mt={[4, 0, 0]}>
3766
{noPermissions ? (
3867
<Empty color="error">{t('translation|No permissions to list pods.')}</Empty>
3968
) : (
4069
<Grid container justifyContent="flex-start" alignItems="stretch" spacing={4}>
41-
<Grid item xs sx={{ maxWidth: '300px' }}>
42-
<CpuCircularChart items={nodes} itemsMetrics={nodeMetrics} noMetrics={noMetrics} />
43-
</Grid>
44-
<Grid item xs sx={{ maxWidth: '300px' }}>
45-
<MemoryCircularChart items={nodes} itemsMetrics={nodeMetrics} noMetrics={noMetrics} />
46-
</Grid>
47-
<Grid item xs sx={{ maxWidth: '300px' }}>
48-
<PodsStatusCircleChart items={pods} />
49-
</Grid>
50-
<Grid item xs sx={{ maxWidth: '300px' }}>
51-
<NodesStatusCircleChart items={nodes} />
52-
</Grid>
70+
{charts.map(chart => (
71+
<Grid key={chart.id} item xs sx={{ maxWidth: '300px' }}>
72+
<chart.component />
73+
</Grid>
74+
))}
5375
</Grid>
5476
)}
5577
</SectionBox>

Diff for: frontend/src/plugin/__snapshots__/pluginLib.snapshot

+2-1
Original file line numberDiff line numberDiff line change
@@ -16110,6 +16110,7 @@
1611016110
"registerDetailsViewSectionsProcessor": [Function],
1611116111
"registerGetTokenFunction": [Function],
1611216112
"registerHeadlampEventCallback": [Function],
16113+
"registerOverviewChartsProcessor": [Function],
1611316114
"registerPluginSettings": [Function],
1611416115
"registerResourceTableColumnsProcessor": [Function],
1611516116
"registerRoute": [Function],
@@ -16118,4 +16119,4 @@
1611816119
"registerSidebarEntry": [Function],
1611916120
"registerSidebarEntryFilter": [Function],
1612016121
"runCommand": [Function],
16121-
}
16122+
}

Diff for: frontend/src/plugin/registry.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
ScaleResourceEvent,
5858
TerminalEvent,
5959
} from '../redux/headlampEventSlice';
60+
import { addOverviewChartsProcessor, OverviewChartsProcessor } from '../redux/overviewChartsSlice';
6061
import { setRoute, setRouteFilter } from '../redux/routesSlice';
6162
import store from '../redux/stores/store';
6263
import {
@@ -97,6 +98,7 @@ export type {
9798
EventListEvent,
9899
PluginSettingsDetailsProps,
99100
PluginSettingsComponentType,
101+
OverviewChartsProcessor,
100102
};
101103
export const DefaultHeadlampEvents = HeadlampEventType;
102104
export const DetailsViewDefaultHeaderActions = DefaultHeaderAction;
@@ -684,6 +686,31 @@ export function registerPluginSettings(
684686
store.dispatch(setPluginSettingsComponent({ name, component, displaySaveButton }));
685687
}
686688

689+
/**
690+
* Add a processor for the overview charts section. Allowing the addition or modification of charts.
691+
*
692+
* @param processor - The processor to add. Returns the new charts to be displayed.
693+
*
694+
* @example
695+
*
696+
* ```tsx
697+
* import { registerOverviewChartsProcessor } from '@kinvolk/headlamp-plugin/lib';
698+
*
699+
* registerOverviewChartsProcessor(function addFailedPodsChart(charts) {
700+
* return [
701+
* ...charts,
702+
* {
703+
* id: 'failed-pods',
704+
* component: () => <FailedPodsChart />
705+
* }
706+
* ];
707+
* });
708+
* ```
709+
*/
710+
export function registerOverviewChartsProcessor(processor: OverviewChartsProcessor) {
711+
store.dispatch(addOverviewChartsProcessor(processor));
712+
}
713+
687714
export {
688715
DefaultAppBarAction,
689716
DefaultDetailsViewSection,

Diff for: frontend/src/redux/overviewChartsSlice.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2+
import { ReactNode } from 'react';
3+
4+
export interface OverviewChart {
5+
id: string;
6+
component: () => ReactNode;
7+
}
8+
9+
export interface OverviewChartsProcessor {
10+
id?: string;
11+
processor: (charts: OverviewChart[]) => OverviewChart[];
12+
}
13+
14+
interface OverviewChartsState {
15+
processors: OverviewChartsProcessor[];
16+
}
17+
18+
const initialState: OverviewChartsState = {
19+
processors: [],
20+
};
21+
22+
const overviewChartsSlice = createSlice({
23+
name: 'overviewCharts',
24+
initialState,
25+
reducers: {
26+
addProcessor: (state, action: PayloadAction<OverviewChartsProcessor>) => {
27+
state.processors.push(action.payload);
28+
},
29+
},
30+
});
31+
32+
export const { addProcessor: addOverviewChartsProcessor } = overviewChartsSlice.actions;
33+
export default overviewChartsSlice.reducer;

Diff for: frontend/src/redux/reducers/reducers.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import clusterAction from '../clusterActionSlice';
88
import configReducer from '../configSlice';
99
import filterReducer from '../filterSlice';
1010
import eventCallbackReducer from '../headlampEventSlice';
11+
import overviewChartsReducer from '../overviewChartsSlice';
1112
import routesReducer from '../routesSlice';
1213
import resourceTableReducer from './../../components/common/Resource/resourceTableSlice';
1314
import detailsViewSectionReducer from './../../components/DetailsViewSection/detailsViewSectionSlice';
@@ -31,6 +32,7 @@ const reducers = combineReducers({
3132
detailsViewSections: detailsViewSectionReducer,
3233
eventCallbackReducer,
3334
pluginConfigs: pluginConfigReducer,
35+
overviewCharts: overviewChartsReducer,
3436
});
3537

3638
export type RootState = ReturnType<typeof reducers>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
// See http://go.microsoft.com/fwlink/?LinkId=827846
3+
// for the documentation about the extensions.json format
4+
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
5+
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Place your settings in this file to overwrite default and user settings.
2+
{
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "esbenp.prettier-vscode",
5+
"[javascript]": {
6+
"editor.defaultFormatter": "esbenp.prettier-vscode"
7+
},
8+
"[javascriptreact]": {
9+
"editor.defaultFormatter": "esbenp.prettier-vscode"
10+
},
11+
"[typescript]": {
12+
"editor.defaultFormatter": "esbenp.prettier-vscode"
13+
},
14+
"[typescriptreact]": {
15+
"editor.defaultFormatter": "esbenp.prettier-vscode"
16+
}
17+
}

Diff for: plugins/examples/resource-charts/.vscode/tasks.json

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// See https://go.microsoft.com/fwlink/?LinkId=733558
2+
// for the documentation about the tasks.json format
3+
{
4+
"version": "2.0.0",
5+
"tasks": [
6+
{
7+
"type": "npm",
8+
"script": "start",
9+
"problemMatcher": ["$tsc-watch", "$eslint-compact"],
10+
"isBackground": true,
11+
"presentation": {
12+
"reveal": "never"
13+
},
14+
"group": {
15+
"kind": "build",
16+
"isDefault": true
17+
}
18+
},
19+
{
20+
"type": "npm",
21+
"script": "test",
22+
"problemMatcher": ["$tsc-watch", "$eslint-compact"],
23+
"isBackground": true,
24+
"presentation": {
25+
"reveal": "always"
26+
},
27+
"group": {
28+
"kind": "test",
29+
"isDefault": true
30+
}
31+
}
32+
]
33+
}

Diff for: plugins/examples/resource-charts/README.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Resource CircularCharts Plugin
2+
3+
This plugin demonstrates how to add custom resource charts to Headlamp's Overview page. Currently, it adds a Pod Failure chart that visualizes the number of failed pods in the cluster.
4+
5+
## Features
6+
7+
- Adds a "Pods Failed" chart to the Overview page
8+
- Uses theme-based colors to highlight failed pods
9+
- Shows percentage and count of failed pods vs total pods
10+
11+
## Usage
12+
13+
To run the plugin:
14+
15+
```bash
16+
cd plugins/examples/resource-charts
17+
npm install
18+
npm start
19+
```
20+
21+
Then visit the Overview page in Headlamp to see the Pod Failure chart in action.
22+
23+
## Development
24+
25+
The main implementation is in [src/index.tsx](src/index.tsx), which shows how to:
26+
27+
- Create a custom chart component using Headlamp's TileChart
28+
- Use Kubernetes resource data with Headlamp's K8s API
29+
- Register charts to appear in the Overview page using the charts processor
30+
31+
For more information on developing Headlamp plugins, please refer to:
32+
33+
- [Getting Started](https://headlamp.dev/docs/latest/development/plugins/)
34+
- [API Reference](https://headlamp.dev/docs/latest/development/api/)
35+
- [UI Component Storybook](https://headlamp.dev/docs/latest/development/frontend/#storybook)

0 commit comments

Comments
 (0)