Skip to content

Conversation

@TheRealJon
Copy link
Member

@TheRealJon TheRealJon commented Jan 28, 2026

Summary

Adds ClusterExtension creation form with comprehensive unit test coverage. The form supports auto-generated namespace and service account configuration, with the ability to edit names via modal, select existing resources from cluster, and configure version constraints, channels, and catalogs.

Components Added

ClusterExtensionForm: Main form component for creating ClusterExtensions

  • Auto-generated namespace and service account names based on extension name
  • Edit auto-generated names via pencil icon modal
  • Select existing namespace/service account from cluster
  • Configure version constraints, channels, and catalogs
  • Form/YAML view switching

TextInputModal: Reusable modal for editing text values

  • Validation support (required fields, custom validators)
  • Error handling and display
  • Customizable labels and help text

SchemaFieldHelp: Popover help icon displaying API schema descriptions with fallback support

Unit Tests (31 total)

  • ClusterExtensionForm.spec.tsx (14 tests): Form fields, auto-generation, radio buttons, channels/catalogs
  • TextInputModal.spec.tsx (12 tests): Modal rendering, validation, error handling
  • SchemaFieldHelp.spec.tsx (5 tests): Schema description display, fallback handling

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Added ClusterExtension creation workflow with intuitive form and YAML editor options.
    • Introduced reusable text input modal component for inline editing and form submissions.
    • Added contextual help indicators for schema fields with detailed descriptions.
    • Enhanced form with namespace and service account management, including inline creation options.
    • Expanded localization for OLM v1 UI with comprehensive field labels and help text.

✏️ Tip: You can customize this high-level summary in your review settings.

TheRealJon and others added 2 commits January 28, 2026 15:46
- Create ClusterExtensionForm with form/YAML view toggle
- Add SchemaFieldHelp component to display API schema documentation
- Add TextInputModal as reusable generic modal in console-shared
- Implement UI-only state for auto-generated namespace and service account names
- Add comprehensive field help descriptions with semantic versioning syntax examples
- Add ServiceAccountDropdown with create option
- Support auto-detection of existing namespaces and service accounts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add TextInputModal.spec.tsx with 12 tests for modal validation and behavior
- Add SchemaFieldHelp.spec.tsx with 5 tests for schema description rendering
- Add ClusterExtensionForm.spec.tsx with 14 tests covering:
  - Form field rendering and initialization
  - Auto-generation of namespace and service account names
  - Radio button toggling between create new and select from cluster
  - Channel and catalog label management
  - Version and package name updates
  - Pencil icon editing for auto-generated names

All 31 unit tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jan 28, 2026
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Jan 28, 2026

@TheRealJon: This pull request references CONSOLE-4976 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Adds ClusterExtension creation form with comprehensive unit test coverage. The form supports auto-generated namespace and service account configuration, with the ability to edit names via modal, select existing resources from cluster, and configure version constraints, channels, and catalogs.

Components Added

ClusterExtensionForm: Main form component for creating ClusterExtensions

  • Auto-generated namespace and service account names based on extension name
  • Edit auto-generated names via pencil icon modal
  • Select existing namespace/service account from cluster
  • Configure version constraints, channels, and catalogs
  • Form/YAML view switching

TextInputModal: Reusable modal for editing text values

  • Validation support (required fields, custom validators)
  • Error handling and display
  • Customizable labels and help text

SchemaFieldHelp: Popover help icon displaying API schema descriptions with fallback support

Unit Tests (31 total)

  • ClusterExtensionForm.spec.tsx (14 tests): Form fields, auto-generation, radio buttons, channels/catalogs
  • TextInputModal.spec.tsx (12 tests): Modal rendering, validation, error handling
  • SchemaFieldHelp.spec.tsx (5 tests): Schema description display, fallback handling

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from rhamilto and sg00dwin January 28, 2026 21:21
@openshift-ci openshift-ci bot added the component/core Related to console core functionality label Jan 28, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 28, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: TheRealJon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added component/olm Related to OLM approved Indicates a PR has been approved by an approver from all required OWNERS files. component/shared Related to console-shared kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated labels Jan 28, 2026
@openshift-ci-robot
Copy link
Contributor

openshift-ci-robot commented Jan 28, 2026

@TheRealJon: This pull request references CONSOLE-4976 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Adds ClusterExtension creation form with comprehensive unit test coverage. The form supports auto-generated namespace and service account configuration, with the ability to edit names via modal, select existing resources from cluster, and configure version constraints, channels, and catalogs.

Components Added

ClusterExtensionForm: Main form component for creating ClusterExtensions

  • Auto-generated namespace and service account names based on extension name
  • Edit auto-generated names via pencil icon modal
  • Select existing namespace/service account from cluster
  • Configure version constraints, channels, and catalogs
  • Form/YAML view switching

TextInputModal: Reusable modal for editing text values

  • Validation support (required fields, custom validators)
  • Error handling and display
  • Customizable labels and help text

SchemaFieldHelp: Popover help icon displaying API schema descriptions with fallback support

Unit Tests (31 total)

  • ClusterExtensionForm.spec.tsx (14 tests): Form fields, auto-generation, radio buttons, channels/catalogs
  • TextInputModal.spec.tsx (12 tests): Modal rendering, validation, error handling
  • SchemaFieldHelp.spec.tsx (5 tests): Schema description display, fallback handling

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
  • Added ClusterExtension creation workflow with intuitive form and YAML editor options.
  • Introduced reusable text input modal component for inline editing and form submissions.
  • Added contextual help indicators for schema fields with detailed descriptions.
  • Enhanced form with namespace and service account management, including inline creation options.
  • Expanded localization for OLM v1 UI with comprehensive field labels and help text.

✏️ Tip: You can customize this high-level summary in your review settings.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link

coderabbitai bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

This pull request introduces UI components and hooks for managing ClusterExtension creation in the Operator Lifecycle Manager v1 package. New reusable components include TextInputModal for validated text input, SchemaFieldHelp for displaying property descriptions, ClusterExtensionForm for form-based resource creation, and modals for creating ServiceAccounts. The refactored CreateClusterExtension component now uses SyncedEditor to coordinate form and YAML editing. Supporting hooks enable modal launching, and localization keys are added for form fields, help text, and error messages. SyncedEditor's context prop becomes optional. Comprehensive test coverage is included.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: adding a ClusterExtension creation form with accompanying unit tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@frontend/packages/console-shared/src/components/modals/TextInputModal.tsx`:
- Line 3: Replace the deprecated Modal import and composed-props usage with the
PatternFly v6 composable Modal API: change the import to "import { Modal,
ModalHeader, ModalBody, ModalFooter } from '@patternfly/react-core'", remove any
use of ModalVariant (e.g., ModalVariant.small) and instead use the Modal's
size/width props, and refactor the Modal JSX in TextInputModal (where title,
actions or ModalVariant are currently passed) to render
<Modal><ModalHeader>...</ModalHeader><ModalBody>...</ModalBody><ModalFooter>...</ModalFooter></Modal>
so the header, body and footer are explicit and action buttons move into
ModalFooter.

In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/ClusterExtensionForm.tsx`:
- Around line 418-423: The modal's initialValue is incorrectly using the
original name variable which discards any in-progress edits; change the
textInputModal call in ClusterExtensionForm (the invocation that passes
title/label/initialValue/onSubmit) to set initialValue to the current namespace
variable instead of name so the modal seeds with the current namespace value
(keep onSubmit as handleNamespaceChange).
- Around line 139-165: When the user edits the extension name in
handleNameChange, detect if the existing values for 'spec.namespace' and
'spec.serviceAccount.name' still match the previous auto-generated pattern
(e.g., derived from the old metadata.name); if they do, update them to the new
auto-generated values too by calling updateFormDataPath for 'spec.namespace' and
'spec.serviceAccount.name' (or invoke handleNamespaceChange /
handleServiceAccountNameChange) so the auto-generated namespace/ServiceAccount
stay in sync with the edited name; use the current form data (formData) to
compute whether the fields match the old pattern and to build the new derived
names before updating.

In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/CreateServiceAccountModal.tsx`:
- Around line 109-131: The Name field uses a nested FormGroup and neither
FormGroup includes fieldId, breaking label-input association; in
CreateServiceAccountModal update the Name block to use a single FormGroup with
fieldId="input-name" that wraps the TextInput (id="input-name") and add
fieldId="input-namespace" to the Namespace FormGroup to match the TextInput
(id="input-namespace"); ensure you leave submit, setName, namespace, and the
TextInput props unchanged while only adjusting FormGroup usage and adding the
fieldId attributes.
🧹 Nitpick comments (4)
frontend/packages/console-shared/src/components/modals/__tests__/TextInputModal.spec.tsx (1)

36-44: Solid test coverage—consider adding keyboard submission test.

The suite covers the critical paths well: validation, error states, custom validators, and button interactions.

One optional enhancement: since the modal wraps inputs in a <form>, users may expect to submit via Enter key. Consider adding a test for keyboard submission (e.g., fireEvent.submit(form) or pressing Enter on the input).

frontend/packages/console-shared/src/components/modals/TextInputModal.tsx (2)

37-55: Consider error boundary for onSubmit failures.

If onSubmit throws synchronously, the modal won't close but also won't display the error to users. For robustness, consider wrapping in try/catch:

♻️ Optional: wrap onSubmit in try/catch
+    try {
       onSubmit(value);
       closeModal();
+    } catch (err) {
+      setErrorMessage(String(err));
+    }

87-114: A11y consideration: link error to input for screen readers.

The error Alert is visually associated but not programmatically linked to the input. For better screen reader support, consider using PatternFly's FormGroup validated and helperTextInvalid props, or add aria-describedby to the input referencing the error's id.

This is optional but aligns with WCAG 3.3.1 (Error Identification).

frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/ClusterExtensionForm.tsx (1)

73-86: Use CATALOG_LABEL_KEY when parsing selectors.

Parsing uses a hard-coded label key string while updates use CATALOG_LABEL_KEY. This risks drift if the constant changes.

♻️ Consistency tweak
-    const catalogLabel = selector.matchLabels?.['olm.operatorframework.io/metadata.name'];
+    const catalogLabel = selector.matchLabels?.[CATALOG_LABEL_KEY];
...
-        expr.key === 'olm.operatorframework.io/metadata.name' && expr.operator === 'In',
+        expr.key === CATALOG_LABEL_KEY && expr.operator === 'In',

@@ -0,0 +1,118 @@
import { useState } from 'react';
import { Button, Alert, TextInput, FormGroup } from '@patternfly/react-core';
import { Modal, ModalVariant } from '@patternfly/react-core/deprecated';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Read the TextInputModal.tsx file to see the actual import and context
cat -n frontend/packages/console-shared/src/components/modals/TextInputModal.tsx | head -80

Repository: openshift/console

Length of output: 2727


🏁 Script executed:

# Search for Modal imports across the codebase to understand migration patterns
rg "from ['\"]@patternfly/react-core" frontend/packages/console-shared --type ts --type tsx | head -20

Repository: openshift/console

Length of output: 88


🏁 Script executed:

# Check if there are any migration tracking comments or TODO items related to PatternFly
rg "PatternFly|deprecated|v5|v6" frontend/packages/console-shared/src/components/modals/ --type ts --type tsx

Repository: openshift/console

Length of output: 88


🏁 Script executed:

# Search for Modal imports across the codebase (corrected command)
rg "Modal" frontend/packages/console-shared/src/components/modals/ -A 1 | head -30

Repository: openshift/console

Length of output: 2726


🏁 Script executed:

# Check how many places import from `@patternfly/react-core/deprecated`
rg "@patternfly/react-core/deprecated" frontend/packages/console-shared

Repository: openshift/console

Length of output: 673


🏁 Script executed:

# Search for Modal imports in the entire console codebase
rg "from.*@patternfly/react-core.*Modal" --max-count 30

Repository: openshift/console

Length of output: 43


🌐 Web query:

PatternFly React v6 Modal component migration deprecated to non-deprecated

💡 Result:

In PatternFly React v6, the non-deprecated Modal is the “new” implementation (formerly the /next Modal). The deprecated one is kept under @patternfly/react-core/deprecated and is no longer maintained. (staging.patternfly.org)

1) Update imports

  • Deprecated (old)
    import { Modal } from '@patternfly/react-core/deprecated';
  • Non-deprecated (v6 recommended)
    import { Modal, ModalHeader, ModalBody, ModalFooter } from '@patternfly/react-core';

PatternFly’s codemods explicitly call out that the “Next” Modal was promoted to the recommended implementation. (github.com)

2) Convert from “props-driven” header/footer/actions → composable subcomponents

Before (deprecated)

Common deprecated usage relies on title, header, footer, actions, etc. (patternfly.org)

<Modal
  title="My title"
  isOpen={isOpen}
  onClose={onClose}
  actions={[
    <Button key="confirm">Confirm</Button>,
    <Button key="cancel" variant="link" onClick={onClose}>Cancel</Button>
  ]}
/>

After (non-deprecated)

In the recommended Modal, you compose with <ModalHeader/>, <ModalBody/>, <ModalFooter/>. (patternfly.org)

<Modal isOpen={isOpen} onClose={onClose}>
  <ModalHeader title="My title" />
  <ModalBody>
    Modal content…
  </ModalBody>
  <ModalFooter>
    <Button>Confirm</Button>
    <Button variant="link" onClick={onClose}>Cancel</Button>
  </ModalFooter>
</Modal>

3) A couple of common behavioral/API gotchas

  • Close button rendering: in the recommended Modal, onClose “needs to be passed to render the close button.” (patternfly.org)
  • Scrollable content: deprecated docs say to set tabIndex={0} on <Modal>; the recommended docs say to set tabIndex={0} on <ModalBody>. (patternfly.org)
  • Custom header: deprecated Modal used header/footer props; recommended Modal uses <ModalHeader> composition for custom header content. (patternfly.org)

If you paste one of your existing deprecated Modal usages (especially if you’re using header, footer, actions, or help), I can rewrite it into the v6 non-deprecated structure.

Citations:


Migrate to non-deprecated PatternFly v6 Modal—deprecated path is no longer maintained.

The import from @patternfly/react-core/deprecated should not be used. PatternFly v6 has already been released, and the deprecated Modal is the old unmaintained implementation. The recommended Modal is available directly from @patternfly/react-core and uses a composable API with ModalHeader, ModalBody, and ModalFooter.

Update the import and refactor to use composed subcomponents instead of props like title, actions, and ModalVariant:

  • Replace import { Modal, ModalVariant } from '@patternfly/react-core/deprecated' with import { Modal, ModalHeader, ModalBody, ModalFooter } from '@patternfly/react-core'
  • Restructure the Modal tree to compose the header, body, and footer explicitly
  • Remove ModalVariant.small and use the Modal's size props instead

This pattern appears in at least 4 files across the codebase (CreateNamespaceModal, CreateProjectModal, Modal.tsx wrapper, and here). Consider a coordinated migration effort.

🤖 Prompt for AI Agents
In `@frontend/packages/console-shared/src/components/modals/TextInputModal.tsx` at
line 3, Replace the deprecated Modal import and composed-props usage with the
PatternFly v6 composable Modal API: change the import to "import { Modal,
ModalHeader, ModalBody, ModalFooter } from '@patternfly/react-core'", remove any
use of ModalVariant (e.g., ModalVariant.small) and instead use the Modal's
size/width props, and refactor the Modal JSX in TextInputModal (where title,
actions or ModalVariant are currently passed) to render
<Modal><ModalHeader>...</ModalHeader><ModalBody>...</ModalBody><ModalFooter>...</ModalFooter></Modal>
so the header, body and footer are explicit and action buttons move into
ModalFooter.

Comment on lines +139 to +165
const handleNameChange = useCallback(
(_event: any, value: string) => {
updateFormDataPath('metadata.name', value);
},
[updateFormDataPath],
);

const handlePackageNameChange = useCallback(
(_event: any, value: string) => {
updateFormDataPath('spec.source.catalog.packageName', value);
},
[updateFormDataPath],
);

const handleNamespaceChange = useCallback(
(value: string) => {
updateFormDataPath('spec.namespace', value);
},
[updateFormDataPath],
);

const handleServiceAccountNameChange = useCallback(
(value: string) => {
updateFormDataPath('spec.serviceAccount.name', value);
},
[updateFormDataPath],
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep auto-generated namespace/ServiceAccount in sync with name edits.

Right now, changing the extension name does not update the auto-generated namespace/serviceAccount, so you can end up creating resources with stale names. If the current values still match the previous auto pattern, update them on name changes to preserve expected “auto” behavior.

🔧 Suggested fix
-  const handleNameChange = useCallback(
-    (_event: any, value: string) => {
-      updateFormDataPath('metadata.name', value);
-    },
-    [updateFormDataPath],
-  );
+  const handleNameChange = useCallback(
+    (_event: any, value: string) => {
+      const prevName = name;
+      updateFormDataPath('metadata.name', value);
+
+      if (useAutoNamespace && namespace === prevName) {
+        updateFormDataPath('spec.namespace', value);
+      }
+      if (
+        useAutoServiceAccount &&
+        serviceAccountName === `${prevName}-service-account`
+      ) {
+        updateFormDataPath('spec.serviceAccount.name', `${value}-service-account`);
+      }
+    },
+    [
+      name,
+      namespace,
+      serviceAccountName,
+      updateFormDataPath,
+      useAutoNamespace,
+      useAutoServiceAccount,
+    ],
+  );
🤖 Prompt for AI Agents
In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/ClusterExtensionForm.tsx`
around lines 139 - 165, When the user edits the extension name in
handleNameChange, detect if the existing values for 'spec.namespace' and
'spec.serviceAccount.name' still match the previous auto-generated pattern
(e.g., derived from the old metadata.name); if they do, update them to the new
auto-generated values too by calling updateFormDataPath for 'spec.namespace' and
'spec.serviceAccount.name' (or invoke handleNamespaceChange /
handleServiceAccountNameChange) so the auto-generated namespace/ServiceAccount
stay in sync with the edited name; use the current form data (formData) to
compute whether the fields match the old pattern and to build the new derived
names before updating.

Comment on lines +418 to +423
textInputModal({
title: t('olm-v1~Edit Namespace Name'),
label: t('olm-v1~Namespace'),
initialValue: name,
onSubmit: handleNamespaceChange,
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use the current namespace as the modal’s initial value.

The edit modal seeds initialValue with name, which overwrites previously edited namespace values. Use the current namespace instead.

✅ Minimal fix
-                          initialValue: name,
+                          initialValue: namespace,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
textInputModal({
title: t('olm-v1~Edit Namespace Name'),
label: t('olm-v1~Namespace'),
initialValue: name,
onSubmit: handleNamespaceChange,
});
textInputModal({
title: t('olm-v1~Edit Namespace Name'),
label: t('olm-v1~Namespace'),
initialValue: namespace,
onSubmit: handleNamespaceChange,
});
🤖 Prompt for AI Agents
In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/ClusterExtensionForm.tsx`
around lines 418 - 423, The modal's initialValue is incorrectly using the
original name variable which discards any in-progress edits; change the
textInputModal call in ClusterExtensionForm (the invocation that passes
title/label/initialValue/onSubmit) to set initialValue to the current namespace
variable instead of name so the modal seeds with the current namespace value
(keep onSubmit as handleNamespaceChange).

Comment on lines +109 to +131
<Form onSubmit={submit}>
<FormGroup>
<FormGroup label={t('olm-v1~Name')}>
<TextInput
id="input-name"
data-test="input-name"
name="name"
type="text"
value={name}
onChange={(e, value) => setName(value)}
/>
</FormGroup>
</FormGroup>
<FormGroup label={t('olm-v1~Namespace')}>
<TextInput
readOnly
id="input-namespace"
data-test="input-namespace"
name="namespace"
value={namespace}
type="text"
/>
</FormGroup>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/CreateServiceAccountModal.tsx | sed -n '100,140p'

Repository: openshift/console

Length of output: 1573


🏁 Script executed:

rg "FormGroup" frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/CreateServiceAccountModal.tsx -A 5 -B 1

Repository: openshift/console

Length of output: 1229


🏁 Script executed:

rg "FormGroup.*label" frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/CreateServiceAccountModal.tsx

Repository: openshift/console

Length of output: 157


🌐 Web query:

PatternFly FormGroup fieldId label accessibility best practice

💡 Result:

  • Always use an explicit label–control association. In PatternFly forms, each field should have an id, and its <label> should have a matching for attribute (or the React equivalent: label wired to the input’s id). This is the primary accessibility best practice for form fields. [3], [4], [6]

  • FormGroup fieldId best practice (React):

    • If your FormGroup contains a single form control, set fieldId to the same value as the control’s id. PatternFly explicitly calls this out. [1]
    • If your FormGroup represents multiple related controls (e.g., a set of radios/checkboxes), use fieldId to identify the group, and set role="radiogroup" (for radios) or role="group" (for other multi-control groupings). PatternFly notes fieldId is required when using those group roles. [1], [3]
  • For helper/extra text, connect it to the input. If you render helper text for a field, give the helper text an id and add aria-describedby on the input pointing to it (PatternFly documents this requirement). [7]

  • Don’t rely on placeholder text for essential labeling/instructions. PatternFly form guidelines call this out because placeholder text isn’t reliably announced by screen readers. [2]


Link labels to inputs with fieldId for screen-reader navigation.

The nested FormGroup structure for the Name field is non-standard, and both fields lack fieldId, breaking the programmatic label-input association required by PatternFly and WCAG. Set fieldId to match each input's id.

♿ Proposed fix
-        <FormGroup>
-          <FormGroup label={t('olm-v1~Name')}>
-            <TextInput
-              id="input-name"
-              data-test="input-name"
-              name="name"
-              type="text"
-              value={name}
-              onChange={(e, value) => setName(value)}
-            />
-          </FormGroup>
-        </FormGroup>
-        <FormGroup label={t('olm-v1~Namespace')}>
-          <TextInput
-            readOnly
-            id="input-namespace"
-            data-test="input-namespace"
-            name="namespace"
-            value={namespace}
-            type="text"
-          />
-        </FormGroup>
+        <FormGroup label={t('olm-v1~Name')} fieldId="input-name">
+          <TextInput
+            id="input-name"
+            data-test="input-name"
+            name="name"
+            type="text"
+            value={name}
+            onChange={(e, value) => setName(value)}
+          />
+        </FormGroup>
+        <FormGroup label={t('olm-v1~Namespace')} fieldId="input-namespace">
+          <TextInput
+            readOnly
+            id="input-namespace"
+            data-test="input-namespace"
+            name="namespace"
+            value={namespace}
+            type="text"
+          />
+        </FormGroup>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Form onSubmit={submit}>
<FormGroup>
<FormGroup label={t('olm-v1~Name')}>
<TextInput
id="input-name"
data-test="input-name"
name="name"
type="text"
value={name}
onChange={(e, value) => setName(value)}
/>
</FormGroup>
</FormGroup>
<FormGroup label={t('olm-v1~Namespace')}>
<TextInput
readOnly
id="input-namespace"
data-test="input-namespace"
name="namespace"
value={namespace}
type="text"
/>
</FormGroup>
<Form onSubmit={submit}>
<FormGroup label={t('olm-v1~Name')} fieldId="input-name">
<TextInput
id="input-name"
data-test="input-name"
name="name"
type="text"
value={name}
onChange={(e, value) => setName(value)}
/>
</FormGroup>
<FormGroup label={t('olm-v1~Namespace')} fieldId="input-namespace">
<TextInput
readOnly
id="input-namespace"
data-test="input-namespace"
name="namespace"
value={namespace}
type="text"
/>
</FormGroup>
🤖 Prompt for AI Agents
In
`@frontend/packages/operator-lifecycle-manager-v1/src/components/cluster-extension/CreateServiceAccountModal.tsx`
around lines 109 - 131, The Name field uses a nested FormGroup and neither
FormGroup includes fieldId, breaking label-input association; in
CreateServiceAccountModal update the Name block to use a single FormGroup with
fieldId="input-name" that wraps the TextInput (id="input-name") and add
fieldId="input-namespace" to the Namespace FormGroup to match the TextInput
(id="input-namespace"); ensure you leave submit, setName, namespace, and the
TextInput props unchanged while only adjusting FormGroup usage and adding the
fieldId attributes.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 28, 2026

@TheRealJon: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-console 894c47b link true /test e2e-gcp-console

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/core Related to console core functionality component/olm Related to OLM component/shared Related to console-shared jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. kind/i18n Indicates issue or PR relates to internationalization or has content that needs to be translated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants