@@ -102,6 +102,13 @@ export const UIProvider: React.FC<UIProviderProps> = ({ children }) => {
102102 props : Omit < PanelProps < P > , "type" | "configured" | "custom" > &
103103 Omit < UIScreenCallbacks < T > , "onBeforeAccept" > = DEFAULT_PANEL_PROPS
104104 ) => {
105+ // Dupe check
106+ const isDuplicate = panels . some ( p => p . content === content )
107+ if ( isDuplicate ) {
108+ const existing = panels . find ( p => p . content === content ) !
109+ setPanels ( p => [ ...p . filter ( x => x !== existing ) , existing ] )
110+ return existing . id
111+ }
105112 const id = uuidv4 ( )
106113 const panel = {
107114 id,
@@ -128,7 +135,42 @@ export const UIProvider: React.FC<UIProviderProps> = ({ children }) => {
128135 panel . onCancel = new UICallback ( )
129136 if ( props . onCancel ) panel . onCancel . setUserDefinedFunc ( props . onCancel )
130137
131- setPanels ( [ ...panels , panel as Panel < any , any > ] )
138+ const contentName = ( content as unknown as { name ?: string } ) ?. name ?? ""
139+ const mutuallyExclusive = [ "ImportMirabufPanel" , "ConfigurePanel" , "InitialConfigPanel" ]
140+ const nextPanels = panels
141+ if ( mutuallyExclusive . includes ( contentName ) ) {
142+ const existing = panels . find ( p =>
143+ mutuallyExclusive . includes ( ( p . content as unknown as { name ?: string } ) ?. name ?? "" )
144+ )
145+ if ( existing ) {
146+ // If the existing panel is ConfigurePanel and a spawn/initial panel is being opened while editing,
147+ // warn the user and keep Configure open. Otherwise, replace existing with the new panel.
148+ const existingName = ( existing . content as unknown as { name ?: string } ) ?. name ?? ""
149+ const isExistingConfigure = existingName === "ConfigurePanel"
150+ const isNewSpawnOrInit =
151+ contentName === "ImportMirabufPanel" || contentName === "InitialConfigPanel"
152+ if ( isExistingConfigure && isNewSpawnOrInit ) {
153+ // Only block if actively configuring an assembly (has selection or a mode set)
154+ const custom = ( existing . props as unknown as { custom ?: any } ) ?. custom ?? { }
155+ const isActivelyConfiguring =
156+ Boolean ( custom ?. selectedAssembly ) || custom ?. configMode !== undefined
157+ if ( isActivelyConfiguring ) {
158+ // Show a warning toast about unsaved configuration
159+ enqueueSnackbar ( "You have unsaved configuration open. Close it before spawning." , {
160+ variant : "warning" ,
161+ action : snackbarAction ,
162+ } )
163+ setPanels ( p => [ ...p . filter ( x => x !== existing ) , existing ] )
164+ return existing . id
165+ }
166+ }
167+ // Replace existing with the new one
168+ setPanels ( p => [ ...p . filter ( x => x !== existing ) , panel as Panel < any , any > ] )
169+ return id
170+ }
171+ }
172+
173+ setPanels ( [ ...nextPanels , panel as Panel < any , any > ] )
132174 return id
133175 } ,
134176 [ panels ]
0 commit comments