Skip to content

Pr/11364#1

Open
parthaa wants to merge 1 commit intomasterfrom
pr/11364
Open

Pr/11364#1
parthaa wants to merge 1 commit intomasterfrom
pr/11364

Conversation

@parthaa
Copy link
Owner

@parthaa parthaa commented May 9, 2025

What are the changes introduced in this pull request?

Considerations taken when implementing this change?

What are the testing steps for this pull request?

Summary by Sourcery

Add a new wizard for bulk managing repository sets content overrides for hosts

New Features:

  • Implement a new bulk repository sets wizard for managing content overrides across multiple hosts

Enhancements:

  • Add a new menu item in host actions bar for repository sets management
  • Create a multi-step wizard for selecting repository sets and hosts

Summary by CodeRabbit

  • New Features

    • Introduced a bulk repository sets management wizard, allowing users to update repository set statuses for multiple hosts at once.
    • Added a "Repository sets" option to the content management dropdown, enabling bulk actions when hosts and an organization are selected.
    • New modal interface for managing repository sets in bulk, including selection, override controls, review, and confirmation steps.
  • Improvements

    • Enhanced review and footer layouts in bulk action wizards for better usability and consistency.

@sourcery-ai
Copy link

sourcery-ai bot commented May 9, 2025

Reviewer's Guide

This pull request implements a new "Bulk Repository Sets Wizard" allowing users to apply content overrides (enable, disable, reset) to repository sets across multiple hosts. The wizard is launched from the Hosts Actions Bar and uses a multi-step interface built with PatternFly components. State is managed via React Context. The first step involves selecting repository sets and actions using a TableIndexPage-based component. Subsequent steps handle host review and a final confirmation. On submission, a Redux action makes a PUT request to /hosts/bulk/content_overrides, with data formatted by a helper. The wizard modal is globally registered. Minor button reordering in existing bulk action wizards' footers ensures UI consistency.

File-Level Changes

Change Details Files
Added a new 'Bulk Repository Sets Wizard' for managing repository set content overrides on hosts.
  • Integrated a 'Repository sets' action into the host actions bar and registered the wizard modal globally.
  • Implemented the multi-step wizard logic, utilizing React Context for state sharing across steps.
  • Developed UI components for repository set selection with override actions, host review, and a final review page.
  • Added a Redux action to call the bulk content overrides API and a helper function to format the request payload.
webpack/components/extensions/Hosts/ActionsBar/index.js
webpack/global_index.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js
Standardized button order in review footers of existing bulk action wizards.
  • Reordered buttons in the review step footers of the Bulk Errata and Bulk Packages wizards for UI consistency.
webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js
webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @parthaa - I've reviewed your changes - here's some feedback:

  • Update the PR title and description to accurately reflect the introduced feature and all related changes.
  • Consider moving the button reordering in the existing Errata and Packages wizard footers to a separate PR to maintain focus.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +45 to +48
const handleFinishButtonClick = () => {
setFinishButtonLoading(true);
saveContentOverrides();
closeModal();
Copy link

Choose a reason for hiding this comment

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

question (bug_risk): Revisit the closeModal invocation in handleFinishButtonClick.

saveContentOverrides already triggers closeModal on success. Please remove the redundant closeModal call or confirm it’s safe to call twice.

const [, setCurrentStep] = useState();
const onStepChange = (_event, newStep) => setCurrentStep((oldStep) => {
setShouldValidateStep1(true);
if (oldStep === 'brsw-step-2') setShouldValidateStep2(true);
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (oldStep === 'brsw-step-2') setShouldValidateStep2(true);
if (oldStep === 'brsw-step-2') {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

const apiOptions = { key: 'BULK_HOST_REPO_SETS' };

const finishButtonText = __('Set content overrides');
const replacementResponse = !modalOpen ? { response: {} } : false;
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): Invert ternary operator to remove negation (invert-ternary)

Suggested change
const replacementResponse = !modalOpen ? { response: {} } : false;
const replacementResponse = modalOpen ? false : { response: {} };


ExplanationNegated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By inverting the ternary condition and swapping the
expressions we can simplify the code.

...bulkParams,
successToast: () => __('Content overrides updating.'),
handleSuccess: (response) => {
if (handleSuccess) handleSuccess(response);
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (handleSuccess) handleSuccess(response);
if (handleSuccess) {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

Refs #38353 - add toggle dropdown

Refs #38353 - add host review and step validation

Refs #38353 - change to table component with children

Refs #38353 - add expandable table rows and semi-broken pagination

Refs #38353 - fix pagination

Refs #38353 - Add review footer

Refs #38353 - Hook it up to the API

Refs #38353 - address comments & fix export

Refs #38353 - Move primary buttons to be consistent

Refs #38353 - address comments
@coderabbitai
Copy link

coderabbitai bot commented May 9, 2025

Walkthrough

A new bulk repository sets management feature is introduced, including a multi-step wizard modal for bulk editing repository set statuses on hosts. This involves new React components, context, Redux actions, helpers, and UI integrations. Additionally, button ordering in existing bulk wizards is updated, and modal registration and menu options are extended to support the new functionality.

Changes

File(s) Change Summary
webpack/components/extensions/Hosts/ActionsBar/index.js Added support for the 'bulk-repo-sets-wizard' modal, a new "Repository sets" menu item, and logic to enable/disable the item based on host/organization selection.
webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js
webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js
Reordered the finishButton in the wizard footers to appear between the "Back" and "Cancel" buttons.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js Introduced BulkRepositorySetsTable and ContentOverrideDropdown components for bulk repository set selection and override management, with selection, validation, and UI controls.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js Added BulkRepositorySetsReview component for reviewing pending repository set status changes before submission.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js Added BulkRepositorySetsReviewFooter component for wizard step 3, handling submission and navigation logic.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js Introduced the main BulkRepositorySetsWizard component, context, and constants, orchestrating the multi-step flow, state, and data fetching.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js Added Redux action creator bulkUpdateHostContentOverrides for bulk updating host content overrides via API.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js Added helper pendingOverrideToApiParamItem for converting pending override UI state to API parameters.
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js Added BulkRepositorySetsWizardModal component to render the wizard in a modal, controlled by modal state.
webpack/global_index.js Registered BulkRepositorySetsWizardModal as a global fill for the hosts index page and updated modal fill priorities.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ActionsBar
    participant ModalSystem
    participant BulkRepoSetsWizard
    participant API

    User->>ActionsBar: Clicks "Repository sets" menu item
    ActionsBar->>ModalSystem: Open 'bulk-repo-sets-wizard' modal
    ModalSystem->>BulkRepoSetsWizard: Render wizard
    BulkRepoSetsWizard->>API: Fetch repository sets data
    User->>BulkRepoSetsWizard: Selects repos, sets overrides, proceeds through steps
    BulkRepoSetsWizard->>API: Fetches/updates selection as needed
    User->>BulkRepoSetsWizard: Clicks "Finish"
    BulkRepoSetsWizard->>API: PUT /hosts/bulk/content_overrides with overrides
    API-->>BulkRepoSetsWizard: Responds with task info
    BulkRepoSetsWizard->>ModalSystem: Close modal
Loading

Poem

🐰
A wizard appears with a modal so bright,
To manage repositories, all in one night.
With clicks and selections, overrides in tow,
Hosts and their sets in a magical flow.
Buttons now shuffled, the order feels right—
Bulk actions are ready, oh what a delight!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

webpack/components/extensions/Hosts/ActionsBar/index.js

Error: Cannot read config file: /webpack/.eslintrc.js
Error: Foreman directory cannot be found! This action requires Foreman to be present in either a parent, sibling, or child directory relative to the plugin.
at foremanLocation (/node_modules/.pnpm/@theforeman+find-foreman@4.15.2/node_modules/@theforeman/find-foreman/index.js:27:13)
at Object. (/webpack/.eslintrc.js:3:21)
at Module._compile (/node_modules/.pnpm/v8-compile-cache@2.4.0/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
at Module.load (node:internal/modules/cjs/loader:1317:32)
at Module._load (node:internal/modules/cjs/loader:1127:12)
at TracingChannel.traceSync (node:diagnostics_channel:315:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
at Module.require (node:internal/modules/cjs/loader:1339:12)
at module.exports (/node_modules/.pnpm/import-fresh@3.3.1/node_modules/import-fresh/index.js:33:91)

webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js

Error: Cannot read config file: /webpack/.eslintrc.js
Error: Foreman directory cannot be found! This action requires Foreman to be present in either a parent, sibling, or child directory relative to the plugin.
at foremanLocation (/node_modules/.pnpm/@theforeman+find-foreman@4.15.2/node_modules/@theforeman/find-foreman/index.js:27:13)
at Object. (/webpack/.eslintrc.js:3:21)
at Module._compile (/node_modules/.pnpm/v8-compile-cache@2.4.0/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
at Module.load (node:internal/modules/cjs/loader:1317:32)
at Module._load (node:internal/modules/cjs/loader:1127:12)
at TracingChannel.traceSync (node:diagnostics_channel:315:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
at Module.require (node:internal/modules/cjs/loader:1339:12)
at module.exports (/node_modules/.pnpm/import-fresh@3.3.1/node_modules/import-fresh/index.js:33:91)

webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js

Error: Cannot read config file: /webpack/.eslintrc.js
Error: Foreman directory cannot be found! This action requires Foreman to be present in either a parent, sibling, or child directory relative to the plugin.
at foremanLocation (/node_modules/.pnpm/@theforeman+find-foreman@4.15.2/node_modules/@theforeman/find-foreman/index.js:27:13)
at Object. (/webpack/.eslintrc.js:3:21)
at Module._compile (/node_modules/.pnpm/v8-compile-cache@2.4.0/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
at Module.load (node:internal/modules/cjs/loader:1317:32)
at Module._load (node:internal/modules/cjs/loader:1127:12)
at TracingChannel.traceSync (node:diagnostics_channel:315:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
at Module.require (node:internal/modules/cjs/loader:1339:12)
at module.exports (/node_modules/.pnpm/import-fresh@3.3.1/node_modules/import-fresh/index.js:33:91)

  • 8 others

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 3

♻️ Duplicate comments (2)
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js (1)

16-16: Use block braces for single-line if statements.

It's recommended to always use braces for if statements, even for single lines, to prevent potential bugs when adding more statements later.

-      if (handleSuccess) handleSuccess(response);
+      if (handleSuccess) {
+        handleSuccess(response);
+      }
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js (1)

41-49: ⚠️ Potential issue

Redundant & premature closeModal() call – re-consider flow

saveContentOverrides() already passes closeModal as both the success and failure callback when dispatching bulkUpdateHostContentOverrides.
Calling closeModal() again immediately after dispatch:

const handleFinishButtonClick = () => {
  setFinishButtonLoading(true);
  saveContentOverrides();
  closeModal();          // ← duplicates callbacks & closes modal before API returns
};

results in the modal being closed three times and, more importantly, unmounts the wizard before the async Redux action completes, so the user never sees success/error toasts and the component tree that owns setFinishButtonLoading is gone.

Suggested fix: let the action creator be responsible for closing the modal once.

 const handleFinishButtonClick = () => {
   setFinishButtonLoading(true);
-  saveContentOverrides();
-  closeModal();
+  saveContentOverrides();
 };
🧹 Nitpick comments (4)
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js (1)

1-26: Replace magic numbers with named constants

The function uses magic numbers (0, 1, 2, 3) to represent different override states. Using named constants would improve code readability and maintainability.

+// Constants for repository override states
+export const OVERRIDE_STATES = {
+  NO_CHANGE: 0,
+  ENABLE: 1,
+  DISABLE: 2,
+  RESET: 3,
+};
+
 export const pendingOverrideToApiParamItem = ({ repoLabel, value }) => {
   switch (Number(value)) {
-  case 0: // No change
+  case OVERRIDE_STATES.NO_CHANGE:
     return null;
-  case 1: // Override to enabled
+  case OVERRIDE_STATES.ENABLE:
     return {
       content_label: repoLabel,
       name: 'enabled',
       value: true,
     };
-  case 2: // Override to disabled
+  case OVERRIDE_STATES.DISABLE:
     return {
       content_label: repoLabel,
       name: 'enabled',
       value: false,
     };
-  case 3: // Reset to default
+  case OVERRIDE_STATES.RESET:
     return {
       content_label: repoLabel,
       name: 'enabled',
       remove: true,
     };
   default:
     return null;
   }
 };
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js (1)

6-6: Consider prefixing API constant with the module name.

To avoid potential naming conflicts, consider prefixing the API constant with the module name or feature area.

-const BULK_HOST_CONTENT_OVERRIDES_KEY = 'BULK_HOST_CONTENT_OVERRIDES';
+const BULK_REPO_SETS_CONTENT_OVERRIDES_KEY = 'BULK_REPO_SETS_CONTENT_OVERRIDES';

Then update the reference on line 11 accordingly.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js (1)

41-44: Ternary could be simplified for readability

replacementResponse = !modalOpen ? { … } : false; contains a negation.
Flip the condition to avoid the mental “double negative”.

-const replacementResponse = !modalOpen ? { response: {} } : false;
+const replacementResponse = modalOpen ? false : { response: {} };
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js (1)

177-191: handleActionToggle never updates actionDropdownValue

When users pick a value from the split-button action, the main button keeps showing the previous label.
Call setActionDropdownValue(value) so the label reflects the last applied action.

 const handleActionToggle = (value) => {
   const result = {};
   selectedResults.forEach((repo) => {
     result[repo.label] = value;
   });
   setPendingOverrides({ ...pendingOverrides, ...result });
   setShouldValidateStep1(true);
+  setActionDropdownValue(value);
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcf06f7 and c0ef78c.

📒 Files selected for processing (11)
  • webpack/components/extensions/Hosts/ActionsBar/index.js (2 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js (1 hunks)
  • webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js (1 hunks)
  • webpack/global_index.js (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js (1)
webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js (1)
  • finishButton (103-130)
webpack/global_index.js (2)
webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/index.js (1)
  • BulkErrataWizardModal (6-22)
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js (1)
  • BulkRepositorySetsWizardModal (6-21)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Ruby / Setup matrix
  • GitHub Check: react-tests / Foreman develop Ruby 2.7 and Node 18
  • GitHub Check: Angular bastion_katello - NodeJS 18
🔇 Additional comments (15)
webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js (1)

137-137: Button order standardized for consistency.

The repositioning of the finish button between the Back and Cancel buttons improves UI consistency across all wizard footers in the application.

webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js (1)

95-95: Button order standardized for consistency.

The repositioning of the finish button between the Back and Cancel buttons improves UI consistency across all wizard footers in the application.

webpack/global_index.js (2)

41-41: New import for the BulkRepositorySetsWizardModal.

The import is correctly placed with the other bulk wizard modal imports.


100-101: Proper modal registration with priority ordering.

The changes:

  1. Update the priority of BulkErrataWizardModal from 200 to 300
  2. Add the new BulkRepositorySetsWizardModal with priority 400

This ensures consistent ordering in the UI and properly integrates the new bulk repository sets wizard.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js (1)

1-24: Well-structured modal component for the new bulk repository sets wizard.

The implementation follows the established pattern for modal components in the application:

  • Uses the useForemanModal hook for modal state management
  • Sets appropriate modal properties including accessibility attributes
  • Provides proper OUIA ID for testing
  • Renders the wizard component within the modal
webpack/components/extensions/Hosts/ActionsBar/index.js (3)

43-43: LGTM! New repository sets wizard modal registration.

The modal registration for the new bulk repository sets wizard is correctly added to the list of managed modals.


51-51: LGTM! Modal hook implementation for repository sets wizard.

The hook for controlling the repository sets wizard modal state is properly implemented following the existing pattern.


89-97: LGTM! Well-implemented Repository sets menu item.

The Repository sets menu item is properly implemented with appropriate disabled state handling and organization context validation, matching the pattern of other menu items.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js (3)

1-17: LGTM! Clean imports and context setup.

The imports and context setup are well organized, properly importing necessary dependencies and the wizard context.


18-27: LGTM! Well-implemented state management and data transformation.

The component efficiently retrieves and filters pending overrides from context, mapping numeric values to descriptive texts.


28-76: LGTM! Clean UI implementation with appropriate OUIA IDs.

The UI implementation is well-structured using Patternfly components with appropriate OUIA IDs for accessibility and testing.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js (1)

8-22: LGTM! Well-implemented API action.

The API call is correctly implemented using the put function, with proper success and error handling.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js (1)

45-47: finishButtonLoading is never reset on failure

When the PUT request fails, the failure callback only closes the modal; if you decide to keep the wizard open (see previous comment), remember to call setFinishButtonLoading(false) in the error path so the button becomes usable again.

webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js (1)

84-92: Validation helper silently accepts NaN

selectionIsValid = count > 0 || isNaN(count) means an undefined/NaN count is treated as valid, potentially allowing users to proceed without any selection.
Consider making the intent explicit:

-const selectionIsValid = count => count > 0;
+const selectionIsValid = count => Number.isFinite(count) && count > 0;
webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js (1)

123-126: useSet expansion key uniqueness

repoIsExpanded relies on label. If two repositories share a label (edge-case but possible across different products), expansion states will collide. Consider using a compound key (productId-label) instead.

Comment on lines +32 to +40
const saveContentOverrides = () => {
const requestBody = {
included: {
search: hostsBulkSelect.fetchBulkParams(),
},
content_overrides: apiParams,
};
dispatch(bulkUpdateHostContentOverrides(
requestBody, hostsBulkSelect.fetchBulkParams(),
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Duplicated fetchBulkParams() argument is unnecessary

bulkUpdateHostContentOverrides receives requestBody and the exact same fetchBulkParams() value again.
If the action creator doesn’t require it twice, remove the second argument to avoid confusing API signatures.

- dispatch(bulkUpdateHostContentOverrides(
-   requestBody, hostsBulkSelect.fetchBulkParams(),
-   closeModal, closeModal,
- ));
+ dispatch(bulkUpdateHostContentOverrides(
+   requestBody,
+   closeModal, closeModal,
+ ));
📝 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
const saveContentOverrides = () => {
const requestBody = {
included: {
search: hostsBulkSelect.fetchBulkParams(),
},
content_overrides: apiParams,
};
dispatch(bulkUpdateHostContentOverrides(
requestBody, hostsBulkSelect.fetchBulkParams(),
const saveContentOverrides = () => {
const requestBody = {
included: {
search: hostsBulkSelect.fetchBulkParams(),
},
content_overrides: apiParams,
};
dispatch(bulkUpdateHostContentOverrides(
requestBody,
closeModal, closeModal,
));
};

Comment on lines +24 to +27
const DEFAULT_PER_PAGE = 5;
export const BulkRepositorySetsWizardContext = createContext({});
export const REPO_SETS_URL = katelloApi.getApiUrl(`/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=1`);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Hard-coded organization_id=1 breaks multi-org installations

Embedding the org id directly in REPO_SETS_URL makes the wizard unusable for any organization except id 1. Retrieve the current organization from Redux/Context (e.g. window.ORG.id) or accept it as a prop.

-export const REPO_SETS_URL = katelloApi.getApiUrl(`/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=1`);
+export const buildRepoSetsUrl = orgId =>
+  katelloApi.getApiUrl(
+    `/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=${orgId}`,
+  );
📝 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
const DEFAULT_PER_PAGE = 5;
export const BulkRepositorySetsWizardContext = createContext({});
export const REPO_SETS_URL = katelloApi.getApiUrl(`/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=1`);
const DEFAULT_PER_PAGE = 5;
export const BulkRepositorySetsWizardContext = createContext({});
export const buildRepoSetsUrl = orgId =>
katelloApi.getApiUrl(
`/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=${orgId}`,
);

Comment on lines +54 to +57
onOpenChange={openVal => setIsOpen(!openVal)}
toggle={toggleRef => (
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
{currentLabel}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

onOpenChange inversion causes dropdown state desync

onOpenChange already provides the new open state (isOpen).
Negating it stores the opposite value, so the UI occasionally shows the wrong state.

- onOpenChange={openVal => setIsOpen(!openVal)}
+ onOpenChange={isOpen => setIsOpen(isOpen)}

Apply the same fix to setActionToggleOpen(!val) in the action dropdown.

📝 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
onOpenChange={openVal => setIsOpen(!openVal)}
toggle={toggleRef => (
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
{currentLabel}
onOpenChange={isOpen => setIsOpen(isOpen)}
toggle={toggleRef => (
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
{currentLabel}

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants