Skip to content

Commit 731dad8

Browse files
committed
Add project README, mock data, and onboarding findings
- Replace template README with plugin-specific content - Add mock-analysis-result.yaml for cluster testing without Lightspeed - Add ONBOARDING-FINDINGS.md documenting API mismatches and dev setup - Updated Helm Charts - Update locales - Update getAnalysisDataFromResult to support arrays
1 parent e72e011 commit 731dad8

4 files changed

Lines changed: 80 additions & 184 deletions

File tree

README.md

Lines changed: 68 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,230 +1,119 @@
1-
# OpenShift console plugin template
2-
3-
This project is a minimal template for writing a new OpenShift Console dynamic
4-
plugin.
5-
6-
[Openshift console plugins](https://github.com/openshift/console/tree/main/frontend/packages/console-dynamic-plugin-sdk)
7-
allow you to extend the [OpenShift web console](https://github.com/openshift/console)
8-
at runtime, adding custom pages and other extensions. They are based on
9-
[webpack module federation](https://webpack.js.org/concepts/module-federation/).
10-
Plugins are registered with console using the `ConsolePlugin` custom resource
11-
and enabled in the console operator config by a cluster administrator.
12-
13-
The `main` branch of this repository contains an example plugin which works
14-
with the latest version. To see an example of a plugin which works with an older
15-
version, visit the appropriate `release-4.x` branch.
16-
17-
[Node.js](https://nodejs.org/en/) and [yarn](https://yarnpkg.com) are required
18-
to build and run the example. To run OpenShift console in a container, either
19-
[Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io) and
20-
[oc](https://console.redhat.com/openshift/downloads) are required.
21-
22-
## Getting started
23-
24-
> [!IMPORTANT]
25-
> To use this template, **DO NOT FORK THIS REPOSITORY**! Click **Use this template**, then select
26-
> [**Create a new repository**](https://github.com/new?template_name=console-plugin-template&template_owner=openshift)
27-
> to create a new repository.
28-
>
29-
> ![A screenshot showing where the "Use this template" button is located](https://i.imgur.com/AhaySbU.png)
30-
>
31-
> **Forking this repository** for purposes outside of contributing to this repository
32-
> **will cause issues**, as users cannot have more than one fork of a template repository
33-
> at a time. This could prevent future users from forking and contributing to your plugin.
34-
>
35-
> Your fork would also behave like a template repository, which might be confusing for
36-
> contributiors, because it is not possible for repositories generated from a template
37-
> repository to contribute back to the template.
38-
39-
After cloning your instantiated repository, you must update the plugin metadata, such as the
40-
plugin name in the `consolePlugin` declaration of [package.json](package.json).
1+
# Cluster Update Console Plugin
412

42-
```json
43-
"consolePlugin": {
44-
"name": "console-plugin-template",
45-
"version": "0.0.1",
46-
"displayName": "My Plugin",
47-
"description": "Enjoy this shiny, new console plugin!",
48-
"exposedModules": {
49-
"ExamplePage": "./components/ExamplePage"
50-
},
51-
"dependencies": {
52-
"@console/pluginAPI": "*"
53-
}
54-
}
55-
```
56-
57-
The template adds a single example page in the Home navigation section. The
58-
extension is declared in the [console-extensions.json](console-extensions.json)
59-
file and the React component is declared in
60-
[src/components/ExamplePage.tsx](src/components/ExamplePage.tsx).
61-
62-
You can run the plugin using a local development environment or build an image
63-
to deploy it to a cluster.
64-
65-
## Development
66-
67-
### Option 1: Local
3+
An OpenShift Console dynamic plugin that provides an AI-driven cluster update experience. It integrates with [OpenShift Lightspeed](https://github.com/openshift/lightspeed-operator) proposals (via the `agentic.openshift.io` API) to assess upgrade readiness, show OLM operator compatibility, and let users approve or reject AI-generated update plans.
684

69-
In one terminal window, run:
5+
## Features
706

71-
1. `yarn install`
72-
2. `yarn run start`
7+
- **Update Plan** — Shows the active AI-generated update proposal with risk assessment, readiness checks, OLM operator compatibility, API deprecation checks, and approve/deny actions.
8+
- **Active Update Plans** — Lists all non-terminal Lightspeed proposals.
9+
- **Update History** — Shows the ClusterVersion update history.
10+
- **Graceful Degradation** — Works without the Lightspeed Proposal CRD installed. The Update History tab is always functional; AI features show a warning banner when unavailable.
7311

74-
In another terminal window, run:
12+
## Prerequisites
7513

76-
1. `oc login` (requires [oc](https://console.redhat.com/openshift/downloads) and an [OpenShift cluster](https://console.redhat.com/openshift/create))
77-
2. `yarn run start-console` (requires [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io))
14+
- OpenShift 4.22+ (uses ConsolePlugin CRD v1 API, Console SDK 4.22)
15+
- [Node.js](https://nodejs.org/en/) 18+ and [Yarn](https://yarnpkg.com) 4.x
16+
- [oc](https://console.redhat.com/openshift/downloads) CLI
17+
- [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io) (for running the console locally)
7818

79-
This will run the OpenShift console in a container connected to the cluster
80-
you've logged into. The plugin HTTP server runs on port 9001 with CORS enabled.
81-
Navigate to <http://localhost:9000/example> to see the running plugin.
19+
## Development
8220

83-
#### Running start-console with Apple silicon and podman
21+
### Local development
8422

85-
If you are using podman on a Mac with Apple silicon, `yarn run start-console`
86-
might fail since it runs an amd64 image. You can workaround the problem with
87-
[qemu-user-static](https://github.com/multiarch/qemu-user-static) by running
88-
these commands:
23+
In one terminal:
8924

9025
```bash
91-
podman machine ssh
92-
sudo -i
93-
rpm-ostree install qemu-user-static
94-
systemctl reboot
26+
yarn install
27+
yarn start
9528
```
9629

97-
### Option 2: Docker + VSCode Remote Container
98-
99-
Make sure the
100-
[Remote Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
101-
extension is installed. This method uses Docker Compose where one container is
102-
the OpenShift console and the second container is the plugin. It requires that
103-
you have access to an existing OpenShift cluster. After the initial build, the
104-
cached containers will help you start developing in seconds.
105-
106-
1. Create a `dev.env` file inside the `.devcontainer` folder with the correct values for your cluster:
30+
In another terminal:
10731

10832
```bash
109-
OC_PLUGIN_NAME=console-plugin-template
110-
OC_URL=https://api.example.com:6443
111-
OC_USER=kubeadmin
112-
OC_PASS=<password>
33+
oc login # log into your OpenShift cluster
34+
yarn start-console
11335
```
11436

115-
2. `(Ctrl+Shift+P) => Remote Containers: Open Folder in Container...`
116-
3. `yarn run start`
117-
4. Navigate to <http://localhost:9000/example>
37+
Navigate to <http://localhost:9000/administration/cluster-update>.
11838

119-
## Docker image
39+
The plugin dev server runs on port 9001 with CORS enabled. The console bridge runs on port 9000.
12040

121-
Before you can deploy your plugin on a cluster, you must build an image and
122-
push it to an image registry.
41+
### Testing with mock data
12342

124-
1. Build the image:
43+
Without the Lightspeed agentic operator installed, Proposals have no analysis data. To test with mock data:
12544

126-
```sh
127-
docker build -t quay.io/my-repository/my-plugin:latest .
45+
1. Verify CVO-created Proposals exist:
46+
```bash
47+
oc -n openshift-lightspeed get proposals.agentic.openshift.io
12848
```
12949

130-
2. Run the image:
131-
132-
```sh
133-
docker run -it --rm -d -p 9001:80 quay.io/my-repository/my-plugin:latest
50+
2. Get the Proposal UID:
51+
```bash
52+
oc -n openshift-lightspeed get proposals.agentic.openshift.io -o custom-columns=NAME:.metadata.name,UID:.metadata.uid
13453
```
13554

136-
3. Push the image:
137-
138-
```sh
139-
docker push quay.io/my-repository/my-plugin:latest
55+
3. Update `mock-analysis-result.yaml` with the correct Proposal name and UID in `ownerReferences`, then apply:
56+
```bash
57+
oc apply -f mock-analysis-result.yaml
14058
```
14159

142-
NOTE: If you have a Mac with Apple silicon, you will need to add the flag
143-
`--platform=linux/amd64` when building the image to target the correct platform
144-
to run in-cluster.
60+
4. Patch the Proposal status to reference the AnalysisResult (see comments in `mock-analysis-result.yaml` for the full command).
61+
62+
5. Patch the AnalysisResult status subresource with options data (the `status` field is a subresource, so `oc apply` won't set it — use `oc patch --subresource status`).
14563

146-
## Deployment on cluster
64+
### Code quality
14765

148-
A [Helm](https://helm.sh) chart is available to deploy the plugin to an OpenShift environment.
66+
```bash
67+
yarn lint # eslint + prettier + stylelint (with --fix)
68+
yarn test # Jest unit tests
69+
```
14970

150-
The following Helm parameters are required:
71+
### Styling rules
15172

152-
`plugin.image`: The location of the image containing the plugin that was previously pushed
73+
The `.stylelintrc.yaml` enforces strict rules to prevent breaking console:
15374

154-
Additional parameters can be specified if desired. Consult the chart [values](charts/openshift-console-plugin/values.yaml) file for the full set of supported parameters.
75+
- No hex colors — use PatternFly CSS variables
76+
- No naked element selectors (`table`, `div`, etc.)
77+
- No `.pf-` or `.co-` prefixed classes
78+
- Prefix all custom classes with `cluster-update-plugin__`
15579

156-
### Installing the Helm Chart
80+
## Building and deploying
15781

158-
Install the chart using the name of the plugin as the Helm release name into a new namespace or an existing namespace as specified by the `plugin_console-plugin-template` parameter and providing the location of the image within the `plugin.image` parameter by using the following command:
82+
### Build the image
15983

160-
```shell
161-
helm upgrade -i my-plugin charts/openshift-console-plugin -n my-namespace --create-namespace --set plugin.image=my-plugin-image-location
84+
```bash
85+
docker build -t quay.io/my-repository/cluster-update-console-plugin:latest .
86+
# For Apple Silicon: add --platform=linux/amd64
16287
```
16388

164-
NOTE: When deploying on OpenShift 4.10, it is recommended to add the parameter `--set plugin.securityContext.enabled=false` which will omit configurations related to Pod Security.
89+
### Deploy via Helm
16590

166-
NOTE: When defining i18n namespace, adhere `plugin__<name-of-the-plugin>` format. The name of the plugin should be extracted from the `consolePlugin` declaration within the [package.json](package.json) file.
91+
```bash
92+
helm upgrade -i cluster-update-console-plugin charts/openshift-console-plugin \
93+
-n cluster-update-console-plugin \
94+
--create-namespace \
95+
--set plugin.image=quay.io/my-repository/cluster-update-console-plugin:latest
96+
```
16797

16898
## i18n
16999

170-
The plugin template demonstrates how you can translate messages in with [react-i18next](https://react.i18next.com/). The i18n namespace must match
171-
the name of the `ConsolePlugin` resource with the `plugin__` prefix to avoid
172-
naming conflicts. For example, the plugin template uses the
173-
`plugin__console-plugin-template` namespace. You can use the `useTranslation` hook
174-
with this namespace as follows:
100+
The i18n namespace is `plugin__cluster-update-console-plugin`. Use the `useTranslation` hook:
175101

176102
```tsx
177-
const Header: React.FC = () => {
178-
const { t } = useTranslation('plugin__console-plugin-template');
179-
return <h1>{t('Hello, World!')}</h1>;
180-
};
103+
import { I18N_NAMESPACE } from '../utils/constants';
104+
const { t } = useTranslation(I18N_NAMESPACE);
181105
```
182106

183-
For labels in `console-extensions.json`, you can use the format
184-
`%plugin__console-plugin-template~My Label%`. Console will replace the value with
185-
the message for the current language from the `plugin__console-plugin-template`
186-
namespace. For example:
187-
107+
For labels in `console-extensions.json`:
188108
```json
189-
{
190-
"type": "console.navigation/section",
191-
"properties": {
192-
"id": "admin-demo-section",
193-
"perspective": "admin",
194-
"name": "%plugin__console-plugin-template~Plugin Template%"
195-
}
196-
}
109+
"name": "%plugin__cluster-update-console-plugin~Cluster Update%"
197110
```
198111

199-
Running `yarn i18n` updates the JSON files in the `locales` folder of the
200-
plugin template when adding or changing messages.
201-
202-
## Linting
203-
204-
This project adds prettier, eslint, and stylelint. Linting can be run with
205-
`yarn run lint`.
206-
207-
The stylelint config disallows defining colors since these cause problems with dark
208-
mode. Use [PatternFly semantic tokens](https://www.patternfly.org/tokens/all-patternfly-tokens)
209-
for colors instead.
210-
211-
The stylelint config also disallows naked element selectors like `table` and
212-
`.pf-` or `.co-` prefixed classes. This prevents plugins from accidentally
213-
overwriting default console styles, breaking the layout of existing pages. The
214-
best practice is to prefix your CSS class names with your plugin name to avoid
215-
conflicts. Please don't disable these rules without understanding how they can
216-
break console styles!
217-
218-
## Reporting
219-
220-
Steps to generate reports
221-
222-
1. In command prompt, navigate to root folder and execute the command `yarn run cypress-merge`
223-
2. Then execute command `yarn run cypress-generate`
224-
The cypress-report.html file is generated and should be in (/integration-tests/screenshots) directory.
112+
Run `yarn i18n` after adding or changing messages to update locale files.
225113

226114
## References
227115

228-
- [Console Plugin SDK README](https://github.com/openshift/console/tree/main/frontend/packages/console-dynamic-plugin-sdk)
229-
- [Customization Plugin Example](https://github.com/spadgett/console-customization-plugin)
116+
- [Console Plugin SDK](https://github.com/openshift/console/tree/main/frontend/packages/console-dynamic-plugin-sdk)
117+
- [PatternFly React](https://www.patternfly.org/get-started/develop)
118+
- [Lightspeed Operator](https://github.com/openshift/lightspeed-operator)
230119
- [Dynamic Plugin Enhancement Proposal](https://github.com/openshift/enhancements/blob/master/enhancements/console/dynamic-plugins.md)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
apiVersion: v2
2-
name: openshift-console-plugin
2+
name: cluster-update-console-plugin
33
description: A Helm chart for Kubernetes
44
type: application
55
version: 0.1.0

locales/en/plugin__cluster-update-console-plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@
7070
"View pod logs": "View pod logs",
7171
"Yes": "Yes",
7272
"z-stream": "z-stream"
73-
}
73+
}

src/models/proposal.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,17 @@ export const getAnalysisDataFromResult = (
218218
return { components: [] };
219219
}
220220
const option = result.status.options[0];
221-
const raw = (option.components as AnalysisDataPayload)?.analysisData;
221+
const comp = option.components;
222222

223-
// analysisData can be an array of typed components (PR 1379 format)
224-
// or a flat object (legacy format)
223+
// components is an array of typed adapter components directly
224+
if (Array.isArray(comp)) {
225+
return {
226+
components: comp as AdapterComponent[],
227+
};
228+
}
229+
230+
// components is an object — check for nested analysisData key
231+
const raw = (comp as AnalysisDataPayload)?.analysisData;
225232
if (Array.isArray(raw)) {
226233
return {
227234
components: raw as AdapterComponent[],

0 commit comments

Comments
 (0)