Skip to content

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 22, 2026

Benchmark PR from qodo-benchmark#230

Summary by CodeRabbit

  • Chores

    • Removed the inactive tabs feature and associated UI components from the tab management system.
    • Removed related accessibility identifiers, settings toggles, and localization strings.
  • Tests

    • Updated tests to reflect removal of inactive tabs-related functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 22, 2026

Walkthrough

This pull request removes the entire inactive tabs feature from the Firefox iOS codebase, including UI components, state management, business logic, middleware handlers, data source configuration, and related test coverage. Approximately 22 files are modified to eliminate all inactive tabs functionality.

Changes

Cohort / File(s) Summary
Project Configuration
firefox-ios/Client.xcodeproj/project.pbxproj
Removed the InactiveTabs group and all associated file references (InactiveTabsCell.swift, InactiveTabsHeaderView.swift, InactiveTabsFooterView.swift, InactiveTabsSectionManager.swift) from the project structure and build phases.
Models & State
firefox-ios/Client/Frontend/Browser/Tabs/Models/InactiveTabsModel.swift, TabDisplayModel.swift
firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift
firefox-ios/Client/Frontend/Browser/Tabs/LayoutManager/InactiveTabsSectionManager.swift
Deleted InactiveTabsModel struct entirely. Removed inactiveTabs and isInactiveTabsExpanded properties from TabDisplayModel and TabsPanelState. Eliminated InactiveTabsSectionManager protocol and class with layout logic. Updated TabsPanelState.ScrollState to remove isInactiveTabSection field.
Actions & Middleware
firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift
firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift
Removed inactive tab action cases (toggleInactiveTabs, closeInactiveTab, undoCloseInactiveTab, closeAllInactiveTabs, undoCloseAllInactiveTabs, refreshInactiveTabs). Removed isInactiveTab property and inactiveTabModels property from action structs. Removed inactive tab handler methods from middleware. Updated selectTab signature to remove isInactiveTab parameter.
UI Components
firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsCell.swift
InactiveTabsHeaderView.swift, InactiveTabsFooterView.swift
firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift
Deleted InactiveTabsCell, InactiveTabsHeaderView, and InactiveTabsFooterView classes entirely. Removed InactiveTabsSectionManagerDelegate conformance from TabDisplayView. Removed inactiveTabsSectionManager property, deleteInactiveTab, toggleInactiveTab methods, and inactive tab cell/supplementary configurations.
Data Source & Animation
firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayDiffableDataSource.swift
firefox-ios/Client/Frontend/Browser/Tabs/Views/Animation/TabAnimation.swift
Removed inactiveTabs(UUID) case from TabSection enum. Removed inactiveTab(InactiveTabsModel) case from TabItem enum. Simplified snapshot construction. Removed inactive tab matching logic from TabAnimation.
Strings & Accessibility
firefox-ios/Shared/Strings.swift
firefox-ios/Client/Application/AccessibilityIdentifiers.swift
firefox-ios/Client/Frontend/Browser/ToastType.swift
Moved InactiveTabs struct from live TabsTray public API to legacy OldStrings v147 namespace. Removed InactiveTabs struct and inactiveTabsSwitch identifier from AccessibilityIdentifiers. Removed closedSingleInactiveTab and closedAllInactiveTabs cases and their handlers from ToastType.
Tests
firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayDiffableDataSourceTests.swift
TabDisplayPanelTests.swift, TabsPanelStateTests.swift
firefox-ios-tests/Tests/XCUITests/FxScreenGraph.swift
TabsTests.swift, registerSettingsNavigation.swift
Removed createInactiveTabs helper and inactive tab assertions across all test files. Simplified test subject creation by removing inactiveTabs parameters. Updated UI test identifiers and settings navigation to remove inactive tabs toggle.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Farewell to tabs that dozed away,
No longer hidden from the fray,
The inactive feature's had its day,
Now unified tabs lead the way,
Simpler code in every way! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing inactive tabs functionality as part of a cleanup task (FXIOS-14327, part 2 final). The PR demonstrates comprehensive removal of inactive tabs across UI, state management, models, and tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabsPanelStateTests.swift (1)

138-153: Implementation has off-by-one error: returns out-of-bounds index.

Line 143 of TabsPanelState.createTabScrollBehavior returns state.tabs.count when no selected tab exists, but this is out of bounds. For an array with 3 elements (indices 0–2), returning index 3 will cause a crash when used with collection views.

The test correctly expects tabCount - 1. The implementation should return state.tabs.count - 1 instead.

firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift (1)

171-181: Change hardcoded section index from 1 to 0 in scrollToTab function.

After inactive tabs removal, TabDisplayDiffableDataSource now contains only a single section (.tabs) at index 0. Line 172 incorrectly hardcodes section: 1, which references a non-existent section. This will cause scrollToItem to fail with an invalid index path.

All tests confirm tabs are expected at section 0:

  • testNumberOfSections_ForRegularTabs: numberOfItems(inSection: 0) = 2
  • testNumberOfSections_PrivateTabs: numberOfItems(inSection: 0) = 9
Suggested fix
    private func scrollToTab(_ scrollState: TabsPanelState.ScrollState) {
-       let indexPath = IndexPath(row: scrollState.toIndex, section: 1)
+       let indexPath = IndexPath(row: scrollState.toIndex, section: 0)
🤖 Fix all issues with AI agents
In `@firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift`:
- Around line 139-144: In TabsPanelState, the fallback ScrollState currently
uses toIndex: state.tabs.count which is off-by-one (points past the last item);
update the return to use the last valid index (state.tabs.count - 1) when
state.tabs is non-empty so scrollToTab receives a valid index; reference
TabsPanelState, the ScrollState construction there, and
TabDisplayView.scrollToTab/isValid(indexPath:) to ensure the chosen index stays
within 0..<state.tabs.count.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d49276 and f7001a1.

📒 Files selected for processing (22)
  • firefox-ios/Client.xcodeproj/project.pbxproj
  • firefox-ios/Client/Application/AccessibilityIdentifiers.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/LayoutManager/InactiveTabsSectionManager.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Models/InactiveTabsModel.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Models/TabDisplayModel.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/Animation/TabAnimation.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsCell.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsFooterView.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsHeaderView.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayDiffableDataSource.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift
  • firefox-ios/Client/Frontend/Browser/ToastType.swift
  • firefox-ios/Shared/Strings.swift
  • firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayDiffableDataSourceTests.swift
  • firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift
  • firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabsPanelStateTests.swift
  • firefox-ios/firefox-ios-tests/Tests/XCUITests/FxScreenGraph.swift
  • firefox-ios/firefox-ios-tests/Tests/XCUITests/TabsTests.swift
  • firefox-ios/firefox-ios-tests/Tests/XCUITests/registerSettingsNavigation.swift
💤 Files with no reviewable changes (12)
  • firefox-ios/Client/Application/AccessibilityIdentifiers.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Models/InactiveTabsModel.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsHeaderView.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Models/TabDisplayModel.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/LayoutManager/InactiveTabsSectionManager.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsFooterView.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/Animation/TabAnimation.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Views/InactiveTabs/InactiveTabsCell.swift
  • firefox-ios/firefox-ios-tests/Tests/XCUITests/FxScreenGraph.swift
  • firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift
  • firefox-ios/Client.xcodeproj/project.pbxproj
🧰 Additional context used
🧬 Code graph analysis (5)
firefox-ios/firefox-ios-tests/Tests/XCUITests/registerSettingsNavigation.swift (2)
firefox-ios/Client/Redux/GlobalState/AppState.swift (1)
  • screenState (16-52)
firefox-ios/firefox-ios-tests/Tests/XCUITests/BaseTestCase.swift (1)
  • tap (534-543)
firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabsPanelStateTests.swift (2)
firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift (1)
  • createTabScrollBehavior (130-156)
firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift (1)
  • scrollToTab (171-181)
firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift (1)
firefox-ios/Client/Frontend/Browser/Tabs/LayoutManager/TabsSectionManager.swift (2)
  • experimentLayoutSection (70-123)
  • layoutSection (32-68)
firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift (1)
firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift (1)
  • scrollToTab (171-181)
firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift (2)
firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayDiffableDataSourceTests.swift (1)
  • createTabs (76-85)
firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabsPanelStateTests.swift (1)
  • createTabs (240-244)
🔇 Additional comments (15)
firefox-ios/firefox-ios-tests/Tests/XCUITests/registerSettingsNavigation.swift (1)

187-190: LGTM!

The TabsSettings screen state correctly reflects the removal of the inactive tabs toggle. With the inactive tabs feature removed, the first switch (boundBy: 0) now controls Tab Groups, and the navigation back to Settings remains intact.

firefox-ios/firefox-ios-tests/Tests/XCUITests/TabsTests.swift (4)

49-52: LGTM!

The tab cell identifier correctly updated from section 1 to section 0, reflecting the removal of the inactive tabs section. The active tabs section is now the first (and only) section.


96-98: LGTM!

Consistent update of the tab cell identifier to use section 0 instead of 1.


353-354: LGTM!

Section index correctly updated to 0 for the tab cell identifier.


529-546: Update tab cell identifiers to match other tests in the file.

This test uses _1_2 for tab cell identifiers (6 occurrences) while all other tests in the same file use section 0 indices (e.g., lines 49, 96, 353). If the inactive tabs removal changed section numbering from 1 to 0 for active tabs, these references should be updated to _0_2 for consistency.

Occurrences in testCloseOneTabUndo
        app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"].buttons[StandardImageIdentifiers.Large.cross].tap()
        mozWaitForElementToNotExist(app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"])
        app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"].press(forDuration: 2)
        mozWaitForElementToNotExist(app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"])
        app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"].swipeLeft()
        mozWaitForElementToNotExist(app.cells[AccessibilityIdentifiers.TabTray.tabCell+"_1_2"])
firefox-ios/Shared/Strings.swift (1)

8461-8482: LGTM — legacy inactive-tabs strings are correctly isolated.

firefox-ios/Client/Frontend/Browser/ToastType.swift (1)

9-72: LGTM!

The ToastType enum has been cleanly simplified by removing the inactive tab cases. The switch statements remain exhaustive, and the redux action mappings for undo functionality are correctly preserved for the active tab cases.

firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift (1)

84-128: LGTM on the reducer simplification.

The middleware action handling and state construction have been cleanly updated to remove inactive tabs state. The reducer logic remains sound and properly handles all action types.

firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayDiffableDataSourceTests.swift (2)

25-47: LGTM!

Test assertions correctly updated to expect a single section after removing inactive tabs. Coverage maintained for regular tabs, private tabs, and empty state scenarios.


50-85: LGTM on helper methods.

The createSubject and createTabs helpers are cleanly simplified to work with the single-section model.

firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayDiffableDataSource.swift (1)

8-25: LGTM!

The diffable data source has been cleanly simplified to a single section and item type. The snapshot construction is straightforward and correct.

firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift (1)

20-71: LGTM!

Test setup and assertions have been cleanly updated to work without inactive tabs state. The tests for isPrivateTabsEmpty remain valid and the helper methods are appropriately simplified.

firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabsPanelStateTests.swift (2)

22-100: LGTM on middleware action tests.

The tests for didLoadTabPanel, didChangeTabPanel, willAppearTabPanel, and refreshTabs are correctly updated and properly verify the reducer behavior without inactive tabs state.


104-117: LGTM on remaining scroll behavior tests.

The tests for edge cases (no tabs, tab doesn't exist) and the scrollToTab behavior are correctly implemented and verify the expected scroll state outcomes.

Also applies to: 155-217

firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift (1)

224-236: LGTM!

The layout creation logic is correctly simplified after removing inactive tabs. The branching now only depends on the experiment flag, delegating to the appropriate TabsSectionManager method.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 139 to 144
} else if !state.tabs.isEmpty {
// If the user switches between the normal and private tab panels, there's a chance this subset of tabs does
// not contain a selected tab. In that case, we should scroll to the bottom of the panel.
// Note: Could optimize further by scrolling to the most recent tab if we had `lastExecutedTime` in our model
return ScrollState(toIndex: state.tabs.count - 1, isInactiveTabSection: false, withAnimation: shouldAnimate)
return ScrollState(toIndex: state.tabs.count, withAnimation: shouldAnimate)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential off-by-one: toIndex: state.tabs.count may exceed valid bounds.

When no selected tab is found, returning state.tabs.count as the index points past the last valid item (valid indices are 0..<count). The comment says "scroll to the bottom," which typically means the last item at index count - 1.

The TabDisplayView.scrollToTab method does guard with isValid(indexPath:), so this won't crash, but the scroll may silently fail or behave unexpectedly.

Suggested fix
             } else if !state.tabs.isEmpty {
                 // If the user switches between the normal and private tab panels, there's a chance this subset of tabs does
                 // not contain a selected tab. In that case, we should scroll to the bottom of the panel.
                 // Note: Could optimize further by scrolling to the most recent tab if we had `lastExecutedTime` in our model
-                return ScrollState(toIndex: state.tabs.count, withAnimation: shouldAnimate)
+                return ScrollState(toIndex: state.tabs.count - 1, withAnimation: shouldAnimate)
             }
🤖 Prompt for AI Agents
In `@firefox-ios/Client/Frontend/Browser/Tabs/State/TabsPanelState.swift` around
lines 139 - 144, In TabsPanelState, the fallback ScrollState currently uses
toIndex: state.tabs.count which is off-by-one (points past the last item);
update the return to use the last valid index (state.tabs.count - 1) when
state.tabs is non-empty so scrollToTab receives a valid index; reference
TabsPanelState, the ScrollState construction there, and
TabDisplayView.scrollToTab/isValid(indexPath:) to ensure the chosen index stays
within 0..<state.tabs.count.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants