;
+
+describe('useMyResources', () => {
+ it('returns resources when loaded', () => {
+ const mockResources = [
+ { metadata: { name: 'test-resource' } }
+ ];
+
+ mockUseK8sWatchResource.mockReturnValue([mockResources, true, undefined]);
+
+ const { result } = renderHook(() => useMyResources('test-namespace'));
+
+ expect(result.current.resources).toEqual(mockResources);
+ expect(result.current.loaded).toBe(true);
+ expect(result.current.loadError).toBeUndefined();
+ });
+
+ it('handles loading error', () => {
+ const mockError = new Error('Failed to load');
+ mockUseK8sWatchResource.mockReturnValue([[], false, mockError]);
+
+ const { result } = renderHook(() => useMyResources('test-namespace'));
+
+ expect(result.current.resources).toEqual([]);
+ expect(result.current.loaded).toBe(false);
+ expect(result.current.loadError).toBe(mockError);
+ });
+});
+```
+
+### Integration Testing with Cypress
+
+```typescript
+// integration-tests/my-plugin.spec.ts
+describe('My Console Plugin', () => {
+ beforeEach(() => {
+ cy.login();
+ cy.visit('/my-plugin');
+ });
+
+ it('should display plugin navigation', () => {
+ cy.get('[data-test="nav-item-my-plugin"]').should('be.visible');
+ });
+
+ it('should load plugin page', () => {
+ cy.get('[data-test="nav-item-my-plugin"]').click();
+ cy.get('[data-test="my-plugin-page"]').should('be.visible');
+ cy.get('h1').should('contain', 'My Plugin');
+ });
+
+ it('should create a new resource', () => {
+ cy.get('[data-test="create-resource-button"]').click();
+ cy.get('[data-test="resource-name-input"]').type('test-resource');
+ cy.get('[data-test="create-button"]').click();
+
+ cy.get('[data-test="resource-list"]').should('contain', 'test-resource');
+ });
+
+ it('should handle error states', () => {
+ cy.intercept('GET', '/api/kubernetes/apis/my-group.io/v1/namespaces/*/myresources', {
+ statusCode: 500,
+ body: { message: 'Server error' }
+ });
+
+ cy.visit('/my-plugin/resources');
+ cy.get('[data-test="error-alert"]').should('be.visible');
+ cy.get('[data-test="error-alert"]').should('contain', 'Error loading resources');
+ });
+});
+```
+
+## Debugging Techniques
+
+### Browser DevTools Debugging
+
+```typescript
+// Add debugging helpers in development
+const MyComponent: React.FC = () => {
+ const [resources, loaded, loadError] = useMyResources();
+
+ // Debug logging in development
+ React.useEffect(() => {
+ if (process.env.NODE_ENV === 'development') {
+ console.log('MyComponent render:', { resources, loaded, loadError });
+ }
+ }, [resources, loaded, loadError]);
+
+ // Debug breakpoint
+ if (process.env.NODE_ENV === 'development' && resources.length > 0) {
+ debugger; // Will pause in browser devtools
+ }
+
+ return Component content
;
+};
+```
+
+### Console Extension Debugging
+```typescript
+// Debug extension loading
+const MyPage: React.FC = () => {
+ React.useEffect(() => {
+ if (process.env.NODE_ENV === 'development') {
+ console.log('Plugin extension loaded:', {
+ pathname: window.location.pathname,
+ extensions: window.SERVER_FLAGS?.consolePlugins
+ });
+ }
+ }, []);
+
+ return ...;
+};
+```
+
+### Network Request Debugging
+```typescript
+// Debug API calls
+const debugApiCall = (url: string, options?: RequestInit) => {
+ if (process.env.NODE_ENV === 'development') {
+ console.log('API Call:', { url, options });
+ }
+ return consoleFetch(url, options);
+};
+
+// Use in API operations
+const createResource = async (data: MyResource) => {
+ try {
+ const response = await debugApiCall('/api/kubernetes/apis/my-group.io/v1/namespaces/default/myresources', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+ return response.json();
+ } catch (error) {
+ console.error('Create resource failed:', error);
+ throw error;
+ }
+};
+```
+
+## Troubleshooting Plugin Loading
+
+### Common Issues and Solutions
+
+#### Plugin Not Loading
+```bash
+# Check webpack dev server is running
+curl http://localhost:9001/plugin-entry.js
+
+# Check console container logs
+docker logs $(docker ps --filter "ancestor=quay.io/openshift/console" --format "{{.ID}}")
+
+# Verify plugin registration
+oc get consolePlugin my-plugin -o yaml
+```
+
+#### Extension Points Not Working
+1. **Check console-extensions.json matches exposedModules**:
+```json
+// console-extensions.json
+"component": { "$codeRef": "MyPage" }
+
+// package.json
+"exposedModules": {
+ "MyPage": "./components/MyPage" // Must match exactly
+}
+```
+
+2. **Verify component exports**:
+```typescript
+// Component must be default export
+const MyPage: React.FC = () => { ... };
+export default MyPage; // Required for $codeRef
+```
+
+#### Module Federation Issues
+```typescript
+// Check webpack.config.ts
+const config: webpack.Configuration = {
+ plugins: [
+ new ModuleFederationPlugin({
+ name: 'my-plugin',
+ filename: 'plugin-entry.js',
+ exposes: {
+ './plugin': './src/plugin.ts', // Entry point
+ './MyPage': './src/components/MyPage', // Components
+ },
+ }),
+ ],
+};
+```
+
+### Development Scripts
+
+Common development commands:
+```json
+{
+ "scripts": {
+ "start": "webpack serve --config webpack.config.ts",
+ "start-console": "./scripts/start-console.sh",
+ "build": "webpack --mode production",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "test-cypress": "cypress open",
+ "test-cypress-headless": "cypress run",
+ "lint": "eslint src --ext .ts,.tsx --fix && stylelint 'src/**/*.css' --fix",
+ "lint:check": "eslint src --ext .ts,.tsx && stylelint 'src/**/*.css'",
+ "tsc": "tsc --noEmit",
+ "i18n": "i18next-scanner --config i18next-scanner.config.js"
+ }
+}
+```
+
+## Performance Monitoring
+
+### Bundle Analysis
+```bash
+# Analyze bundle size
+npm run build
+npx webpack-bundle-analyzer dist/
+
+# Check for large dependencies
+npm install -g webpack-bundle-analyzer
+webpack-bundle-analyzer dist/main.js
+```
+
+### Runtime Performance
+```typescript
+// Performance monitoring in development
+const withPerformanceMonitoring = (
+ WrappedComponent: React.ComponentType
+) => {
+ return (props: P) => {
+ React.useEffect(() => {
+ if (process.env.NODE_ENV === 'development') {
+ const startTime = performance.now();
+ return () => {
+ const endTime = performance.now();
+ console.log(`${WrappedComponent.name} render time: ${endTime - startTime}ms`);
+ };
+ }
+ });
+
+ return ;
+ };
+};
+
+// Usage
+export default withPerformanceMonitoring(MyExpensiveComponent);
+```
+
+## Error Handling and Monitoring
+
+### Error Boundaries
+```typescript
+// Global error boundary for plugin
+class PluginErrorBoundary extends React.Component<
+ React.PropsWithChildren<{}>,
+ { hasError: boolean; error?: Error }
+> {
+ constructor(props: React.PropsWithChildren<{}>) {
+ super(props);
+ this.state = { hasError: false };
+ }
+
+ static getDerivedStateFromError(error: Error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+ console.error('Plugin error:', error, errorInfo);
+
+ // Send error to monitoring service in production
+ if (process.env.NODE_ENV === 'production') {
+ // sendErrorToMonitoring(error, errorInfo);
+ }
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+ window.location.reload()}>
+ Reload Page
+
+ }
+ >
+ Something went wrong in the plugin. Please try reloading the page.
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
+```
+
+### Development vs Production Configurations
+
+```typescript
+// Environment-specific configurations
+const isDevelopment = process.env.NODE_ENV === 'development';
+
+export const config = {
+ // API endpoints
+ apiBaseUrl: isDevelopment
+ ? 'http://localhost:8080/api'
+ : '/api',
+
+ // Logging level
+ logLevel: isDevelopment ? 'debug' : 'error',
+
+ // Debug features
+ enableDebugPanel: isDevelopment,
+
+ // Performance monitoring
+ enablePerformanceMonitoring: isDevelopment,
+
+ // Error reporting
+ enableErrorReporting: !isDevelopment,
+};
+```
+
+## Related Skills
+
+- [openshift-console-plugin-setup](../openshift-console-plugin-setup/SKILL.md) - Project setup and dependencies
+- [openshift-console-plugin-components](../openshift-console-plugin-components/SKILL.md) - Component testing patterns
+- [openshift-console-plugin-data](../openshift-console-plugin-data/SKILL.md) - Testing data hooks and operations
+- [openshift-console-plugin-deployment](../openshift-console-plugin-deployment/SKILL.md) - Build and deployment workflow
+
+## Development Checklist
+
+- [ ] Set up local development with both dev server and console container
+- [ ] Configure linting and run before all commits
+- [ ] Write unit tests for components and hooks
+- [ ] Add integration tests for critical user flows
+- [ ] Set up error boundaries for error handling
+- [ ] Configure debugging tools and logging
+- [ ] Monitor bundle size and performance
+- [ ] Test plugin loading and extension points
+- [ ] Verify authentication and API access
+- [ ] Test in different browser environments
+- [ ] Check accessibility with screen readers
+- [ ] Validate i18n translations work correctly
+
+## Common Development Commands
+
+```bash
+# Start development environment
+npm run start # Plugin dev server
+npm run start-console # Console container
+npm test # Run unit tests
+npm run test:watch # Watch mode for tests
+npm run test-cypress # Integration tests
+npm run lint # Code quality checks
+npm run build # Production build
+npm run i18n # Update translations
+
+# Debugging
+npm run lint:check # Check without fixes
+npm run tsc # TypeScript check
+npx webpack-bundle-analyzer dist/ # Analyze bundle
+
+# Cleanup
+rm -rf node_modules dist # Clean install
+npm ci # Fresh install
+```
\ No newline at end of file
diff --git a/.claude/skills/openshift-console-plugin-extensions/SKILL.md b/.claude/skills/openshift-console-plugin-extensions/SKILL.md
new file mode 100644
index 00000000..0cd01c1b
--- /dev/null
+++ b/.claude/skills/openshift-console-plugin-extensions/SKILL.md
@@ -0,0 +1,450 @@
+---
+name: openshift-console-plugin-extensions
+description: Console extension points, navigation, routes, and integration patterns for OpenShift Console plugins
+---
+
+# OpenShift Console Plugin Extensions
+
+This skill covers console extension points and integration patterns for extending the OpenShift Console with custom functionality. Learn how to add navigation, routes, tabs, and actions to the console.
+
+## Console Extensions Overview
+
+Console extensions are declared in `console-extensions.json` and define how your plugin integrates with the OpenShift Console. Each extension must have a corresponding module in your `package.json` `exposedModules` section.
+
+### Critical Requirements
+- **Extension-Module Mapping**: Every `$codeRef` in extensions must match an entry in `exposedModules`
+- **Type Safety**: Use proper TypeScript types for all extension properties
+- **i18n Support**: Use translation keys for user-facing strings
+
+## Navigation Extensions
+
+### Navigation Sections
+Create logical groupings for your plugin's navigation items:
+
+```json
+{
+ "type": "console.navigation/section",
+ "properties": {
+ "id": "my-plugin-section",
+ "perspective": "admin",
+ "name": "%plugin__my-console-plugin~My Section%"
+ }
+}
+```
+
+### Navigation Links
+Add navigation items that link to your plugin pages:
+
+```json
+{
+ "type": "console.navigation/href",
+ "properties": {
+ "id": "my-plugin-nav",
+ "name": "%plugin__my-console-plugin~My Feature%",
+ "href": "/my-feature",
+ "perspective": "admin",
+ "section": "my-plugin-section",
+ "insertAfter": "workloads"
+ }
+}
+```
+
+### Navigation with Resources
+Link navigation to specific Kubernetes resources:
+
+```json
+{
+ "type": "console.navigation/resource-ns",
+ "properties": {
+ "id": "my-resources-nav",
+ "name": "%plugin__my-console-plugin~My Resources%",
+ "section": "my-plugin-section",
+ "model": {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource"
+ }
+ }
+}
+```
+
+## Page Routes
+
+### Basic Page Routes
+Define routes for your plugin pages:
+
+```json
+{
+ "type": "console.page/route",
+ "properties": {
+ "path": "/my-feature",
+ "component": { "$codeRef": "MyPage" }
+ }
+}
+```
+
+### Parameterized Routes
+Create routes with URL parameters:
+
+```json
+{
+ "type": "console.page/route",
+ "properties": {
+ "path": "/my-feature/:id",
+ "component": { "$codeRef": "MyDetailsPage" }
+ }
+}
+```
+
+### Namespace-scoped Routes
+Routes that work within namespace contexts:
+
+```json
+{
+ "type": "console.page/route",
+ "properties": {
+ "path": "/ns/:ns/my-feature",
+ "component": { "$codeRef": "MyNamespacedPage" }
+ }
+}
+```
+
+## Resource Pages
+
+### Resource List Pages
+Override or create list pages for Kubernetes resources:
+
+```json
+{
+ "type": "console.page/resource/list",
+ "properties": {
+ "model": {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource"
+ },
+ "component": { "$codeRef": "MyResourceList" }
+ }
+}
+```
+
+### Resource Detail Pages
+Create detailed views for individual resources:
+
+```json
+{
+ "type": "console.page/resource/details",
+ "properties": {
+ "model": {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource"
+ },
+ "component": { "$codeRef": "MyResourceDetails" }
+ }
+}
+```
+
+## Tab Extensions
+
+### Resource Detail Tabs
+Add tabs to existing resource detail pages:
+
+```json
+{
+ "type": "console.tab",
+ "properties": {
+ "model": {
+ "group": "apps",
+ "version": "v1",
+ "kind": "Deployment"
+ },
+ "component": { "$codeRef": "MyResourceMonitoringTab" },
+ "name": "%plugin__my-console-plugin~Monitoring%"
+ }
+}
+```
+
+### Conditional Tabs
+Show tabs only when certain conditions are met:
+
+```json
+{
+ "type": "console.tab",
+ "properties": {
+ "model": {
+ "group": "apps",
+ "version": "v1",
+ "kind": "Deployment"
+ },
+ "component": { "$codeRef": "MyConditionalTab" },
+ "name": "%plugin__my-console-plugin~Advanced%"
+ },
+ "flags": {
+ "required": ["MY_FEATURE_FLAG"]
+ }
+}
+```
+
+## Action Extensions
+
+### Resource Actions
+Add actions to resource pages (kebab menus, buttons):
+
+```json
+{
+ "type": "console.action/resource-provider",
+ "properties": {
+ "model": {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource"
+ },
+ "provider": { "$codeRef": "myResourceActions" }
+ }
+}
+```
+
+### Global Actions
+Add actions to global areas like the utility menu:
+
+```json
+{
+ "type": "console.action/provider",
+ "properties": {
+ "contextId": "topnav-utility-menu",
+ "provider": { "$codeRef": "myGlobalActions" }
+ }
+}
+```
+
+## Feature Flags
+
+### Declaring Feature Flags
+Enable conditional functionality:
+
+```json
+{
+ "type": "console.flag",
+ "properties": {
+ "flag": "MY_FEATURE_FLAG",
+ "handler": { "$codeRef": "myFeatureFlag" }
+ }
+}
+```
+
+### Using Flags in Extensions
+Control extension visibility with flags:
+
+```json
+{
+ "type": "console.page/route",
+ "properties": {
+ "path": "/experimental-feature",
+ "component": { "$codeRef": "ExperimentalPage" }
+ },
+ "flags": {
+ "required": ["EXPERIMENTAL_FEATURES"]
+ }
+}
+```
+
+## Dashboard Extensions
+
+### Dashboard Cards
+Add cards to overview dashboards:
+
+```json
+{
+ "type": "console.dashboards/overview/health/url",
+ "properties": {
+ "title": "%plugin__my-console-plugin~My Service Health%",
+ "url": "/api/my-plugin/health",
+ "healthHandler": { "$codeRef": "myHealthHandler" }
+ }
+}
+```
+
+### Activity Cards
+Show activities in the Home page:
+
+```json
+{
+ "type": "console.dashboards/overview/activity/resource",
+ "properties": {
+ "k8sResource": {
+ "prop": "myResources",
+ "isList": true,
+ "kind": "MyResource"
+ },
+ "component": { "$codeRef": "MyActivityCard" }
+ }
+}
+```
+
+## Model Registration
+
+### Custom Resource Models
+Register your custom resources with the console:
+
+```json
+{
+ "type": "console.model",
+ "properties": {
+ "models": [
+ {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource",
+ "plural": "myresources",
+ "namespaced": true,
+ "crd": true
+ }
+ ]
+ }
+}
+```
+
+## YAML Template Extensions
+
+### YAML Templates
+Provide templates for creating resources:
+
+```json
+{
+ "type": "console.yaml-template",
+ "properties": {
+ "model": {
+ "group": "my-group.io",
+ "version": "v1",
+ "kind": "MyResource"
+ },
+ "template": { "$codeRef": "myResourceTemplate" },
+ "name": "My Resource Template"
+ }
+}
+```
+
+## Extension Best Practices
+
+### 1. Consistent Naming
+```json
+{
+ "id": "my-plugin-feature-name", // Use plugin prefix
+ "name": "%plugin__my-console-plugin~Feature Name%" // Always use i18n
+}
+```
+
+### 2. Proper Model References
+```json
+{
+ "model": {
+ "group": "apps", // Separate group property
+ "version": "v1", // Separate version property
+ "kind": "Deployment" // Exact kind name
+ }
+}
+```
+
+### 3. Code Reference Mapping
+```json
+// In console-extensions.json
+"component": { "$codeRef": "MyPage" }
+
+// In package.json
+"exposedModules": {
+ "MyPage": "./components/MyPage" // Must match exactly
+}
+```
+
+### 4. Perspective Targeting
+```json
+{
+ "perspective": "admin", // Target specific perspective
+ "perspective": "dev", // Or developer perspective
+ "perspective": "*" // Or all perspectives
+}
+```
+
+## Common Extension Patterns
+
+### Multi-tab Resource Page
+```json
+[
+ {
+ "type": "console.page/resource/details",
+ "properties": {
+ "model": { "group": "my-group.io", "version": "v1", "kind": "MyResource" },
+ "component": { "$codeRef": "MyResourceDetails" }
+ }
+ },
+ {
+ "type": "console.tab",
+ "properties": {
+ "model": { "group": "my-group.io", "version": "v1", "kind": "MyResource" },
+ "component": { "$codeRef": "MyResourceEventsTab" },
+ "name": "%plugin__my-console-plugin~Events%"
+ }
+ },
+ {
+ "type": "console.tab",
+ "properties": {
+ "model": { "group": "my-group.io", "version": "v1", "kind": "MyResource" },
+ "component": { "$codeRef": "MyResourceLogsTab" },
+ "name": "%plugin__my-console-plugin~Logs%"
+ }
+ }
+]
+```
+
+### Navigation with Sub-items
+```json
+[
+ {
+ "type": "console.navigation/section",
+ "properties": {
+ "id": "my-plugin-section",
+ "perspective": "admin",
+ "name": "%plugin__my-console-plugin~My Plugin%"
+ }
+ },
+ {
+ "type": "console.navigation/href",
+ "properties": {
+ "id": "my-plugin-overview",
+ "name": "%plugin__my-console-plugin~Overview%",
+ "href": "/my-plugin",
+ "section": "my-plugin-section"
+ }
+ },
+ {
+ "type": "console.navigation/resource-ns",
+ "properties": {
+ "id": "my-resources",
+ "section": "my-plugin-section",
+ "model": { "group": "my-group.io", "version": "v1", "kind": "MyResource" }
+ }
+ }
+]
+```
+
+## Related Skills
+
+- [openshift-console-plugin-setup](../openshift-console-plugin-setup/SKILL.md) - Project setup and dependencies
+- [openshift-console-plugin-components](../openshift-console-plugin-components/SKILL.md) - React component development
+- [openshift-console-plugin-i18n](../openshift-console-plugin-i18n/SKILL.md) - Internationalization for extensions
+- [openshift-console-plugin-development](../openshift-console-plugin-development/SKILL.md) - Development and testing workflow
+
+## Extension Reference
+
+### Most Common Extension Types
+- `console.navigation/section` - Navigation sections
+- `console.navigation/href` - Navigation links
+- `console.navigation/resource-ns` - Resource navigation
+- `console.page/route` - Custom routes
+- `console.page/resource/list` - Resource list pages
+- `console.page/resource/details` - Resource detail pages
+- `console.tab` - Resource detail tabs
+- `console.action/resource-provider` - Resource actions
+- `console.flag` - Feature flags
+- `console.model` - Custom resource models
\ No newline at end of file
diff --git a/.claude/skills/openshift-console-plugin-i18n/SKILL.md b/.claude/skills/openshift-console-plugin-i18n/SKILL.md
new file mode 100644
index 00000000..f3b02931
--- /dev/null
+++ b/.claude/skills/openshift-console-plugin-i18n/SKILL.md
@@ -0,0 +1,565 @@
+---
+name: openshift-console-plugin-i18n
+description: Internationalization and localization for OpenShift Console plugins
+---
+
+# OpenShift Console Plugin Internationalization (i18n)
+
+This skill covers internationalization and localization for OpenShift Console plugins, including translation setup, namespace conventions, and best practices for multi-language support.
+
+## i18n Overview
+
+Internationalization enables your console plugin to support multiple languages and regions. The OpenShift Console uses react-i18next for translation management, and plugins must follow specific namespace conventions.
+
+### Core Requirements
+- **Namespace Convention**: `plugin__` (matches ConsolePlugin resource name)
+- **Translation Files**: Located in `/locales` directory
+- **Default Language**: English (en) is required
+- **Key Format**: Use descriptive, hierarchical keys
+
+## Namespace Convention
+
+**⚠️ CRITICAL: Namespace must match your ConsolePlugin resource name**
+
+```typescript
+// If your ConsolePlugin resource is named "my-console-plugin"
+const PLUGIN_NAMESPACE = 'plugin__my-console-plugin';
+
+// Use this namespace in all translation calls
+const { t } = useTranslation('plugin__my-console-plugin');
+```
+
+### ConsolePlugin Resource Name Matching
+```yaml
+# In your Helm chart or YAML manifest
+apiVersion: console.openshift.io/v1
+kind: ConsolePlugin
+metadata:
+ name: my-console-plugin # This determines your i18n namespace
+spec:
+ displayName: "My Console Plugin"
+```
+
+```typescript
+// i18n namespace MUST match the resource name above
+const namespace = 'plugin__my-console-plugin';
+```
+
+## Translation Setup
+
+### Directory Structure
+```
+my-console-plugin/
+├── locales/
+│ ├── en/
+│ │ └── plugin__my-console-plugin.json
+│ ├── es/
+│ │ └── plugin__my-console-plugin.json
+│ ├── fr/
+│ │ └── plugin__my-console-plugin.json
+│ └── zh/
+│ └── plugin__my-console-plugin.json
+├── src/
+│ └── components/
+└── package.json
+```
+
+### English Translation File (Required)
+```json
+{
+ "My Plugin": "My Plugin",
+ "Dashboard": "Dashboard",
+ "Resources": "Resources",
+ "Create Resource": "Create Resource",
+ "Edit Resource": "Edit Resource",
+ "Delete Resource": "Delete Resource",
+ "Name": "Name",
+ "Namespace": "Namespace",
+ "Status": "Status",
+ "Created": "Created",
+ "Actions": "Actions",
+ "Loading": "Loading...",
+ "No resources found": "No resources found",
+ "Error loading resources": "Error loading resources",
+ "Resource created successfully": "Resource created successfully",
+ "Failed to create resource": "Failed to create resource",
+ "Are you sure you want to delete {{name}}?": "Are you sure you want to delete {{name}}?",
+ "This action cannot be undone": "This action cannot be undone",
+ "resource": "resource",
+ "resources": "resources",
+ "{{count}} resource": "{{count}} resource",
+ "{{count}} resource_plural": "{{count}} resources",
+ "Welcome": "Welcome",
+ "Getting Started": "Getting Started",
+ "Documentation": "Documentation",
+ "Support": "Support",
+ "Settings": "Settings",
+ "Configuration": "Configuration",
+ "Advanced": "Advanced",
+ "Overview": "Overview",
+ "Details": "Details",
+ "YAML": "YAML",
+ "Events": "Events",
+ "Logs": "Logs",
+ "Metrics": "Metrics",
+ "Ready": "Ready",
+ "Pending": "Pending",
+ "Error": "Error",
+ "Unknown": "Unknown",
+ "Healthy": "Healthy",
+ "Unhealthy": "Unhealthy",
+ "Running": "Running",
+ "Stopped": "Stopped",
+ "Success": "Success",
+ "Warning": "Warning",
+ "Info": "Information"
+}
+```
+
+## Using Translations in Components
+
+### Basic Translation Hook
+```typescript
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Page, PageSection, Title } from '@patternfly/react-core';
+
+const MyPage: React.FC = () => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+
+ return (
+
+
+ {t('My Plugin')}
+
+
+ {t('Welcome to the plugin dashboard')}
+
+
+ );
+};
+```
+
+### Translations with Variables
+```typescript
+const ResourceCard: React.FC<{ resource: MyResource }> = ({ resource }) => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+ const name = resource.metadata?.name;
+
+ return (
+
+ {t('Resource Details for {{name}}', { name })}
+
+ {t('Status: {{status}}', { status: resource.status?.phase })}
+ {t('Created: {{date}}', {
+ date: new Date(resource.metadata?.creationTimestamp).toLocaleDateString()
+ })}
+
+
+ );
+};
+```
+
+### Pluralization
+```typescript
+const ResourceList: React.FC<{ resources: MyResource[] }> = ({ resources }) => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+
+ return (
+
+
+ {t('{{count}} resource', { count: resources.length })}
+
+ {resources.length === 0 && (
+
+ {t('No resources found')}
+
+ )}
+
+ );
+};
+```
+
+### Complex Formatting
+```typescript
+const DeleteConfirmation: React.FC<{ resourceName: string }> = ({ resourceName }) => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+
+ return (
+
+
+
+ {t('Are you sure you want to delete {{name}}?', { name: resourceName })}
+
+
+
+
+
+
+ );
+};
+```
+
+## Console Extensions i18n
+
+### Navigation Extensions
+```json
+{
+ "type": "console.navigation/section",
+ "properties": {
+ "id": "my-plugin-section",
+ "perspective": "admin",
+ "name": "%plugin__my-console-plugin~My Plugin%"
+ }
+}
+```
+
+### Page Routes with i18n
+```json
+{
+ "type": "console.navigation/href",
+ "properties": {
+ "id": "my-plugin-dashboard",
+ "name": "%plugin__my-console-plugin~Dashboard%",
+ "href": "/my-plugin/dashboard",
+ "section": "my-plugin-section"
+ }
+}
+```
+
+### Tab Extensions
+```json
+{
+ "type": "console.tab",
+ "properties": {
+ "model": {
+ "group": "apps",
+ "version": "v1",
+ "kind": "Deployment"
+ },
+ "component": { "$codeRef": "MyResourceTab" },
+ "name": "%plugin__my-console-plugin~Monitoring%"
+ }
+}
+```
+
+## Advanced Translation Patterns
+
+### Conditional Translations
+```typescript
+const StatusBadge: React.FC<{ status: string; isError: boolean }> = ({ status, isError }) => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+
+ const getStatusText = () => {
+ if (isError) return t('Error');
+
+ switch (status) {
+ case 'Ready': return t('Ready');
+ case 'Pending': return t('Pending');
+ case 'Running': return t('Running');
+ default: return t('Unknown');
+ }
+ };
+
+ return (
+
+ );
+};
+```
+
+### Date and Time Formatting
+```typescript
+const ResourceTimestamp: React.FC<{ timestamp: string }> = ({ timestamp }) => {
+ const { t, i18n } = useTranslation('plugin__my-console-plugin');
+
+ const formatDate = (dateString: string) => {
+ const date = new Date(dateString);
+ return new Intl.DateTimeFormat(i18n.language, {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit'
+ }).format(date);
+ };
+
+ return (
+
+ {formatDate(timestamp)}
+
+ );
+};
+```
+
+### Number Formatting
+```typescript
+const ResourceMetrics: React.FC<{ cpuUsage: number; memoryUsage: number }> = ({
+ cpuUsage,
+ memoryUsage
+}) => {
+ const { t, i18n } = useTranslation('plugin__my-console-plugin');
+
+ const formatNumber = (value: number) => {
+ return new Intl.NumberFormat(i18n.language, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2
+ }).format(value);
+ };
+
+ return (
+
+
+ {t('CPU Usage')}
+
+ {t('{{value}}%', { value: formatNumber(cpuUsage) })}
+
+
+
+ {t('Memory Usage')}
+
+ {t('{{value}} MB', { value: formatNumber(memoryUsage) })}
+
+
+
+ );
+};
+```
+
+## Translation Workflow
+
+### Adding New Translations
+```bash
+# 1. Add new keys to English translation file
+# locales/en/plugin__my-console-plugin.json
+
+# 2. Use the translation in your component
+const { t } = useTranslation('plugin__my-console-plugin');
+const text = t('New feature description');
+
+# 3. Update all translation files
+npm run i18n
+
+# 4. Send translation files to translators
+# 5. Update translation files with translated content
+```
+
+### Translation Build Process
+```json
+{
+ "scripts": {
+ "i18n": "i18next-scanner --config i18next-scanner.config.js",
+ "i18n:extract": "i18next-scanner",
+ "i18n:build": "node scripts/build-i18n.js"
+ }
+}
+```
+
+### i18n Scanner Configuration
+```javascript
+// i18next-scanner.config.js
+module.exports = {
+ input: [
+ 'src/**/*.{js,jsx,ts,tsx}',
+ 'console-extensions.json'
+ ],
+ output: './locales',
+ options: {
+ debug: false,
+ func: {
+ list: ['t', 'i18next.t', 'i18n.t'],
+ extensions: ['.js', '.jsx', '.ts', '.tsx']
+ },
+ trans: {
+ component: 'Trans',
+ i18nKey: 'i18nKey',
+ defaultsKey: 'defaults',
+ extensions: ['.js', '.jsx', '.ts', '.tsx']
+ },
+ lngs: ['en'],
+ ns: [`plugin__${require('./package.json').consolePlugin.name}`],
+ defaultLng: 'en',
+ defaultNs: `plugin__${require('./package.json').consolePlugin.name}`,
+ resource: {
+ loadPath: '{{lng}}/{{ns}}.json',
+ savePath: '{{lng}}/{{ns}}.json',
+ jsonIndent: 2
+ },
+ nsSeparator: '~',
+ keySeparator: false
+ }
+};
+```
+
+## Multi-language Support
+
+### Spanish Translation Example
+```json
+{
+ "My Plugin": "Mi Plugin",
+ "Dashboard": "Panel de Control",
+ "Resources": "Recursos",
+ "Create Resource": "Crear Recurso",
+ "Edit Resource": "Editar Recurso",
+ "Delete Resource": "Eliminar Recurso",
+ "Name": "Nombre",
+ "Namespace": "Espacio de Nombres",
+ "Status": "Estado",
+ "Created": "Creado",
+ "Actions": "Acciones",
+ "Loading": "Cargando...",
+ "No resources found": "No se encontraron recursos",
+ "Error loading resources": "Error al cargar recursos",
+ "Resource created successfully": "Recurso creado exitosamente",
+ "Failed to create resource": "Error al crear recurso",
+ "Are you sure you want to delete {{name}}?": "¿Está seguro de que desea eliminar {{name}}?",
+ "This action cannot be undone": "Esta acción no se puede deshacer",
+ "{{count}} resource": "{{count}} recurso",
+ "{{count}} resource_plural": "{{count}} recursos"
+}
+```
+
+### French Translation Example
+```json
+{
+ "My Plugin": "Mon Plugin",
+ "Dashboard": "Tableau de Bord",
+ "Resources": "Ressources",
+ "Create Resource": "Créer une Ressource",
+ "Edit Resource": "Modifier la Ressource",
+ "Delete Resource": "Supprimer la Ressource",
+ "Name": "Nom",
+ "Namespace": "Espace de Noms",
+ "Status": "État",
+ "Created": "Créé",
+ "Actions": "Actions",
+ "Loading": "Chargement...",
+ "No resources found": "Aucune ressource trouvée",
+ "Error loading resources": "Erreur lors du chargement des ressources",
+ "{{count}} resource": "{{count}} ressource",
+ "{{count}} resource_plural": "{{count}} ressources"
+}
+```
+
+## Testing Translations
+
+### Translation Testing
+```typescript
+// src/utils/i18n-test.ts
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+
+// Test translations
+const testResources = {
+ en: {
+ 'plugin__my-console-plugin': {
+ 'My Plugin': 'My Plugin',
+ 'Dashboard': 'Dashboard',
+ 'Loading': 'Loading...',
+ 'No resources found': 'No resources found'
+ }
+ }
+};
+
+i18n
+ .use(initReactI18next)
+ .init({
+ lng: 'en',
+ fallbackLng: 'en',
+ debug: false,
+ resources: testResources,
+ ns: ['plugin__my-console-plugin'],
+ defaultNS: 'plugin__my-console-plugin'
+ });
+
+export default i18n;
+```
+
+### Component Testing with i18n
+```typescript
+// src/components/__tests__/MyPage.test.tsx
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { I18nextProvider } from 'react-i18next';
+import i18n from '../../utils/i18n-test';
+import MyPage from '../MyPage';
+
+describe('MyPage with i18n', () => {
+ const renderWithI18n = (component: React.ReactElement) => {
+ return render(
+
+ {component}
+
+ );
+ };
+
+ it('renders translated content', () => {
+ renderWithI18n();
+ expect(screen.getByText('My Plugin')).toBeInTheDocument();
+ expect(screen.getByText('Dashboard')).toBeInTheDocument();
+ });
+});
+```
+
+## Best Practices
+
+### Translation Key Naming
+```json
+{
+ "page.dashboard.title": "Dashboard",
+ "page.dashboard.description": "View system overview",
+ "action.create": "Create",
+ "action.edit": "Edit",
+ "action.delete": "Delete",
+ "status.ready": "Ready",
+ "status.pending": "Pending",
+ "status.error": "Error",
+ "message.success.create": "Resource created successfully",
+ "message.error.create": "Failed to create resource",
+ "modal.delete.title": "Delete Resource",
+ "modal.delete.confirm": "Are you sure you want to delete {{name}}?"
+}
+```
+
+### Context-Aware Translations
+```typescript
+const ActionButton: React.FC<{ action: 'create' | 'edit' | 'delete'; resource: string }> = ({
+ action,
+ resource
+}) => {
+ const { t } = useTranslation('plugin__my-console-plugin');
+
+ const getActionText = () => {
+ switch (action) {
+ case 'create': return t('action.create.resource', { resource });
+ case 'edit': return t('action.edit.resource', { resource });
+ case 'delete': return t('action.delete.resource', { resource });
+ }
+ };
+
+ return ;
+};
+```
+
+## Related Skills
+
+- [openshift-console-plugin-extensions](../openshift-console-plugin-extensions/SKILL.md) - Using i18n in console extensions
+- [openshift-console-plugin-components](../openshift-console-plugin-components/SKILL.md) - Component translation patterns
+- [openshift-console-plugin-setup](../openshift-console-plugin-setup/SKILL.md) - Project setup with i18n
+- [openshift-console-plugin-development](../openshift-console-plugin-development/SKILL.md) - Testing translations
+
+## i18n Checklist
+
+- [ ] Namespace matches ConsolePlugin resource name
+- [ ] English translation file exists and is complete
+- [ ] All user-facing strings use translation keys
+- [ ] Console extensions use i18n format (%namespace~key%)
+- [ ] Pluralization rules implemented for count-based content
+- [ ] Date and number formatting uses locale-aware methods
+- [ ] Translation extraction process configured
+- [ ] Tests include i18n provider
+- [ ] Variable interpolation used for dynamic content
+- [ ] Context-aware translations for ambiguous terms
+- [ ] All supported languages have translation files
+- [ ] Translation build process integrated into CI/CD
\ No newline at end of file
diff --git a/.claude/skills/openshift-console-plugin-setup/SKILL.md b/.claude/skills/openshift-console-plugin-setup/SKILL.md
new file mode 100644
index 00000000..0ce7e5d3
--- /dev/null
+++ b/.claude/skills/openshift-console-plugin-setup/SKILL.md
@@ -0,0 +1,221 @@
+---
+name: openshift-console-plugin-setup
+description: Project setup, dependencies, and version compatibility for OpenShift Console plugins
+---
+
+# OpenShift Console Plugin Setup
+
+This skill provides guidance for setting up OpenShift Console plugin projects, managing dependencies, and ensuring version compatibility. This is the foundation for all console plugin development.
+
+## Project Structure and Setup
+
+### Essential Files and Directories
+```
+my-console-plugin/
+├── src/
+│ ├── components/ # React components
+│ ├── types/ # TypeScript type definitions
+│ └── index.ts # Entry point
+├── console-extensions.json # Plugin extension declarations
+├── package.json # Dependencies and plugin metadata
+├── webpack.config.ts # Module federation configuration
+├── tsconfig.json # TypeScript configuration
+├── locales/ # i18n translation files
+├── charts/ # Helm chart for deployment
+└── integration-tests/ # Cypress e2e tests
+```
+
+### Plugin Metadata in package.json
+
+```json
+{
+ "name": "@my-org/my-console-plugin",
+ "consolePlugin": {
+ "name": "my-console-plugin",
+ "version": "1.0.0",
+ "displayName": "My Console Plugin",
+ "description": "Extends OpenShift Console with custom functionality",
+ "exposedModules": {
+ "MyPage": "./components/MyPage",
+ "MyListPage": "./components/MyListPage",
+ "MyDetailsPage": "./components/MyDetailsPage"
+ },
+ "dependencies": {
+ "@console/pluginAPI": "^4.21.0"
+ }
+ }
+}
+```
+
+## OpenShift Version Compatibility
+
+**⚠️ CRITICAL: Version compatibility is essential for plugin stability**
+
+Plugin development requires careful attention to OpenShift Console and shared library versions. Always reference the [official SDK documentation](https://github.com/openshift/console/blob/main/frontend/packages/console-dynamic-plugin-sdk/README.md) for the latest compatibility matrix.
+
+### Console SDK Version Mapping
+```json
+{
+ "devDependencies": {
+ "@openshift-console/dynamic-plugin-sdk": "4.21-latest",
+ "@openshift-console/dynamic-plugin-sdk-webpack": "4.21-latest"
+ }
+}
+```
+
+**SDK Version Scheme:**
+- SDK packages follow semver where major/minor version indicates supported OpenShift Console version
+- Example: `4.21.x` supports OpenShift Console 4.21.x
+- Prerelease versions: `"4.19.0-prerelease.1"` (development builds)
+- Full releases: `"4.19.0"` (published after Console GA)
+
+### PatternFly Version Compatibility Matrix
+
+| OpenShift Console Version | Supported PatternFly Versions | Recommended |
+|---------------------------|-------------------------------|-------------|
+| 4.22.x | PatternFly 6.x | ✅ PF6 |
+| 4.19.x - 4.22.x | PatternFly 6.x, 5.x | ✅ PF6 |
+| 4.15.x - 4.18.x | PatternFly 5.x, 4.x | ✅ PF5 |
+| 4.12.x - 4.14.x | PatternFly 4.x | ⚠️ PF4 (legacy) |
+
+```json
+{
+ "devDependencies": {
+ "@patternfly/react-core": "^6.0.0",
+ "@patternfly/react-icons": "^6.0.0",
+ "@patternfly/react-table": "^6.0.0"
+ }
+}
+```
+
+### Shared Libraries Provided by Console
+
+The OpenShift Console provides these shared modules to avoid duplication:
+
+**Core Libraries:**
+- `@openshift/dynamic-plugin-sdk`
+- `@openshift-console/dynamic-plugin-sdk`
+- `react` (version managed by console)
+- `react-dom`
+- `react-redux`
+- `redux`
+
+**UI Libraries:**
+- `@patternfly/react-core`
+- `@patternfly/react-icons`
+- `@patternfly/react-table`
+
+**Additional Libraries:**
+- Various utility libraries (check the [official SDK documentation](https://github.com/openshift/console/blob/main/frontend/packages/console-dynamic-plugin-sdk/README.md) for current list)
+
+## Version Selection Best Practices
+
+1. **Target Specific Console Version**: Use exact SDK version matching your target OpenShift release
+```json
+{
+ "@openshift-console/dynamic-plugin-sdk": "4.21.0" // Exact version
+}
+```
+
+2. **Use Version Ranges for Broader Compatibility**:
+```json
+{
+ "@openshift-console/dynamic-plugin-sdk": "^4.21.0" // Compatible versions
+}
+```
+
+3. **Pin PatternFly Major Version**:
+```json
+{
+ "@patternfly/react-core": "^6.0.0" // Pin to PF6 for console 4.22+
+}
+```
+
+4. **Check Compatibility Before Upgrading**:
+```bash
+# Always check latest compatibility matrix
+curl -s https://raw.githubusercontent.com/openshift/console/main/frontend/packages/console-dynamic-plugin-sdk/README.md | grep -A 20 "Version compatibility"
+```
+
+## TypeScript Configuration
+
+### Basic TypeScript Setup
+```json
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "target": "es2021",
+ "sourceMap": true,
+ "jsx": "react-jsx",
+ "allowJs": true,
+ "strict": false,
+ "noUnusedLocals": true,
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "lib": ["ES2021", "DOM", "DOM.Iterable"]
+ },
+ "include": ["src"],
+ "exclude": ["node_modules"]
+}
+```
+
+### Strict TypeScript Setup (Recommended)
+```json
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "target": "es2021",
+ "sourceMap": true,
+ "jsx": "react-jsx",
+ "allowJs": false,
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "lib": ["ES2021", "DOM", "DOM.Iterable"]
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
+```
+
+## Version Troubleshooting
+
+### Common Version-Related Issues
+- **Runtime errors**: Version mismatch between plugin and console shared modules
+- **Styling issues**: PatternFly version incompatibility
+- **Build failures**: SDK version doesn't support target OpenShift version
+- **Type errors**: TypeScript definitions mismatch
+
+### Resolution Steps
+1. Verify OpenShift cluster version: `oc version`
+2. Check console version in cluster
+3. Update SDK versions to match console version
+4. Update PatternFly to compatible version
+5. Clear node_modules and reinstall: `rm -rf node_modules && npm install`
+
+## Related Skills
+
+- [openshift-console-plugin-extensions](../openshift-console-plugin-extensions/SKILL.md) - Console extension points and integration
+- [openshift-console-plugin-components](../openshift-console-plugin-components/SKILL.md) - React component development patterns
+- [openshift-console-plugin-development](../openshift-console-plugin-development/SKILL.md) - Development workflow and testing
+- [openshift-console-plugin-deployment](../openshift-console-plugin-deployment/SKILL.md) - Build and deployment strategies
+
+## Quick Setup Checklist
+
+- [ ] Create project structure with essential directories
+- [ ] Configure package.json with plugin metadata
+- [ ] Set up TypeScript configuration
+- [ ] Install compatible SDK and PatternFly versions
+- [ ] Verify version compatibility with target OpenShift release
+- [ ] Configure webpack for module federation
+- [ ] Set up development scripts
+- [ ] Initialize i18n support
+- [ ] Configure linting and testing
\ No newline at end of file
diff --git a/.claude/skills/openshift-console-plugin-styling/SKILL.md b/.claude/skills/openshift-console-plugin-styling/SKILL.md
new file mode 100644
index 00000000..bc60c24c
--- /dev/null
+++ b/.claude/skills/openshift-console-plugin-styling/SKILL.md
@@ -0,0 +1,618 @@
+---
+name: openshift-console-plugin-styling
+description: UI design, PatternFly usage, and CSS best practices for OpenShift Console plugins
+---
+
+# OpenShift Console Plugin Styling
+
+This skill covers UI design, PatternFly component usage, and CSS best practices for creating consistent, accessible, and theme-compatible OpenShift Console plugins.
+
+## PatternFly First Approach
+
+**⚠️ CRITICAL: Always prefer PatternFly components over custom implementations**
+
+The OpenShift Console uses PatternFly as its design system. Using PatternFly components ensures consistency, accessibility, theming support, and reduces maintenance burden. Avoid creating custom components when PatternFly alternatives exist.
+
+### Why Use PatternFly Components
+
+1. **Consistency**: Matches OpenShift Console's look and feel
+2. **Accessibility**: Built-in ARIA attributes and keyboard navigation
+3. **Theming**: Automatic dark/light mode support
+4. **Responsive**: Mobile and desktop optimized
+5. **Maintenance**: Updates handled by PatternFly team
+6. **Performance**: Optimized and tested components
+
+## Core PatternFly Components for Console Plugins
+
+### Dashboard and Layout Components
+```typescript
+import {
+ Page, // Main page wrapper
+ PageSection, // Content sections
+ Card, // Content cards
+ CardTitle, // Card headers
+ CardBody, // Card content
+ Gallery, // Responsive grid layout
+ GalleryItem, // Grid items
+ Grid, // Manual grid system
+ GridItem, // Grid cells
+ Flex, // Flexbox layout
+ FlexItem, // Flex children
+ Stack, // Vertical stacking
+ StackItem // Stack children
+} from '@patternfly/react-core';
+
+// Example: Dashboard with cards
+const MyDashboard: React.FC = () => (
+
+
+
+
+
+ Cluster Status
+ Content here
+
+
+
+
+ Resource Usage
+ More content
+
+
+
+
+
+);
+```
+
+### Data Display Components
+```typescript
+import {
+ Table, // Data tables
+ Thead, // Table header
+ Tbody, // Table body
+ Tr, // Table rows
+ Th, // Header cells
+ Td, // Data cells
+ DataList, // Alternative to tables
+ DataListItem, // List items
+ DescriptionList, // Key-value pairs
+ Label, // Status labels
+ Badge, // Count indicators
+ Progress, // Progress bars
+ Spinner // Loading indicators
+} from '@patternfly/react-core';
+
+// Example: Resource status display
+const ResourceStatus: React.FC<{ resource }> = ({ resource }) => (
+
+
+
+
+ Status
+
+
+
+
+
+ Progress
+
+
+
+
+
+
+
+);
+```
+
+### Navigation and Actions
+```typescript
+import {
+ Tabs, // Tab navigation
+ Tab, // Individual tabs
+ TabTitleText, // Tab labels
+ Breadcrumb, // Navigation breadcrumbs
+ BreadcrumbItem, // Breadcrumb links
+ Button, // Action buttons
+ Dropdown, // Action menus
+ DropdownItem, // Menu items
+ KebabToggle, // Three-dot menu
+ Toolbar, // Action toolbars
+ ToolbarContent, // Toolbar sections
+ ToolbarGroup, // Toolbar groups
+ ToolbarItem // Individual tools
+} from '@patternfly/react-core';
+
+// Example: Resource actions toolbar
+const ResourceActions: React.FC = () => (
+
+
+
+
+
+
+
+ }
+ dropdownItems={[
+ Edit,
+ Delete
+ ]}
+ />
+
+
+
+
+);
+```
+
+### Forms and Input Components
+```typescript
+import {
+ Form, // Form wrapper
+ FormGroup, // Form sections
+ TextInput, // Text fields
+ Select, // Dropdowns
+ SelectOption, // Dropdown options
+ Checkbox, // Checkboxes
+ Radio, // Radio buttons
+ Switch, // Toggle switches
+ FormHelperText, // Help text
+ Alert // Validation messages
+} from '@patternfly/react-core';
+
+// Example: Configuration form
+const ConfigForm: React.FC = () => (
+
+);
+```
+
+### Status and Feedback Components
+```typescript
+import {
+ Alert, // Notifications
+ AlertGroup, // Alert containers
+ Banner, // Page banners
+ EmptyState, // No data states
+ EmptyStateBody, // Empty state content
+ EmptyStateIcon, // Empty state icons
+ Modal, // Dialog modals
+ ModalVariant, // Modal types
+ NotificationDrawer, // Notification panel
+ Tooltip // Help tooltips
+} from '@patternfly/react-core';
+
+// Example: Empty state for resource lists
+const NoResourcesFound: React.FC = () => (
+
+
+ No resources found
+
+ Create your first resource to get started.
+
+
+
+);
+```
+
+## PatternFly vs Custom Components Decision Guide
+
+| Use Case | Prefer PatternFly | Consider Custom |
+|----------|-------------------|-----------------|
+| Data tables | ✅ Table component | ❌ |
+| Status displays | ✅ Label, Badge | ❌ |
+| Forms | ✅ Form components | ❌ |
+| Navigation | ✅ Tabs, Breadcrumb | ❌ |
+| Cards/panels | ✅ Card component | ❌ |
+| Buttons/actions | ✅ Button, Dropdown | ❌ |
+| Loading states | ✅ Spinner, Progress | ❌ |
+| Empty states | ✅ EmptyState | ❌ |
+| Modals/dialogs | ✅ Modal | ❌ |
+| Unique visualizations | Consider first | ✅ Charts, diagrams |
+| Domain-specific widgets | Consider first | ✅ If no PF equivalent |
+
+## Styling Best Practices
+
+**⚠️ NEVER use inline styles - Always use CSS classes or PatternFly props**
+
+Inline styles should be avoided in OpenShift Console plugins for several critical reasons:
+
+### Why Avoid Inline Styles?
+1. **Theming Breaks**: Inline styles override CSS custom properties, breaking dark/light theme switching
+2. **Responsiveness**: Cannot use media queries or responsive design patterns
+3. **Accessibility**: Harder to implement focus states, high contrast modes, and screen reader optimizations
+4. **Maintenance**: Difficult to update styling across components
+5. **Performance**: Inline styles prevent CSS caching and optimization
+6. **Consistency**: Prevents using PatternFly design tokens and variables
+7. **CSP Violations**: May violate Content Security Policy rules
+
+### ✅ CORRECT Styling Approaches
+
+#### CSS Classes with Plugin Prefixing
+```css
+/* Use plugin prefix for all custom classes */
+.my-console-plugin__container {
+ padding: var(--pf-v6-global-spacer-md);
+}
+
+.my-console-plugin__card {
+ background: var(--pf-v6-global-palette--grey-100);
+ border: 1px solid var(--pf-v6-global-BorderColor-300);
+}
+
+.my-console-plugin__status-running {
+ color: var(--pf-v6-global-palette--green-500);
+}
+
+.my-console-plugin__status-failed {
+ color: var(--pf-v6-global-palette--red-500);
+}
+
+/* Never use hex colors - use CSS variables */
+.my-console-plugin__highlight {
+ background-color: var(--pf-v6-global-palette--blue-50);
+ color: var(--pf-v6-global-palette--blue-700);
+}
+```
+
+### ❌ WRONG - Avoid These Patterns
+```typescript
+// DON'T DO THIS - Inline styles break theming
+const BadComponent: React.FC = () => (
+
+ Content
+
+);
+
+// DON'T DO THIS - Conditional inline styles
+const AnotherBadComponent: React.FC = ({ isError }) => (
+
+ Status
+
+);
+```
+
+## Component Styling - Correct Approaches
+
+### Method 1: CSS Classes with Conditional Styling
+```typescript
+import React from 'react';
+import {
+ Card,
+ CardTitle,
+ CardBody,
+ Label,
+ Flex,
+ FlexItem
+} from '@patternfly/react-core';
+import './MyComponent.css';
+
+interface MyComponentProps {
+ status: 'running' | 'failed' | 'pending';
+ isHighlighted?: boolean;
+}
+
+const MyComponent: React.FC = ({ status, isHighlighted }) => {
+ // Use conditional className instead of inline styles
+ const containerClassName = [
+ 'my-console-plugin__status-card',
+ isHighlighted && 'my-console-plugin__status-card--highlighted'
+ ].filter(Boolean).join(' ');
+
+ return (
+
+ Status Overview
+
+
+
+
+ {status}
+
+
+
+ {/* Use PatternFly color props when available */}
+
+
+
+
+
+ );
+};
+
+export default MyComponent;
+```
+
+### Method 2: PatternFly Component Props
+```typescript
+import React from 'react';
+import {
+ Card,
+ CardTitle,
+ CardBody,
+ Alert,
+ Button,
+ Flex,
+ FlexItem
+} from '@patternfly/react-core';
+
+const MyAlertComponent: React.FC<{ hasError: boolean }> = ({ hasError }) => (
+
+
+ {/* Use PatternFly variant props instead of inline styles */}
+
+
+
+ {/* Use PatternFly size and variant props */}
+
+
+
+
+
+);
+```
+
+### Method 3: CSS-in-JS Alternative (Use Sparingly)
+```typescript
+import React from 'react';
+import { Card } from '@patternfly/react-core';
+
+// If CSS-in-JS is absolutely necessary, use CSS custom properties
+const MyDynamicComponent: React.FC<{ progress: number }> = ({ progress }) => {
+ // Use CSS custom properties, not direct style values
+ const cardStyle = {
+ '--my-progress-width': `${progress}%`
+ } as React.CSSProperties;
+
+ return (
+
+ {/* Progress bar uses CSS custom property in stylesheet */}
+
+
+ );
+};
+```
+
+## CSS File Organization
+
+### Component CSS Structure
+```css
+/* MyComponent.css */
+
+/* Main component styles */
+.my-console-plugin__status-card {
+ margin-bottom: var(--pf-v6-global-spacer-md);
+ border-radius: var(--pf-v6-global-BorderRadius-md);
+}
+
+/* Modifier classes for state variations */
+.my-console-plugin__status-card--highlighted {
+ border: 2px solid var(--pf-v6-global-palette--blue-300);
+ box-shadow: var(--pf-v6-global-box-shadow-md);
+}
+
+/* Status indicator styles */
+.my-console-plugin__status {
+ font-weight: var(--pf-v6-global-FontWeight-bold);
+ padding: var(--pf-v6-global-spacer-xs);
+ border-radius: var(--pf-v6-global-BorderRadius-sm);
+}
+
+.my-console-plugin__status--running {
+ background-color: var(--pf-v6-global-palette--green-50);
+ color: var(--pf-v6-global-palette--green-700);
+}
+
+.my-console-plugin__status--failed {
+ background-color: var(--pf-v6-global-palette--red-50);
+ color: var(--pf-v6-global-palette--red-700);
+}
+
+.my-console-plugin__status--pending {
+ background-color: var(--pf-v6-global-palette--orange-50);
+ color: var(--pf-v6-global-palette--orange-700);
+}
+
+/* CSS custom property approach for dynamic values */
+.my-console-plugin__progress-card {
+ position: relative;
+ overflow: hidden;
+}
+
+.my-console-plugin__progress-bar {
+ width: var(--my-progress-width);
+ height: 4px;
+ background-color: var(--pf-v6-global-palette--blue-300);
+ transition: width 0.3s ease;
+}
+
+/* Responsive design using media queries */
+@media (max-width: 768px) {
+ .my-console-plugin__status-card {
+ margin-bottom: var(--pf-v6-global-spacer-sm);
+ }
+
+ .my-console-plugin__status {
+ font-size: var(--pf-v6-global-FontSize-sm);
+ }
+}
+
+/* Dark theme considerations */
+@media (prefers-color-scheme: dark) {
+ .my-console-plugin__status-card--highlighted {
+ border-color: var(--pf-v6-global-palette--blue-200);
+ }
+}
+```
+
+## Theme Compatibility
+
+### Using CSS Custom Properties
+```css
+/* Always use PatternFly CSS variables for colors */
+.my-plugin__primary-text {
+ color: var(--pf-v6-global-Color-100);
+}
+
+.my-plugin__secondary-text {
+ color: var(--pf-v6-global-Color-200);
+}
+
+.my-plugin__background {
+ background-color: var(--pf-v6-global-BackgroundColor-100);
+}
+
+.my-plugin__border {
+ border: 1px solid var(--pf-v6-global-BorderColor-100);
+}
+
+/* Status colors */
+.my-plugin__success {
+ color: var(--pf-v6-global-success-color-100);
+}
+
+.my-plugin__warning {
+ color: var(--pf-v6-global-warning-color-100);
+}
+
+.my-plugin__danger {
+ color: var(--pf-v6-global-danger-color-100);
+}
+```
+
+### Responsive Design Patterns
+```css
+/* Mobile-first approach */
+.my-plugin__card-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--pf-v6-global-spacer-md);
+}
+
+/* Tablet */
+@media (min-width: 768px) {
+ .my-plugin__card-grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+/* Desktop */
+@media (min-width: 1200px) {
+ .my-plugin__card-grid {
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+/* Large screens */
+@media (min-width: 1600px) {
+ .my-plugin__card-grid {
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
+```
+
+## Accessibility in Styling
+
+### Focus States
+```css
+/* Ensure visible focus indicators */
+.my-plugin__interactive-element {
+ border-radius: var(--pf-v6-global-BorderRadius-sm);
+ transition: all 0.2s ease;
+}
+
+.my-plugin__interactive-element:focus {
+ outline: 2px solid var(--pf-v6-global-palette--blue-300);
+ outline-offset: 2px;
+}
+
+.my-plugin__interactive-element:focus:not(:focus-visible) {
+ outline: none;
+}
+
+.my-plugin__interactive-element:focus-visible {
+ outline: 2px solid var(--pf-v6-global-palette--blue-300);
+ outline-offset: 2px;
+}
+```
+
+### High Contrast Mode
+```css
+/* High contrast media query support */
+@media (prefers-contrast: high) {
+ .my-plugin__card {
+ border: 2px solid;
+ }
+
+ .my-plugin__status--running {
+ background-color: transparent;
+ border: 2px solid var(--pf-v6-global-palette--green-500);
+ }
+}
+```
+
+## Performance Considerations
+
+### CSS Loading Strategy
+```typescript
+// Lazy load CSS for large components
+const LazyStyledComponent = React.lazy(async () => {
+ // Import CSS
+ await import('./LazyComponent.css');
+ // Import component
+ return import('./LazyComponent');
+});
+```
+
+### CSS Optimization Tips
+1. **Use CSS Custom Properties**: Better performance than CSS-in-JS
+2. **Minimize CSS Specificity**: Use single classes when possible
+3. **Avoid Deep Nesting**: Keep CSS selectors shallow
+4. **Group Related Styles**: Organize CSS logically
+5. **Use PatternFly Utilities**: Leverage existing utility classes
+
+## Related Skills
+
+- [openshift-console-plugin-components](../openshift-console-plugin-components/SKILL.md) - React component development patterns
+- [openshift-console-plugin-setup](../openshift-console-plugin-setup/SKILL.md) - Project setup and PatternFly versions
+- [openshift-console-plugin-development](../openshift-console-plugin-development/SKILL.md) - Linting CSS and styling workflow
+- [openshift-console-plugin-advanced](../openshift-console-plugin-advanced/SKILL.md) - Performance optimization for styles
+
+## Styling Checklist
+
+- [ ] Use PatternFly components instead of custom implementations
+- [ ] Never use inline styles - use CSS classes or PatternFly props
+- [ ] Prefix all custom CSS classes with plugin name
+- [ ] Use PatternFly CSS variables instead of hex colors
+- [ ] Implement responsive design with media queries
+- [ ] Add proper focus states for accessibility
+- [ ] Test in both light and dark themes
+- [ ] Use semantic color variables (success, warning, danger)
+- [ ] Optimize CSS for performance
+- [ ] Follow mobile-first design approach
\ No newline at end of file
diff --git a/.claude/skills/openshift-console-plugin/SKILL.md b/.claude/skills/openshift-console-plugin/SKILL.md
new file mode 100644
index 00000000..b00d40bc
--- /dev/null
+++ b/.claude/skills/openshift-console-plugin/SKILL.md
@@ -0,0 +1,206 @@
+---
+name: openshift-console-plugin
+description: Comprehensive guide for developing OpenShift Console dynamic plugins - overview and navigation to specialized skills
+---
+
+# OpenShift Console Plugin Development
+
+This is the main skill for OpenShift Console plugin development. For comprehensive guidance, this skill has been organized into specialized skills covering different aspects of plugin development. Use this overview to navigate to the specific area you need.
+
+## Skill Overview
+
+The OpenShift Console plugin development workflow is broken down into focused, specialized skills:
+
+### 🏗️ [Project Setup](../openshift-console-plugin-setup/SKILL.md)
+**Essential first step** - Project initialization, dependencies, and version compatibility
+
+**When to use:** Starting a new plugin project, updating dependencies, or troubleshooting version compatibility issues.
+
+**Key topics:**
+- Project structure and essential files
+- OpenShift version compatibility matrix
+- PatternFly version mapping
+- TypeScript configuration
+- Package.json plugin metadata
+
+---
+
+### 🧩 [Console Extensions](../openshift-console-plugin-extensions/SKILL.md)
+**Core integration** - Console extension points, navigation, routes, and integration patterns
+
+**When to use:** Adding navigation items, creating custom pages, adding tabs to existing resources, or integrating with console features.
+
+**Key topics:**
+- Navigation extensions and sections
+- Page routes and resource pages
+- Tab extensions and action providers
+- Feature flags and conditional extensions
+- Extension best practices
+
+---
+
+### ⚛️ [Component Development](../openshift-console-plugin-components/SKILL.md)
+**UI building blocks** - React component patterns and development best practices
+
+**When to use:** Creating React components, building user interfaces, implementing component patterns, or optimizing component performance.
+
+**Key topics:**
+- Component development patterns
+- Resource list and detail components
+- Modal and form patterns
+- Error handling and loading states
+- TypeScript interfaces and accessibility
+
+---
+
+### 📊 [Data Management](../openshift-console-plugin-data/SKILL.md)
+**K8s integration** - Data fetching, SDK helpers, and state management
+
+**When to use:** Working with Kubernetes resources, implementing data fetching, managing application state, or optimizing API calls.
+
+**Key topics:**
+- K8s SDK helpers (useK8sWatchResource, k8sGet)
+- API group/version configuration
+- Resource mutations (create, update, delete)
+- Custom hooks and state management
+- Error handling and performance optimization
+
+---
+
+### 🎨 [UI Design & Styling](../openshift-console-plugin-styling/SKILL.md)
+**Visual consistency** - PatternFly usage, CSS best practices, and theming
+
+**When to use:** Styling components, ensuring design consistency, implementing responsive design, or troubleshooting theme compatibility.
+
+**Key topics:**
+- PatternFly component usage
+- CSS best practices and avoiding inline styles
+- Component styling approaches
+- Theme compatibility and responsive design
+- Performance optimization for styles
+
+---
+
+### 🔄 [Development Workflow](../openshift-console-plugin-development/SKILL.md)
+**Development process** - Local development, testing, linting, and debugging
+
+**When to use:** Setting up local development, running tests, debugging issues, or establishing development workflows.
+
+**Key topics:**
+- Local development setup (dev server + console container)
+- Testing strategies (Jest, Cypress)
+- Code quality and linting
+- Debugging techniques
+- Pre-commit workflows and best practices
+
+---
+
+### 🌍 [Internationalization](../openshift-console-plugin-i18n/SKILL.md)
+**Multi-language support** - Translation setup, namespace conventions, and localization
+
+**When to use:** Adding multi-language support, setting up translations, or implementing i18n in components and extensions.
+
+**Key topics:**
+- i18n namespace conventions
+- Translation file structure
+- Using translations in React components
+- Console extension i18n
+- Translation workflow and testing
+
+---
+
+### 🚀 [Deployment](../openshift-console-plugin-deployment/SKILL.md)
+**Production delivery** - Build, containerization, Helm charts, and CI/CD
+
+**When to use:** Building production releases, creating container images, setting up deployments, or configuring CI/CD pipelines.
+
+**Key topics:**
+- Webpack production builds
+- Containerization with Docker/Podman
+- Helm chart development
+- CI/CD integration (GitHub Actions)
+- Production deployment strategies
+
+---
+
+### 🏆 [Advanced Patterns](../openshift-console-plugin-advanced/SKILL.md)
+**Expert techniques** - Performance optimization, security, and complex patterns
+
+**When to use:** Optimizing performance, implementing security best practices, handling complex state management, or building advanced plugin features.
+
+**Key topics:**
+- Code splitting and lazy loading
+- Security best practices and CSP
+- Advanced state management patterns
+- Error handling and resilience
+- Performance optimization techniques
+
+---
+
+## Quick Start Guide
+
+### For New Plugin Development:
+1. **Start with [Setup](../openshift-console-plugin-setup/SKILL.md)** - Initialize project and configure dependencies
+2. **Define [Extensions](../openshift-console-plugin-extensions/SKILL.md)** - Plan your console integration points
+3. **Build [Components](../openshift-console-plugin-components/SKILL.md)** - Create your React components
+4. **Implement [Data](../openshift-console-plugin-data/SKILL.md)** - Add K8s resource integration
+5. **Apply [Styling](../openshift-console-plugin-styling/SKILL.md)** - Use PatternFly for consistent UI
+6. **Setup [Development](../openshift-console-plugin-development/SKILL.md)** - Configure testing and workflows
+
+### For Existing Plugin Enhancement:
+- **Adding features** → [Extensions](../openshift-console-plugin-extensions/SKILL.md) + [Components](../openshift-console-plugin-components/SKILL.md)
+- **Performance issues** → [Advanced Patterns](../openshift-console-plugin-advanced/SKILL.md)
+- **Multi-language** → [Internationalization](../openshift-console-plugin-i18n/SKILL.md)
+- **Production deployment** → [Deployment](../openshift-console-plugin-deployment/SKILL.md)
+
+### For Troubleshooting:
+- **Plugin not loading** → [Development](../openshift-console-plugin-development/SKILL.md)
+- **Version conflicts** → [Setup](../openshift-console-plugin-setup/SKILL.md)
+- **UI/styling issues** → [Styling](../openshift-console-plugin-styling/SKILL.md)
+- **Data/API problems** → [Data Management](../openshift-console-plugin-data/SKILL.md)
+
+## Development Principles
+
+### Core Principles Across All Skills:
+
+1. **Use SDK Helpers**: Always use OpenShift Console SDK helpers for K8s operations
+2. **PatternFly First**: Prefer PatternFly components over custom implementations
+3. **TypeScript**: Use TypeScript for type safety and better development experience
+4. **Accessibility**: Follow WCAG guidelines and use proper ARIA attributes
+5. **Internationalization**: Support multiple languages from the start
+6. **Testing**: Write tests for components, hooks, and critical user flows
+7. **Security**: Validate inputs, sanitize outputs, and follow security best practices
+8. **Performance**: Optimize for bundle size and runtime performance
+
+### Quality Standards:
+
+- ✅ **Linting**: Run `yarn lint` before every commit
+- ✅ **Testing**: Maintain comprehensive test coverage
+- ✅ **Type Safety**: Use TypeScript interfaces for all data structures
+- ✅ **Accessibility**: Test with screen readers and keyboard navigation
+- ✅ **Documentation**: Keep documentation updated with code changes
+- ✅ **Consistency**: Follow established patterns across the codebase
+
+## Common Tasks Quick Reference
+
+| Task | Primary Skill | Supporting Skills |
+|------|---------------|------------------|
+| Project initialization | [Setup](../openshift-console-plugin-setup/SKILL.md) | [Development](../openshift-console-plugin-development/SKILL.md) |
+| Add navigation menu | [Extensions](../openshift-console-plugin-extensions/SKILL.md) | [i18n](../openshift-console-plugin-i18n/SKILL.md) |
+| Create custom page | [Components](../openshift-console-plugin-components/SKILL.md) | [Extensions](../openshift-console-plugin-extensions/SKILL.md) |
+| Fetch K8s resources | [Data Management](../openshift-console-plugin-data/SKILL.md) | [Components](../openshift-console-plugin-components/SKILL.md) |
+| Style components | [Styling](../openshift-console-plugin-styling/SKILL.md) | [Components](../openshift-console-plugin-components/SKILL.md) |
+| Add translations | [i18n](../openshift-console-plugin-i18n/SKILL.md) | [Components](../openshift-console-plugin-components/SKILL.md) |
+| Deploy to production | [Deployment](../openshift-console-plugin-deployment/SKILL.md) | [Advanced](../openshift-console-plugin-advanced/SKILL.md) |
+| Optimize performance | [Advanced](../openshift-console-plugin-advanced/SKILL.md) | [Styling](../openshift-console-plugin-styling/SKILL.md) |
+
+## Getting Help
+
+Each specialized skill contains:
+- **Comprehensive examples** with copy-paste code
+- **Best practices** and common patterns
+- **Troubleshooting guides** for common issues
+- **Cross-references** to related skills
+- **Checklists** to ensure completeness
+
+Start with the skill most relevant to your current task, and follow the cross-references to related skills as needed.
\ No newline at end of file