mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: style project resources component (#8636)
This PR adds full styling for the project resources UI widget, adding icons, links, and sorting out the layout. Light mode: <img width="663" alt="image" src="https://github.com/user-attachments/assets/51231c67-1a0f-4018-9603-c476dac3b03a"> Dark mode: <img width="663" alt="image" src="https://github.com/user-attachments/assets/8943e479-2ecb-4917-9fad-fb6e1f1649a5"> On narrower screens: <img width="474" alt="image" src="https://github.com/user-attachments/assets/e0133f79-c389-444c-8d82-226cffd1015c">
This commit is contained in:
		
							parent
							
								
									2e99452645
								
							
						
					
					
						commit
						9a5d965636
					
				@ -1,22 +1,99 @@
 | 
				
			|||||||
import { styled } from '@mui/material';
 | 
					import { Typography, styled } from '@mui/material';
 | 
				
			||||||
import { useProjectApiTokens } from 'hooks/api/getters/useProjectApiTokens/useProjectApiTokens';
 | 
					import { useProjectApiTokens } from 'hooks/api/getters/useProjectApiTokens/useProjectApiTokens';
 | 
				
			||||||
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
 | 
					import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
 | 
				
			||||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
 | 
					import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
 | 
				
			||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
					import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
 | 
				
			||||||
import { useMemo } from 'react';
 | 
					import {
 | 
				
			||||||
 | 
					    type ReactNode,
 | 
				
			||||||
 | 
					    useMemo,
 | 
				
			||||||
 | 
					    type FC,
 | 
				
			||||||
 | 
					    type PropsWithChildren,
 | 
				
			||||||
 | 
					} from 'react';
 | 
				
			||||||
 | 
					import UsersIcon from '@mui/icons-material/Group';
 | 
				
			||||||
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
 | 
					import ApiKeyIcon from '@mui/icons-material/Key';
 | 
				
			||||||
 | 
					import SegmentsIcon from '@mui/icons-material/DonutLarge';
 | 
				
			||||||
 | 
					import ConnectedIcon from '@mui/icons-material/Cable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Wrapper = styled('article')(({ theme }) => ({
 | 
					const Wrapper = styled('article')(({ theme }) => ({
 | 
				
			||||||
    backgroundColor: theme.palette.envAccordion.expanded,
 | 
					    backgroundColor: theme.palette.envAccordion.expanded,
 | 
				
			||||||
    padding: theme.spacing(2),
 | 
					    padding: theme.spacing(3),
 | 
				
			||||||
    borderRadius: theme.shape.borderRadiusExtraLarge,
 | 
					    borderRadius: theme.shape.borderRadiusExtraLarge,
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ProjectResourcesInner = styled('div')(({ theme }) => ({
 | 
					const ProjectResourcesInner = styled('div')(({ theme }) => ({
 | 
				
			||||||
    display: 'flex',
 | 
					    display: 'flex',
 | 
				
			||||||
    flexDirection: 'column',
 | 
					    flexDirection: 'column',
 | 
				
			||||||
    gap: '1rem',
 | 
					    gap: theme.spacing(2),
 | 
				
			||||||
 | 
					    containerType: 'inline-size',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ItemContent = styled('span')(({ theme }) => ({
 | 
				
			||||||
 | 
					    display: 'inline-flex',
 | 
				
			||||||
 | 
					    flexFlow: 'row nowrap',
 | 
				
			||||||
 | 
					    gap: theme.spacing(1),
 | 
				
			||||||
 | 
					    svg: {
 | 
				
			||||||
 | 
					        fill: theme.palette.primary.main,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onNarrowWidget = (css: object) => ({
 | 
				
			||||||
 | 
					    '@container (max-width: 400px)': css,
 | 
				
			||||||
 | 
					    '@supports not (container-type: inline-size)': {
 | 
				
			||||||
 | 
					        '@media (max-width: 400px)': css,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ListItemRow = styled('li')(({ theme }) => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        display: 'flex',
 | 
				
			||||||
 | 
					        flexFlow: 'row',
 | 
				
			||||||
 | 
					        justifyContent: 'space-between',
 | 
				
			||||||
 | 
					        alignItems: 'center',
 | 
				
			||||||
 | 
					        gap: theme.spacing(1),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ...onNarrowWidget({
 | 
				
			||||||
 | 
					            flexFlow: 'column',
 | 
				
			||||||
 | 
					            alignItems: 'flex-start',
 | 
				
			||||||
 | 
					            justifyContent: 'unset',
 | 
				
			||||||
 | 
					            '& + li': {
 | 
				
			||||||
 | 
					                marginTop: theme.spacing(5),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ResourceList = styled('ul')(({ theme }) => ({
 | 
				
			||||||
 | 
					    margin: 0,
 | 
				
			||||||
 | 
					    listStyle: 'none',
 | 
				
			||||||
 | 
					    padding: 0,
 | 
				
			||||||
 | 
					    'li + li': {
 | 
				
			||||||
 | 
					        marginTop: theme.spacing(2),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ...onNarrowWidget({
 | 
				
			||||||
 | 
					        'li + li': {
 | 
				
			||||||
 | 
					            marginTop: theme.spacing(4),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ListItem: FC<
 | 
				
			||||||
 | 
					    PropsWithChildren<{
 | 
				
			||||||
 | 
					        linkUrl: string;
 | 
				
			||||||
 | 
					        linkText: string;
 | 
				
			||||||
 | 
					        icon: ReactNode;
 | 
				
			||||||
 | 
					    }>
 | 
				
			||||||
 | 
					> = ({ children, linkUrl, linkText, icon }) => (
 | 
				
			||||||
 | 
					    <ListItemRow>
 | 
				
			||||||
 | 
					        <ItemContent>
 | 
				
			||||||
 | 
					            {icon}
 | 
				
			||||||
 | 
					            <span>{children}</span>
 | 
				
			||||||
 | 
					        </ItemContent>
 | 
				
			||||||
 | 
					        <Link to={linkUrl}>{linkText}</Link>
 | 
				
			||||||
 | 
					    </ListItemRow>
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ProjectResources = () => {
 | 
					export const ProjectResources = () => {
 | 
				
			||||||
    const projectId = useRequiredPathParam('projectId');
 | 
					    const projectId = useRequiredPathParam('projectId');
 | 
				
			||||||
    const { project, loading: loadingProject } = useProjectOverview(projectId);
 | 
					    const { project, loading: loadingProject } = useProjectOverview(projectId);
 | 
				
			||||||
@ -34,11 +111,42 @@ export const ProjectResources = () => {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Wrapper>
 | 
					        <Wrapper>
 | 
				
			||||||
            <ProjectResourcesInner>
 | 
					            <ProjectResourcesInner>
 | 
				
			||||||
                <h3>Project Resources</h3>
 | 
					                <Typography variant='h3' sx={{ margin: 0 }}>
 | 
				
			||||||
                <span>{project.members} project member(s)</span>
 | 
					                    Project Resources
 | 
				
			||||||
                <span>{tokens.length} API key(s)</span>
 | 
					                </Typography>
 | 
				
			||||||
                <span>1 SDK connection(s)</span>
 | 
					                <ResourceList>
 | 
				
			||||||
                <span>{segmentCount} project segment(s)</span>
 | 
					                    <ListItem
 | 
				
			||||||
 | 
					                        linkUrl={`/projects/${projectId}/settings/access`}
 | 
				
			||||||
 | 
					                        linkText='Add members'
 | 
				
			||||||
 | 
					                        icon={<UsersIcon />}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        {project.members} project member(s)
 | 
				
			||||||
 | 
					                    </ListItem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ListItem
 | 
				
			||||||
 | 
					                        linkUrl={`/projects/${projectId}/settings/api-access`}
 | 
				
			||||||
 | 
					                        linkText='Add new key'
 | 
				
			||||||
 | 
					                        icon={<ApiKeyIcon />}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        {tokens.length} API key(s)
 | 
				
			||||||
 | 
					                    </ListItem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ListItem
 | 
				
			||||||
 | 
					                        linkUrl={`/projects/${projectId}/settings/placeholder`}
 | 
				
			||||||
 | 
					                        linkText='View connections'
 | 
				
			||||||
 | 
					                        icon={<ConnectedIcon />}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        1 connected environment(s)
 | 
				
			||||||
 | 
					                    </ListItem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <ListItem
 | 
				
			||||||
 | 
					                        linkUrl={`/projects/${projectId}/settings/segments`}
 | 
				
			||||||
 | 
					                        linkText='Add segments'
 | 
				
			||||||
 | 
					                        icon={<SegmentsIcon />}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        {segmentCount} project segment(s)
 | 
				
			||||||
 | 
					                    </ListItem>
 | 
				
			||||||
 | 
					                </ResourceList>
 | 
				
			||||||
            </ProjectResourcesInner>
 | 
					            </ProjectResourcesInner>
 | 
				
			||||||
        </Wrapper>
 | 
					        </Wrapper>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user