1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-24 01:18:01 +02:00

Refactor/make styles batch 6 part 3 (#2823)

Last set of components refactoring for batch 6
This commit is contained in:
Fredrik Strand Oseberg 2023-01-05 09:45:17 +01:00 committed by GitHub
parent 005e4b6858
commit 94c90b7731
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 351 additions and 386 deletions

View File

@ -29,6 +29,7 @@ interface IPermissionIconButtonProps {
interface IButtonProps extends IPermissionIconButtonProps { interface IButtonProps extends IPermissionIconButtonProps {
onClick: (event: React.SyntheticEvent) => void; onClick: (event: React.SyntheticEvent) => void;
style?: React.CSSProperties;
} }
interface ILinkProps extends IPermissionIconButtonProps { interface ILinkProps extends IPermissionIconButtonProps {
@ -107,6 +108,7 @@ const PermissionIconButton = (props: IButtonProps | ILinkProps) => {
/> />
); );
} }
return <RootPermissionIconButton {...props} />; return <RootPermissionIconButton {...props} />;
}; };

View File

@ -1,39 +1,36 @@
import { makeStyles } from 'tss-react/mui'; import Input from 'component/common/Input/Input';
import { TextField, Button, styled } from '@mui/material';
export const useStyles = makeStyles()(theme => ({ export const StyledForm = styled('form')(() => ({
form: { display: 'flex',
display: 'flex', flexDirection: 'column',
flexDirection: 'column', height: '100%',
height: '100%', }));
},
container: { export const StyledContainer = styled('div')(() => ({
maxWidth: '400px', maxWidth: '400px',
}, }));
input: { width: '100%', marginBottom: '1rem' },
label: { export const StyledDescription = styled('p')(({ theme }) => ({
minWidth: '300px', marginBottom: theme.spacing(1),
[theme.breakpoints.down(600)]: { }));
minWidth: 'auto',
}, export const StyledInput = styled(Input)(({ theme }) => ({
}, width: '100%',
buttonContainer: { marginBottom: theme.spacing(2),
marginTop: 'auto', }));
display: 'flex',
justifyContent: 'flex-end', export const StyledTextField = styled(TextField)(({ theme }) => ({
}, width: '100%',
cancelButton: { marginBottom: theme.spacing(2),
marginLeft: '1.5rem', }));
},
inputDescription: { export const StyledButtonContainer = styled('div')(() => ({
marginBottom: '0.5rem', marginTop: 'auto',
}, display: 'flex',
permissionErrorContainer: { justifyContent: 'flex-end',
position: 'relative', }));
},
errorMessage: { export const StyledButton = styled(Button)(({ theme }) => ({
fontSize: theme.fontSizes.smallBody, marginLeft: theme.spacing(3),
color: theme.palette.error.main,
position: 'absolute',
top: '-8px',
},
})); }));

View File

@ -1,9 +1,14 @@
import Input from 'component/common/Input/Input';
import { TextField, Button } from '@mui/material';
import { useStyles } from './ProjectForm.styles';
import React from 'react'; import React from 'react';
import { trim } from 'component/common/util'; import { trim } from 'component/common/util';
import {
StyledForm,
StyledContainer,
StyledDescription,
StyledInput,
StyledTextField,
StyledButtonContainer,
StyledButton,
} from './ProjectForm.styles';
interface IProjectForm { interface IProjectForm {
projectId: string; projectId: string;
projectName: string; projectName: string;
@ -34,16 +39,11 @@ const ProjectForm: React.FC<IProjectForm> = ({
validateProjectId, validateProjectId,
clearErrors, clearErrors,
}) => { }) => {
const { classes: styles } = useStyles();
return ( return (
<form onSubmit={handleSubmit} className={styles.form}> <StyledForm onSubmit={handleSubmit}>
<div className={styles.container}> <StyledContainer>
<p className={styles.inputDescription}> <StyledDescription>What is your project Id?</StyledDescription>
What is your project Id? <StyledInput
</p>
<Input
className={styles.input}
label="Project Id" label="Project Id"
value={projectId} value={projectId}
onChange={e => setProjectId(trim(e.target.value))} onChange={e => setProjectId(trim(e.target.value))}
@ -56,11 +56,10 @@ const ProjectForm: React.FC<IProjectForm> = ({
required required
/> />
<p className={styles.inputDescription}> <StyledDescription>
What is your project name? What is your project name?
</p> </StyledDescription>
<Input <StyledInput
className={styles.input}
label="Project name" label="Project name"
value={projectName} value={projectName}
onChange={e => setProjectName(e.target.value)} onChange={e => setProjectName(e.target.value)}
@ -70,11 +69,10 @@ const ProjectForm: React.FC<IProjectForm> = ({
required required
/> />
<p className={styles.inputDescription}> <StyledDescription>
What is your project description? What is your project description?
</p> </StyledDescription>
<TextField <StyledTextField
className={styles.input}
label="Project description" label="Project description"
variant="outlined" variant="outlined"
multiline multiline
@ -82,15 +80,13 @@ const ProjectForm: React.FC<IProjectForm> = ({
value={projectDesc} value={projectDesc}
onChange={e => setProjectDesc(e.target.value)} onChange={e => setProjectDesc(e.target.value)}
/> />
</div> </StyledContainer>
<div className={styles.buttonContainer}> <StyledButtonContainer>
{children} {children}
<Button onClick={handleCancel} className={styles.cancelButton}> <StyledButton onClick={handleCancel}>Cancel</StyledButton>
Cancel </StyledButtonContainer>
</Button> </StyledForm>
</div>
</form>
); );
}; };

View File

@ -1,85 +1,83 @@
import { makeStyles } from 'tss-react/mui'; import { Link } from 'react-router-dom';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import { flexRow } from 'themes/themeStyles';
import { styled } from '@mui/material';
export const useStyles = makeStyles()(theme => ({ export const StyledDivContainer = styled('div')(({ theme }) => ({
projectInfo: { ...flexRow,
width: '225px', width: '225px',
display: 'flex', flexDirection: 'column',
flexDirection: 'column', boxShadow: 'none',
alignItems: 'center', [theme.breakpoints.down('md')]: {
boxShadow: 'none', flexDirection: 'row',
[theme.breakpoints.down('md')]: { alignItems: 'stretch',
flexDirection: 'row',
alignItems: 'stretch',
width: '100%',
marginBottom: '1rem',
},
},
percentageContainer: {
display: 'flex',
justifyContent: 'center',
margin: '1rem 0',
},
projectIcon: {
margin: '2rem 0',
[theme.breakpoints.down('md')]: {
margin: '0 0 0.25rem 0',
width: '53px',
},
},
subtitle: {
marginBottom: '1rem',
},
emphazisedText: {
fontSize: '1.5rem',
marginBottom: '1rem',
[theme.breakpoints.down('md')]: {
fontSize: '1rem',
marginBottom: '2rem',
},
},
infoSection: {
margin: '0',
textAlign: 'center',
marginBottom: '1rem',
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadiusLarge,
width: '100%', width: '100%',
padding: '1.5rem 1rem 1.5rem 1rem', marginBottom: theme.spacing(2),
[theme.breakpoints.down('md')]: { },
margin: '0 0.25rem', }));
display: 'flex',
flexDirection: 'column', export const StyledDivPercentageContainer = styled('div')(({ theme }) => ({
alignItems: 'center', display: 'flex',
justifyContent: 'center', justifyContent: 'center',
fontSize: '0.8rem', margin: theme.spacing(2, 0),
position: 'relative', }));
padding: '0.8rem',
'&:first-of-type': { export const StyledDivInfoContainer = styled('div')(({ theme }) => ({
marginLeft: '0', margin: '0',
}, textAlign: 'center',
'&:last-of-type': { marginBottom: theme.spacing(2),
marginRight: '0', backgroundColor: theme.palette.background.paper,
}, borderRadius: theme.shape.borderRadiusLarge,
width: '100%',
padding: theme.spacing(3, 2, 3, 2),
[theme.breakpoints.down('md')]: {
margin: theme.spacing(0, 0.5),
...flexRow,
flexDirection: 'column',
justifyContent: 'center',
fontSize: theme.fontSizes.smallBody,
position: 'relative',
padding: theme.spacing(1.5),
'&:first-of-type': {
marginLeft: '0',
}, },
}, '&:last-of-type': {
arrowIcon: { marginRight: '0',
color: '#635dc5',
marginLeft: '0.5rem',
},
permissionButtonShortDesc: {
transform: `translateY(-10px)`,
},
infoLink: {
textDecoration: 'none',
color: '#635dc5',
[theme.breakpoints.down('md')]: {
position: 'absolute',
bottom: '5px',
},
},
linkText: {
[theme.breakpoints.down('md')]: {
display: 'none',
}, },
}, },
})); }));
export const StyledParagraphSubtitle = styled('p')(({ theme }) => ({
marginBottom: theme.spacing(2),
}));
export const StyledParagraphEmphasizedText = styled('p')(({ theme }) => ({
fontSize: '1.5rem',
marginBottom: theme.spacing(2),
[theme.breakpoints.down('md')]: {
fontSize: theme.fontSizes.bodySize,
marginBottom: theme.spacing(4),
},
}));
export const StyledSpanLinkText = styled('p')(({ theme }) => ({
[theme.breakpoints.down('md')]: {
display: 'none',
},
}));
export const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
...flexRow,
justifyContent: 'center',
color: theme.palette.primary.main,
[theme.breakpoints.down('md')]: {
position: 'absolute',
bottom: theme.spacing(1.5),
},
}));
export const StyledArrowIcon = styled(ArrowForwardIcon)(({ theme }) => ({
color: theme.palette.primary.main,
marginLeft: theme.spacing(1),
}));

View File

@ -1,14 +1,18 @@
import { useStyles } from './ProjectInfo.styles';
import { Link } from 'react-router-dom';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import classnames from 'classnames';
import { useThemeStyles } from 'themes/themeStyles';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle'; import PercentageCircle from 'component/common/PercentageCircle/PercentageCircle';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { DEFAULT_PROJECT_ID } from '../../../../hooks/api/getters/useDefaultProject/useDefaultProjectId'; import { DEFAULT_PROJECT_ID } from '../../../../hooks/api/getters/useDefaultProject/useDefaultProjectId';
import {
StyledDivContainer,
StyledDivInfoContainer,
StyledDivPercentageContainer,
StyledParagraphSubtitle,
StyledParagraphEmphasizedText,
StyledLink,
StyledSpanLinkText,
StyledArrowIcon,
} from './ProjectInfo.styles';
interface IProjectInfoProps { interface IProjectInfoProps {
id: string; id: string;
@ -19,8 +23,6 @@ interface IProjectInfoProps {
} }
const ProjectInfo = ({ id, memberCount, health }: IProjectInfoProps) => { const ProjectInfo = ({ id, memberCount, health }: IProjectInfoProps) => {
const { classes: themeStyles } = useThemeStyles();
const { classes: styles } = useStyles();
const { uiConfig } = useUiConfig(); const { uiConfig } = useUiConfig();
let link = `/admin/users`; let link = `/admin/users`;
@ -31,69 +33,44 @@ const ProjectInfo = ({ id, memberCount, health }: IProjectInfoProps) => {
return ( return (
<aside> <aside>
<div className={styles.projectInfo}> <StyledDivContainer>
<div className={styles.infoSection}> <StyledDivInfoContainer>
<div data-loading className={styles.percentageContainer}> <StyledDivPercentageContainer>
<PercentageCircle percentage={health} /> <PercentageCircle percentage={health} />
</div> </StyledDivPercentageContainer>
<p className={styles.subtitle} data-loading> <StyledParagraphSubtitle data-loading>
Overall health rating Overall health rating
</p> </StyledParagraphSubtitle>
<p className={styles.emphazisedText} data-loading> <StyledParagraphEmphasizedText data-loading>
{health}% {health}%
</p> </StyledParagraphEmphasizedText>
<Link <StyledLink data-loading to={`/projects/${id}/health`}>
data-loading <StyledSpanLinkText data-loading>
className={classnames(
themeStyles.flexRow,
themeStyles.justifyCenter,
styles.infoLink
)}
to={`/projects/${id}/health`}
>
<span className={styles.linkText} data-loading>
view more{' '} view more{' '}
</span> </StyledSpanLinkText>
<ArrowForwardIcon <StyledArrowIcon data-loading />
data-loading </StyledLink>
className={styles.arrowIcon} </StyledDivInfoContainer>
/>
</Link>
</div>
<ConditionallyRender <ConditionallyRender
condition={id !== DEFAULT_PROJECT_ID} condition={id !== DEFAULT_PROJECT_ID}
show={ show={
<div <StyledDivInfoContainer style={{ marginBottom: '0' }}>
className={styles.infoSection} <StyledParagraphSubtitle data-loading>
style={{ marginBottom: '0' }}
>
<p className={styles.subtitle} data-loading>
Project members Project members
</p> </StyledParagraphSubtitle>
<p data-loading className={styles.emphazisedText}> <StyledParagraphEmphasizedText data-loading>
{memberCount} {memberCount}
</p> </StyledParagraphEmphasizedText>
<Link <StyledLink data-loading to={link}>
data-loading <StyledSpanLinkText data-loading>
className={classnames(
themeStyles.flexRow,
themeStyles.justifyCenter,
styles.infoLink
)}
to={link}
>
<span className={styles.linkText} data-loading>
view more{' '} view more{' '}
</span> </StyledSpanLinkText>
<ArrowForwardIcon <StyledArrowIcon data-loading />
data-loading </StyledLink>
className={styles.arrowIcon} </StyledDivInfoContainer>
/>
</Link>
</div>
} }
/> />
</div> </StyledDivContainer>
</aside> </aside>
); );
}; };

View File

@ -1,63 +1,76 @@
import { makeStyles } from 'tss-react/mui'; import { styled } from '@mui/material';
import { Card, Box } from '@mui/material';
import { Delete, Edit } from '@mui/icons-material';
import { ReactComponent as ProjectIcon } from 'assets/icons/projectIcon.svg';
import { flexRow } from 'themes/themeStyles';
export const useStyles = makeStyles()(theme => ({ export const StyledProjectCard = styled(Card)(({ theme }) => ({
projectCard: { padding: theme.spacing(1, 2, 2, 2),
padding: theme.spacing(1, 2, 2, 2), width: '220px',
width: '220px', height: '204px',
height: '204px', display: 'flex',
display: 'flex', flexDirection: 'column',
flexDirection: 'column', justifyContent: 'space-between',
justifyContent: 'space-between', margin: theme.spacing(1),
margin: '0.5rem', boxShadow: 'none',
boxShadow: 'none', border: `1px solid ${theme.palette.tertiary.contrast}`,
border: '1px solid #efefef', [theme.breakpoints.down('sm')]: {
[theme.breakpoints.down('sm')]: { justifyContent: 'center',
justifyContent: 'center',
},
'&:hover': {
transition: 'background-color 0.2s ease-in-out',
backgroundColor: theme.palette.projectCard.hover,
},
}, },
header: { '&:hover': {
display: 'flex', transition: 'background-color 0.2s ease-in-out',
alignItems: 'center', backgroundColor: theme.palette.projectCard.hover,
},
title: {
fontWeight: 'normal',
fontSize: '1rem',
lineClamp: 2,
display: '-webkit-box',
boxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden',
alignItems: 'flex-start',
},
projectIcon: {
margin: '1rem auto',
width: '80px',
display: 'block',
},
info: {
display: 'flex',
justifyContent: 'space-between',
fontSize: '0.8rem',
},
infoBox: {
textAlign: 'center',
},
infoStats: {
color: theme.palette.projectCard.textColor,
fontWeight: 'bold',
},
actionsBtn: {
transform: 'translateX(15px)',
marginLeft: 'auto',
marginRight: theme.spacing(1),
},
icon: {
color: theme.palette.grey[700],
marginRight: '0.5rem',
}, },
})); }));
export const StyledDivHeader = styled('div')(() => ({
...flexRow,
width: '100%',
}));
export const StyledH2Title = styled('h2')(({ theme }) => ({
fontWeight: 'normal',
fontSize: theme.fontSizes.bodySize,
lineClamp: 2,
display: '-webkit-box',
boxOrient: 'vertical',
textOverflow: 'ellipsis',
overflow: 'hidden',
alignItems: 'flex-start',
}));
export const StyledBox = styled(Box)(() => ({
...flexRow,
marginRight: 'auto',
}));
export const StyledEditIcon = styled(Edit)(({ theme }) => ({
color: theme.palette.neutral.main,
marginRight: theme.spacing(1),
}));
export const StyledDeleteIcon = styled(Delete)(({ theme }) => ({
color: theme.palette.neutral.main,
marginRight: theme.spacing(1),
}));
export const StyledProjectIcon = styled(ProjectIcon)(({ theme }) => ({
margin: theme.spacing(2, 'auto'),
width: '80px',
display: 'block',
}));
export const StyledDivInfo = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
fontSize: theme.fontSizes.smallerBody,
}));
export const StyledDivInfoContainer = styled('div')(() => ({
textAlign: 'center',
}));
export const StyledParagraphInfo = styled('p')(({ theme }) => ({
color: theme.palette.projectCard.textColor,
fontWeight: 'bold',
}));

View File

@ -1,10 +1,7 @@
import { Card, Menu, MenuItem } from '@mui/material'; import { Menu, MenuItem } from '@mui/material';
import { useStyles } from './ProjectCard.styles';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import { ReactComponent as ProjectIcon } from 'assets/icons/projectIcon.svg';
import React, { SyntheticEvent, useContext, useState } from 'react'; import React, { SyntheticEvent, useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Delete, Edit } from '@mui/icons-material';
import { getProjectEditPath } from 'utils/routePathHelpers'; import { getProjectEditPath } from 'utils/routePathHelpers';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
import { import {
@ -19,6 +16,20 @@ import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton'; import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton';
import { DeleteProjectDialogue } from '../Project/DeleteProject/DeleteProjectDialogue'; import { DeleteProjectDialogue } from '../Project/DeleteProject/DeleteProjectDialogue';
import { styled } from '@mui/material';
import { flexRow } from 'themes/themeStyles';
import {
StyledProjectCard,
StyledDivHeader,
StyledBox,
StyledH2Title,
StyledEditIcon,
StyledDeleteIcon,
StyledProjectIcon,
StyledDivInfo,
StyledDivInfoContainer,
StyledParagraphInfo,
} from './ProjectCard.styles';
interface IProjectCardProps { interface IProjectCardProps {
name: string; name: string;
@ -39,9 +50,8 @@ export const ProjectCard = ({
id, id,
isFavorite = false, isFavorite = false,
}: IProjectCardProps) => { }: IProjectCardProps) => {
const { classes } = useStyles();
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const { isOss, uiConfig } = useUiConfig(); const { isOss } = useUiConfig();
const [anchorEl, setAnchorEl] = useState<Element | null>(null); const [anchorEl, setAnchorEl] = useState<Element | null>(null);
const [showDelDialog, setShowDelDialog] = useState(false); const [showDelDialog, setShowDelDialog] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
@ -67,17 +77,20 @@ export const ProjectCard = ({
}; };
return ( return (
<Card className={classes.projectCard} onMouseEnter={onHover}> <StyledProjectCard onMouseEnter={onHover}>
<div className={classes.header} data-loading> <StyledDivHeader data-loading>
<FavoriteIconButton <StyledBox>
onClick={onFavorite} <FavoriteIconButton
isFavorite={isFavorite} onClick={onFavorite}
size="medium" isFavorite={isFavorite}
sx={{ ml: -1 }} size="medium"
/> sx={{ ml: -1 }}
<h2 className={classes.title}>{name}</h2> />
<StyledH2Title>{name}</StyledH2Title>
</StyledBox>
<PermissionIconButton <PermissionIconButton
style={{ transform: 'translateX(7px)' }}
permission={UPDATE_PROJECT} permission={UPDATE_PROJECT}
hidden={isOss()} hidden={isOss()}
projectId={id} projectId={id}
@ -85,7 +98,6 @@ export const ProjectCard = ({
onClick={handleClick} onClick={handleClick}
tooltipProps={{ tooltipProps={{
title: 'Options', title: 'Options',
className: classes.actionsBtn,
}} }}
> >
<MoreVertIcon /> <MoreVertIcon />
@ -110,7 +122,7 @@ export const ProjectCard = ({
navigate(getProjectEditPath(id)); navigate(getProjectEditPath(id));
}} }}
> >
<Edit className={classes.icon} /> <StyledEditIcon />
Edit project Edit project
</MenuItem> </MenuItem>
<MenuItem <MenuItem
@ -120,42 +132,42 @@ export const ProjectCard = ({
}} }}
disabled={!canDeleteProject} disabled={!canDeleteProject}
> >
<Delete className={classes.icon} /> <StyledDeleteIcon />
{id === DEFAULT_PROJECT_ID && !canDeleteProject {id === DEFAULT_PROJECT_ID && !canDeleteProject
? "You can't delete the default project" ? "You can't delete the default project"
: 'Delete project'} : 'Delete project'}
</MenuItem> </MenuItem>
</Menu> </Menu>
</div> </StyledDivHeader>
<div data-loading> <div data-loading>
<ProjectIcon className={classes.projectIcon} /> <StyledProjectIcon />
</div> </div>
<div className={classes.info}> <StyledDivInfo>
<div className={classes.infoBox}> <StyledDivInfoContainer>
<p className={classes.infoStats} data-loading> <StyledParagraphInfo data-loading>
{featureCount} {featureCount}
</p> </StyledParagraphInfo>
<p data-loading>toggles</p> <p data-loading>toggles</p>
</div> </StyledDivInfoContainer>
<div className={classes.infoBox}> <StyledDivInfoContainer>
<p className={classes.infoStats} data-loading> <StyledParagraphInfo data-loading>
{health}% {health}%
</p> </StyledParagraphInfo>
<p data-loading>health</p> <p data-loading>health</p>
</div> </StyledDivInfoContainer>
<ConditionallyRender <ConditionallyRender
condition={id !== DEFAULT_PROJECT_ID} condition={id !== DEFAULT_PROJECT_ID}
show={ show={
<div className={classes.infoBox}> <StyledDivInfoContainer>
<p className={classes.infoStats} data-loading> <StyledParagraphInfo data-loading>
{memberCount} {memberCount}
</p> </StyledParagraphInfo>
<p data-loading>members</p> <p data-loading>members</p>
</div> </StyledDivInfoContainer>
} }
/> />
</div> </StyledDivInfo>
<DeleteProjectDialogue <DeleteProjectDialogue
project={id} project={id}
open={showDelDialog} open={showDelDialog}
@ -164,6 +176,6 @@ export const ProjectCard = ({
setShowDelDialog(false); setShowDelDialog(false);
}} }}
/> />
</Card> </StyledProjectCard>
); );
}; };

View File

@ -1,24 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
[theme.breakpoints.down('sm')]: {
justifyContent: 'center',
},
},
apiError: {
maxWidth: '400px',
marginBottom: '1rem',
},
cardLink: {
color: 'inherit',
textDecoration: 'none',
border: 'none',
padding: '0',
background: 'transparent',
fontFamily: theme.typography.fontFamily,
pointer: 'cursor',
},
}));

View File

@ -1,6 +1,5 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './ProjectEnvironment.styles';
import { PageContent } from 'component/common/PageContent/PageContent'; import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader'; import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions'; import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions';
@ -38,6 +37,19 @@ const StyledAlert = styled(Alert)(({ theme }) => ({
marginBottom: theme.spacing(4), marginBottom: theme.spacing(4),
})); }));
const StyledDivContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexWrap: 'wrap',
[theme.breakpoints.down('sm')]: {
justifyContent: 'center',
},
}));
const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '400px',
marginBottom: theme.spacing(2),
}));
const ProjectEnvironmentList = () => { const ProjectEnvironmentList = () => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const projectName = useProjectNameOrId(projectId); const projectName = useProjectNameOrId(projectId);
@ -56,7 +68,6 @@ const ProjectEnvironmentList = () => {
const [selectedEnvironment, setSelectedEnvironment] = const [selectedEnvironment, setSelectedEnvironment] =
useState<IProjectEnvironment>(); useState<IProjectEnvironment>();
const [hideDialog, setHideDialog] = useState(false); const [hideDialog, setHideDialog] = useState(false);
const { classes: styles } = useStyles();
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
const projectEnvironments = useMemo<IProjectEnvironment[]>( const projectEnvironments = useMemo<IProjectEnvironment[]>(
@ -77,9 +88,8 @@ const ProjectEnvironmentList = () => {
const renderError = () => { const renderError = () => {
return ( return (
<ApiError <StyledApiError
onClick={refetch} onClick={refetch}
className={styles.apiError}
text="Error fetching environments" text="Error fetching environments"
/> />
); );
@ -229,7 +239,7 @@ const ProjectEnvironmentList = () => {
<ConditionallyRender <ConditionallyRender
condition={uiConfig.flags.E} condition={uiConfig.flags.E}
show={ show={
<div className={styles.container}> <StyledDivContainer>
<ConditionallyRender <ConditionallyRender
condition={Boolean(error)} condition={Boolean(error)}
show={renderError()} show={renderError()}
@ -305,7 +315,7 @@ const ProjectEnvironmentList = () => {
setOpen={setHideDialog} setOpen={setHideDialog}
onConfirm={onHideConfirm} onConfirm={onHideConfirm}
/> />
</div> </StyledDivContainer>
} }
elseShow={ elseShow={
<Alert security="success"> <Alert security="success">

View File

@ -1,24 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
[theme.breakpoints.down('sm')]: {
justifyContent: 'center',
},
},
apiError: {
maxWidth: '400px',
marginBottom: '1rem',
},
cardLink: {
color: 'inherit',
textDecoration: 'none',
border: 'none',
padding: '0',
background: 'transparent',
fontFamily: theme.typography.fontFamily,
pointer: 'cursor',
},
}));

View File

@ -5,7 +5,6 @@ import { getProjectFetcher } from 'hooks/api/getters/useProject/getProjectFetche
import useProjects from 'hooks/api/getters/useProjects/useProjects'; import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ProjectCard } from '../ProjectCard/ProjectCard'; import { ProjectCard } from '../ProjectCard/ProjectCard';
import { useStyles } from './ProjectList.styles';
import { IProjectCard } from 'interfaces/project'; import { IProjectCard } from 'interfaces/project';
import loadingData from './loadingData'; import loadingData from './loadingData';
import { PageContent } from 'component/common/PageContent/PageContent'; import { PageContent } from 'component/common/PageContent/PageContent';
@ -17,7 +16,7 @@ import { Add } from '@mui/icons-material';
import ApiError from 'component/common/ApiError/ApiError'; import ApiError from 'component/common/ApiError/ApiError';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { TablePlaceholder } from 'component/common/Table'; import { TablePlaceholder } from 'component/common/Table';
import { useMediaQuery } from '@mui/material'; import { useMediaQuery, styled } from '@mui/material';
import theme from 'themes/theme'; import theme from 'themes/theme';
import { Search } from 'component/common/Search/Search'; import { Search } from 'component/common/Search/Search';
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
@ -25,6 +24,29 @@ import { ITooltipResolverProps } from 'component/common/TooltipResolver/TooltipR
import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg'; import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
import { safeRegExp } from '@server/util/escape-regex'; import { safeRegExp } from '@server/util/escape-regex';
const StyledDivContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexWrap: 'wrap',
[theme.breakpoints.down('sm')]: {
justifyContent: 'center',
},
}));
const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '400px',
marginBottom: theme.spacing(2),
}));
const StyledCardLink = styled(Link)(({ theme }) => ({
color: 'inherit',
textDecoration: 'none',
border: 'none',
padding: '0',
background: 'transparent',
fontFamily: theme.typography.fontFamily,
pointer: 'cursor',
}));
type PageQueryType = Partial<Record<'search', string>>; type PageQueryType = Partial<Record<'search', string>>;
type projectMap = { type projectMap = {
@ -71,7 +93,6 @@ function resolveCreateButtonData(
export const ProjectListNew = () => { export const ProjectListNew = () => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
const navigate = useNavigate(); const navigate = useNavigate();
const { classes: styles } = useStyles();
const { projects, loading, error, refetch } = useProjects(); const { projects, loading, error, refetch } = useProjects();
const [fetchedProjects, setFetchedProjects] = useState<projectMap>({}); const [fetchedProjects, setFetchedProjects] = useState<projectMap>({});
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
@ -127,11 +148,7 @@ export const ProjectListNew = () => {
const renderError = () => { const renderError = () => {
return ( return (
<ApiError <StyledApiError onClick={refetch} text="Error fetching projects" />
onClick={refetch}
className={styles.apiError}
text="Error fetching projects"
/>
); );
}; };
@ -187,7 +204,7 @@ export const ProjectListNew = () => {
} }
> >
<ConditionallyRender condition={error} show={renderError()} /> <ConditionallyRender condition={error} show={renderError()} />
<div className={styles.container}> <StyledDivContainer>
<ConditionallyRender <ConditionallyRender
condition={filteredProjects.length < 1 && !loading} condition={filteredProjects.length < 1 && !loading}
show={ show={
@ -227,10 +244,9 @@ export const ProjectListNew = () => {
elseShow={() => elseShow={() =>
filteredProjects.map( filteredProjects.map(
(project: IProjectCard) => ( (project: IProjectCard) => (
<Link <StyledCardLink
key={project.id} key={project.id}
to={`/projects/${project.id}`} to={`/projects/${project.id}`}
className={styles.cardLink}
> >
<ProjectCard <ProjectCard
onHover={() => onHover={() =>
@ -247,14 +263,14 @@ export const ProjectListNew = () => {
} }
isFavorite={project.favorite} isFavorite={project.favorite}
/> />
</Link> </StyledCardLink>
) )
) )
} }
/> />
} }
/> />
</div> </StyledDivContainer>
</PageContent> </PageContent>
); );
}; };

View File

@ -1,12 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
deleteInput: {
marginTop: '1rem',
},
link: {
textDecoration: 'none',
color: theme.palette.primary.main,
fontWeight: theme.fontWeight.bold,
},
}));

View File

@ -1,9 +1,13 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Dialogue } from 'component/common/Dialogue/Dialogue'; import { Dialogue } from 'component/common/Dialogue/Dialogue';
import Input from 'component/common/Input/Input'; import Input from 'component/common/Input/Input';
import { useStyles } from './SegmentDeleteConfirm.styles';
import { ISegment } from 'interfaces/segment'; import { ISegment } from 'interfaces/segment';
import { SEGMENT_DIALOG_NAME_ID } from 'utils/testIds'; import { SEGMENT_DIALOG_NAME_ID } from 'utils/testIds';
import { styled } from '@mui/material';
const StyledInput = styled(Input)(({ theme }) => ({
marginTop: theme.spacing(2),
}));
interface ISegmentDeleteConfirmProps { interface ISegmentDeleteConfirmProps {
segment: ISegment; segment: ISegment;
@ -18,7 +22,6 @@ export const SegmentDeleteConfirm = ({
onClose, onClose,
onRemove, onRemove,
}: ISegmentDeleteConfirmProps) => { }: ISegmentDeleteConfirmProps) => {
const { classes: styles } = useStyles();
const [confirmName, setConfirmName] = useState(''); const [confirmName, setConfirmName] = useState('');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => const handleChange = (e: React.ChangeEvent<HTMLInputElement>) =>
@ -49,12 +52,11 @@ export const SegmentDeleteConfirm = ({
</p> </p>
<form id={formId}> <form id={formId}>
<Input <StyledInput
autoFocus autoFocus
onChange={handleChange} onChange={handleChange}
value={confirmName} value={confirmName}
label="Segment name" label="Segment name"
className={styles.deleteInput}
data-testid={SEGMENT_DIALOG_NAME_ID} data-testid={SEGMENT_DIALOG_NAME_ID}
/> />
</form> </form>

View File

@ -1,5 +1,4 @@
import { Dialogue } from 'component/common/Dialogue/Dialogue'; import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { useStyles } from '../SegmentDeleteConfirm/SegmentDeleteConfirm.styles';
import { ISegment } from 'interfaces/segment'; import { ISegment } from 'interfaces/segment';
import { IFeatureStrategy } from 'interfaces/strategy'; import { IFeatureStrategy } from 'interfaces/strategy';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -11,6 +10,12 @@ const StyledUl = styled('ul')({
marginBottom: 0, marginBottom: 0,
}); });
const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
color: theme.palette.primary.main,
fontWeight: theme.fontWeight.bold,
}));
interface ISegmentDeleteUsedSegmentProps { interface ISegmentDeleteUsedSegmentProps {
segment: ISegment; segment: ISegment;
open: boolean; open: boolean;
@ -24,8 +29,6 @@ export const SegmentDeleteUsedSegment = ({
onClose, onClose,
strategies, strategies,
}: ISegmentDeleteUsedSegmentProps) => { }: ISegmentDeleteUsedSegmentProps) => {
const { classes: styles } = useStyles();
return ( return (
<Dialogue <Dialogue
title="You can't delete a segment that's currently in use" title="You can't delete a segment that's currently in use"
@ -40,7 +43,7 @@ export const SegmentDeleteUsedSegment = ({
<StyledUl> <StyledUl>
{strategies?.map(strategy => ( {strategies?.map(strategy => (
<li key={strategy.id}> <li key={strategy.id}>
<Link <StyledLink
to={formatEditStrategyPath( to={formatEditStrategyPath(
strategy.projectId!, strategy.projectId!,
strategy.featureName!, strategy.featureName!,
@ -49,11 +52,10 @@ export const SegmentDeleteUsedSegment = ({
)} )}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className={styles.link}
> >
{strategy.featureName!}{' '} {strategy.featureName!}{' '}
{formatStrategyNameParens(strategy)} {formatStrategyNameParens(strategy)}
</Link> </StyledLink>
</li> </li>
))} ))}
</StyledUl> </StyledUl>