@@ -163,6 +163,7 @@ import {
163163 findHighlightedCommandPaletteItem ,
164164 type CommandPaletteActionItem ,
165165 type CommandPaletteOpenIntent ,
166+ type CommandPaletteProject ,
166167 type CommandPaletteSubmenuItem ,
167168 type CommandPaletteView ,
168169 filterCommandPaletteGroups ,
@@ -1309,89 +1310,94 @@ function OpenCommandPaletteDialog(props: {
13091310 ] ,
13101311 ) ;
13111312
1312- const projectThreadItems = useMemo (
1313- ( ) =>
1314- enumerateCommandPaletteItems ( [
1315- ...buildProjectActionItems ( {
1316- // The no-project home shows once, as the "No project" item below.
1317- projects : pickerProjects . filter (
1318- ( project ) => ! isScratchProject ( project , scratchWorkspaceRootFor ( project . environmentId ) ) ,
1319- ) ,
1320- valuePrefix : "new-thread-in" ,
1321- searchTerms : ( project ) => {
1322- const group = projectGroupByTargetKey . get ( `${ project . environmentId } :${ project . id } ` ) ;
1323- const location = projectEnvironmentLocationById . get ( project . environmentId ) ;
1324- return [
1325- ...( group ?. memberProjects . flatMap ( ( member ) => [ member . title , member . workspaceRoot ] ) ??
1326- [ ] ) ,
1327- ...( location ? [ location . label ] : [ ] ) ,
1328- ] ;
1329- } ,
1330- renderDescription : ( project ) => {
1331- const location = projectEnvironmentLocationById . get ( project . environmentId ) ?? {
1332- kind : "remote" ,
1333- label : "Remote" ,
1334- machine : "server" as const ,
1335- } ;
1336- return (
1337- < span className = "flex min-w-0 items-center gap-1" >
1338- < span className = "inline-flex min-w-0 items-center gap-1" >
1339- { location . kind === "remote" ? (
1340- < EnvironmentMachineIcon
1341- aria-hidden
1342- kind = { location . machine }
1343- className = { COMMAND_PALETTE_META_ICON_CLASS }
1344- />
1345- ) : null }
1346- < span className = "truncate" > { location . label } </ span >
1347- </ span >
1348- < CommandPaletteMetaDot />
1349- < span className = "truncate" > { project . workspaceRoot } </ span >
1313+ const projectThreadItems = useMemo ( ( ) => {
1314+ const isScratch = ( project : CommandPaletteProject ) =>
1315+ isScratchProject ( project , scratchWorkspaceRootFor ( project . environmentId ) ) ;
1316+ const projectItems = enumerateCommandPaletteItems (
1317+ buildProjectActionItems ( {
1318+ // The no-project home shows once, as the "No project" item below.
1319+ projects : pickerProjects . filter ( ( project ) => ! isScratch ( project ) ) ,
1320+ valuePrefix : "new-thread-in" ,
1321+ searchTerms : ( project ) => {
1322+ const group = projectGroupByTargetKey . get ( `${ project . environmentId } :${ project . id } ` ) ;
1323+ const location = projectEnvironmentLocationById . get ( project . environmentId ) ;
1324+ return [
1325+ ...( group ?. memberProjects . flatMap ( ( member ) => [ member . title , member . workspaceRoot ] ) ??
1326+ [ ] ) ,
1327+ ...( location ? [ location . label ] : [ ] ) ,
1328+ ] ;
1329+ } ,
1330+ renderDescription : ( project ) => {
1331+ const location = projectEnvironmentLocationById . get ( project . environmentId ) ?? {
1332+ kind : "remote" ,
1333+ label : "Remote" ,
1334+ machine : "server" as const ,
1335+ } ;
1336+ return (
1337+ < span className = "flex min-w-0 items-center gap-1" >
1338+ < span className = "inline-flex min-w-0 items-center gap-1" >
1339+ { location . kind === "remote" ? (
1340+ < EnvironmentMachineIcon
1341+ aria-hidden
1342+ kind = { location . machine }
1343+ className = { COMMAND_PALETTE_META_ICON_CLASS }
1344+ />
1345+ ) : null }
1346+ < span className = "truncate" > { location . label } </ span >
13501347 </ span >
1348+ < CommandPaletteMetaDot />
1349+ < span className = "truncate" > { project . workspaceRoot } </ span >
1350+ </ span >
1351+ ) ;
1352+ } ,
1353+ icon : projectFaviconIcon ,
1354+ runProject : async ( project ) => {
1355+ const group = projectGroupByTargetKey . get ( `${ project . environmentId } :${ project . id } ` ) ;
1356+ const contextualRefBelongsToGroup =
1357+ contextualProjectRef !== null &&
1358+ group ?. memberProjectRefs . some (
1359+ ( projectRef ) =>
1360+ projectRef . environmentId === contextualProjectRef . environmentId &&
1361+ projectRef . projectId === contextualProjectRef . projectId ,
13511362 ) ;
1352- } ,
1353- icon : projectFaviconIcon ,
1354- runProject : async ( project ) => {
1355- const group = projectGroupByTargetKey . get ( `${ project . environmentId } :${ project . id } ` ) ;
1356- const contextualRefBelongsToGroup =
1357- contextualProjectRef !== null &&
1358- group ?. memberProjectRefs . some (
1359- ( projectRef ) =>
1360- projectRef . environmentId === contextualProjectRef . environmentId &&
1361- projectRef . projectId === contextualProjectRef . projectId ,
1362- ) ;
1363- await handleNewThread (
1364- contextualRefBelongsToGroup
1365- ? contextualProjectRef
1366- : scopeProjectRef ( project . environmentId , project . id ) ,
1367- ) ;
1368- } ,
1369- } ) ,
1370- ...( scratchTargetEnvironmentId === null
1371- ? [ ]
1372- : [
1373- {
1374- kind : "action" as const ,
1375- value : "new-thread-in:no-project" ,
1376- searchTerms : [ "no project" , "without project" , "none" ] ,
1377- title : "No project" ,
1378- icon : < MessageSquareDashedIcon className = { ITEM_ICON_CLASS } /> ,
1379- shortcutCommand : "chat.newWithoutProject" as const ,
1380- run : ( ) => startScratchThread ( scratchTargetEnvironmentId ) ,
1381- } ,
1382- ] ) ,
1383- ] ) ,
1384- [
1385- contextualProjectRef ,
1386- handleNewThread ,
1387- pickerProjects ,
1388- projectEnvironmentLocationById ,
1389- projectGroupByTargetKey ,
1390- scratchTargetEnvironmentId ,
1391- scratchWorkspaceRootFor ,
1392- startScratchThread ,
1393- ] ,
1394- ) ;
1363+ await handleNewThread (
1364+ contextualRefBelongsToGroup
1365+ ? contextualProjectRef
1366+ : scopeProjectRef ( project . environmentId , project . id ) ,
1367+ ) ;
1368+ } ,
1369+ } ) ,
1370+ ) ;
1371+ if ( scratchTargetEnvironmentId === null ) return projectItems ;
1372+
1373+ // "No project" goes right after the current project: visible without
1374+ // scrolling past every project, while Enter still starts in the current
1375+ // one. When the current thread has no project, it is the current entry and
1376+ // goes first. It keeps its own shortcut, so the projects' mod+1..9 hold.
1377+ const noProjectIndex = pickerProjects [ 0 ] !== undefined && isScratch ( pickerProjects [ 0 ] ) ? 0 : 1 ;
1378+ return [
1379+ ...projectItems . slice ( 0 , noProjectIndex ) ,
1380+ {
1381+ kind : "action" as const ,
1382+ value : "new-thread-in:no-project" ,
1383+ searchTerms : [ "no project" , "without project" , "none" ] ,
1384+ title : "No project" ,
1385+ icon : < MessageSquareDashedIcon className = { ITEM_ICON_CLASS } /> ,
1386+ shortcutCommand : "chat.newWithoutProject" as const ,
1387+ run : ( ) => startScratchThread ( scratchTargetEnvironmentId ) ,
1388+ } ,
1389+ ...projectItems . slice ( noProjectIndex ) ,
1390+ ] ;
1391+ } , [
1392+ contextualProjectRef ,
1393+ handleNewThread ,
1394+ pickerProjects ,
1395+ projectEnvironmentLocationById ,
1396+ projectGroupByTargetKey ,
1397+ scratchTargetEnvironmentId ,
1398+ scratchWorkspaceRootFor ,
1399+ startScratchThread ,
1400+ ] ) ;
13951401
13961402 const allThreadItems = useMemo (
13971403 ( ) =>
@@ -1848,35 +1854,12 @@ function OpenCommandPaletteDialog(props: {
18481854 setNewProjectFlow ( null ) ;
18491855 setViewStack ( [ ] ) ;
18501856 setQuery ( "" ) ;
1851- const currentPrefix =
1852- currentProjectEnvironmentId && currentProjectId
1853- ? `new-thread-in:${ currentProjectEnvironmentId } :${ currentProjectId } `
1854- : null ;
1855- const prioritized = currentPrefix
1856- ? [
1857- ...projectThreadItems . filter ( ( item ) => item . value === currentPrefix ) ,
1858- ...projectThreadItems . filter ( ( item ) => item . value !== currentPrefix ) ,
1859- ]
1860- : projectThreadItems ;
1857+ // projectThreadItems already lists the current project first.
18611858 pushPaletteView ( {
18621859 addonIcon : < SquarePenIcon className = { ADDON_ICON_CLASS } /> ,
1863- groups : [
1864- {
1865- value : "projects" ,
1866- label : "Projects" ,
1867- items : enumerateCommandPaletteItems ( prioritized ) ,
1868- } ,
1869- ] ,
1860+ groups : [ { value : "projects" , label : "Projects" , items : projectThreadItems } ] ,
18701861 } ) ;
1871- } , [
1872- clearOpenIntent ,
1873- browseNavigation ,
1874- currentProjectEnvironmentId ,
1875- currentProjectId ,
1876- openIntent ,
1877- projectThreadItems ,
1878- pushPaletteView ,
1879- ] ) ;
1862+ } , [ clearOpenIntent , browseNavigation , openIntent , projectThreadItems , pushPaletteView ] ) ;
18801863
18811864 const actionItems : Array < CommandPaletteActionItem | CommandPaletteSubmenuItem > = [ ] ;
18821865
0 commit comments