@@ -4,34 +4,46 @@ import { useHistory } from 'react-router-dom'
44import {
55 API_STATUS_CODES ,
66 Backdrop ,
7- GenericFilterEmptyState ,
7+ GenericSectionErrorState ,
88 getUserPreferences ,
99 KeyboardShortcut ,
1010 logExceptionToSentry ,
11+ noop ,
1112 ResponseType ,
1213 SearchBar ,
1314 stopPropagation ,
1415 SupportedKeyboardKeysType ,
1516 ToastManager ,
1617 ToastVariantType ,
1718 updateUserPreferences ,
19+ useMainContext ,
1820 useQuery ,
1921 useRegisterShortcut ,
2022 UserPreferencesType ,
2123} from '@devtron-labs/devtron-fe-common-lib'
2224
2325import CommandGroup from './CommandGroup'
24- import { NAVIGATION_GROUPS , RECENT_ACTIONS_GROUP , RECENT_NAVIGATION_ITEM_ID_PREFIX , SHORT_CUTS } from './constants'
26+ import { RECENT_ACTIONS_GROUP , RECENT_NAVIGATION_ITEM_ID_PREFIX , SHORT_CUTS } from './constants'
2527import { CommandBarBackdropProps , CommandBarGroupType } from './types'
26- import { getNewSelectedIndex , sanitizeItemId } from './utils'
27-
28- const CommandBarBackdrop = ( { handleClose } : CommandBarBackdropProps ) => {
28+ import {
29+ getAdditionalNavGroups ,
30+ getNavigationGroups ,
31+ getNewSelectedIndex ,
32+ parseAppListToNavItems ,
33+ sanitizeItemId ,
34+ } from './utils'
35+
36+ const CommandBarBackdrop = ( { handleClose, isLoadingAppList, appList } : CommandBarBackdropProps ) => {
2937 const history = useHistory ( )
3038 const { registerShortcut, unregisterShortcut } = useRegisterShortcut ( )
3139
3240 const [ searchText , setSearchText ] = useState ( '' )
3341 const [ selectedItemIndex , setSelectedItemIndex ] = useState ( 0 )
3442
43+ const { serverMode, isSuperAdmin } = useMainContext ( )
44+
45+ const navigationGroups = useMemo ( ( ) => getNavigationGroups ( serverMode , isSuperAdmin ) , [ serverMode , isSuperAdmin ] )
46+
3547 const { data : recentActionsGroup , isLoading } = useQuery ( {
3648 queryFn : ( { signal } ) =>
3749 getUserPreferences ( signal ) . then ( ( response ) => {
@@ -45,14 +57,16 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
4557 queryKey : [ 'recentNavigationActions' ] ,
4658 select : ( { result } ) =>
4759 result . commandBar . recentNavigationActions . reduce < CommandBarGroupType > ( ( acc , action ) => {
48- const requiredGroup = structuredClone ( NAVIGATION_GROUPS ) . find ( ( group ) =>
49- group . items . some ( ( item ) => item . id === action . id ) ,
50- )
60+ const allGroups = [ ... navigationGroups , ... parseAppListToNavItems ( appList ) ]
61+
62+ const requiredGroup = allGroups . find ( ( group ) => group . items . some ( ( item ) => item . id === action . id ) )
5163
5264 if ( requiredGroup ) {
5365 const requiredItem = requiredGroup . items . find ( ( item ) => item . id === action . id )
54- requiredItem . id = `${ RECENT_NAVIGATION_ITEM_ID_PREFIX } ${ action . id } `
55- acc . items . push ( requiredItem )
66+ acc . items . push ( {
67+ ...requiredItem ,
68+ id : `${ RECENT_NAVIGATION_ITEM_ID_PREFIX } ${ action . id } ` ,
69+ } )
5670 }
5771 return acc
5872 } , structuredClone ( RECENT_ACTIONS_GROUP ) ) ,
@@ -78,10 +92,11 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
7892 const lowerCaseSearchText = searchText . toLowerCase ( )
7993
8094 if ( ! searchText ) {
81- return NAVIGATION_GROUPS
95+ return navigationGroups
8296 }
8397
84- return NAVIGATION_GROUPS . reduce < typeof NAVIGATION_GROUPS > ( ( acc , group ) => {
98+ const additionalGroups = getAdditionalNavGroups ( searchText , appList )
99+ const parsedGroups = navigationGroups . reduce < typeof navigationGroups > ( ( acc , group ) => {
85100 const filteredItems = group . items . filter ( ( item ) => item . title . toLowerCase ( ) . includes ( lowerCaseSearchText ) )
86101
87102 if ( filteredItems . length > 0 ) {
@@ -93,31 +108,28 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
93108
94109 return acc
95110 } , [ ] )
111+
112+ const combinedGroups = [ ...additionalGroups , ...parsedGroups ]
113+
114+ return combinedGroups
96115 } , [ searchText ] )
97116
117+ const showEmptyState = areFiltersApplied && ! filteredGroups . length
118+
98119 const itemFlatList : CommandBarGroupType [ 'items' ] = useMemo ( ( ) => {
99120 if ( areFiltersApplied ) {
100121 return filteredGroups . flatMap ( ( group ) => group . items )
101122 }
102123
103124 return recentActionsGroup
104- ? [ ...recentActionsGroup . items , ...NAVIGATION_GROUPS . flatMap ( ( group ) => group . items ) ]
105- : [ ...NAVIGATION_GROUPS . flatMap ( ( group ) => group . items ) ]
125+ ? [ ...recentActionsGroup . items , ...navigationGroups . flatMap ( ( group ) => group . items ) ]
126+ : [ ...navigationGroups . flatMap ( ( group ) => group . items ) ]
106127 } , [ areFiltersApplied , recentActionsGroup , filteredGroups ] )
107128
108129 const handleClearFilters = ( ) => {
109130 setSearchText ( '' )
110131 }
111132
112- const handleEscape = ( ) => {
113- if ( searchText ) {
114- handleClearFilters ( )
115- return
116- }
117-
118- handleClose ( )
119- }
120-
121133 const focusSearchBar = ( ) => {
122134 if ( searchBarRef . current ) {
123135 searchBarRef . current . focus ( )
@@ -199,18 +211,27 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
199211 } , [ isLoading , recentActionsGroup ] )
200212
201213 useEffect ( ( ) => {
202- const { keys, description } = SHORT_CUTS . FOCUS_SEARCH_BAR
214+ const handleKeyDown = ( e : KeyboardEvent ) => {
215+ if ( e . key === 'Escape' ) {
216+ e . stopPropagation ( )
217+
218+ if ( searchText ) {
219+ handleClearFilters ( )
220+ setTimeout ( ( ) => {
221+ focusSearchBar ( )
222+ } , 100 )
223+ } else {
224+ handleClose ( )
225+ }
226+ }
227+ }
203228
204- registerShortcut ( {
205- keys,
206- description,
207- callback : focusSearchBar ,
208- } )
229+ window . addEventListener ( 'keydown' , handleKeyDown )
209230
210231 return ( ) => {
211- unregisterShortcut ( keys )
232+ window . removeEventListener ( 'keydown' , handleKeyDown )
212233 }
213- } , [ ] )
234+ } , [ searchText ] )
214235
215236 useEffect ( ( ) => {
216237 const { keys, description } = SHORT_CUTS . ENTER_ITEM
@@ -283,13 +304,18 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
283304 )
284305
285306 return (
286- < Backdrop onEscape = { handleEscape } onClick = { handleClose } deactivateFocusOnEscape = { ! ! searchText } >
307+ < Backdrop
308+ onEscape = { noop }
309+ onClick = { handleClose }
310+ deactivateFocusOnEscape = { ! ! searchText }
311+ returnFocusOnDeactivate = { false }
312+ >
287313 < div
288314 onClick = { stopPropagation }
289- className = "dc__mxw-800 mxh-450 flexbox-col dc__overflow-hidden dc__content-space br-12 bg__modal--primary command-bar__container w-100 h-100"
315+ className = "dc__mxw-720 mxh-500 flexbox-col dc__overflow-hidden dc__content-space br-12 bg__modal--primary command-bar__container w-100 h-100"
290316 >
291- < div className = "flexbox-col dc__overflow-hidden" >
292- < div className = "px-20 py-8 " >
317+ < div className = "flexbox-col dc__overflow-hidden flex-grow-1 " >
318+ < div className = "px-16 py-12 " >
293319 < SearchBar
294320 inputProps = { {
295321 autoFocus : true ,
@@ -299,14 +325,22 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
299325 initialSearchText = { searchText }
300326 handleSearchChange = { handleSearchChange }
301327 noBackgroundAndBorder
328+ shouldDebounce
329+ isLoading = { isLoadingAppList }
302330 />
303331 </ div >
304332
305- { areFiltersApplied && ! filteredGroups . length ? (
306- < GenericFilterEmptyState handleClearFilters = { handleClearFilters } />
333+ { showEmptyState ? (
334+ < GenericSectionErrorState
335+ title = "No results found"
336+ subTitle = ""
337+ description = ""
338+ useInfoIcon
339+ rootClassName = "flex-grow-1"
340+ />
307341 ) : (
308342 < div
309- className = "flexbox-col dc__overflow-auto border__primary--top pt-8 "
343+ className = "flexbox-col dc__overflow-auto border__primary--top"
310344 role = "listbox"
311345 aria-label = "Command Menu"
312346 aria-activedescendant = { itemFlatList [ selectedItemIndex ] ?. id }
@@ -331,12 +365,17 @@ const CommandBarBackdrop = ({ handleClose }: CommandBarBackdropProps) => {
331365 </ div >
332366
333367 < div className = "flexbox dc__content-space dc__align-items-center px-20 py-12 border__primary--top bg__secondary" >
334- < div className = "flexbox dc__gap-20 dc__align-items-center" >
335- { renderKeyboardShortcuts ( [ 'ArrowUp' , 'ArrowDown' ] , 'to navigate' ) }
336- { renderKeyboardShortcuts ( [ 'Enter' ] , 'to select' ) }
337- { renderKeyboardShortcuts ( [ 'Escape' ] , 'to close' ) }
368+ < div
369+ className = { `flexbox dc__gap-20 dc__align-items-center flex-grow-1 ${ showEmptyState ? 'dc__content-center' : '' } ` }
370+ >
371+ { ! showEmptyState && (
372+ < >
373+ { renderKeyboardShortcuts ( [ 'ArrowUp' , 'ArrowDown' ] , 'to navigate' ) }
374+ { renderKeyboardShortcuts ( [ 'Enter' ] , 'to select' ) }
375+ </ >
376+ ) }
377+ { renderKeyboardShortcuts ( [ 'Escape' ] , searchText ? 'to clear search' : 'to close' ) }
338378 </ div >
339- { renderKeyboardShortcuts ( [ '>' ] , 'to search actions' ) }
340379 </ div >
341380 </ div >
342381 </ Backdrop >
0 commit comments