Scroll settings hint to import controls

This commit is contained in:
Lawrence Chen 2026-03-17 04:48:21 -07:00
parent c5ae8dc9eb
commit d369778f7f
No known key found for this signature in database
7 changed files with 77 additions and 11 deletions

View file

@ -8944,6 +8944,7 @@ private final class FeedbackComposerMessageEditorView: NSView {
}
private enum SidebarHelpMenuAction {
case importBrowserData
case keyboardShortcuts
case docs
case changelog
@ -9514,6 +9515,12 @@ private struct SidebarHelpMenuButton: View {
accessibilityIdentifier: "SidebarHelpMenuOptionKeyboardShortcuts",
isExternalLink: false
)
helpOptionButton(
title: String(localized: "menu.view.importFromBrowser", defaultValue: "Import From Browser…"),
action: .importBrowserData,
accessibilityIdentifier: "SidebarHelpMenuOptionImportBrowserData",
isExternalLink: false
)
if docsURL != nil {
helpOptionButton(
title: String(localized: "about.docs", defaultValue: "Docs"),
@ -9618,6 +9625,11 @@ private struct SidebarHelpMenuButton: View {
private func perform(_ action: SidebarHelpMenuAction) {
switch action {
case .importBrowserData:
isPopoverPresented = false
DispatchQueue.main.async {
BrowserDataImportCoordinator.shared.presentImportDialog()
}
case .keyboardShortcuts:
isPopoverPresented = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) {

View file

@ -259,7 +259,7 @@ enum BrowserImportHintSettings {
static let variantKey = "browserImportHintVariant"
static let showOnBlankTabsKey = "browserImportHintShowOnBlankTabs"
static let dismissedKey = "browserImportHintDismissed"
static let defaultVariant: BrowserImportHintVariant = .inlineStrip
static let defaultVariant: BrowserImportHintVariant = .toolbarChip
static let defaultShowOnBlankTabs = true
static let defaultDismissed = false

View file

@ -873,6 +873,14 @@ struct BrowserPanelView: View {
}
.buttonStyle(.plain)
Button {
presentImportDialogFromProfileMenu()
} label: {
Text(String(localized: "menu.view.importFromBrowser", defaultValue: "Import From Browser…"))
.font(.system(size: 12))
}
.buttonStyle(.plain)
if browserProfileStore.canRenameProfile(id: panel.profileID) {
Button {
isBrowserProfileMenuPresented = false
@ -1470,6 +1478,16 @@ struct BrowserPanelView: View {
private func presentImportDialogFromHint() {
isBrowserImportHintPopoverPresented = false
// Let the popover fully dismiss before entering the modal import flow.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) {
BrowserDataImportCoordinator.shared.presentImportDialog(
defaultDestinationProfileID: panel.profileID
)
}
}
private func presentImportDialogFromProfileMenu() {
isBrowserProfileMenuPresented = false
DispatchQueue.main.async {
BrowserDataImportCoordinator.shared.presentImportDialog(
defaultDestinationProfileID: panel.profileID
@ -1479,7 +1497,7 @@ struct BrowserPanelView: View {
private func openBrowserImportSettings() {
isBrowserImportHintPopoverPresented = false
AppDelegate.presentPreferencesWindow(navigationTarget: .browser)
AppDelegate.presentPreferencesWindow(navigationTarget: .browserImport)
}
private func dismissBrowserImportHint() {

View file

@ -2252,6 +2252,7 @@ final class SettingsWindowController: NSWindowController, NSWindowDelegate {
enum SettingsNavigationTarget: String {
case browser
case browserImport
case keyboardShortcuts
}
@ -4659,6 +4660,7 @@ struct SettingsView: View {
}
.buttonStyle(.bordered)
.controlSize(.small)
.accessibilityIdentifier("SettingsBrowserImportChooseButton")
Button(String(localized: "settings.browser.import.refresh", defaultValue: "Refresh")) {
refreshDetectedImportBrowsers()
@ -4680,6 +4682,8 @@ struct SettingsView: View {
.foregroundStyle(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
.id(SettingsNavigationTarget.browserImport)
.accessibilityIdentifier("SettingsBrowserImportSection")
.padding(.horizontal, 14)
.padding(.vertical, 10)

View file

@ -2550,6 +2550,24 @@ final class AppDelegateShortcutRoutingTests: XCTestCase {
XCTAssertEqual(activateApplicationCallCount, 1)
}
func testPresentPreferencesWindowForwardsBrowserImportNavigationTarget() {
var receivedNavigationTarget: SettingsNavigationTarget?
var activateApplicationCallCount = 0
AppDelegate.presentPreferencesWindow(
navigationTarget: .browserImport,
showFallbackSettingsWindow: { navigationTarget in
receivedNavigationTarget = navigationTarget
},
activateApplication: {
activateApplicationCallCount += 1
}
)
XCTAssertEqual(receivedNavigationTarget, .browserImport)
XCTAssertEqual(activateApplicationCallCount, 1)
}
private func makeKeyDownEvent(
key: String,
modifiers: NSEvent.ModifierFlags,

View file

@ -144,14 +144,15 @@ final class BrowserImportMappingTests: XCTestCase {
XCTAssertTrue(manyProfilesPresentation.showsHelpText)
}
func testBrowserImportHintPresentationDefaultsToInlineStrip() {
let presentation = BrowserImportHintPresentation(
variant: .inlineStrip,
showOnBlankTabs: true,
isDismissed: false
)
func testBrowserImportHintSettingsDefaultToToolbarChip() throws {
let suiteName = "BrowserImportHintDefaults-\(UUID().uuidString)"
let defaults = try XCTUnwrap(UserDefaults(suiteName: suiteName))
defaults.removePersistentDomain(forName: suiteName)
defer { defaults.removePersistentDomain(forName: suiteName) }
XCTAssertEqual(presentation.blankTabPlacement, .inlineStrip)
let presentation = BrowserImportHintSettings.presentation(defaults: defaults)
XCTAssertEqual(presentation.blankTabPlacement, .toolbarChip)
XCTAssertEqual(presentation.settingsStatus, .visible)
}

View file

@ -119,9 +119,22 @@ final class BrowserImportProfilesUITests: XCTestCase {
XCTAssertTrue(settingsButton.waitForExistence(timeout: 5.0))
settingsButton.click()
let importSection = app.otherElements["SettingsBrowserImportSection"]
XCTAssertTrue(
app.switches["SettingsBrowserImportHintToggle"].waitForExistence(timeout: 5.0),
"Expected Browser Settings to open from the blank-tab import hint"
importSection.waitForExistence(timeout: 5.0),
"Expected Browser Settings to scroll to the import section"
)
let chooseButton = app.buttons["SettingsBrowserImportChooseButton"]
XCTAssertTrue(
chooseButton.waitForExistence(timeout: 5.0),
"Expected Browser Settings to expose the import actions"
)
XCTAssertTrue(
browserImportPollUntil(timeout: 5.0) {
importSection.isHittable && chooseButton.isHittable
},
"Expected Browser Settings to scroll directly to the import controls"
)
}