This document provides context and guidelines for AI coding assistants working on this codebase.
This is the Cluster Update Console Plugin — an OpenShift Console dynamic plugin that provides an AI-driven cluster update experience. It integrates with OpenShift Lightspeed 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.
This repo was instantiated from the console-plugin-template.
Key Technologies:
- TypeScript + React 17
- PatternFly 6 (UI component library)
- Webpack 5 with Module Federation
- react-i18next for internationalization
- Jest + ts-jest for unit tests
- Cypress for e2e testing
- Helm for deployment
Compatibility: Requires OpenShift 4.12+ (uses ConsolePlugin CRD v1 API). The Lightspeed Proposal CRD (agentic.openshift.io/v1alpha1) is optional — the plugin degrades gracefully when it is not installed.
This plugin uses webpack module federation to load at runtime into the OpenShift Console. Key files:
console-extensions.json: Declares what the plugin adds to console (routes, nav items)package.jsonconsolePluginsection: Plugin metadata and exposed modules mappingwebpack.config.ts: Configures module federation and build
Critical: Any component referenced in console-extensions.json must have a corresponding entry in package.json under consolePlugin.exposedModules.
The plugin exposes a single page at /administration/cluster-update with three tabs:
- Update Plan — Shows the active AI-generated update proposal or lets the user generate one. Contains risk assessment, readiness checks, OLM operator compatibility, API deprecations, maintenance details, and approve/deny actions.
- Active Update Plans — Lists all non-terminal Lightspeed proposals.
- Update History — Shows the ClusterVersion update history.
useClusterVersion()— watches theClusterVersionresource (always present)useUpdateProposals()— watchesProposalresources inopenshift-lightspeednamespace (optional CRD)getAnalysisData(proposal)— extracts the selected remediation option and its adapter components from a proposal. Computed once inActivePlanViewand passed asanalysisDataprop to all child components.- Component extractors (
getReadinessSummary,getFindings,getOlmOperatorStatus) filter the sharedcomponentsarray for typed data.
If the Lightspeed Proposal CRD is not installed:
- The page still loads and shows ClusterVersion data (Update History tab works fully)
- A warning banner explains that AI features are unavailable
- The Update Plan tab shows the "no active plan" view without crashing
- The
useCreateProposalhook catches and displays errors if the user tries to create a proposal
- Use functional components with hooks (NO class components)
- All components should be TypeScript (
.tsx) - Follow PatternFly component patterns
- Use PatternFly CSS variables instead of hex colors (dark mode compatibility)
IMPORTANT: The .stylelintrc.yaml enforces strict rules to prevent breaking console:
- NO hex colors — use PatternFly CSS variables (e.g.,
var(--pf-t--global--spacer--md)) - NO naked element selectors (like
table,div) — prevents overwriting console styles - NO
.pf-or.co-prefixed classes — reserved for PatternFly and console - Prefix all custom classes with
cluster-update-plugin__(e.g.,cluster-update-plugin__header)
Namespace: plugin__cluster-update-console-plugin
import { I18N_NAMESPACE } from '../utils/constants';
const { t } = useTranslation(I18N_NAMESPACE);
return <h1>{t('Cluster Update')}</h1>;"name": "%plugin__cluster-update-console-plugin~Cluster Update%"After adding/changing messages: Run yarn i18n to update locale files in /locales
src/
components/
ClusterUpdatePage.tsx # Main page (entry point)
shared/ # Reusable UI components
PhaseIcon.tsx # Proposal phase icons
PhaseLabel.tsx # Proposal phase labels
ReadinessStatusIcon.tsx # Pass/warn/fail icons
SeverityLabel.tsx # Finding severity labels
update-plan/ # Update plan tab components
ActivePlanView.tsx # Container for active proposal view
NoActivePlanView.tsx # Shown when no active proposal
AIAssessmentCard.tsx # AI assessment summary
AIUpdateAgentCard.tsx # Version selector + generate plan
PlanHeader.tsx # Proposal version/type header
PlanStepChecklist.tsx # Readiness check results
RiskAssessment.tsx # Risk level + decision alert
CompatibilityTable.tsx # Findings table
OLMOperators.tsx # OLM operator lifecycle table
APIDeprecations.tsx # API deprecation checks
ClusterMetrics.tsx # Live Prometheus metrics
MaintenanceWindow.tsx # Upgrade/monitor commands
DecisionActions.tsx # Approve/deny with confirmation
PrerequisitesSidebar.tsx # Prerequisites list
UpdatePlanTab.tsx # Tab container
active-plans/ # Active plans tab
update-history/ # Update history tab
hooks/
useClusterVersion.ts # ClusterVersion watcher
useUpdateProposals.ts # Proposal list watcher
useCreateProposal.ts # Create new proposal
useApprovalActions.ts # Approve/deny proposal
models/
clusterversion.ts # ClusterVersion types + model
proposal.ts # Proposal types, model, helpers
utils/
constants.ts # Plugin name, labels, terminal phases
version.ts # SemVer parsing, comparison, sanitization
time.ts # Duration/date formatting
error.ts # Error message extraction
__tests__/ # Unit tests (Jest)
__mocks__/ # SDK mocks for Jest
console-extensions.json # Plugin extension declarations
jest.config.ts # Jest configuration
package.json # Plugin metadata
webpack.config.ts # Module federation + build config
locales/ # i18n translation files
charts/ # Helm chart for deployment
integration-tests/ # Cypress e2e tests
yarn install— install dependenciesyarn start— starts webpack dev server on port 9001 with CORSyarn start-console— runs OpenShift console in container (requires cluster login)- Navigate to http://localhost:9000/administration/cluster-update
yarn lint— runs eslint, prettier, and stylelint (with --fix)yarn test— runs Jest unit tests- Linting and tests are mandatory before commits
yarn test— runs unit tests (utils, models, helpers)yarn test-cypress— opens Cypress UI for e2e testsyarn test-cypress-headless— runs Cypress in CI mode
- Tests live in
src/__tests__/matching the module they test - SDK is mocked via
src/__mocks__/@openshift-console/dynamic-plugin-sdk.ts - Jest config uses
ts-jestpreset with module name mapping for the SDK mock
docker build -t quay.io/my-repository/cluster-update-console-plugin:latest .
# For Apple Silicon: add --platform=linux/amd64helm upgrade -i cluster-update-console-plugin charts/openshift-console-plugin \
-n cluster-update-console-plugin \
--create-namespace \
--set plugin.image=my-plugin-image-location# Push to cluster internal registry
REGISTRY=$(oc get route default-route -n openshift-image-registry -o jsonpath='{.spec.host}')
TOKEN=$(oc create token builder -n cluster-update-console-plugin)
docker save cluster-update-console-plugin:latest | \
skopeo copy --dest-tls-verify=false --dest-creds="unused:${TOKEN}" \
docker-archive:/dev/stdin \
docker://${REGISTRY}/cluster-update-console-plugin/cluster-update-console-plugin:latest
# Deploy with internal registry image
helm upgrade -i cluster-update-console-plugin charts/openshift-console-plugin \
-n cluster-update-console-plugin \
--set plugin.image=image-registry.openshift-image-registry.svc:5000/cluster-update-console-plugin/cluster-update-console-plugin:latest- i18n namespace must match ConsolePlugin resource name with
plugin__prefix - CSS class prefixes prevent style conflicts — always use
cluster-update-plugin__ - Module federation requires exact module mapping —
exposedModulesmust match$codeRefvalues - PatternFly CSS variables only — hex colors break dark mode
- No webpack HMR for extensions — changes to
console-extensions.jsonrequire restart - React 17, not 18 — matches console's React version
- Proposal CRD is optional — all code paths must handle missing
agentic.openshift.ioresources gracefully getAnalysisDatais computed once — inActivePlanView, passed down asanalysisDataprop. Never call it in child components.
- Functional components with hooks (NO classes)
- TypeScript for all new files
- Use PatternFly components whenever possible
- Keep components focused and composable
- Prefer named exports for components
- Use
React.FCor explicit return types - CSS-in-files (not CSS-in-JS)
- No comments unless the WHY is non-obvious