Skip to content

Commit e794450

Browse files
authored
feat(pages): add Diagnostics views (#485)
* feat(pages): add Diagnostics views * add the same Diagnostic page version checks to the Heap and Thread dump pages * prettier * add function to check version, and display spinner while fetching version data * run prettier * update cryostat-web to latest * fix loading when cryostat not selected * add unit tests for the version check function * add unit tests for the Diagnostics page
1 parent e2a7cf6 commit e794450

15 files changed

+613
-77
lines changed

console-extensions.json

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,30 @@
9494
"path": "/cryostat/instrumentation",
9595
"component": { "$codeRef": "InstrumentationPage" }
9696
}
97+
},
98+
{
99+
"type": "console.page/route",
100+
"properties": {
101+
"exact": true,
102+
"path": "/cryostat/diagnostics",
103+
"component": { "$codeRef": "DiagnosticsPage" }
104+
}
105+
},
106+
{
107+
"type": "console.page/route",
108+
"properties": {
109+
"exact": true,
110+
"path": "/cryostat/thread-dumps",
111+
"component": { "$codeRef": "ThreadDumpsPage" }
112+
}
113+
},
114+
{
115+
"type": "console.page/route",
116+
"properties": {
117+
"exact": true,
118+
"path": "/cryostat/heapdumps",
119+
"component": { "$codeRef": "HeapDumpsPage" }
120+
}
97121
},
98122
{
99123
"type": "console.page/route",
@@ -214,6 +238,44 @@
214238
"section": "cryostat-section",
215239
"insertAfter": "instrumentation"
216240
}
241+
},
242+
{
243+
"type": "console.navigation/href",
244+
"properties": {
245+
"id": "diagnostics",
246+
"name": "%plugin__cryostat-plugin~Navigation.Diagnostics%",
247+
"href": "/cryostat/diagnostics",
248+
"perspective": "admin",
249+
"section": "cryostat-section"
250+
}
251+
},
252+
{
253+
"type": "console.navigation/href",
254+
"properties": {
255+
"id": "threaddumps",
256+
"name": "%plugin__cryostat-plugin~Navigation.ThreadDumps%",
257+
"href": "/cryostat/thread-dumps",
258+
"perspective": "admin",
259+
"section": "cryostat-section"
260+
}
261+
},
262+
{
263+
"type": "console.navigation/href",
264+
"properties": {
265+
"id": "heapdumps",
266+
"name": "%plugin__cryostat-plugin~Navigation.HeapDumps%",
267+
"href": "/cryostat/heapdumps",
268+
"perspective": "admin",
269+
"section": "cryostat-section"
270+
}
271+
},
272+
{
273+
"type": "console.navigation/separator",
274+
"properties": {
275+
"id": "pf-separator",
276+
"section": "cryostat-section",
277+
"insertAfter": "heapdumps"
278+
}
217279
},
218280
{
219281
"type": "console.navigation/href",

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module.exports = {
5555
// An array of regexp pattern strings that are matched against all source file paths before transformation.
5656
// If the file path matches any of the patterns, it will not be transformed.
5757
transformIgnorePatterns: [
58-
"/node_modules/(?!(@openshift-console\\S*?|@openshift/dynamic-plugin-sdk-utils|@patternfly|d3|d3-array|internmap|delaunator|robust-predicates|uuid))",
58+
"/node_modules/(?!(@openshift-console\\S*?|@openshift/dynamic-plugin-sdk-utils|@patternfly|d3|d3-array|internmap|delaunator|nanoid|robust-predicates|uuid))",
5959
],
6060

6161
roots: ['<rootDir>/src']

locales/en/common.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
"Navigation.Archives": "Archives",
1010
"Navigation.Events": "Events",
1111
"Navigation.Instrumentation": "Instrumentation",
12+
"Navigation.Diagnostics": "Diagnostics",
13+
"Navigation.HeapDumps": "Analyze Heap Dumps",
14+
"Navigation.ThreadDumps": "Analyze Thread Dumps",
1215
"Navigation.Security": "Security",
1316
"Navigation.About": "About",
1417
"DEPLOYMENT_ACTION_TITLE": "Register with Cryostat",
@@ -18,5 +21,8 @@
1821
"DEPLOYMENT_ACTION_NAMESPACE_NOT_A_TARGET_NAMESPACE": "Warning: {{deploymentNamespace}} is not in the list of target namespaces for {{cryostatName}}",
1922
"DEPLOYMENT_ACTION_NO_UPDATE_PERMISSIONS": "Warning: user does not have permissions to update deployment: {{deploymentName}}",
2023
"DEPLOYMENT_ACTION_NO_CRYOSTAT_OPERATOR_CR": "Warning: this registration feature requires at least one Cryostat custom resource associated with a Cryostat Operator",
21-
"DEPLOYMENT_ACTION_HELM_CRYOSTAT_SELECTED": "Warning: {{cryostatName}} was installed using a Helm chart. This feature requires the Cryostat Operator for dynamic attachment."
24+
"DEPLOYMENT_ACTION_HELM_CRYOSTAT_SELECTED": "Warning: {{cryostatName}} was installed using a Helm chart. This feature requires the Cryostat Operator for dynamic attachment.",
25+
"FEATURE_NOT_AVAILABLE_PAGE_TITLE": "Cryostat update is required to use this feature",
26+
"CURRENT_VERSION": "Current Version: {{currentVersion}}",
27+
"REQUIRED_VERSION": "Required Version: {{requiredVersion}}"
2228
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@
140140
"ArchivesPage": "./openshift/pages/ArchivesPage",
141141
"EventsPage": "./openshift/pages/EventsPage",
142142
"InstrumentationPage": "./openshift/pages/InstrumentationPage",
143+
"DiagnosticsPage": "./openshift/pages/DiagnosticsPage",
144+
"ThreadDumpsPage": "./openshift/pages/ThreadDumpsPage",
145+
"HeapDumpsPage": "./openshift/pages/HeapDumpsPage",
143146
"SecurityPage": "./openshift/pages/SecurityPage",
144147
"DeploymentLabelActionProvider": "./openshift/actions/DeploymentLabelAction/DeploymentLabelActionProvider",
145148
"getDeploymentDecorator": "./openshift/actions/DeploymentLabelAction/getDeploymentDecorator"

src/cryostat-web

Submodule cryostat-web updated 79 files

src/openshift/components/CryostatContainer.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ import _ from 'lodash';
6363
import * as React from 'react';
6464
import { Provider } from 'react-redux';
6565
import { map, Observable, of } from 'rxjs';
66-
import { CryostatController } from './CryostatController';
6766
import CryostatSelector from './CryostatSelector';
6867

6968
export const SESSIONSTORAGE_SVC_NS_KEY = 'cryostat-svc-ns';
@@ -132,7 +131,7 @@ const chartControllers = (svcs: Services): Controllers => {
132131
};
133132
};
134133

135-
const LoadingState: React.FC = () => {
134+
export const LoadingState: React.FC = () => {
136135
return (
137136
<Bullseye>
138137
<Spinner />
@@ -254,7 +253,7 @@ const InstancedContainer: React.FC<{
254253
<ChartContext.Provider value={chartContext}>
255254
<NotificationsContext.Provider value={NotificationsInstance}>
256255
<NotificationGroup />
257-
<CryostatController key={`${service.namespace}-${service.name}`}>{children}</CryostatController>
256+
{children}
258257
</NotificationsContext.Provider>
259258
</ChartContext.Provider>
260259
</ServiceContext.Provider>
@@ -342,6 +341,20 @@ const NamespacedContainer: React.FC<{ searchNamespace: string; children: React.R
342341
(service: CryostatService) => {
343342
sessionStorage.setItem(SESSIONSTORAGE_SVC_NS_KEY, service.namespace);
344343
sessionStorage.setItem(SESSIONSTORAGE_SVC_NAME_KEY, service.name);
344+
window.dispatchEvent(
345+
new StorageEvent('storage', {
346+
key: SESSIONSTORAGE_SVC_NS_KEY,
347+
newValue: service.namespace,
348+
storageArea: sessionStorage,
349+
}),
350+
);
351+
window.dispatchEvent(
352+
new StorageEvent('storage', {
353+
key: SESSIONSTORAGE_SVC_NAME_KEY,
354+
newValue: service.name,
355+
storageArea: sessionStorage,
356+
}),
357+
);
345358
setService(service);
346359
},
347360
[setService],
@@ -373,7 +386,6 @@ const NamespacedContainer: React.FC<{ searchNamespace: string; children: React.R
373386
() => !service || (service.namespace == NO_INSTANCE.namespace && service.name == NO_INSTANCE.name),
374387
[service],
375388
);
376-
377389
return (
378390
<>
379391
<CryostatSelector

src/openshift/components/CryostatController.tsx

Lines changed: 0 additions & 65 deletions
This file was deleted.

src/openshift/pages/DashboardPage.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ import { CryostatContainer } from '@console-plugin/components/CryostatContainer'
1818
import '@app/app.css';
1919

2020
export default function DashboardPage() {
21-
// The Kiali plugin here runs a number of functions
22-
// Including:
23-
// - setting the router basename
24-
// - initializing listeners
25-
2621
return (
2722
<CryostatContainer>
2823
<Dashboard />
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright The Cryostat Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { CaptureDiagnostics } from '@app/Diagnostics/CaptureDiagnostics';
17+
import {
18+
CryostatContainer,
19+
LoadingState,
20+
SESSIONSTORAGE_SVC_NAME_KEY,
21+
SESSIONSTORAGE_SVC_NS_KEY,
22+
} from '@console-plugin/components/CryostatContainer';
23+
import '@app/app.css';
24+
import { getOperatorCryostatVersion, isVersionEqualOrGreaterThan } from '@console-plugin/utils/utils';
25+
import { K8sResourceKind, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
26+
import React from 'react';
27+
import { FeatureNotAvailablePage } from './FeatureNotAvailablePage';
28+
29+
export default function DiagnosticsPage() {
30+
const [sessionCryostatName, setSessionCryostatName] = React.useState(() => {
31+
return sessionStorage.getItem(SESSIONSTORAGE_SVC_NAME_KEY) || '';
32+
});
33+
const [sessionCryostatNs, setSessionCryostatNs] = React.useState(() => {
34+
return sessionStorage.getItem(SESSIONSTORAGE_SVC_NS_KEY) || '';
35+
});
36+
const [version, setVersion] = React.useState('');
37+
const [cryostats, cryostatsLoaded] = useK8sWatchResource<K8sResourceKind[]>({
38+
groupVersionKind: {
39+
group: '',
40+
kind: 'Service',
41+
version: 'v1',
42+
},
43+
selector: {
44+
matchLabels: {
45+
'app.kubernetes.io/part-of': 'cryostat',
46+
'app.kubernetes.io/component': 'cryostat',
47+
},
48+
},
49+
isList: true,
50+
});
51+
const [csvs, csvsLoaded] = useK8sWatchResource<K8sResourceKind[]>({
52+
groupVersionKind: {
53+
group: 'operators.coreos.com',
54+
kind: 'ClusterServiceVersion',
55+
version: 'v1alpha1',
56+
},
57+
isList: true,
58+
});
59+
60+
React.useEffect(() => {
61+
const handleStorageChange = (event) => {
62+
if (event.key === SESSIONSTORAGE_SVC_NAME_KEY && event.newValue !== sessionCryostatName) {
63+
setSessionCryostatName(event.newValue);
64+
}
65+
if (event.key === SESSIONSTORAGE_SVC_NS_KEY && event.newValue !== sessionCryostatNs) {
66+
setSessionCryostatNs(event.newValue);
67+
}
68+
};
69+
window.addEventListener('storage', handleStorageChange);
70+
}, [sessionCryostatName, sessionCryostatNs]);
71+
72+
React.useEffect(() => {
73+
const currentCryostat = cryostats.find(
74+
(cryostat) => cryostat.metadata?.name == sessionCryostatName && cryostat.metadata?.namespace == sessionCryostatNs,
75+
);
76+
77+
if ((!cryostatsLoaded && !csvsLoaded) || !currentCryostat) {
78+
return;
79+
}
80+
81+
if (
82+
currentCryostat.metadata?.labels &&
83+
currentCryostat.metadata?.labels['app.kubernetes.io/managed-by'] == 'Helm'
84+
) {
85+
setVersion(currentCryostat.metadata?.labels['app.kubernetes.io/version']);
86+
} else {
87+
setVersion(getOperatorCryostatVersion(sessionCryostatNs, csvs));
88+
}
89+
}, [cryostats, cryostatsLoaded, version, sessionCryostatName, sessionCryostatNs, csvs, csvsLoaded]);
90+
91+
return (
92+
<CryostatContainer>
93+
{!version ? (
94+
<LoadingState />
95+
) : !isVersionEqualOrGreaterThan(version, '4.1.0') ? (
96+
<FeatureNotAvailablePage currentVersion={version} requiredVersion={'4.1.0'}></FeatureNotAvailablePage>
97+
) : (
98+
<CaptureDiagnostics></CaptureDiagnostics>
99+
)}
100+
</CryostatContainer>
101+
);
102+
}

0 commit comments

Comments
 (0)