1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: last viewed project (#7191)

This commit is contained in:
Mateusz Kwasniewski 2024-05-28 15:47:26 +02:00 committed by GitHub
parent 61a8908694
commit dbc14fa7e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 103 additions and 24 deletions

View File

@ -9,14 +9,14 @@ import CustomStrategiesIcon from '@mui/icons-material/ExtensionOutlined';
import TagTypesIcon from '@mui/icons-material/LabelImportantOutlined'; import TagTypesIcon from '@mui/icons-material/LabelImportantOutlined';
import EnvironmentsIcon from '@mui/icons-material/CloudOutlined'; import EnvironmentsIcon from '@mui/icons-material/CloudOutlined';
import UsersIcon from '@mui/icons-material/GroupOutlined'; import UsersIcon from '@mui/icons-material/GroupOutlined';
import ServiceAccountIcon from '@mui/icons-material/SmartToyOutlined'; import ServiceAccountIcon from '@mui/icons-material/Computer';
import GroupsIcon from '@mui/icons-material/GroupsOutlined'; import GroupsIcon from '@mui/icons-material/GroupsOutlined';
import RoleIcon from '@mui/icons-material/AdminPanelSettingsOutlined'; import RoleIcon from '@mui/icons-material/AdminPanelSettingsOutlined';
import ApiAccessIcon from '@mui/icons-material/KeyOutlined'; import ApiAccessIcon from '@mui/icons-material/KeyOutlined';
import SingleSignOnIcon from '@mui/icons-material/AssignmentOutlined'; import SingleSignOnIcon from '@mui/icons-material/AssignmentOutlined';
import NetworkIcon from '@mui/icons-material/HubOutlined'; import NetworkIcon from '@mui/icons-material/HubOutlined';
import MaintenanceIcon from '@mui/icons-material/BuildOutlined'; import MaintenanceIcon from '@mui/icons-material/BuildOutlined';
import BannersIcon from '@mui/icons-material/PhotoOutlined'; import BannersIcon from '@mui/icons-material/ViewCarousel';
import InstanceStatsIcon from '@mui/icons-material/QueryStatsOutlined'; import InstanceStatsIcon from '@mui/icons-material/QueryStatsOutlined';
import LicenseIcon from '@mui/icons-material/ReceiptLongOutlined'; import LicenseIcon from '@mui/icons-material/ReceiptLongOutlined';
import InstancePrivacyIcon from '@mui/icons-material/ShieldOutlined'; import InstancePrivacyIcon from '@mui/icons-material/ShieldOutlined';

View File

@ -4,7 +4,9 @@ import {
ListItemButton, ListItemButton,
ListItemIcon, ListItemIcon,
ListItemText, ListItemText,
styled,
Tooltip, Tooltip,
Typography,
} from '@mui/material'; } from '@mui/material';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { basePath } from 'utils/formatPath'; import { basePath } from 'utils/formatPath';
@ -19,6 +21,13 @@ const listItemButtonStyle = (theme: Theme) => ({
}, },
}); });
const CappedText = styled(Typography)({
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '160px',
});
export const FullListItem: FC<{ export const FullListItem: FC<{
href: string; href: string;
text: string; text: string;
@ -38,7 +47,9 @@ export const FullListItem: FC<{
<ListItemIcon sx={(theme) => ({ minWidth: theme.spacing(4) })}> <ListItemIcon sx={(theme) => ({ minWidth: theme.spacing(4) })}>
{children} {children}
</ListItemIcon> </ListItemIcon>
<ListItemText sx={{ whiteSpace: 'nowrap' }} primary={text} /> <ListItemText>
<CappedText>{text}</CappedText>
</ListItemText>
{badge} {badge}
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>

View File

@ -7,7 +7,7 @@ import {
MiniListItem, MiniListItem,
SignOutItem, SignOutItem,
} from './ListItems'; } from './ListItems';
import { List, styled, Tooltip, Typography } from '@mui/material'; import { Box, List, styled, Tooltip, Typography } from '@mui/material';
import { IconRenderer, StyledProjectIcon } from './IconRenderer'; import { IconRenderer, StyledProjectIcon } from './IconRenderer';
import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge'; import { EnterpriseBadge } from 'component/common/EnterpriseBadge/EnterpriseBadge';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
@ -98,6 +98,27 @@ export const OtherLinksList = () => {
); );
}; };
export const RecentProjectsList: FC<{
projectId: string;
mode: NavigationMode;
onClick: () => void;
}> = ({ projectId, mode, onClick }) => {
const DynamicListItem = mode === 'mini' ? MiniListItem : FullListItem;
return (
<List>
<DynamicListItem
href={`/projects/${projectId}`}
text={projectId}
onClick={onClick}
selected={false}
>
<StyledProjectIcon />
</DynamicListItem>
</List>
);
};
export const PrimaryNavigationList: FC<{ export const PrimaryNavigationList: FC<{
mode: NavigationMode; mode: NavigationMode;
onClick: (activeItem: string) => void; onClick: (activeItem: string) => void;
@ -177,3 +198,26 @@ export const SecondaryNavigation: FC<{
</Accordion> </Accordion>
); );
}; };
export const RecentProjectsNavigation: FC<{
mode: NavigationMode;
projectId: string;
onClick: () => void;
}> = ({ mode, onClick, projectId }) => {
return (
<Box>
{mode === 'full' && (
<Typography
sx={{ fontWeight: 'bold', fontSize: 'small', mb: 1, ml: 1 }}
>
Recent project
</Typography>
)}
<RecentProjectsList
projectId={projectId}
mode={mode}
onClick={onClick}
/>
</Box>
);
};

View File

@ -7,10 +7,12 @@ import { useExpanded } from './useExpanded';
import { import {
OtherLinksList, OtherLinksList,
PrimaryNavigationList, PrimaryNavigationList,
RecentProjectsNavigation,
SecondaryNavigation, SecondaryNavigation,
SecondaryNavigationList, SecondaryNavigationList,
} from './NavigationList'; } from './NavigationList';
import { useInitialPathname } from './useInitialPathname'; import { useInitialPathname } from './useInitialPathname';
import { useLastViewedProject } from 'hooks/useLastViewedProject';
export const MobileNavigationSidebar: FC<{ onClick: () => void }> = ({ export const MobileNavigationSidebar: FC<{ onClick: () => void }> = ({
onClick, onClick,
@ -37,7 +39,11 @@ export const MobileNavigationSidebar: FC<{ onClick: () => void }> = ({
export const StyledBox = styled(Box)(({ theme }) => ({ export const StyledBox = styled(Box)(({ theme }) => ({
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
padding: theme.spacing(2, 2, 6, 2), padding: theme.spacing(2, 2, 2, 2),
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(3),
zIndex: theme.zIndex.tooltip,
})); }));
export const NavigationSidebar = () => { export const NavigationSidebar = () => {
@ -49,6 +55,9 @@ export const NavigationSidebar = () => {
const [activeItem, setActiveItem] = useState(initialPathname); const [activeItem, setActiveItem] = useState(initialPathname);
const { lastViewed } = useLastViewedProject();
const showRecentProject = mode === 'full' && lastViewed;
return ( return (
<StyledBox> <StyledBox>
<PrimaryNavigationList <PrimaryNavigationList
@ -71,21 +80,32 @@ export const NavigationSidebar = () => {
activeItem={activeItem} activeItem={activeItem}
/> />
</SecondaryNavigation> </SecondaryNavigation>
<SecondaryNavigation {mode === 'full' && (
expanded={expanded.includes('admin')} <SecondaryNavigation
onExpandChange={(expand) => { expanded={expanded.includes('admin')}
changeExpanded('admin', expand); onExpandChange={(expand) => {
}} changeExpanded('admin', expand);
mode={mode} }}
title='Admin'
>
<SecondaryNavigationList
routes={routes.adminRoutes}
mode={mode} mode={mode}
onClick={setActiveItem} title='Admin'
activeItem={activeItem} >
<SecondaryNavigationList
routes={routes.adminRoutes}
mode={mode}
onClick={setActiveItem}
activeItem={activeItem}
/>
</SecondaryNavigation>
)}
{showRecentProject && (
<RecentProjectsNavigation
mode={mode}
projectId={lastViewed}
onClick={() => setActiveItem('/projects')}
/> />
</SecondaryNavigation> )}
<ShowHide <ShowHide
mode={mode} mode={mode}
onChange={() => { onChange={() => {

View File

@ -1,8 +1,8 @@
import { Box, IconButton, styled, Tooltip } from '@mui/material'; import { Box, IconButton, styled, Tooltip } from '@mui/material';
import type { NavigationMode } from './NavigationMode'; import type { NavigationMode } from './NavigationMode';
import type { FC } from 'react'; import type { FC } from 'react';
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; import HideIcon from '@mui/icons-material/KeyboardDoubleArrowLeft';
import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import ExpandIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
const ShowHideWrapper = styled(Box, { const ShowHideWrapper = styled(Box, {
shouldForwardProp: (prop) => prop !== 'mode', shouldForwardProp: (prop) => prop !== 'mode',
@ -10,7 +10,8 @@ const ShowHideWrapper = styled(Box, {
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',
margin: theme.spacing(2, 1, 0, mode === 'mini' ? 1.5 : 2), padding: theme.spacing(2, 1, 0, mode === 'mini' ? 1.5 : 2),
marginTop: 'auto',
cursor: 'pointer', cursor: 'pointer',
})); }));
@ -32,10 +33,13 @@ export const ShowHide: FC<{ mode: NavigationMode; onChange: () => void }> = ({
)} )}
<IconButton> <IconButton>
{mode === 'full' ? ( {mode === 'full' ? (
<ChevronLeftIcon /> <HideIcon color='primary' />
) : ( ) : (
<Tooltip title='Expand (⌘ + B)' placement='right'> <Tooltip title='Expand (⌘ + B)' placement='right'>
<ChevronRightIcon data-testid='expand-navigation' /> <ExpandIcon
data-testid='expand-navigation'
color='primary'
/>
</Tooltip> </Tooltip>
)} )}
</IconButton> </IconButton>

View File

@ -5,7 +5,7 @@ import { basePath } from 'utils/formatPath';
export const useLastViewedProject = () => { export const useLastViewedProject = () => {
const key = `${basePath}:unleash-lastViewedProject`; const key = `${basePath}:unleash-lastViewedProject`;
const [lastViewed, setLastViewed] = useState(() => { const [lastViewed, setLastViewed] = useState<string | undefined>(() => {
return getLocalStorageItem(key); return getLocalStorageItem(key);
}); });