@@ -38,6 +38,7 @@ import {
3838import { buildMonteCarloProjection } from "./analytics-projection.js" ;
3939import { summarizeBootThroughput } from "./analytics-metrics.js" ;
4040import { formatCompactNumber , formatSignedCompactNumber } from "./number-format.js" ;
41+ import { handleKeyboardActivation , shouldIgnoreGlobalShortcut } from "./keyboard-access.js" ;
4142import {
4243 readControlCenterSettings ,
4344 summarizeBudgetStatus ,
@@ -3905,10 +3906,36 @@ export function App() {
39053906 } ;
39063907 } , [ api , call , callMcpTool , cortexBase , readAuthToken , runRefreshAll , runRestartDaemonSequence , waitForDaemonReachable , writeDevVerificationReport ] ) ;
39073908
3909+ useEffect ( ( ) => {
3910+ if ( ! showConnectionDialog && ! showEditorSetupWizard ) {
3911+ return undefined ;
3912+ }
3913+
3914+ function handleDialogKey ( event ) {
3915+ if ( event . key !== "Escape" ) {
3916+ return ;
3917+ }
3918+
3919+ if ( showEditorSetupWizard && ! isSettingUpEditors ) {
3920+ event . preventDefault ( ) ;
3921+ setShowEditorSetupWizard ( false ) ;
3922+ return ;
3923+ }
3924+
3925+ if ( showConnectionDialog ) {
3926+ event . preventDefault ( ) ;
3927+ dismissConnectionDialog ( ) ;
3928+ }
3929+ }
3930+
3931+ window . addEventListener ( "keydown" , handleDialogKey ) ;
3932+ return ( ) => window . removeEventListener ( "keydown" , handleDialogKey ) ;
3933+ } , [ dismissConnectionDialog , isSettingUpEditors , showConnectionDialog , showEditorSetupWizard ] ) ;
3934+
39083935 // Keyboard nav
39093936 useEffect ( ( ) => {
39103937 function handleKey ( e ) {
3911- if ( e . target . tagName === "INPUT" || e . target . tagName === "SELECT" || e . target . tagName === "TEXTAREA" ) return ;
3938+ if ( shouldIgnoreGlobalShortcut ( e , showConnectionDialog || showEditorSetupWizard ) ) return ;
39123939 const idx = panelIndex ( panel ) ;
39133940 if ( e . key === "ArrowDown" || e . key === "j" ) {
39143941 e . preventDefault ( ) ;
@@ -3926,7 +3953,7 @@ export function App() {
39263953 }
39273954 window . addEventListener ( "keydown" , handleKey ) ;
39283955 return ( ) => window . removeEventListener ( "keydown" , handleKey ) ;
3929- } , [ changePanel , panel ] ) ;
3956+ } , [ changePanel , panel , showConnectionDialog , showEditorSetupWizard ] ) ;
39303957
39313958 const effectiveSidebarCollapsed = sidebarCollapsed || isNarrowViewport ;
39323959 const canStartDaemon = Boolean ( invokeRef . current && ! restartingDaemon && ! daemonState . running ) ;
@@ -4076,10 +4103,16 @@ export function App() {
40764103 < span className = "topbar-stat" > < span className = "topbar-label" > DEC</ span > { stats . decisions } </ span >
40774104 < span className = "topbar-stat" > < span className = "topbar-label" > EVT</ span > { stats . events } </ span >
40784105 < span className = "topbar-stat" > < span className = "topbar-label" > AGENTS</ span > { normalizedSessions . length } </ span >
4079- < span className = "topbar-stat topbar-connection" onClick = { openConnectionDialog } title = "Click to change connection" >
4106+ < button
4107+ type = "button"
4108+ className = "topbar-stat topbar-connection"
4109+ onClick = { openConnectionDialog }
4110+ title = "Click to change connection"
4111+ aria-label = { `Connection host ${ hostLabel } . Open connection settings.` }
4112+ >
40804113 < span className = "topbar-label" > HOST</ span >
40814114 { hostLabel }
4082- </ span >
4115+ </ button >
40834116 < span className = { `topbar-status ${ daemonStatusBadge . className } ` } title = { daemonStatusBadge . title } >
40844117 { daemonStatusBadge . label }
40854118 </ span >
@@ -4489,20 +4522,27 @@ export function App() {
44894522 < span className = "sys-label" > TASKS</ span >
44904523 < span className = "sys-value" > { pendingTasks . length } PENDING</ span >
44914524 </ div >
4492- < div
4525+ < button
4526+ type = "button"
44934527 className = { `sys-item sys-item-action ${ isSettingUpEditors ? "sys-item-disabled" : "" } ` }
4494- onClick = { isSettingUpEditors ? undefined : openEditorSetupWizard }
4495- title = "Preview and register Cortex MCP in supported clients"
4528+ onClick = { openEditorSetupWizard }
4529+ title = "Preview and register Cortex MCP in supported clients"
4530+ disabled = { isSettingUpEditors }
44964531 >
44974532 < span className = "sys-label" > MCP</ span >
44984533 < span className = "sys-value" >
44994534 { isSettingUpEditors ? "WORKING" : editorSetup ? `${ editorSetupSummary . registered } EDITORS` : "SETUP" }
45004535 </ span >
4501- </ div >
4502- < div className = "sys-item sys-item-action" onClick = { ( ) => changePanel ( "memory" ) } title = "Open memory health and conflict resolution" >
4536+ </ button >
4537+ < button
4538+ type = "button"
4539+ className = "sys-item sys-item-action"
4540+ onClick = { ( ) => changePanel ( "memory" ) }
4541+ title = "Open memory health and conflict resolution"
4542+ >
45034543 < span className = "sys-label" > RECALL</ span >
45044544 < span className = { `sys-value ${ latestRecallHitRate >= 85 ? "sys-ok" : "" } ` } > { latestRecallHitRate || 0 } %</ span >
4505- </ div >
4545+ </ button >
45064546 </ div >
45074547
45084548 { editorSetupSummary . results . length ? (
@@ -5115,7 +5155,17 @@ export function App() {
51155155 ) : null }
51165156 < ul className = "item-list" >
51175157 { memoryResults . length ? memoryResults . map ( ( match , index ) => (
5118- < li key = { `${ match . source } -${ index } ` } className = "memory-item" onClick = { ( ) => ! match . expanded && handleMemoryExpand ( match . source ) } >
5158+ < li
5159+ key = { `${ match . source } -${ index } ` }
5160+ className = { `memory-item ${ match . expanded ? "" : "memory-item-action" } ` }
5161+ role = { match . expanded ? undefined : "button" }
5162+ tabIndex = { match . expanded ? undefined : 0 }
5163+ aria-expanded = { match . expanded ? undefined : false }
5164+ onClick = { ( ) => ! match . expanded && handleMemoryExpand ( match . source ) }
5165+ onKeyDown = { ( event ) =>
5166+ ! match . expanded && handleKeyboardActivation ( event , ( ) => handleMemoryExpand ( match . source ) )
5167+ }
5168+ >
51195169 < div className = "memory-header" >
51205170 < span className = "memory-method" > { match . method } </ span >
51215171 < span className = "memory-relevance" > { ( match . relevance * 100 ) . toFixed ( 0 ) } %</ span >
@@ -5124,7 +5174,7 @@ export function App() {
51245174 { match . expanded && match . excerpt ? (
51255175 < div className = "memory-excerpt" > { match . excerpt } </ div >
51265176 ) : null }
5127- { ! match . expanded ? < div className = "memory-expand-hint" > Click to expand</ div > : null }
5177+ { ! match . expanded ? < div className = "memory-expand-hint" > Press Enter or Space to expand</ div > : null }
51285178 </ li >
51295179 ) ) : memoryQuery ? < EmptyItem text = "No matches -- try different keywords" /> : < EmptyItem text = "Search to explore Cortex memories" /> }
51305180 </ ul >
0 commit comments