diff --git a/.gitignore b/.gitignore
index 28b624e..3d70b7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ AGENTS.override.md
.claude/pr/*
.mcp*
.tmp
+.pi-subagents
# Editors
*.code-workspace
diff --git a/.pi/prompts/create-pr.md b/.pi/prompts/create-pr.md
new file mode 120000
index 0000000..faf199e
--- /dev/null
+++ b/.pi/prompts/create-pr.md
@@ -0,0 +1 @@
+../../.claude/commands/create-pr.md
\ No newline at end of file
diff --git a/.pi/prompts/pdf-transcription-demo.md b/.pi/prompts/pdf-transcription-demo.md
new file mode 120000
index 0000000..473af60
--- /dev/null
+++ b/.pi/prompts/pdf-transcription-demo.md
@@ -0,0 +1 @@
+../../.claude/commands/pdf-transcription-demo.md
\ No newline at end of file
diff --git a/README.md b/README.md
index 087d707..60e42c0 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ Check out the **[Github page](https://github.com/openshift/faas-console-plugin)*
| [PR Template](.github/pull_request_template.md) | Pull request description format |
| [Jira Epic](docs/templates/jira-epic-template.md) | Template for creating Jira epics |
| [Jira Story](docs/templates/jira-story-template.md) | Template for creating Jira stories |
+| [Jira Bug](docs/templates/jira-bug-template.md) | Template for filing Jira bugs |
### Slash Commands
diff --git a/docs/AGILE.md b/docs/AGILE.md
index 88ac264..398db37 100644
--- a/docs/AGILE.md
+++ b/docs/AGILE.md
@@ -18,6 +18,7 @@ We use Jira for planning and tracking. Issues are organized as:
- **Epics** group related stories under a single initiative (see [epic template](templates/jira-epic-template.md))
- **Stories** describe a unit of deliverable work (see [story template](templates/jira-story-template.md))
+- **Bugs** describe a defect to fix (see [bug template](templates/jira-bug-template.md))
- **Sub-tasks** break a story into smaller pieces when needed
## Jira Story Status
diff --git a/docs/TESTING.md b/docs/TESTING.md
index 669e105..23a8892 100644
--- a/docs/TESTING.md
+++ b/docs/TESTING.md
@@ -13,6 +13,8 @@ Red/green/refactor TDD — **one test at a time**:
Do NOT write all test cases first and then implement everything at once.
+**Bug fixes require a regression test.** Add a unit test that reproduces the bug, or an e2e test if the bug is not testable at the unit level.
+
## Test Layers
| Layer | Tool | Scope |
@@ -326,7 +328,6 @@ test.describe('My feature', () => {
});
```
-
---
## Backend (Go)
diff --git a/docs/references/ocp-dynamic-plugin-reference.md b/docs/references/ocp-dynamic-plugin-reference.md
index ebed7c4..45a2cb8 100644
--- a/docs/references/ocp-dynamic-plugin-reference.md
+++ b/docs/references/ocp-dynamic-plugin-reference.md
@@ -208,3 +208,35 @@ return
{t('Hello, World!')}
;
1. Module federation requires exact module mapping: `exposedModules` must match `$codeRef` values
2. No webpack HMR for extensions: changes to `console-extensions.json` require restart
3. React 17, not 18: matches console's React version
+
+## Plugin Inventory
+
+[OCP Dynamic Plugin Inventory](https://docs.google.com/spreadsheets/d/1wcCdc1s4ewzxtUJ42VdRhAJ9wFA8UwoTajGSftrr5fM/edit?gid=0#gid=0)
+
+| Plugin | Repo | Description |
+|--------|------|-------------|
+| Console Plugin Template | [openshift/console-plugin-template](https://github.com/openshift/console-plugin-template) | Starter template for OCP dynamic plugins |
+| Console Demo Plugin | [openshift/console (demo)](https://github.com/openshift/console/tree/main/dynamic-demo-plugin) | SDK feature testing and reference |
+| KubeVirt | [kubevirt-ui/kubevirt-plugin](https://github.com/kubevirt-ui/kubevirt-plugin) | Virtual machine management UI |
+| Forklift | [kubev2v/forklift-console-plugin](https://github.com/kubev2v/forklift-console-plugin) | VM migration from other platforms to KubeVirt |
+| Monitoring | [openshift/monitoring-plugin](https://github.com/openshift/monitoring-plugin) | Prometheus monitoring dashboards and alerts |
+| Logging | [openshift/logging-view-plugin](https://github.com/openshift/logging-view-plugin) | Log viewing and querying |
+| Distributed Tracing | [openshift/distributed-tracing-console-plugin](https://github.com/openshift/distributed-tracing-console-plugin) | Distributed tracing with Tempo/Jaeger |
+| Console Dashboards | [openshift/console-dashboards-plugin](https://github.com/openshift/console-dashboards-plugin) | Custom dashboard support for OCP console |
+| Troubleshooting Panel | [openshift/troubleshooting-panel-console-plugin](https://github.com/openshift/troubleshooting-panel-console-plugin) | Guided troubleshooting for cluster issues |
+| Networking | [openshift/networking-console-plugin](https://github.com/openshift/networking-console-plugin) | Network policies, routes, and services |
+| Network Observability | [netobserv/network-observability-console-plugin](https://github.com/netobserv/network-observability-console-plugin) | Network traffic flow visualization |
+| OpenShift Pipelines | [openshift-pipelines/console-plugin](https://github.com/openshift-pipelines/console-plugin) | Tekton pipeline builder and viewer |
+| OpenShift GitOps | [redhat-developer/gitops-console-plugin](https://github.com/redhat-developer/gitops-console-plugin) | ArgoCD/GitOps application status |
+| OpenShift Data Foundation | [red-hat-storage/odf-console](https://github.com/red-hat-storage/odf-console) | Ceph/NooBaa storage management |
+| Service Mesh (Kiali) | [kiali/openshift-servicemesh-plugin](https://github.com/kiali/openshift-servicemesh-plugin) | Istio service mesh observability |
+| ACM / MCE | [stolostron/console](https://github.com/stolostron/console) | Advanced Cluster Management multi-cluster UI |
+| Cluster Templates | [stolostron/cluster-templates-operator](https://github.com/stolostron/cluster-templates-operator) | Cluster provisioning templates |
+| Crane (Migration) | [migtools/crane-ui-plugin](https://github.com/migtools/crane-ui-plugin) | Application migration toolkit |
+| NMState | [nmstate/nmstate-console-plugin](https://github.com/nmstate/nmstate-console-plugin) | Declarative node network configuration |
+| Console Telemetry | [christianvogt/console-telemetry-plugin](https://github.com/christianvogt/console-telemetry-plugin) | Usage telemetry collection for console |
+| Lightspeed | [openshift/lightspeed-console](https://github.com/openshift/lightspeed-console) | AI assistant for OpenShift |
+| Cryostat | [cryostatio/cryostat-openshift-console-plugin](https://github.com/cryostatio/cryostat-openshift-console-plugin) | JFR profiling and recording management |
+| Node Remediation | [medik8s/node-remediation-console](https://github.com/medik8s/node-remediation-console) | Automated node health check and remediation |
+| Skupper | [bartoval/skupper-site-console](https://github.com/bartoval/skupper-site-console) | Multi-cluster service connectivity |
+| Kuadrant | [Kuadrant/kuadrant-console-plugin](https://github.com/Kuadrant/kuadrant-console-plugin) | API gateway policies (rate limiting, auth) |
diff --git a/docs/templates/jira-bug-template.md b/docs/templates/jira-bug-template.md
new file mode 100644
index 0000000..9d9c5e6
--- /dev/null
+++ b/docs/templates/jira-bug-template.md
@@ -0,0 +1,37 @@
+# Jira Bug Template
+
+```
+### Summary
+
+
+
+Every bug fix requires a regression test (see [Testing](../TESTING.md#approach)).
+
+### Steps to Reproduce
+
+1.
+
+### Expected Behavior
+
+
+
+### Actual Behavior
+
+
+
+### Environment
+
+
+
+### Root Cause (optional)
+
+
+
+### Fix (optional)
+
+
+
+### References
+
+
+```
diff --git a/e2e/use-cases/edit/edit-javascript-function.test.ts b/e2e/use-cases/edit/edit-javascript-function.test.ts
new file mode 100644
index 0000000..eeb7506
--- /dev/null
+++ b/e2e/use-cases/edit/edit-javascript-function.test.ts
@@ -0,0 +1,60 @@
+import { test, expect } from '../../fixtures/authenticated-page';
+import { navigateToEditPage } from '../../helpers/navigation';
+import { PRESEEDED_FUNC_NAME } from '../../mocks/github';
+
+test.describe('Edit JavaScript function', () => {
+ test('regression SRVOCF-1007: editor loads JS files without Monaco worker errors', async ({
+ page,
+ }) => {
+ const consoleErrors: string[] = [];
+ page.on('pageerror', (err) => consoleErrors.push(err.message));
+
+ await test.step('navigate to edit page', async () => {
+ await navigateToEditPage(page, PRESEEDED_FUNC_NAME);
+ await expect(page.getByRole('heading', { name: 'Edit function' })).toBeVisible({
+ timeout: 10_000,
+ });
+ });
+
+ await test.step('verify editor loads with JavaScript syntax highlighting', async () => {
+ const editor = page.locator('.monaco-editor');
+ await expect(editor.first()).toBeVisible({ timeout: 10_000 });
+ await expect(editor.first()).toContainText('module.exports');
+
+ // Language label shows JAVASCRIPT
+ await expect(page.getByText('JAVASCRIPT')).toBeVisible();
+ });
+
+ await test.step('verify no webpack error overlay appeared', async () => {
+ const overlay = page.locator('#webpack-dev-server-client-overlay');
+ await expect(overlay).toHaveCount(0);
+ });
+
+ await test.step('verify no "Unexpected usage" errors in console', async () => {
+ const workerErrors = consoleErrors.filter((msg) => msg.includes('Unexpected usage'));
+ expect(workerErrors).toHaveLength(0);
+ });
+
+ await test.step('verify file tree loaded', async () => {
+ const tree = page.getByRole('tree', { name: 'File tree' });
+ await expect(tree.getByText('func.yaml')).toBeVisible();
+ await expect(tree.getByText('index.js')).toBeVisible();
+ });
+
+ await test.step('verify switching files works without errors', async () => {
+ const tree = page.getByRole('tree', { name: 'File tree' });
+ await tree.getByText('func.yaml', { exact: true }).click();
+
+ const editor = page.locator('.monaco-editor');
+ await expect(editor.first()).toContainText('runtime: node');
+
+ // Switch back to JS file
+ await tree.getByText('index.js', { exact: true }).click();
+ await expect(editor.first()).toContainText('module.exports');
+
+ // Still no worker errors after switching
+ const workerErrors = consoleErrors.filter((msg) => msg.includes('Unexpected usage'));
+ expect(workerErrors).toHaveLength(0);
+ });
+ });
+});
diff --git a/src/pages/function-edit/FunctionEditPage.tsx b/src/pages/function-edit/FunctionEditPage.tsx
index 0ee7216..c13267d 100644
--- a/src/pages/function-edit/FunctionEditPage.tsx
+++ b/src/pages/function-edit/FunctionEditPage.tsx
@@ -1,5 +1,6 @@
import { CodeEditor, DocumentTitle, ListPageHeader } from '@openshift-console/dynamic-plugin-sdk';
import type { Language } from '@patternfly/react-code-editor';
+import type { Monaco } from '@monaco-editor/react';
import {
DescriptionList,
DescriptionListDescription,
@@ -90,6 +91,15 @@ function FunctionEditPageContent() {
}
isLanguageLabelVisible
+ editorProps={{
+ beforeMount: (monaco: Monaco) => {
+ // SRVOCF-1007: the OCP console does not bundle Monaco's TS worker.
+ // Disable all worker-dependent features for JS/TS so the missing
+ // worker is never requested. Monarch syntax highlighting is unaffected.
+ monaco.languages.typescript.javascriptDefaults.setModeConfiguration({});
+ monaco.languages.typescript.typescriptDefaults.setModeConfiguration({});
+ },
+ }}
/>