go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/frontend/ui/src/components/top_bar/top_bar.tsx (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { 16 useContext, 17 useMemo, 18 } from 'react'; 19 import { 20 Link as RouterLink, 21 useParams, 22 } from 'react-router-dom'; 23 24 import Link from '@mui/material/Link'; 25 import RuleIcon from '@mui/icons-material/Rule'; 26 import SpokeIcon from '@mui/icons-material/Spoke'; 27 import AppBar from '@mui/material/AppBar'; 28 import Box from '@mui/material/Box'; 29 import Button from '@mui/material/Button'; 30 // eslint-disable-next-line import/no-unresolved 31 import { OverridableComponent } from '@mui/material/OverridableComponent'; 32 import { SvgIconTypeMap } from '@mui/material/SvgIcon'; 33 import Toolbar from '@mui/material/Toolbar'; 34 35 import { DynamicComponentNoProps } from '@/tools/rendering_tools'; 36 37 import CollapsedMenu from './collapsed_menu/collapsed_menu'; 38 import Logo from './logo/logo'; 39 import { 40 TopBarContext, 41 TopBarContextProvider, 42 } from './top_bar_context'; 43 import UserActions from './user_actions/user_actions'; 44 45 type AppBarPageTitle = 'Clusters' | 'Rules'; 46 47 export interface AppBarPage { 48 title: AppBarPageTitle; 49 url: string; 50 icon: OverridableComponent<SvgIconTypeMap>; 51 } 52 53 function generatePages(projectId: string | undefined): AppBarPage[] { 54 if (!projectId) { 55 return []; 56 } 57 return [ 58 { 59 title: 'Clusters', 60 url: `/p/${projectId}/clusters`, 61 icon: SpokeIcon, 62 }, 63 { 64 title: 'Rules', 65 url: `/p/${projectId}/rules`, 66 icon: RuleIcon, 67 }, 68 ]; 69 } 70 71 const TopBar = () => { 72 const { setAnchorElNav } = useContext(TopBarContext); 73 74 const handleCloseNavMenu = () => { 75 setAnchorElNav(null); 76 }; 77 78 const { project: projectId } = useParams(); 79 80 const pages = useMemo<AppBarPage[]>(() => generatePages(projectId), [projectId]); 81 82 return ( 83 <TopBarContextProvider> 84 <AppBar position="static"> 85 <Toolbar > 86 <Box sx={{ 87 display: { 88 xs: 'none', 89 md: 'flex', 90 }, 91 mr: 1, 92 width: '3rem', 93 }}> 94 <Logo /> 95 </Box> 96 <Link 97 variant="h6" 98 noWrap 99 component={RouterLink} 100 to="/" 101 underline="none" 102 color="inherit" 103 sx={{ 104 mr: 2, 105 display: { xs: 'none', md: 'flex' }, 106 }}> 107 LUCI Analysis 108 </Link> 109 <CollapsedMenu pages={pages}/> 110 <Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}> 111 {pages.map((page) => ( 112 <Button 113 component={RouterLink} 114 to={page.url} 115 key={page.title} 116 onClick={handleCloseNavMenu} 117 sx={{ color: 'white' }} 118 startIcon={<DynamicComponentNoProps component={page.icon}/>} 119 > 120 {page.title} 121 </Button> 122 ))} 123 </Box> 124 <UserActions /> 125 </Toolbar> 126 </AppBar> 127 </TopBarContextProvider> 128 ); 129 }; 130 131 export default TopBar;