Skip to content

#2183: dynamically generate form fields for selected commandlet - #2233

Open
Hiepiscus wants to merge 25 commits into
devonfw:mainfrom
Hiepiscus:2183-dynamically-generate-form-fields-for-selected-commandlet
Open

#2183: dynamically generate form fields for selected commandlet#2233
Hiepiscus wants to merge 25 commits into
devonfw:mainfrom
Hiepiscus:2183-dynamically-generate-form-fields-for-selected-commandlet

Conversation

@Hiepiscus

@Hiepiscus Hiepiscus commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #2183

Introduces dynamic form generation for commandlets. Instead of using a static input field, the UI now creates appropriate form fields based on the properties of the selected commandlet for a more flexible configuration experience.
Show more lines

Implemented changes:

  • Dynamically generate form fields based on the selected commandlet properties
  • PropertyFormFieldFactory (new): create appropriate UI based on commandlet:
    • TextField for positional parameters and named options
    • CheckBox for boolean flags
  • Replaced static TextField with a ScrollPane + VBox in the FXML layout
  • Added onCommandletSelected() listener to regenerate the form on selection change
  • Adapted runCommandlet() to read property values from generated form fields

Testing instructions

Please add conscise, understandable instructions on how a reviewer can test/verify the functionality of your contribution here:

  1. Run AppLauncher
  2. Set a project and workspace
  3. Click Commandlets
  4. Select a commandlet from the combobox
  5. Verify that the displayed form fields change depending on the selected commandlet
  6. Enter parameters in the generated fields
  7. Click Run
  8. Verify that the commandlet executes successfully

Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summarizes what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labeled
    with internal
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

@github-project-automation github-project-automation Bot moved this to 🆕 New in IDEasy board Jul 29, 2026
@Hiepiscus Hiepiscus self-assigned this Jul 29, 2026
@Hiepiscus Hiepiscus added GUI Graphical User Interface of IDEasy (aka dashboard) build with JavaFx commandlet ide sub-command labels Jul 29, 2026
@Hiepiscus Hiepiscus moved this from 🆕 New to Team Review in IDEasy board Jul 29, 2026

@quando632 quando632 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice split into PropertyFormFieldFactory, that keeps the controller readable. Checking KeywordProperty before BooleanProperty is easy to get wrong since one extends the other, and it is correct here. All three tasks from #2183 are covered.

One theme runs through the findings: runCommandlet executes a different order than AbstractIdeContext.applyAndRun (reset, assign, validate, run), while working on the commandlet singletons that CommandletManagerImpl shares with the CLI context.

Still open from the DoD checklist: the CHANGELOG.adoc entry, and tests. The gui module already has AppBaseTest and HeadlessApplicationTest, and PropertyFormFieldFactory is a static factory, so "property type maps to expected node type" should be cheap to assert.

Comment thread gui/src/main/java/com/devonfw/ide/gui/CommandletController.java Outdated
Comment thread gui/src/main/java/com/devonfw/ide/gui/CommandletController.java
property) {
for (javafx.scene.Node child : hbox.getChildren()) {
if (child instanceof javafx.scene.control.TextField textField) {
property.setValueAsString(textField.getText(), context);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blank fields are assigned as well, and ToolProperty.parse("") throws, so pressing Run on install without input ends in the default uncaught exception handler. Skipping blank input leaves the property unset, which is what the CLI does for a missing optional argument.

Suggested change
property.setValueAsString(textField.getText(), context);
String value = textField.getText();
if (!value.isBlank()) {
property.assignValueAsString(value, this.context, this.selectedCommandlet);
}

}
}

this.selectedCommandlet.run();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Without validate() a missing required value reaches run(), for example create would start with an empty project name. validate() gives us the message to show instead. Needs imports of com.devonfw.tools.ide.validation.ValidationResult and com.devonfw.ide.gui.modal.IdeDialog.

Suggested change
this.selectedCommandlet.run();
ValidationResult result = this.selectedCommandlet.validate();
if (!result.isValid()) {
new IdeDialog(IdeDialog.AlertType.ERROR, result.getErrorMessage()).showAndWait();
return;
}
this.selectedCommandlet.run();

}

this.selectedCommandlet.run();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

applyAndRun also calls ensureLicenseAgreement(cmd) and checks isIdeHomeRequired() and isIdeRootRequired() before running. Skipping the license gate means a tool can be installed from the GUI without the agreement the CLI asks for.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed. I added the validate() check before running the commandlet, but moved the validation logic into a dedicated method.

Parent root = loader.load();

Stage stage = (Stage) selectedProject.getScene().getWindow();
stage.setScene(new Scene(root));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Replacing the scene of the primary stage leaves no way back to the main view, so the app has to be restarted after opening the commandlet view. A back button in commandlet-view.fxml or a separate Stage for the view would solve it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. I've updated the navigation logic so that the commandlet view is displayed in the existing window by replacing the center content of the BorderPane. A back button was added to the commandlet view, allowing users to return to the main view without restarting the application.

Comment thread gui/src/main/resources/com/devonfw/ide/gui/main-view.fxml Outdated
}
}

this.selectedCommandlet.run();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The result of the run never reaches the view. A success writes everything to the console and leaves the window unchanged, and a failure escapes as an uncaught exception, for example build outside a project throws CliException: Could not find build descriptor straight out of the handler. Wrapping run() in a try/catch and reporting both outcomes in the view would close the loop.

commandletSelector.getItems().clear();
commandletSelector.getItems().addAll(context.getCommandletManager().getCommandlets().stream()
.map(Commandlet::getName)
.toList());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: .sorted() was dropped in 8f8f191, so the combo box lists about 40 commandlets unsorted. Was that intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The removal was intentional. I was considering a future approach where frequently used commandlets would be shown first. However, the current unsorted order is not predictable, so I've added .sorted() back for now.

return name;
}

if (name.isEmpty() && alias != null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: the non option branch reimplements Property#getNameOrAlias().

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

Labels

commandlet ide sub-command GUI Graphical User Interface of IDEasy (aka dashboard) build with JavaFx

Projects

Status: Team Review

Development

Successfully merging this pull request may close these issues.

Dynamically generate form fields for selected commandlet

2 participants