Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 130 additions & 65 deletions src/components/NavItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import ListItemButton from '@mui/material/ListItemButton';
import Collapse from '@mui/material/Collapse';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import ListSubheader from '@mui/material/ListSubheader';
import Tooltip from '@mui/material/Tooltip';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';
import UserIcon from '@mui/icons-material/Person';
Expand All @@ -31,10 +33,11 @@ interface ListItemLinkProps extends ListItemProps {
displayText: string;
displayIcon?: JSX.Element;
open?: boolean;
tooltip?: string;
}

function ListItemLink(props: ListItemLinkProps) {
const {to, displayText, displayIcon, open, ...other} = props;
const {to, displayText, displayIcon, open, tooltip, ...other} = props;

let icon = null;
if (open != null) {
Expand All @@ -43,84 +46,125 @@ function ListItemLink(props: ListItemLinkProps) {

other.sx = Object.assign({textDecoration: 'none', color: 'inherit', p: 0}, other.sx ?? {});

const button = (
<ListItemButton>
<ListItemIcon>{displayIcon}</ListItemIcon>
<ListItemText primary={displayText} />
{icon}
</ListItemButton>
);

return (
<ListItem component={RouterLink as any} to={to} {...other}>
<ListItemButton>
<ListItemIcon>{displayIcon}</ListItemIcon>
<ListItemText primary={displayText} />
{icon}
</ListItemButton>
{tooltip ? (
<Tooltip title={tooltip} placement="right" enterDelay={400}>
{button}
</Tooltip>
) : (
button
)}
</ListItem>
);
}

const subheaderSx = {
pl: 4,
lineHeight: '2rem',
fontSize: '0.7rem',
fontWeight: 600,
letterSpacing: '0.08em',
textTransform: 'uppercase',
color: 'text.secondary',
};

interface NavItemsProps {
open: boolean;
}

// Integration MUI Link with React Router Link
// https://mui.com/material-ui/guides/routing/#link
export default function NavItems(props: NavItemsProps) {
const [openRequests, setOpenRequests] = React.useState(false);
const [openRoleRequests, setOpenRoleRequests] = React.useState(false);
const [openAccessRequests, setOpenAccessRequests] = React.useState(false);
const [openGroupRequests, setOpenGroupRequests] = React.useState(false);
const [openExpiringGroups, setOpenExpiringGroups] = React.useState(false);
const [openExpiringRoles, setOpenExpiringRoles] = React.useState(false);
const [openExpiringAccess, setOpenExpiringAccess] = React.useState(false);

return (
<List>
<ListItemLink to="/users" displayText="Users" displayIcon={<UserIcon />} />
<ListItemLink to="/groups" displayText="Groups" displayIcon={<GroupIcon />} />
<ListItemLink to="/roles" displayText="Roles" displayIcon={<RoleIcon />} />
<ListItemLink to="/apps" displayText="Apps" displayIcon={<AppIcon />} sx={{pb: 1}} />
<ListItemLink
to="/users"
displayText="Users"
displayIcon={<UserIcon />}
tooltip="View users in your organization"
/>
<ListItemLink to="/roles" displayText="Roles" displayIcon={<RoleIcon />} tooltip="View and manage roles" />
<ListItemLink to="/apps" displayText="Apps" displayIcon={<AppIcon />} tooltip="View and manage connected apps" />
<ListItemLink
to="/groups"
displayText="Groups"
displayIcon={<GroupIcon />}
sx={{pb: 1}}
tooltip="View and manage all kinds of groups, including roles and app groups"
/>
<Divider />
<ListItemLink
to="/requests"
to="/role-requests"
displayText="Access Requests"
displayIcon={<AccessRequestIcon />}
open={openRequests}
onClick={() => setOpenRequests(!openRequests)}
open={openAccessRequests}
onClick={() => setOpenAccessRequests(!openAccessRequests)}
sx={{pt: 1}}
tooltip="Create or review requests for individuals or roles to join groups"
/>
<Collapse component="li" in={props.open && openRequests} timeout="auto" unmountOnExit>
<Collapse component="li" in={props.open && openAccessRequests} timeout="auto" unmountOnExit>
<List disablePadding>
<ListSubheader disableSticky sx={subheaderSx}>
Role-Based
</ListSubheader>
<ListItemLink
to="/requests?requester_user_id=@me"
to="/role-requests?requester_user_id=@me"
displayText="From Me"
displayIcon={<RequestFromMe />}
sx={{pl: 4}}
tooltip="Role-based access requests you submitted"
/>
<ListItemLink
to="/requests?assignee_user_id=@me"
to="/role-requests?assignee_user_id=@me"
displayText="Assigned to Me"
displayIcon={<RequestToMe />}
sx={{pl: 4}}
tooltip="Role-based access requests awaiting your approval"
/>
<ListItemLink to="/requests" displayText="All" displayIcon={<RequestAll />} sx={{pl: 4}} />
</List>
</Collapse>
<ListItemLink
to="/role-requests"
displayText="Role Requests"
displayIcon={<RoleRequestIcon />}
open={openRoleRequests}
onClick={() => setOpenRoleRequests(!openRoleRequests)}
sx={{pt: 1}}
/>
<Collapse component="li" in={props.open && openRoleRequests} timeout="auto" unmountOnExit>
<List disablePadding>
<ListItemLink
to="/role-requests?requester_user_id=@me"
to="/role-requests"
displayText="All"
displayIcon={<RequestAll />}
sx={{pl: 4}}
tooltip="All role-based access requests"
/>
<ListSubheader disableSticky sx={subheaderSx}>
Individual
</ListSubheader>
<ListItemLink
to="/requests?requester_user_id=@me"
displayText="From Me"
displayIcon={<RequestFromMe />}
sx={{pl: 4}}
tooltip="Individual access requests you submitted"
/>
<ListItemLink
to="/role-requests?assignee_user_id=@me"
to="/requests?assignee_user_id=@me"
displayText="Assigned to Me"
displayIcon={<RequestToMe />}
sx={{pl: 4}}
tooltip="Individual access requests awaiting your approval"
/>
<ListItemLink
to="/requests"
displayText="All"
displayIcon={<RequestAll />}
sx={{pl: 4}}
tooltip="All individual access requests"
/>
<ListItemLink to="/role-requests" displayText="All" displayIcon={<RequestAll />} sx={{pl: 4}} />
</List>
</Collapse>
<ListItemLink
Expand All @@ -130,6 +174,7 @@ export default function NavItems(props: NavItemsProps) {
open={openGroupRequests}
onClick={() => setOpenGroupRequests(!openGroupRequests)}
sx={{py: 1}}
tooltip="Requests to create new groups, including roles and app groups"
/>
<Collapse component="li" in={props.open && openGroupRequests} timeout="auto" unmountOnExit>
<List disablePadding>
Expand All @@ -138,64 +183,84 @@ export default function NavItems(props: NavItemsProps) {
displayText="From Me"
displayIcon={<RequestFromMe />}
sx={{pl: 4}}
tooltip="Group creation requests you submitted"
/>
<ListItemLink
to="/group-requests?assignee_user_id=@me"
displayText="Assigned to Me"
displayIcon={<RequestToMe />}
sx={{pl: 4}}
tooltip="Group creation requests awaiting your approval"
/>
<ListItemLink
to="/group-requests"
displayText="All"
displayIcon={<RequestAll />}
sx={{pl: 4}}
tooltip="All group creation requests"
/>
<ListItemLink to="/group-requests" displayText="All" displayIcon={<RequestAll />} sx={{pl: 4}} />
</List>
</Collapse>
<Divider />
<ListItemLink
to="/expiring-groups"
displayText="Expiring Groups"
to="/expiring-roles"
displayText="Expiring Access"
displayIcon={<ExpiringGroupsIcon />}
open={openExpiringGroups}
onClick={() => setOpenExpiringGroups(!openExpiringGroups)}
open={openExpiringAccess}
onClick={() => setOpenExpiringAccess(!openExpiringAccess)}
sx={{pt: 1}}
tooltip="Review access expiring soon"
/>
<Collapse component="li" in={props.open && openExpiringGroups} timeout="auto" unmountOnExit>
<Collapse component="li" in={props.open && openExpiringAccess} timeout="auto" unmountOnExit>
<List disablePadding>
<ListSubheader disableSticky sx={subheaderSx}>
Role-Based
</ListSubheader>
<ListItemLink
to="/expiring-groups?user_id=@me"
displayText="My Access"
displayIcon={<ExpiringMyAccess />}
to="/expiring-roles?role_owner_id=@me"
displayText="My Roles"
displayIcon={<ExpiringRolesOwnedByMe />}
sx={{pl: 4}}
tooltip="Roles you own that are losing access soon"
/>
<ListItemLink
to="/expiring-groups?owner_id=@me"
displayText="Owned by Me"
to="/expiring-roles?owner_id=@me"
displayText="My Groups"
displayIcon={<ExpiringOwnedByMe />}
sx={{pl: 4}}
tooltip="Groups you own with expiring role-based access"
/>
<ListItemLink to="/expiring-groups" displayText="All" displayIcon={<ExpiringAll />} sx={{pl: 4}} />
</List>
</Collapse>
<ListItemLink
to="/expiring-roles"
displayText="Expiring Roles"
displayIcon={<ExpiringRolesIcon />}
open={openExpiringRoles}
onClick={() => setOpenExpiringRoles(!openExpiringRoles)}
/>
<Collapse component="li" in={props.open && openExpiringRoles} timeout="auto" unmountOnExit>
<List disablePadding>
<ListItemLink
to="/expiring-roles?owner_id=@me"
displayText="Owned Groups"
to="/expiring-roles"
displayText="All"
displayIcon={<ExpiringAll />}
sx={{pl: 4}}
tooltip="All expiring role-based access"
/>
<ListSubheader disableSticky sx={subheaderSx}>
Individual
</ListSubheader>
<ListItemLink
to="/expiring-groups?user_id=@me"
displayText="My Access"
displayIcon={<ExpiringMyAccess />}
sx={{pl: 4}}
tooltip="Your individual access expiring soon"
/>
<ListItemLink
to="/expiring-groups?owner_id=@me"
displayText="My Groups"
displayIcon={<ExpiringOwnedByMe />}
sx={{pl: 4}}
tooltip="Groups you own with expiring individual access"
/>
<ListItemLink
to="/expiring-roles?role_owner_id=@me"
displayText="Owned Roles"
displayIcon={<ExpiringRolesOwnedByMe />}
to="/expiring-groups"
displayText="All"
displayIcon={<ExpiringAll />}
sx={{pl: 4}}
tooltip="All expiring individual access"
/>
<ListItemLink to="/expiring-roles" displayText="All" displayIcon={<ExpiringAll />} sx={{pl: 4}} />
</List>
</Collapse>
</List>
Expand Down
Loading