Refactor environment's dashboard backend

Summary

The Environments Dashboard - -/operations/environments - has been developed out of the Operations dashboard, and there are a number of technical improvements that should be made. The issues are:

  • non-standard controller action names (OperationsController#environments and OperationsController#environments_list)
  • complex code which retrieves all the data in a single call
  • difficulties in extending the existing code due to tight coupling elsewhere
  • growing performance issues due to the single call
  • array-based pagination

When Environments Dashboard is loaded, there are 2 calls to the backend:

Initial page load

When the page is first loaded via GET https://gitlab.com/-/operations/environments, it:

This component simply renders the basic page and passes environments_data:, which is a helper ee/app/helpers/ee/operations_helper.rb and just passes on the paths from the backend.

'add-path' => add_operations_project_path,
'list-path' => operations_environments_list_path,
etc

Data load

The Vue component (attached to #js-environments) then loads all of the backend data needed to populate the environments dashboard. This is done via this sequence:

OperationsController#environments_list - `GET https://gitlab.com/-/operations/environments_list`
  Dashboard::Environments::ListService
    Dashboard::Projects::ListService
      ProjectsFinder

The Dashboard::Environments::ListService uses this preloader code:

  ActiveRecord::Associations::Preloader.new.preload(projects, [
          :route,
          environments_for_dashboard: [
            last_visible_pipeline: [
              :user,
              project: [:route, :group, :project_feature, namespace: :route]
            ],
            last_visible_deployment: [
              deployable: [
                :metadata,
                :pipeline,
                project: [:project_feature, :group, :route, namespace: :route]
              ],
              project: [:route, namespace: :route]
            ],
            project: [:project_feature, :group, namespace: :route]
          ],
          namespace: [:route, :owner]
        ])

Related work

Improvements

  • Move the Environments endpoints into their own REST-complaint controller, or better still move them to GraphQL. For example they could become EnvironmentDashboardController#index and EnvironmentDashboardDataController#index.
  • Simplify the code in Dashboard::Projects::ListService and consider if there are better-fit alternatives to using the ProjectsFinder, for example a new finder that combines the Projects and Environments data directly.
  • Consider breaking the data load into 2 pieces
    1. render the projects and possibly environments in the first load
    2. call additional endpoint(s) to populate the detail
  • database-level pagination for projects + environments instead of array pagination (should be OK to bring both back together as the first call).

Operations Dashboard

  • It would probably be good to refactor the Operations Dashboard at the same time, producing decoupled shared components.
  • The Operations Dashboard uses shared code but does not pass pagination so there is implied knowledge in this test

Risks

  • Front-end impact is unknown, and needs investigation.
  • Impact on Operations Dashboard

Involved components

Optional: Intended side effects

  • performance
  • simplify code and allow for future enhancements
  • reduce dependencies with the Operations Dashboard

Optional: Missing test coverage

Existing tests look at a small number (usually 1) project + environment, this should be scaled up, perhaps using fixtures or let_it_be to assist with test performance.

Edited by Sean Carroll