@@ -3,7 +3,7 @@ import { WebContents } from 'electron';
33
44import { createLogger } from '@/utils/logger' ;
55
6- import { AppBrowsersIdentifiers , appBrowsers } from '../../appBrowsers' ;
6+ import { AppBrowsersIdentifiers , appBrowsers , WindowTemplate , WindowTemplateIdentifiers , windowTemplates } from '../../appBrowsers' ;
77import type { App } from '../App' ;
88import type { BrowserWindowOpts } from './Browser' ;
99import Browser from './Browser' ;
@@ -14,9 +14,9 @@ const logger = createLogger('core:BrowserManager');
1414export class BrowserManager {
1515 app : App ;
1616
17- browsers : Map < AppBrowsersIdentifiers , Browser > = new Map ( ) ;
17+ browsers : Map < string , Browser > = new Map ( ) ;
1818
19- private webContentsMap = new Map < WebContents , AppBrowsersIdentifiers > ( ) ;
19+ private webContentsMap = new Map < WebContents , string > ( ) ;
2020
2121 constructor ( app : App ) {
2222 logger . debug ( 'Initializing BrowserManager' ) ;
@@ -51,12 +51,12 @@ export class BrowserManager {
5151 } ;
5252
5353 broadcastToWindow = < T extends MainBroadcastEventKey > (
54- identifier : AppBrowsersIdentifiers ,
54+ identifier : string ,
5555 event : T ,
5656 data : MainBroadcastParams < T > ,
5757 ) => {
5858 logger . debug ( `Broadcasting event ${ event } to window: ${ identifier } ` ) ;
59- this . browsers . get ( identifier ) . broadcast ( event , data ) ;
59+ this . browsers . get ( identifier ) ? .broadcast ( event , data ) ;
6060 } ;
6161
6262 /**
@@ -87,13 +87,21 @@ export class BrowserManager {
8787 * @param identifier Window identifier
8888 * @param subPath Sub-path, such as 'agent', 'about', etc.
8989 */
90- async redirectToPage ( identifier : AppBrowsersIdentifiers , subPath ?: string ) {
90+ async redirectToPage ( identifier : string , subPath ?: string ) {
9191 try {
9292 // Ensure window is retrieved or created
9393 const browser = this . retrieveByIdentifier ( identifier ) ;
9494 browser . hide ( ) ;
9595
96- const baseRoute = appBrowsers [ identifier ] . path ;
96+ // Handle both static and dynamic windows
97+ let baseRoute : string ;
98+ if ( identifier in appBrowsers ) {
99+ baseRoute = appBrowsers [ identifier as AppBrowsersIdentifiers ] . path ;
100+ } else {
101+ // For dynamic windows, extract base route from the browser options
102+ const browserOptions = browser . options ;
103+ baseRoute = browserOptions . path ;
104+ }
97105
98106 // Build complete URL path
99107 const fullPath = subPath ? `${ baseRoute } /${ subPath } ` : baseRoute ;
@@ -114,13 +122,75 @@ export class BrowserManager {
114122 /**
115123 * get Browser by identifier
116124 */
117- retrieveByIdentifier ( identifier : AppBrowsersIdentifiers ) {
125+ retrieveByIdentifier ( identifier : string ) {
118126 const browser = this . browsers . get ( identifier ) ;
119127
120128 if ( browser ) return browser ;
121129
122- logger . debug ( `Browser ${ identifier } not found, initializing new instance` ) ;
123- return this . retrieveOrInitialize ( appBrowsers [ identifier ] ) ;
130+ // Check if it's a static browser
131+ if ( identifier in appBrowsers ) {
132+ logger . debug ( `Browser ${ identifier } not found, initializing new instance` ) ;
133+ return this . retrieveOrInitialize ( appBrowsers [ identifier as AppBrowsersIdentifiers ] ) ;
134+ }
135+
136+ throw new Error ( `Browser ${ identifier } not found and is not a static browser` ) ;
137+ }
138+
139+ /**
140+ * Create a multi-instance window from template
141+ * @param templateId Template identifier
142+ * @param path Full path with query parameters
143+ * @param uniqueId Optional unique identifier, will be generated if not provided
144+ * @returns The window identifier and Browser instance
145+ */
146+ createMultiInstanceWindow ( templateId : WindowTemplateIdentifiers , path : string , uniqueId ?: string ) {
147+ const template = windowTemplates [ templateId ] ;
148+ if ( ! template ) {
149+ throw new Error ( `Window template ${ templateId } not found` ) ;
150+ }
151+
152+ // Generate unique identifier
153+ const windowId = uniqueId || `${ template . baseIdentifier } _${ Date . now ( ) } _${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) } ` ;
154+
155+ // Create browser options from template
156+ const browserOpts : BrowserWindowOpts = {
157+ ...template ,
158+ identifier : windowId ,
159+ path : path ,
160+ } ;
161+
162+ logger . debug ( `Creating multi-instance window: ${ windowId } with path: ${ path } ` ) ;
163+
164+ const browser = this . retrieveOrInitialize ( browserOpts ) ;
165+
166+ return {
167+ identifier : windowId ,
168+ browser : browser ,
169+ } ;
170+ }
171+
172+ /**
173+ * Get all windows based on template
174+ * @param templateId Template identifier
175+ * @returns Array of window identifiers matching the template
176+ */
177+ getWindowsByTemplate ( templateId : string ) : string [ ] {
178+ const prefix = `${ templateId } _` ;
179+ return Array . from ( this . browsers . keys ( ) ) . filter ( id => id . startsWith ( prefix ) ) ;
180+ }
181+
182+ /**
183+ * Close all windows based on template
184+ * @param templateId Template identifier
185+ */
186+ closeWindowsByTemplate ( templateId : string ) : void {
187+ const windowIds = this . getWindowsByTemplate ( templateId ) ;
188+ windowIds . forEach ( id => {
189+ const browser = this . browsers . get ( id ) ;
190+ if ( browser ) {
191+ browser . close ( ) ;
192+ }
193+ } ) ;
124194 }
125195
126196 /**
@@ -144,7 +214,7 @@ export class BrowserManager {
144214 * @param options Browser window options
145215 */
146216 private retrieveOrInitialize ( options : BrowserWindowOpts ) {
147- let browser = this . browsers . get ( options . identifier as AppBrowsersIdentifiers ) ;
217+ let browser = this . browsers . get ( options . identifier ) ;
148218 if ( browser ) {
149219 logger . debug ( `Retrieved existing browser: ${ options . identifier } ` ) ;
150220 return browser ;
@@ -153,7 +223,7 @@ export class BrowserManager {
153223 logger . debug ( `Creating new browser: ${ options . identifier } ` ) ;
154224 browser = new Browser ( options , this . app ) ;
155225
156- const identifier = options . identifier as AppBrowsersIdentifiers ;
226+ const identifier = options . identifier ;
157227 this . browsers . set ( identifier , browser ) ;
158228
159229 // 记录 WebContents 和 identifier 的映射
@@ -166,32 +236,32 @@ export class BrowserManager {
166236
167237 browser . browserWindow . on ( 'show' , ( ) => {
168238 if ( browser . webContents )
169- this . webContentsMap . set ( browser . webContents , browser . identifier as AppBrowsersIdentifiers ) ;
239+ this . webContentsMap . set ( browser . webContents , browser . identifier ) ;
170240 } ) ;
171241
172242 return browser ;
173243 }
174244
175245 closeWindow ( identifier : string ) {
176- const browser = this . browsers . get ( identifier as AppBrowsersIdentifiers ) ;
246+ const browser = this . browsers . get ( identifier ) ;
177247 browser ?. close ( ) ;
178248 }
179249
180250 minimizeWindow ( identifier : string ) {
181- const browser = this . browsers . get ( identifier as AppBrowsersIdentifiers ) ;
251+ const browser = this . browsers . get ( identifier ) ;
182252 browser ?. browserWindow . minimize ( ) ;
183253 }
184254
185255 maximizeWindow ( identifier : string ) {
186- const browser = this . browsers . get ( identifier as AppBrowsersIdentifiers ) ;
187- if ( browser . browserWindow . isMaximized ( ) ) {
256+ const browser = this . browsers . get ( identifier ) ;
257+ if ( browser ? .browserWindow . isMaximized ( ) ) {
188258 browser ?. browserWindow . unmaximize ( ) ;
189259 } else {
190260 browser ?. browserWindow . maximize ( ) ;
191261 }
192262 }
193263
194- getIdentifierByWebContents ( webContents : WebContents ) : AppBrowsersIdentifiers | null {
264+ getIdentifierByWebContents ( webContents : WebContents ) : string | null {
195265 return this . webContentsMap . get ( webContents ) || null ;
196266 }
197267
0 commit comments