@@ -483,6 +483,10 @@ export class WindowPresenter implements IWindowPresenter {
483483 ! this . settingsWindow . isDestroyed ( ) &&
484484 this . settingsWindow . id === windowId
485485 ) {
486+ if ( this . tryNavigateSettingsWindowByUrl ( channel , args ) ) {
487+ return true
488+ }
489+
486490 if ( this . shouldQueueSettingsMessage ( channel ) ) {
487491 this . pendingSettingsMessages . push ( { channel, args } )
488492 return true
@@ -1244,7 +1248,22 @@ export class WindowPresenter implements IWindowPresenter {
12441248 this . settingsWindow . show ( )
12451249 this . settingsWindow . focus ( )
12461250 if ( navigation ) {
1247- this . sendToWindow ( this . settingsWindow . id , SETTINGS_EVENTS . NAVIGATE , navigation )
1251+ if ( this . settingsWindowReady ) {
1252+ this . sendToWindow ( this . settingsWindow . id , SETTINGS_EVENTS . NAVIGATE , navigation )
1253+ } else {
1254+ this . pendingSettingsMessages . push ( {
1255+ channel : SETTINGS_EVENTS . NAVIGATE ,
1256+ args : [ navigation ]
1257+ } )
1258+
1259+ const targetUrl = this . getSettingsWindowTargetUrl ( navigation )
1260+ console . log ( `Settings window is not ready, reloading to target URL: ${ targetUrl } ` )
1261+ console . info ( '[Startup][Settings][Main] loadURL start' , targetUrl )
1262+ await this . settingsWindow . loadURL ( targetUrl )
1263+ console . info (
1264+ `[Startup][Settings][Main] loadURL end windowId=${ this . settingsWindow . id } elapsed=${ Date . now ( ) - settingsStartupStart } ms`
1265+ )
1266+ }
12481267 }
12491268 return this . settingsWindow . id
12501269 }
@@ -1368,29 +1387,10 @@ export class WindowPresenter implements IWindowPresenter {
13681387 } )
13691388
13701389 // Load settings renderer HTML
1371- const initialNavigationPath = navigation
1372- ? resolveSettingsNavigationPath ( navigation . routeName , navigation . params )
1373- : null
1374-
1375- if ( is . dev && process . env [ 'ELECTRON_RENDERER_URL' ] ) {
1376- const settingsUrl = new URL ( '/settings/index.html' , process . env [ 'ELECTRON_RENDERER_URL' ] )
1377- if ( initialNavigationPath ) {
1378- settingsUrl . hash = initialNavigationPath
1379- }
1380- console . log ( `Loading settings renderer URL in dev mode: ${ settingsUrl . toString ( ) } ` )
1381- console . info ( '[Startup][Settings][Main] loadURL start' , settingsUrl . toString ( ) )
1382- await settingsWindow . loadURL ( settingsUrl . toString ( ) )
1383- } else {
1384- const packagedSettingsUrl = pathToFileURL (
1385- join ( __dirname , '../renderer/settings/index.html' )
1386- ) . toString ( )
1387- const targetUrl = initialNavigationPath
1388- ? `${ packagedSettingsUrl } #${ initialNavigationPath } `
1389- : packagedSettingsUrl
1390- console . log ( `Loading packaged settings renderer URL: ${ targetUrl } ` )
1391- console . info ( '[Startup][Settings][Main] loadURL start' , targetUrl )
1392- await settingsWindow . loadURL ( targetUrl )
1393- }
1390+ const targetUrl = this . getSettingsWindowTargetUrl ( navigation )
1391+ console . log ( `Loading settings renderer URL: ${ targetUrl } ` )
1392+ console . info ( '[Startup][Settings][Main] loadURL start' , targetUrl )
1393+ await settingsWindow . loadURL ( targetUrl )
13941394
13951395 console . info (
13961396 `[Startup][Settings][Main] loadURL end windowId=${ windowId } elapsed=${ Date . now ( ) - settingsStartupStart } ms`
@@ -1488,6 +1488,103 @@ export class WindowPresenter implements IWindowPresenter {
14881488 this . settingsWindowReady = false
14891489 }
14901490
1491+ private tryNavigateSettingsWindowByUrl ( channel : string , args : unknown [ ] ) : boolean {
1492+ if (
1493+ channel !== SETTINGS_EVENTS . NAVIGATE ||
1494+ ! this . settingsWindow ||
1495+ this . settingsWindow . isDestroyed ( ) ||
1496+ this . settingsWindow . webContents . isDestroyed ( )
1497+ ) {
1498+ return false
1499+ }
1500+
1501+ const navigation = this . toSettingsNavigationPayload ( args [ 0 ] )
1502+ if ( ! navigation || navigation . routeName !== 'settings-provider' ) {
1503+ return false
1504+ }
1505+
1506+ const targetUrl = this . getSettingsWindowTargetUrl ( navigation )
1507+ const currentUrl = this . settingsWindow . webContents . getURL ( )
1508+
1509+ if ( currentUrl === targetUrl && this . settingsWindowReady ) {
1510+ return false
1511+ }
1512+
1513+ this . pendingSettingsMessages . push ( { channel, args : [ navigation ] } )
1514+ console . log ( `Reloading settings window to target URL: ${ targetUrl } ` )
1515+ console . info ( '[Startup][Settings][Main] loadURL start' , targetUrl )
1516+ void this . settingsWindow . webContents
1517+ . loadURL ( targetUrl )
1518+ . then ( ( ) => {
1519+ if ( ! this . settingsWindow || this . settingsWindow . isDestroyed ( ) ) {
1520+ return
1521+ }
1522+
1523+ console . info (
1524+ `[Startup][Settings][Main] loadURL end windowId=${ this . settingsWindow . id } target=${ targetUrl } `
1525+ )
1526+ } )
1527+ . catch ( ( error ) => {
1528+ console . error ( `Failed to reload settings window for navigation: ${ targetUrl } ` , error )
1529+ } )
1530+ return true
1531+ }
1532+
1533+ private toSettingsNavigationPayload ( raw : unknown ) : SettingsNavigationPayload | null {
1534+ if ( ! raw || typeof raw !== 'object' ) {
1535+ return null
1536+ }
1537+
1538+ const candidate = raw as {
1539+ routeName ?: unknown
1540+ params ?: unknown
1541+ section ?: unknown
1542+ }
1543+
1544+ if ( typeof candidate . routeName !== 'string' ) {
1545+ return null
1546+ }
1547+
1548+ const params =
1549+ candidate . params && typeof candidate . params === 'object'
1550+ ? Object . entries ( candidate . params as Record < string , unknown > ) . reduce <
1551+ Record < string , string >
1552+ > ( ( acc , [ key , value ] ) => {
1553+ if ( typeof value === 'string' && value . trim ( ) . length > 0 ) {
1554+ acc [ key ] = value
1555+ }
1556+ return acc
1557+ } , { } )
1558+ : undefined
1559+
1560+ return {
1561+ routeName : candidate . routeName as SettingsNavigationPayload [ 'routeName' ] ,
1562+ params : params && Object . keys ( params ) . length > 0 ? params : undefined ,
1563+ section : typeof candidate . section === 'string' ? candidate . section : undefined
1564+ }
1565+ }
1566+
1567+ private getSettingsWindowTargetUrl ( navigation ?: SettingsNavigationPayload ) : string {
1568+ const initialNavigationPath = navigation
1569+ ? resolveSettingsNavigationPath ( navigation . routeName , navigation . params )
1570+ : null
1571+
1572+ if ( is . dev && process . env [ 'ELECTRON_RENDERER_URL' ] ) {
1573+ const settingsUrl = new URL ( '/settings/index.html' , process . env [ 'ELECTRON_RENDERER_URL' ] )
1574+ if ( initialNavigationPath ) {
1575+ settingsUrl . hash = initialNavigationPath
1576+ }
1577+ return settingsUrl . toString ( )
1578+ }
1579+
1580+ const packagedSettingsUrl = pathToFileURL (
1581+ join ( __dirname , '../renderer/settings/index.html' )
1582+ ) . toString ( )
1583+ return initialNavigationPath
1584+ ? `${ packagedSettingsUrl } #${ initialNavigationPath } `
1585+ : packagedSettingsUrl
1586+ }
1587+
14911588 private flushPendingSettingsMessages ( ) : void {
14921589 if (
14931590 ! this . settingsWindow ||
0 commit comments