@@ -64,6 +64,15 @@ import {
6464 MenuTrigger ,
6565} from "../ui/menu" ;
6666import { toastManager } from "../ui/toast" ;
67+ import {
68+ AlertDialog ,
69+ AlertDialogClose ,
70+ AlertDialogDescription ,
71+ AlertDialogFooter ,
72+ AlertDialogHeader ,
73+ AlertDialogPopup ,
74+ AlertDialogTitle ,
75+ } from "../ui/alert-dialog" ;
6776import { Button } from "../ui/button" ;
6877import { DraftInput } from "../ui/draft-input" ;
6978import { NumberField , NumberFieldGroup , NumberFieldInput } from "../ui/number-field" ;
@@ -533,12 +542,18 @@ function BrowserProfilesSetting({ disabled }: { readonly disabled: boolean }) {
533542 const updateSettings = useUpdatePrimarySettings ( ) ;
534543 const environmentId = usePrimaryEnvironment ( ) ?. environmentId ;
535544 const [ sources , setSources ] = useState < ReadonlyArray < BrowserImportSource > | null > ( null ) ;
545+ const [ profilePendingRemoval , setProfilePendingRemoval ] = useState < BrowserProfile | null > ( null ) ;
536546 const [ busy , setBusy ] = useState ( false ) ;
537547 const [ profilePendingRemoval , setProfilePendingRemoval ] = useState < BrowserProfile | null > ( null ) ;
538548
539549 const profiles = resolveBrowserProfiles ( userProfiles ) ;
550+ // Incognito is deliberately not a row — it holds nothing to manage — so the
551+ // default has to resolve against the list that renders. A stored
552+ // `browserDefaultProfileId` of "incognito" would otherwise leave the section
553+ // with no Default badge at all.
554+ const listedProfiles = profiles . filter ( ( profile ) => profile . kind !== "incognito" ) ;
540555 const resolvedDefaultId =
541- findBrowserProfile ( profiles , defaultProfileId ) ?. id ?? DEFAULT_BROWSER_PROFILE_ID ;
556+ findBrowserProfile ( listedProfiles , defaultProfileId ) ?. id ?? DEFAULT_BROWSER_PROFILE_ID ;
542557
543558 const uniqueName = ( base : string ) => {
544559 const taken = new Set ( profiles . map ( ( profile ) => profile . name ) ) ;
@@ -599,6 +614,10 @@ function BrowserProfilesSetting({ disabled }: { readonly disabled: boolean }) {
599614
600615 const loadSources = ( ) => {
601616 if ( ! previewBridge ) return ;
617+ // Cleared first: availability changes while the app runs (quitting a
618+ // browser clears `browserRunning`), and showing the previous answer during
619+ // the refresh lets the user start an import the source no longer supports.
620+ setSources ( null ) ;
602621 void previewBridge
603622 . listBrowserImportSources ( )
604623 . then ( setSources )
@@ -740,69 +759,70 @@ function BrowserProfilesSetting({ disabled }: { readonly disabled: boolean }) {
740759 }
741760 >
742761 < div className = "mt-2 overflow-hidden rounded-lg border border-border/60" >
743- { profiles
744- . filter ( ( profile ) => profile . kind !== "incognito" )
745- . map ( ( profile , index ) => {
746- const builtIn = isBuiltInBrowserProfileId ( profile . id ) ;
747- const isDefault = profile . id === resolvedDefaultId ;
748- return (
749- < div
750- key = { profile . id }
751- className = { cn (
752- "flex items-center gap-3 px-3 py-2" ,
753- index > 0 && "border-t border-border/60" ,
762+ { listedProfiles . map ( ( profile , index ) => {
763+ const builtIn = isBuiltInBrowserProfileId ( profile . id ) ;
764+ const isDefault = profile . id === resolvedDefaultId ;
765+ return (
766+ < div
767+ key = { profile . id }
768+ className = { cn (
769+ "flex items-center gap-3 px-3 py-2" ,
770+ index > 0 && "border-t border-border/60" ,
771+ ) }
772+ >
773+ < span className = "flex min-w-0 flex-1 items-center gap-2" >
774+ { builtIn ? (
775+ < span className = "truncate text-sm text-foreground" > { profile . name } </ span >
776+ ) : (
777+ < DraftInput
778+ nativeInput
779+ size = "sm"
780+ className = "w-full max-w-56"
781+ aria-label = { `Rename ${ profile . name } ` }
782+ disabled = { disabled }
783+ maxLength = { BROWSER_PROFILE_NAME_MAX_LENGTH }
784+ value = { profile . name }
785+ onCommit = { ( next ) => renameProfile ( profile . id , next ) }
786+ />
754787 ) }
755- >
756- < span className = "flex min-w-0 flex-1 items-center gap-2" >
757- { builtIn ? (
758- < span className = "truncate text-sm text-foreground" > { profile . name } </ span >
759- ) : (
760- < DraftInput
761- nativeInput
762- size = "sm"
763- className = "w-full max-w-56"
764- aria-label = { `Rename ${ profile . name } ` }
788+ { isDefault ? < Badge > Default</ Badge > : null }
789+ </ span >
790+ < Menu >
791+ < MenuTrigger
792+ render = {
793+ < Button
794+ size = "icon-sm"
795+ variant = "ghost-muted"
765796 disabled = { disabled }
766- maxLength = { BROWSER_PROFILE_NAME_MAX_LENGTH }
767- value = { profile . name }
768- onCommit = { ( next ) => renameProfile ( profile . id , next ) }
797+ aria-label = { `${ profile . name } options` }
769798 />
770- ) }
771- { isDefault ? < Badge > Default</ Badge > : null }
772- </ span >
773- < Menu >
774- < MenuTrigger
775- render = {
776- < Button
777- size = "icon-sm"
778- variant = "ghost-muted"
779- disabled = { disabled }
780- aria-label = { `${ profile . name } options` }
781- />
782- }
799+ }
800+ >
801+ < MoreVertical />
802+ </ MenuTrigger >
803+ < MenuPopup align = "end" className = "min-w-44" >
804+ < MenuItem
805+ disabled = { isDefault }
806+ onClick = { ( ) => updateSettings ( { browserDefaultProfileId : profile . id } ) }
783807 >
784- < MoreVertical />
785- </ MenuTrigger >
786- < MenuPopup align = "end" className = "min-w-44" >
808+ Set as default
809+ </ MenuItem >
810+ < MenuItem onClick = { ( ) => clearProfileData ( profile . id , profile . name ) } >
811+ Clear cookies and cache
812+ </ MenuItem >
813+ { builtIn ? null : (
787814 < MenuItem
788- disabled = { isDefault }
789- onClick = { ( ) => updateSettings ( { browserDefaultProfileId : profile . id } ) }
815+ variant = "destructive"
816+ onClick = { ( ) => setProfilePendingRemoval ( profile ) }
790817 >
791- Set as default
792- </ MenuItem >
793- < MenuItem onClick = { ( ) => clearProfileData ( profile . id , profile . name ) } >
794- Clear cookies and cache
818+ Remove profile and data
795819 </ MenuItem >
796- { builtIn ? null : (
797- < MenuItem variant = "destructive" onClick = { ( ) => removeProfile ( profile . id ) } >
798- Remove profile and data
799- </ MenuItem >
800- ) }
801- </ MenuPopup >
802- </ Menu >
803- </ div >
804- ) ;
805- } ) }
820+ ) }
821+ </ MenuPopup >
822+ </ Menu >
823+ </ div >
824+ ) ;
825+ } ) }
806826 </ div >
807827 < AlertDialog
808828 open = { profilePendingRemoval !== null }
0 commit comments