Reorganize user preferences page into tabs

What does this MR do and why?

Reorganizes the user Preferences page (/-/profile/preferences) into Pajamas tabs: Appearance, Behavior, Editing, Localization, and Integrations (shown only when an integration is available). The tabbed layout is behind the preferences_tabs feature flag; with the flag disabled, the same sections render on one page without tabs.

Why:

  • The page had grown into one long list of unrelated settings. Users who arrive from links elsewhere in the product, such as the Web IDE or the merge request widget, landed in the middle of that list with no sense of where they were.
  • Related settings were spread out: layout width sat far from the other appearance settings, and Markdown, editor, and code options were mixed with navigation defaults. Tabs give each area a name, and section headings inside each tab give the fields a hierarchy.

What changes for users:

  • Tabs group the existing settings. No setting was added or removed; every field still submits through the same form and the same Save changes button.
  • Deep links keep working: a hash naming a tab opens it, a hash naming a field inside a tab opens that tab and scrolls to the field, and the page search shows matches across every tab.
  • GitLab Duo and GitLab Orbit settings stay in Behavior in this MR; !257859 moves them to an AI assistance tab.

Implementation notes for reviewers:

  • Tabs use the gl_tabs_nav / gl_tab_link_to helpers with GlTabsBehavior. Pane ids differ from tab hrefs so a tab hash never triggers native anchor scrolling on reload. Panes stay inside the single remote form, so hidden fields are still submitted.
  • Hash handling (deep links into a pane, hash changes after load) lives in GlTabsBehavior since !261545 (merged). The page adds only what it alone knows: native validation reveals the tab holding the invalid field through revealElement, and the settings search, which now dispatches a settings-search-term-changed DOM event on its root, shows every pane and hides the tab navigation while a term is active. No CSS overrides and no attribute queries in page code.
  • A tab definition can carry locals for its partial, so the Integrations tab computes integration_views once and hands it to the partial.
  • Section headings keep the default SettingsSectionComponent size and element.
  • With the flag disabled, each tab's sections are wrapped in an element carrying the tab id, so the anchors the page has always had (#appearance, #behavior, #localization) keep working.
  • Docs are regrouped by tab with all existing anchors preserved.

Feature flag: preferences_tabs (gitlab_com_derisk). Rollout issue: #631894.

Stacked merge requests

This is part 4 of the user preferences page tabs series. The MRs are stacked and merge in order; each one is complete on its own.

# MR Scope
1 !257856 (merged) Fix: apply the layout width preference without a reload (merged)
2 !257857 (merged) Shared inputs: heading_classes, labelDescription (merged)
3 !257858 (merged) Refactor: extract the Integrations section into its own Vue app (merged)
3b !261545 (merged) GlTabsBehavior: hash changes, deep links, revealElement (merged)
4 !257460 (merged) Feature: reorganize the preferences page into tabs, behind the preferences_tabs flag
5 !257859 Feature (EE): move GitLab Duo and Orbit preferences into an AI assistance tab

Series split from the original single MR after review feedback in !257460 (merged).

References

Screenshots or screen recordings

Captured in GDK with the flag enabled and Ona turned on, so the Integrations tab is visible.

Before

One long page. GitLab Duo and GitLab Orbit settings sit inside Behavior, between the overview defaults and the Web IDE options.

Top of the page Behavior section
before-top before-behavior

After

Appearance

tab-appearance

Behavior

tab-behavior

Editing

tab-editing

Localization

tab-localization

Integrations

tab-integrations

Section headings in these screenshots are one step smaller than in the current revision, which uses the component default.

How to set up and validate locally

  1. Enable the flag: Feature.enable(:preferences_tabs) in bin/rails console.
  2. Visit http://127.0.0.1:3000/-/profile/preferences and switch between tabs. Change a setting in one tab and one in another, select Save changes, and confirm both persisted.
  3. Reload with a tab hash, for example #localization, and confirm the tab opens with the tab bar still visible.
  4. Open http://127.0.0.1:3000/-/profile/preferences#user_tab_width from another page and confirm the Editing tab opens and scrolls to Tab width.
  5. In Editing, set Tab width to -1, switch to Appearance, select Save changes, and confirm the page switches back to Editing and shows the validation message.
  6. Type Time preferences in Search page and confirm the matching section appears even though it lives in another tab; clear the search and confirm the tabs return.
  7. To see Integrations, turn on Ona or Sourcegraph in Admin > Settings > General.
  8. Disable the flag and confirm every section renders on one page, saving still works, and #behavior still scrolls to the Behavior sections.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Simon Kim

Merge request reports

Loading
Loading