Skip to content

Commit 5e4cb6f

Browse files
Exposed topology components to dynamic plugins
1 parent c95be0d commit 5e4cb6f

34 files changed

+1304
-211
lines changed

dynamic-demo-plugin/console-extensions.json

+21-1
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@
402402
"href": "/test-horizontalnav"
403403
}
404404
},
405-
{
405+
{
406406
"type": "console.create-project-modal",
407407
"properties": {
408408
"component": { "$codeRef": "createProjectModal" }
@@ -444,5 +444,25 @@
444444
"name": "%plugin__console-demo-plugin~Example Namespaced Page%",
445445
"href": "/example-namespaced-page"
446446
}
447+
},
448+
{
449+
"type": "console.page/route",
450+
"properties": {
451+
"exact": true,
452+
"path": ["/example-topology-page"],
453+
"component": {
454+
"$codeRef": "exampleTopologyPage.ExampleTopologyPage"
455+
}
456+
}
457+
},
458+
{
459+
"type": "console.navigation/href",
460+
"properties": {
461+
"id": "demo-example-topology-page",
462+
"perspective": "admin",
463+
"section": "admin-demo-section",
464+
"name": "%plugin__console-demo-plugin~Example Topology Page%",
465+
"href": "/example-topology-page"
466+
}
447467
}
448468
]

dynamic-demo-plugin/locales/en/plugin__console-demo-plugin.json

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
"Prometheus data": "Prometheus data",
2222
"Dynamic Plugin Proxy Services example": "Dynamic Plugin Proxy Services example",
2323
"Proxy: consoleFetchJSON": "Proxy: consoleFetchJSON",
24+
"Example Topology Page": "Example Topology Page",
25+
"CPU Cell Component": "CPU Cell Component",
26+
"Memory Cell Component": "Memory Cell Component",
27+
"Topology List View Node": "Topology List View Node",
2428
"Extensions of type Console.flag/Model": "Extensions of type Console.flag/Model",
2529
"Group": "Group",
2630
"Version": "Version",

dynamic-demo-plugin/package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@
66
"clean": "rm -rf dist",
77
"build": "yarn clean && NODE_ENV=production yarn ts-node node_modules/.bin/webpack",
88
"build-dev": "yarn clean && yarn ts-node node_modules/.bin/webpack",
9-
"build-plugin-sdk": "yarn --cwd ../frontend build-plugin-sdk && rm -rf node_modules/@openshift-console && yarn install --check-files",
9+
"build-plugin-sdk": "yarn --cwd ../frontend build-plugin-sdk && yarn install-plugin-sdk",
10+
"install-plugin-sdk": "rm -rf node_modules/@openshift-console && yarn install --check-files",
1011
"start-console": "./start-console.sh",
1112
"http-server": "./http-server.sh dist",
1213
"i18n": "i18next \"src/**/*.{js,jsx,ts,tsx}\" [-oc] -c i18next-parser.config.js",
1314
"ts-node": "ts-node -O '{\"module\":\"commonjs\"}'"
1415
},
1516
"devDependencies": {
1617
"@openshift-console/dynamic-plugin-sdk": "file:../frontend/packages/console-dynamic-plugin-sdk/dist/core",
18+
"@openshift-console/dynamic-plugin-sdk-internal": "file:../frontend/packages/console-dynamic-plugin-sdk/dist/internal",
1719
"@openshift-console/dynamic-plugin-sdk-webpack": "file:../frontend/packages/console-dynamic-plugin-sdk/dist/webpack",
1820
"@openshift-console/plugin-shared": "file:../frontend/packages/console-plugin-shared/dist",
1921
"@patternfly/react-core": "5.1.1",
2022
"@patternfly/react-icons": "5.1.1",
2123
"@patternfly/react-table": "5.1.1",
24+
"@patternfly/react-topology": "5.3.0",
2225
"@types/react": "16.8.13",
2326
"@types/react-measure": "^2.0.6",
2427
"@types/react-router": "^5.1.20",
@@ -72,7 +75,8 @@
7275
"projectOverview": "./utils/project-overview",
7376
"modalPage": "./components/Modals/ModalPage",
7477
"sampleErrorBoundaryPage": "./components/ErrorBoundary/SampleErrorBoundaryPage",
75-
"createProjectModal": "./components/Modals/CreateProjectModal"
78+
"createProjectModal": "./components/Modals/CreateProjectModal",
79+
"exampleTopologyPage": "./components/ExampleTopologyPage"
7680
},
7781
"disableStaticPlugins": [
7882
"@console/demo-plugin"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
import * as React from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import {
4+
CpuCellComponent,
5+
MemoryCellComponent,
6+
TopologyListViewNode,
7+
} from '@openshift-console/dynamic-plugin-sdk-internal';
8+
import { DataList, DataListCell } from '@patternfly/react-core';
9+
import { Node } from '@patternfly/react-topology';
10+
11+
export const ExampleTopologyPage: React.FC = () => {
12+
const { t } = useTranslation('plugin__console-demo-plugin');
13+
14+
const mockNode = {
15+
getId: () => 'mock-node-1',
16+
getData: () => ({
17+
id: '79d13a76-20b0-41cf-8ec3-286bbf702a03',
18+
name: 'test1',
19+
type: 'workload',
20+
resource: {
21+
kind: 'Deployment',
22+
apiVersion: 'apps/v1',
23+
metadata: {
24+
name: 'test1',
25+
namespace: 'prabhu',
26+
uid: '79d13a76-20b0-41cf-8ec3-286bbf702a03',
27+
resourceVersion: '77155',
28+
generation: 1,
29+
creationTimestamp: '2025-01-17T06:11:36Z',
30+
annotations: {
31+
'deployment.kubernetes.io/revision': '1',
32+
},
33+
},
34+
spec: {
35+
replicas: 3,
36+
selector: {
37+
matchLabels: {
38+
app: 'test1',
39+
},
40+
},
41+
template: {
42+
metadata: {
43+
creationTimestamp: null,
44+
labels: {
45+
app: 'test1',
46+
},
47+
},
48+
spec: {
49+
containers: [
50+
{
51+
name: 'container',
52+
image: 'image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest',
53+
ports: [
54+
{
55+
containerPort: 8080,
56+
protocol: 'TCP',
57+
},
58+
],
59+
resources: {},
60+
terminationMessagePath: '/dev/termination-log',
61+
terminationMessagePolicy: 'File',
62+
imagePullPolicy: 'Always',
63+
},
64+
],
65+
restartPolicy: 'Always',
66+
terminationGracePeriodSeconds: 30,
67+
dnsPolicy: 'ClusterFirst',
68+
securityContext: {},
69+
schedulerName: 'default-scheduler',
70+
},
71+
},
72+
strategy: {
73+
type: 'RollingUpdate',
74+
rollingUpdate: {
75+
maxUnavailable: '25%',
76+
maxSurge: '25%',
77+
},
78+
},
79+
revisionHistoryLimit: 10,
80+
progressDeadlineSeconds: 600,
81+
},
82+
status: {
83+
observedGeneration: 1,
84+
replicas: 3,
85+
updatedReplicas: 3,
86+
readyReplicas: 3,
87+
availableReplicas: 3,
88+
conditions: [
89+
{
90+
type: 'Available',
91+
status: 'True',
92+
lastUpdateTime: '2025-01-17T06:11:47Z',
93+
lastTransitionTime: '2025-01-17T06:11:47Z',
94+
reason: 'MinimumReplicasAvailable',
95+
message: 'Deployment has minimum availability.',
96+
},
97+
{
98+
type: 'Progressing',
99+
status: 'True',
100+
lastUpdateTime: '2025-01-17T06:11:47Z',
101+
lastTransitionTime: '2025-01-17T06:11:36Z',
102+
reason: 'NewReplicaSetAvailable',
103+
message: 'ReplicaSet "test1-59d845d69c" has successfully progressed.',
104+
},
105+
],
106+
},
107+
},
108+
resources: {
109+
obj: {
110+
kind: 'Deployment',
111+
apiVersion: 'apps/v1',
112+
metadata: {
113+
name: 'test1',
114+
namespace: 'prabhu',
115+
uid: '79d13a76-20b0-41cf-8ec3-286bbf702a03',
116+
resourceVersion: '77155',
117+
generation: 1,
118+
creationTimestamp: '2025-01-17T06:11:36Z',
119+
annotations: {
120+
'deployment.kubernetes.io/revision': '1',
121+
},
122+
},
123+
spec: {
124+
replicas: 3,
125+
selector: {
126+
matchLabels: {
127+
app: 'test1',
128+
},
129+
},
130+
template: {
131+
metadata: {
132+
creationTimestamp: null,
133+
labels: {
134+
app: 'test1',
135+
},
136+
},
137+
spec: {
138+
containers: [
139+
{
140+
name: 'container',
141+
image:
142+
'image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest',
143+
ports: [
144+
{
145+
containerPort: 8080,
146+
protocol: 'TCP',
147+
},
148+
],
149+
resources: {},
150+
terminationMessagePath: '/dev/termination-log',
151+
terminationMessagePolicy: 'File',
152+
imagePullPolicy: 'Always',
153+
},
154+
],
155+
restartPolicy: 'Always',
156+
terminationGracePeriodSeconds: 30,
157+
dnsPolicy: 'ClusterFirst',
158+
securityContext: {},
159+
schedulerName: 'default-scheduler',
160+
},
161+
},
162+
strategy: {
163+
type: 'RollingUpdate',
164+
rollingUpdate: {
165+
maxUnavailable: '25%',
166+
maxSurge: '25%',
167+
},
168+
},
169+
revisionHistoryLimit: 10,
170+
progressDeadlineSeconds: 600,
171+
},
172+
status: {
173+
observedGeneration: 1,
174+
replicas: 3,
175+
updatedReplicas: 3,
176+
readyReplicas: 3,
177+
availableReplicas: 3,
178+
conditions: [
179+
{
180+
type: 'Available',
181+
status: 'True',
182+
lastUpdateTime: '2025-01-17T06:11:47Z',
183+
lastTransitionTime: '2025-01-17T06:11:47Z',
184+
reason: 'MinimumReplicasAvailable',
185+
message: 'Deployment has minimum availability.',
186+
},
187+
{
188+
type: 'Progressing',
189+
status: 'True',
190+
lastUpdateTime: '2025-01-17T06:11:47Z',
191+
lastTransitionTime: '2025-01-17T06:11:36Z',
192+
reason: 'NewReplicaSetAvailable',
193+
message: 'ReplicaSet "test1-59d845d69c" has successfully progressed.',
194+
},
195+
],
196+
},
197+
},
198+
hpas: [],
199+
isMonitorable: true,
200+
monitoringAlerts: [],
201+
isOperatorBackedService: false,
202+
},
203+
data: {
204+
monitoringAlerts: [],
205+
kind: 'apps~v1~Deployment',
206+
contextDir: null,
207+
builderImage: 'static/assets/public/imgs/logos/openshift.svg',
208+
isKnativeResource: false,
209+
},
210+
}),
211+
getLabel: () => 'Mock Node',
212+
isVisible: () => true,
213+
isGroup: () => false,
214+
isCollapsed: () => false,
215+
getResource: () => ({
216+
kind: 'Pod',
217+
metadata: {
218+
name: 'mock-pod',
219+
namespace: 'default',
220+
},
221+
}),
222+
} as unknown as Node;
223+
224+
const onSelect = (ids: string[]) => console.log('Selected Node IDs:', ids);
225+
226+
const cpuStats = {
227+
totalCores: 2,
228+
cpuByPod: [
229+
{ name: 'pod1', formattedValue: '500m', value: 0.5 },
230+
{ name: 'pod2', formattedValue: '500m', value: 0.5 },
231+
],
232+
};
233+
234+
const memoryStats = {
235+
totalBytes: 1024 * 512,
236+
memoryByPod: [
237+
{ name: 'pod1', value: 256 * 1024 * 1024, formattedValue: '500m' },
238+
{ name: 'pod2', value: 256 * 1024 * 1024, formattedValue: '500m' },
239+
],
240+
};
241+
242+
return (
243+
<div>
244+
<h1>{t('Example Topology Page')}</h1>
245+
<div>
246+
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
247+
<div>
248+
<h3>{t('CPU Cell Component')}</h3>
249+
<CpuCellComponent cpuByPod={cpuStats.cpuByPod} totalCores={cpuStats.totalCores} />
250+
</div>
251+
<div>
252+
<h3>{t('Memory Cell Component')}</h3>
253+
<MemoryCellComponent
254+
memoryByPod={memoryStats.memoryByPod}
255+
totalBytes={memoryStats.totalBytes}
256+
/>
257+
</div>
258+
</div>
259+
</div>
260+
<div>
261+
<h2>{t('Topology List View Node')}</h2>
262+
<DataList aria-label="Topology List View">
263+
<TopologyListViewNode
264+
item={mockNode}
265+
selectedIds={[]}
266+
onSelect={onSelect}
267+
cpuCell={
268+
<DataListCell key="cpu" id="cpu-cell-component">
269+
<CpuCellComponent cpuByPod={cpuStats.cpuByPod} totalCores={cpuStats.totalCores} />
270+
</DataListCell>
271+
}
272+
memoryCell={
273+
<DataListCell key="cpu" id="memory-cell-component">
274+
<MemoryCellComponent
275+
memoryByPod={memoryStats.memoryByPod}
276+
totalBytes={memoryStats.totalBytes}
277+
/>
278+
</DataListCell>
279+
}
280+
/>
281+
</DataList>
282+
</div>
283+
</div>
284+
);
285+
};

0 commit comments

Comments
 (0)