Description

Form Layout provides a dedicated UI for organising entity edit forms into structured groups (vertical tabs, horizontal tabs, or details), without cluttering the standard “Manage form display” widget table.

Key features:

  • Per-bundle and per-form-mode layout configuration.
  • Dedicated “Manage form layout” page for defining groups and assigning fields.
  • Group management UI with label + machine key + open-by-default + drag ordering.
  • Drag-and-drop field assignment into groups.
  • Support for nested forms (including Paragraphs widget subforms).
  • Automatically hides empty/inaccessible groups.

How this differs from similar projects:

  • Compared with Field Group, this project keeps layout configuration in a separate workflow instead of mixing it into the main field/widget management table.
  • The goal is cleaner editorial configuration and less noise in the default field display screens.

Screenshot:

See attached for,

  1. Manage form layout configuration UI.Manage form layout configuration UI
  2. Resulting grouped content edit form UI.Resulting grouped content edit form UI.

Project link

https://www.drupal.org/project/form_layout

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

  • 1.0.x Comparecompare

Comments

lukus created an issue. See original summary.

vishal.kadam’s picture

Issue summary: View changes
avpaderno’s picture

Thank you for applying!

Before giving links helpful to understand how the review process works, what to expect from a review, and what to do to avoid a review takes more time than needed, I would like to thank all the reviewers for the work they do.
These applications are volunters-driven, which also means it is not possible to predict when an application will be marked fixed and the applicant will get the permission to opt projects into security advisory policy. While we aim to make an application as quick as possible, it is also important for us that more people review the project used for an application. In this way, we make sure applications do not miss some important points that should be instead reported.
Applications are not meant to be complete debugging sessions that eliminate every existing bug, though. I apologize if sometimes applications seem to go into too-detailed reviews.

Please read Review process for security advisory coverage: What to expect for more details and Security advisory coverage application checklist to understand what reviewers look for. Tips for ensuring a smooth review gives some hints for a smoother review.

The important notes are the following.

  • If you have not done it yet, you should enable GitLab CI for the project and fix the PHP_CodeSniffer errors/warnings it reports.
  • For the time this application is open, only your commits are allowed.
  • The purpose of this application is giving you a new drupal.org role that allows you to opt projects into security advisory coverage, either projects you already created, or projects you will create. The project status will not be changed by this application; once this application is closed, you will be able to change the project status from Not covered to Opt into security advisory coverage. This is possible only 14 days after the project is created.

    Keep in mind that once the project is opted into security advisory coverage, only Security Team members may change coverage.
  • Only the person who created the application will get the permission to opt projects into security advisory coverage. No other person will get the same permission from the same application; that applies also to co-maintainers/maintainers of the project used for the application.
  • We only accept an application per user. If you change your mind about the project to use for this application, or it is necessary to use a different project for the application, please update the issue summary with the link to the correct project and the issue title with the project name and the branch to review.

To the reviewers

Please read How to review security advisory coverage applications, Application workflow, What to cover in an application review, and Tools to use for reviews.

The important notes are the following.

  • It is preferable to wait for a project moderator before posting the first comment on newly created applications. Project moderators will do some preliminary checks that are necessary before any change on the project files is suggested.
  • Reviewers should show the output of a CLI tool only once per application.
  • It may be best to have the applicant fix things before further review.

For new reviewers, I would also suggest to first read In which way the issue queue for coverage applications is different from other project queues.

avpaderno’s picture

As a side note, please check the email address used to make commits, and be sure it is the same email address associated to your account, or your commits will not be associated to your account.

vishal.kadam’s picture

Status: Needs review » Needs work

1. FILE: README.md

The README file is missing the required section - Configuration.

2. FILE: form_layout.info.yml

package: Custom

This line is used by custom modules created for specific sites. It is not a package name used for projects hosted on drupal.org.

3. FILE: form_layout.module

For a new module that aims to be compatible with Drupal 10 and Drupal 11, I would rather implement hooks as class methods as described in Support for object oriented hook implementations using autowired services.
It would require increasing the minimum Drupal 10 version supported, but Drupal 10.1 is no longer supported.

4. FILE: src/Form/FormLayoutSettingsForm.php

  /**
   * The entity type manager.
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * The entity display repository.
   */
  protected EntityDisplayRepositoryInterface $entityDisplayRepository;

  /**
   * The entity field manager.
   */
  protected EntityFieldManagerInterface $entityFieldManager;

  /**
   * Constructs a FormLayoutSettingsForm object.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    EntityDisplayRepositoryInterface $entity_display_repository,
    RouteMatchInterface $route_match,
    EntityFieldManagerInterface $entity_field_manager,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityDisplayRepository = $entity_display_repository;
    $this->routeMatch = $route_match;
    $this->entityFieldManager = $entity_field_manager;
  }

FILE: src/Form/GlobalSettingsForm.php

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The router builder.
   *
   * @var \Drupal\Core\Routing\RouteBuilderInterface
   */
  protected $routerBuilder;

  /**
   * Constructs a GlobalSettingsForm object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Routing\RouteBuilderInterface $router_builder
   *   The router builder.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    RouteBuilderInterface $router_builder,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->routerBuilder = $router_builder;
  }

FILE: src/Plugin/Derivative/EditorFormLayoutTasks.php

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a new EditorFormLayoutTasks.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    EntityTypeManagerInterface $entity_type_manager,
  ) {
    $this->configFactory = $config_factory;
    $this->entityTypeManager = $entity_type_manager;
  }

FILE: src/Routing/RouteSubscriber.php

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a RouteSubscriber object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    EntityTypeManagerInterface $entity_type_manager,
  ) {
    $this->configFactory = $config_factory;
    $this->entityTypeManager = $entity_type_manager;
  }

New modules, which are compatible with Drupal 10 and higher versions are expected to include type declarations in property definitions, and use constructor property promotion.

5. FILE: src/Form/GlobalSettingsForm.php

ConfigFormBase::__construct() needs to be called. Since its parameters changed in Drupal 10.2, the project cannot be compatible with all the Drupal 10 releases and Drupal 11; it needs to require at least Drupal 10.2.

With Drupal 10 and Drupal 11, there is no longer need to use #default_value for each form element, when the parent class is ConfigFormBase: It is sufficient to use #config_target, as in the following code.

    $form['image_toolkit'] = [
      '#type' => 'radios',
      '#title' => $this->t('Select an image processing toolkit'),
      '#config_target' => 'system.image:toolkit',
      '#options' => [],
    ];

Using that code, it is no longer needed to save the configuration values in the form submission handler: The parent class will take care of that.
For this change, it is necessary to require at least Drupal 10.3, but that is not an issue, since Drupal 10.2.x is no longer supported.

lukus’s picture

Thank you for the review @vishal.kadam.

I'll action these changes ASAP.

lukus’s picture

I've now pushed these changes for review.

The changes requested have been pushed directly to 1.0.x on the project repo. I also carried out some refactoring for the tests.

--

I absentmindedly created a fork for the issue, but quickly realised what I was doing wasn't going to work. Wondering whether it's useful having a record of the changes on the issue, so they can also be found on the forked repo.

lukus’s picture

Status: Needs work » Needs review
vishal.kadam’s picture

Rest seems fine to me.

Please wait for other reviewers and Project Moderator to take a look and if everything goes fine, you will get the role.

lukus’s picture

Thanks @vishal.kadam!

lukus’s picture

Is it okay to push non-security updates (/ make releases) during security review?

avpaderno’s picture

@lukus These applications are not security reviews; we verify the code does not contain possible security issues, but that is not our focus. Changes that we require are also about correctly using the Drupal API and following the Drupal coding standards, for which non-security commits are necessary.

As for making new releases, it is preferable not creating new releases during these applications, because they could require non-backward-compatible changes, for which a new release could create issues.

lukus’s picture

Thanks for the clarification @avpaderno. I'll hold tight in that case!

batigolix’s picture

I reviewed this and it looks solid. I give other reviewers some time to have a look as well, before marking it RTBC

scontzen’s picture

Status: Needs review » Needs work
StatusFileSize
new648.11 KB

Automated Review

GitLab CI enabled, pipeline looks correct.

Manual Review

Individual user account
Yes, follows the guidelines for individual user accounts.
No duplication
Yes. Similar to Field Group, but with a separate configuration UI.
Master Branch
Yes, uses 1.0.x.
Licensing
Yes, follows the licensing requirements.
3rd party assets/code
Yes, no third-party libraries.
README.txt/README.md
Yes. Minor: "Supporting this Module" links to field_layout instead of form_layout.
Code long/complex enough for review
Yes.
Secure code
Yes, meets the security requirements. No direct database queries, everything goes through Entity API and Config API. Routes use entity-type-specific permissions.
Coding style & Drupal API usage
Agreeing with @batigolix that the PHP code looks solid.
  1. (*)(+) Broken HTML in horizontal_tabs.js - Line 37: Prettier has added spaces inside the HTML tags in the template literal: button type = "button" role = "tab" aria - controls = "${id}". The browser won't parse button as a tag, so the buttons render as plain text. Tested on a local Drupal 11 install: horizontal tabs are broken on the current 1.0.x branch. Introduced in commit dfd50c5.

The starred item (*) warrants going back to Needs Work.

This review uses the Project Application Review Template.

lukus’s picture

Thanks @scontzen and @batigolix.

I've updated the repo. I actually had some changes waiting relating to surfacing validation errors within panes, which was was holding back pushing until after review, but as the fix for the *'d item was part of this bundle I thought it might be worth pushing now.

Hopefully this won't disrupt the process; but I can roll back if it does.

lukus’s picture

Status: Needs work » Needs review
scontzen’s picture

Status: Needs review » Needs work

Looked at the latest changes.

Horizontal tabs work now, tested on a local Drupal 11 install.

Still open:

  1. form_layout.info.yml line 3: description reads "Field Layout provides..." instead of "Form Layout".
  2. README line 47: "Supporting this Module" links to drupal.org/project/issues/field_layout instead of form_layout.
  3. FormLayoutSettingsForm still uses the old constructor pattern (lines 26-50) instead of Constructor Property Promotion as requested in #3575215-5: [1.0.x] Form Layout. All other classes in the module already use CPP. Also, $this->routeMatch (line 50) has no property declaration.
  4. Minor: composer.json is still missing. Not a blocker since drupal.org generates it, but good to have.

Setting to Needs work.

lukus’s picture

Status: Needs work » Needs review

Thanks for the pointers.

Ready to review.