Skip to content

feat: sidebar tabs#15470

Draft
JarrodMFlesch wants to merge 29 commits intomainfrom
feature/sidebar-tabs
Draft

feat: sidebar tabs#15470
JarrodMFlesch wants to merge 29 commits intomainfrom
feature/sidebar-tabs

Conversation

@JarrodMFlesch
Copy link
Contributor

@JarrodMFlesch JarrodMFlesch commented Feb 2, 2026

Summary

Adds configurable sidebar tabs to the admin panel, allowing users to organize navigation content into custom tabs with icons and components.

Changes

  • New admin.components.sidebar.tabs config - Configure custom tabs with icons and components
  • Default Collections tab - Automatically included showing all collections in an organized grid (if there are none, there will be no tabs and the view will look like it always has).
  • Tab state persistence - Active tab selection saved to user preferences

Configuration Example

  admin: {                                                                                                            
    components: {                                                                                                     
      sidebar: {                                                                                                      
        tabs: [                                                                                                       
          {                                                                                                           
            slug: 'folders',                                                                                          
            label: 'Folders',                                                                                         
            icon: '@payloadcms/ui#FolderIcon',                                                                        
            component: {                                                                                              
              path: '/components/CustomTab#CustomTab',                                                                
              clientProps: {                                                                                          
                heading: 'Folders',                                                                                   
                content: 'Example folders tab content.'                                                               
              }                                                                                                       
            }                                                                                                         
          }                                                                                                           
        ]                                                                                                             
      }                                                                                                               
    }                                                                                                                 
  }

Visual

CleanShot.2026-02-03.at.13.25.59.mp4

Related discussion

JarrodMFlesch and others added 16 commits January 15, 2026 14:41
Add type definitions for extensible sidebar tab system. Tabs can be
registered at config.admin.sidebar.tabs with icon, content component,
and override/disable support.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create default tab component for displaying collections and globals.
This will be the built-in tab shown by default in sidebar.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create function that returns built-in sidebar tabs. Currently just
the collections tab, but more can be added later.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement config merging logic for sidebar tabs:
- Combines built-in + user tabs
- Merges by slug (override support)
- Filters disabled tabs
- Fully tested

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Ensure sidebar tab icons and components are included in import map
generation so they can be resolved at runtime.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Load active tab from user preferences on mount and save changes.
Ensures tab selection persists across sessions.

- Add activeTab field to NavPreferences type
- Update getNavPrefs to fetch sidebar preferences separately
- Pass navPreferences to SidebarTabsClient
- Save tab changes using setPreference hook

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move sidebar.tabs from admin.sidebar to admin.components.sidebar
  to be consistent with other component slots
- Update styles to be edge-to-edge like original DefaultNavClient
- Remove horizontal padding from tabs and content
- Add proper width and flex-grow to match nav layout

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace made-up CSS variables with actual design system:
- Use base() SCSS function for spacing
- Use --style-radius-l for border radius
- Use --theme-border-color for borders
- Use @include shadow-sm mixin
- Use proper sr-only pattern for labels

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use auto-fit grid with 24% minmax for responsive 4-column layout
- Remove aspect-ratio for flexible tab sizing
- Reduce padding on individual tabs to calc(var(--base) / 4)
- Update border radius: container to --style-radius-m, tabs to --style-radius-s
- Remove container padding, use gap only
- Active tab border color to --theme-elevation-100

Result: 2-4 tabs fill width, 5+ tabs wrap to max 4 per row.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create packages/payload/src/preferences/keys.ts with PREFERENCE_KEYS constants
- Replace all preference key strings with imported constants
- Rename sidebar preference key from 'sidebar' to 'nav-sidebar-active-tab'
- Update all files using preferences to import PREFERENCE_KEYS

This prevents typos and makes preference keys more discoverable and maintainable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove CollectionsTab component (poorly named, showed collections AND globals)
- Replace with DefaultNavClient throughout for consistency
- Update Nav to fall back to DefaultNavClient when no custom tabs configured
- Pass explicit props instead of spreading to SidebarTabs
- Move test components from test/_community to test/admin
- Add e2e tests for sidebar tabs functionality

Tests cover:
- Rendering custom sidebar tabs
- Switching between tabs
- Persisting active tab in preferences
- Default nav tab behavior

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2026

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 941.50 KB ⚠️ +3.89 KB (+0.4%)
packages/payload/meta_index.json esbuild/index.js 1.32 MB ⚠️ +116 B (+0.0%)
packages/payload/meta_shared.json esbuild/exports/shared.js 168.58 KB ⚠️ +48 B (+0.0%)
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 281.40 KB ✅ No change
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.17 MB ⚠️ +430 B (+0.0%)
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 16.32 KB ✅ No change
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████▍ }}}$ 81.9%, 766.88 KB
dist/views/Version ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 51.26 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 16.69 KB
dist/views/Document ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 16.18 KB
dist/views/List ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 11.28 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 9.85 KB
dist/views/Root ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 9.03 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 6.16 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.08 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.46 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.81 KB
dist/views/Login ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.40 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 3.09 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.3%, 2.91 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.3%, 2.81 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.3%, 2.63 KB
dist/views/BrowseByFolder ${{\color{Goldenrod}{ }}}$ 0.3%, 2.61 KB
dist/views/CollectionFolders ${{\color{Goldenrod}{ }}}$ 0.3%, 2.44 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 2.40 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.2%, 1.94 KB
(other) ${{\color{Goldenrod}{ ████▌ }}}$ 18.1%, 169.94 KB

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████▉ }}}$ 67.8%, 887.18 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▊ }}}$ 3.3%, 43.58 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 39.75 KB
dist/versions/migrations ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 18.50 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.74 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.17 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.84 KB
dist/queues/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.80 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 12.07 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.54 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.89 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.35 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.74 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.69 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.54 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.83 KB
dist/collections/endpoints ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.22 KB
dist/config/sanitize.js ${{\color{Goldenrod}{ }}}$ 0.4%, 5.58 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.50 KB
dist/auth/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 5.42 KB
(other) ${{\color{Goldenrod}{ ████████ }}}$ 32.2%, 422.26 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▎ }}}$ 77.1%, 127.13 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 10.54 KB
dist/config/orderable ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 3.13 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 2.54 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.28 KB
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 943 B
dist/folders/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 916 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.4%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.3%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/fields/getFieldPaths.js ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.3%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.3%, 413 B
(other) ${{\color{Goldenrod}{ █████▋ }}}$ 22.9%, 37.82 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███▏ }}}$ 12.6%, 35.14 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▉ }}}$ 11.5%, 32.00 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▏ }}}$ 8.8%, 24.36 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 23.70 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▋ }}}$ 6.8%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▋ }}}$ 6.5%, 18.11 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 17.75 KB
dist/features/upload ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 13.77 KB
dist/features/textState ${{\color{Goldenrod}{ █ }}}$ 4.0%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 9.03 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 8.22 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.39 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 7.15 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 7.05 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.17 KB
dist/lexical/theme ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.62 KB
dist/features/indent ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.50 KB
(other) ${{\color{Goldenrod}{ █████████████████████▊ }}}$ 87.4%, 243.00 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████▍ }}}$ 49.7%, 578.70 KB
dist/elements/FolderView ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 29.29 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 27.61 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 17.09 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 16.74 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.79 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.77 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.26 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.20 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 13.70 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 10.32 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 9.03 KB
dist/providers/Folders ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.45 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/ListHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.90 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.81 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.73 KB
dist/views/CollectionFolder ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.38 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.34 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.99 KB
(other) ${{\color{Goldenrod}{ ████████████▌ }}}$ 50.3%, 586.83 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ █████ }}}$ 20.0%, 3.12 KB
../../node_modules ${{\color{Goldenrod}{ ████▎ }}}$ 17.0%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▍ }}}$ 9.8%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 862 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █▎ }}}$ 5.2%, 814 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ █▏ }}}$ 4.9%, 762 B
dist/utilities/api.js ${{\color{Goldenrod}{ █▏ }}}$ 4.8%, 756 B
dist/elements/Translation ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 440 B
dist/utilities/traverseForLocalizedFields.js ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 399 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 339 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 329 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 301 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 159 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 146 B
(other) ${{\color{Goldenrod}{ ████████████████████ }}}$ 80.0%, 12.51 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

JarrodMFlesch added a commit that referenced this pull request Feb 3, 2026
Allows custom components to be slotted in before the nav, and not
specifically beforeNavLinks. `beforeNavLinks` semantically means before
the links themselves, but for a PR like
#15470, we will want to be
able to place things outside of the nav links section. Think about the
multi-tenant selector, you would not want that visible in just the first
tab, but outside of the tabs - i.e. before the nav.
@paulpopus paulpopus requested a review from Copilot February 4, 2026 23:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a configurable sidebar tabs feature to the admin panel, enabling users to organize navigation content into custom tabs with icons and components. A default Collections tab is automatically included when custom tabs are configured.

Changes:

  • Added sidebar tabs configuration with icon and component support
  • Implemented tab state persistence via user preferences
  • Created lazy-loading mechanism for tab content with loading states

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/uploads/int.spec.ts Added initialization to uninitialized variable
test/admin/e2e/sidebar-tabs/e2e.spec.ts New E2E test suite for sidebar tabs functionality
test/admin/config.ts Added sidebar tabs configuration for testing
test/admin/components/CustomTab.tsx Test component for custom tab content
test/admin/components/CustomIcon.tsx Test component for custom tab icon
packages/ui/src/exports/client/index.ts Exported Spinner component and types
packages/ui/src/elements/Tooltip/index.tsx Increased tooltip delay from 350ms to 500ms
packages/ui/src/elements/Tooltip/index.scss Removed light theme specific tooltip styles
packages/ui/src/elements/Spinner/index.tsx New Spinner component implementation
packages/ui/src/elements/Spinner/index.scss Spinner component styles
packages/payload/src/preferences/keys.ts Added preference key for active sidebar tab
packages/payload/src/index.ts Reorganized exports and moved baseAccountLockFields
packages/payload/src/config/types.ts Added SidebarTab type definition and config options
packages/payload/src/admin/types.ts Exported sidebar tab props types
packages/payload/src/admin/elements/Nav.ts Added activeTab to NavPreferences and sidebar tab types
packages/next/src/utilities/handleServerFunctions.ts Registered render-tab server function
packages/next/src/elements/Nav/index.tsx Integrated SidebarTabs component into Nav
packages/next/src/elements/Nav/getNavPrefs.ts Added sidebar tab preference retrieval
packages/next/src/elements/Nav/SidebarTabs/renderTabServerFn.ts Server function for lazy-loading tab content
packages/next/src/elements/Nav/SidebarTabs/index.tsx Server component for rendering sidebar tabs
packages/next/src/elements/Nav/SidebarTabs/index.scss Sidebar tabs styles
packages/next/src/elements/Nav/SidebarTabs/index.client.tsx Client component for tab interaction and state
packages/next/src/elements/Nav/SidebarTabs/constants.ts Default nav tab slug constant
packages/next/src/elements/Nav/SidebarTabs/TabError/index.tsx Error state component for failed tab loads
packages/next/src/elements/Nav/SidebarTabs/TabError/index.scss Tab error component styles
packages/graphql/src/utilities/select.ts Formatting improvements for if statements
CLAUDE.md Added translation/label handling guideline

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const customTabContent = page.locator('text=Example folders tab content.')

await expect(customTabContent).toBeVisible()
await expect(customTabButton).toHaveClass(/sidebar-tabs__tab--active/)
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The test expects an active CSS class but doesn't ensure the tab content is actually visible before checking the class. Consider adding await expect(customTabContent).toBeVisible() before the class assertion to ensure the UI state is fully rendered.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +67
const navPrefs = await req.payload
.find({
collection: 'payload-preferences',
depth: 0,
limit: 1,
pagination: false,
req,
where: {
and: [
{
key: {
equals: PREFERENCE_KEYS.NAV,
},
},
{
'user.relationTo': {
equals: req.user.collection,
},
},
{
'user.value': {
equals: req?.user?.id,
},
},
],
},
})
?.then((res) => res?.docs?.[0]?.value)

const sidebarPrefs = await req.payload
.find({
collection: 'payload-preferences',
depth: 0,
limit: 1,
pagination: false,
req,
where: {
and: [
{
key: {
equals: PREFERENCE_KEYS.NAV_SIDEBAR_ACTIVE_TAB,
},
},
{
'user.relationTo': {
equals: req.user.collection,
},
},
})
?.then((res) => res?.docs?.[0]?.value)
: null
{
'user.value': {
equals: req?.user?.id,
},
},
],
},
})
?.then((res) => res?.docs?.[0]?.value)
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

Two separate database queries are executed sequentially to fetch different preference keys. Consider combining these into a single query with an OR condition on the key field, or use Promise.all to parallelize the queries to reduce database round-trips.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +46
const preferredTabSlug =
navPreferences.activeTab || tabs.find((tab) => tab.isDefaultActive)?.slug || tabs[0]?.slug

// Verify the preferred tab actually exists, otherwise fall back to default or first tab
const activeTab =
tabs.find((t) => t.slug === preferredTabSlug) ||
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The fallback logic is duplicated between preferredTabSlug and activeTab. The preferredTabSlug variable is computed but then immediately validated again in activeTab. Simplify by computing activeTab directly without the intermediate preferredTabSlug variable.

Suggested change
const preferredTabSlug =
navPreferences.activeTab || tabs.find((tab) => tab.isDefaultActive)?.slug || tabs[0]?.slug
// Verify the preferred tab actually exists, otherwise fall back to default or first tab
const activeTab =
tabs.find((t) => t.slug === preferredTabSlug) ||
const activeTab =
tabs.find((t) => t.slug === navPreferences.activeTab) ||

Copilot uses AI. Check for mistakes.
<div className={`${baseClass}__content`}>
<span>{message}</span>
<button className={`${baseClass}__retry`} onClick={onRetry} type="button">
Refresh
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

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

The button text 'Refresh' is hardcoded in English. Consider using the translation system to support internationalization, consistent with other UI elements in the codebase.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant