1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-26 01:17:00 +02:00

Refactor/make styles batch 6 part 2 (#2811)

Adds another batch of refactored components
This commit is contained in:
Fredrik Strand Oseberg 2023-01-03 16:15:22 +01:00 committed by GitHub
parent b631618532
commit 093156f5f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 271 additions and 327 deletions

View File

@ -33,7 +33,7 @@ export const FeatureStrategyItem = ({
style={{
borderColor: result.enabled
? theme.palette.success.main
: 'inherit',
: 'none',
}}
strategy={{ ...strategy, id: `${objectId(strategy)}` }}
orderNumber={index + 1}

View File

@ -1,9 +1,7 @@
import { Chip, Typography, useTheme } from '@mui/material';
import { Chip, Typography, useTheme, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './PlaygroundParametertem.styles';
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
import { CancelOutlined } from '@mui/icons-material';
import classnames from 'classnames';
interface IConstraintItemProps {
value: Array<string | number>;
@ -12,29 +10,55 @@ interface IConstraintItemProps {
showReason?: boolean;
}
const StyledDivContainer = styled('div', {
shouldForwardProp: prop => prop !== 'showReason',
})<{ showReason?: boolean }>(({ theme, showReason }) => ({
width: '100%',
padding: theme.spacing(2, 3),
borderRadius: theme.shape.borderRadiusMedium,
border: `1px solid ${theme.palette.dividerAlternative}`,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: theme.spacing(2),
opacity: showReason ? 0.9 : 1,
backgroundColor: showReason ? theme.palette.background.paper : 'inherit',
}));
const StyledDivColumn = styled('div')(({ theme }) => ({
flexDirection: 'column',
}));
const StyledChip = styled(Chip)(({ theme }) => ({
margin: theme.spacing(0.5),
}));
const StyledParagraph = styled('p')(({ theme }) => ({
display: 'inline',
margin: theme.spacing(0.5, 0),
maxWidth: '95%',
textAlign: 'center',
wordBreak: 'break-word',
}));
export const PlaygroundParameterItem = ({
value,
text,
input,
showReason = false,
}: IConstraintItemProps) => {
const { classes: styles } = useStyles();
const theme = useTheme();
const color = input === 'no value' ? 'error' : 'neutral';
const reason = `value does not match any ${text}`;
return (
<div
className={classnames(
styles.container,
showReason ? styles.disabled : ''
)}
>
<StyledDivContainer showReason={showReason}>
<Typography variant="subtitle1" color={theme.palette[color].main}>
{`${input}`}
</Typography>
<div className={styles.column}>
<StyledDivColumn>
<ConditionallyRender
condition={Boolean(showReason)}
show={
@ -51,13 +75,13 @@ export const PlaygroundParameterItem = ({
show={<p>No {text}s added yet.</p>}
elseShow={
<div>
<p className={styles.paragraph}>
<StyledParagraph>
{value.length}{' '}
{value.length > 1 ? `${text}s` : text} will get
access.
</p>
</StyledParagraph>
{value.map((v: string | number) => (
<Chip
<StyledChip
key={v}
label={
<StringTruncator
@ -66,18 +90,17 @@ export const PlaygroundParameterItem = ({
maxLength={50}
/>
}
className={styles.chip}
/>
))}
</div>
}
/>
</div>
</StyledDivColumn>
<ConditionallyRender
condition={Boolean(showReason)}
show={<CancelOutlined color={'error'} />}
elseShow={<div />}
/>
</div>
</StyledDivContainer>
);
};

View File

@ -1,32 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
width: '100%',
padding: theme.spacing(2, 3),
borderRadius: theme.shape.borderRadiusMedium,
border: `1px solid ${theme.palette.dividerAlternative}`,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: theme.spacing(2),
},
disabled: {
backgroundColor: theme.palette.neutral.light,
opacity: '90%',
},
chip: {
margin: '0.25rem',
},
column: {
flexDirection: 'column',
},
paragraph: {
display: 'inline',
margin: '0.25rem 0',
maxWidth: '95%',
textAlign: 'center',
wordBreak: 'break-word',
},
}));

View File

@ -1,61 +1,87 @@
import { makeStyles } from 'tss-react/mui';
import { styled, Tab } from '@mui/material';
import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton';
export const useStyles = makeStyles()(theme => ({
containerStyles: {
display: 'flex',
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
export const StyledDiv = styled('div')(() => ({
display: 'flex',
}));
export const StyledTopRow = styled('div')(() => ({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
}));
export const StyledColumn = styled('div')(() => ({
display: 'flex',
flexDirection: 'column',
}));
export const StyledName = styled('div')(() => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}));
export const StyledTitle = styled('span')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
fontWeight: 'normal',
}));
export const StyledText = styled(StyledTitle)(({ theme }) => ({
color: theme.palette.neutral.dark,
}));
export const StyledFavoriteIconButton = styled(FavoriteIconButton)(
({ theme }) => ({
marginLeft: theme.spacing(-1.5),
})
);
export const StyledHeader = styled('div')(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadiusLarge,
marginBottom: theme.spacing(2),
}));
export const StyledInnerContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(2.5, 5),
display: 'flex',
flexDirection: 'column',
alignItems: 'start',
}));
export const StyledProjectTitle = styled('h2')(({ theme }) => ({
margin: 0,
width: '100%',
fontSize: theme.fontSizes.mainHeader,
fontWeight: 'bold',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: theme.spacing(2),
}));
export const StyledSeparator = styled('div')(({ theme }) => ({
width: '100%',
backgroundColor: theme.palette.tertiary.light,
height: '1px',
}));
export const StyledTabContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(0, 4),
}));
export const StyledTab = styled(Tab)(({ theme }) => ({
textTransform: 'none',
fontSize: theme.fontSizes.bodySize,
flexGrow: 1,
flexBasis: 0,
[theme.breakpoints.down('md')]: {
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
},
projectToggles: {
width: '100%',
minWidth: 0,
},
header: {
backgroundColor: theme.palette.background.paper,
borderRadius: theme.shape.borderRadiusLarge,
marginBottom: '1rem',
},
innerContainer: {
padding: '1.25rem 2rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'start',
},
separator: {
width: '100%',
backgroundColor: theme.palette.grey[200],
height: '1px',
},
tabContainer: {
padding: '0 2rem',
},
tabButton: {
textTransform: 'none',
fontSize: '1rem',
flexGrow: 1,
flexBasis: 0,
[theme.breakpoints.down('md')]: {
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
},
[theme.breakpoints.up('md')]: {
minWidth: 160,
},
},
title: {
margin: 0,
width: '100%',
fontSize: theme.fontSizes.mainHeader,
fontWeight: 'bold',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: '1rem',
},
titleText: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
[theme.breakpoints.up('md')]: {
minWidth: 160,
},
}));

View File

@ -2,8 +2,22 @@ import { useNavigate } from 'react-router';
import useProject from 'hooks/api/getters/useProject/useProject';
import useLoading from 'hooks/useLoading';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './Project.styles';
import { styled, Tab, Tabs } from '@mui/material';
import {
StyledColumn,
StyledDiv,
StyledFavoriteIconButton,
StyledHeader,
StyledInnerContainer,
StyledName,
StyledProjectTitle,
StyledSeparator,
StyledTab,
StyledTabContainer,
StyledText,
StyledTitle,
StyledTopRow,
} from './Project.styles';
import { Tabs } from '@mui/material';
import { Delete, Edit } from '@mui/icons-material';
import useToast from 'hooks/useToast';
import useQueryParams from 'hooks/useQueryParams';
@ -28,53 +42,17 @@ import { MainLayout } from 'component/layout/MainLayout/MainLayout';
import { ProjectChangeRequests } from '../../changeRequest/ProjectChangeRequests/ProjectChangeRequests';
import { ProjectSettings } from './ProjectSettings/ProjectSettings';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton';
import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
const StyledDiv = styled('div')(() => ({
display: 'flex',
}));
const StyledTopRow = styled('div')(() => ({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
}));
const Column = styled('div')(() => ({
display: 'flex',
flexDirection: 'column',
}));
const StyledName = styled('div')(() => ({
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}));
const StyledTitle = styled('span')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
fontWeight: 'normal',
}));
const StyledText = styled(StyledTitle)(({ theme }) => ({
color: theme.palette.grey[800],
}));
const StyledFavoriteIconButton = styled(FavoriteIconButton)(({ theme }) => ({
marginLeft: theme.spacing(-1.5),
}));
const Project = () => {
const projectId = useRequiredPathParam('projectId');
const params = useQueryParams();
const { project, loading, refetch } = useProject(projectId);
const ref = useLoading(loading);
const { setToastData } = useToast();
const { classes: styles } = useStyles();
const navigate = useNavigate();
const { pathname } = useLocation();
const { isOss, uiConfig } = useUiConfig();
const { isOss } = useUiConfig();
const basePath = `/projects/${projectId}`;
const projectName = project?.name || projectId;
const { isChangeRequestConfiguredInAnyEnv } =
@ -152,19 +130,19 @@ const Project = () => {
) : null
}
>
<div className={styles.header}>
<div className={styles.innerContainer}>
<StyledHeader>
<StyledInnerContainer>
<StyledTopRow>
<StyledDiv>
<StyledFavoriteIconButton
onClick={onFavorite}
isFavorite={project?.favorite}
/>
<h2 className={styles.title}>
<StyledProjectTitle>
<StyledName data-loading>
{projectName}
</StyledName>
</h2>
</StyledProjectTitle>
</StyledDiv>
<StyledDiv>
<PermissionIconButton
@ -197,8 +175,8 @@ const Project = () => {
</PermissionIconButton>
</StyledDiv>
</StyledTopRow>
<Column>
<h2 className={styles.title}>
<StyledColumn>
<StyledProjectTitle>
<div>
<ConditionallyRender
condition={Boolean(project.description)}
@ -222,12 +200,12 @@ const Project = () => {
</StyledText>
</StyledDiv>
</div>
</h2>
</Column>
</div>
</StyledProjectTitle>
</StyledColumn>
</StyledInnerContainer>
<div className={styles.separator} />
<div className={styles.tabContainer}>
<StyledSeparator />
<StyledTabContainer>
<Tabs
value={activeTab?.path}
indicatorColor="primary"
@ -236,17 +214,16 @@ const Project = () => {
allowScrollButtonsMobile
>
{tabs.map(tab => (
<Tab
<StyledTab
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
className={styles.tabButton}
/>
))}
</Tabs>
</div>
</div>
</StyledTabContainer>
</StyledHeader>
<DeleteProjectDialogue
project={projectId}
open={showDelDialog}

View File

@ -1,19 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
cell: {
display: 'flex',
justifyContent: 'center',
paddingRight: theme.spacing(2),
},
menuContainer: {
borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(1, 1.5),
},
item: {
borderRadius: theme.shape.borderRadius,
},
text: {
fontSize: theme.fontSizes.smallBody,
},
}));

View File

@ -9,19 +9,26 @@ import {
Popover,
Tooltip,
Typography,
styled,
} from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import FileCopyIcon from '@mui/icons-material/FileCopy';
import ArchiveIcon from '@mui/icons-material/Archive';
import WatchLaterIcon from '@mui/icons-material/WatchLater';
import { useStyles } from './ActionsCell.styles';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
import {
CREATE_FEATURE,
DELETE_FEATURE,
UPDATE_FEATURE,
} from 'component/providers/AccessProvider/permissions';
import { defaultBorderRadius } from 'themes/themeStyles';
const StyledBoxCell = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'center',
paddingRight: theme.spacing(2),
}));
interface IActionsCellProps {
projectId: string;
@ -42,7 +49,6 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
onOpenStaleDialog,
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const { classes } = useStyles();
const {
original: { name: featureId, stale },
} = row;
@ -58,7 +64,7 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
const menuId = `${id}-menu`;
return (
<Box className={classes.cell}>
<StyledBoxCell>
<Tooltip title="Feature toggle actions" arrow describeChild>
<IconButton
id={id}
@ -80,7 +86,10 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
disableScrollLock={true}
PaperProps={{
className: classes.menuContainer,
sx: theme => ({
borderRadius: theme.shape.borderRadius,
padding: theme.spacing(1, 1.5),
}),
}}
>
<MenuList aria-labelledby={id}>
@ -90,7 +99,7 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
>
{({ hasAccess }) => (
<MenuItem
className={classes.item}
sx={defaultBorderRadius}
onClick={handleClose}
disabled={!hasAccess}
component={RouterLink}
@ -113,7 +122,7 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
>
{({ hasAccess }) => (
<MenuItem
className={classes.item}
sx={defaultBorderRadius}
onClick={() => {
onOpenArchiveDialog(featureId);
handleClose();
@ -137,7 +146,7 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
>
{({ hasAccess }) => (
<MenuItem
className={classes.item}
sx={defaultBorderRadius}
onClick={() => {
handleClose();
onOpenStaleDialog({
@ -160,6 +169,6 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
</PermissionHOC>
</MenuList>
</Popover>
</Box>
</StyledBoxCell>
);
};

View File

@ -1,35 +1,41 @@
import { makeStyles } from 'tss-react/mui';
import {
Box,
Checkbox,
Divider,
IconButton,
MenuItem,
styled,
} from '@mui/material';
export const useStyles = makeStyles()(theme => ({
container: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
button: {
margin: theme.spacing(-1, 0),
},
menuContainer: {
borderRadius: theme.shape.borderRadiusLarge,
paddingBottom: theme.spacing(2),
},
menuHeader: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: theme.spacing(1, 1, 0, 4),
},
menuItem: {
padding: theme.spacing(0, 2),
margin: theme.spacing(0, 2),
borderRadius: theme.shape.borderRadius,
},
checkbox: {
padding: theme.spacing(0.75, 1),
},
divider: {
'&.MuiDivider-root.MuiDivider-fullWidth': {
margin: theme.spacing(0.75, 0),
},
import { flexRow } from 'themes/themeStyles';
export const StyledBoxContainer = styled(Box)(() => ({
...flexRow,
justifyContent: 'center',
}));
export const StyledIconButton = styled(IconButton)(({ theme }) => ({
margin: theme.spacing(-1, 0),
}));
export const StyledBoxMenuHeader = styled(Box)(({ theme }) => ({
...flexRow,
justifyContent: 'space-between',
padding: theme.spacing(1, 1, 0, 4),
}));
export const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
padding: theme.spacing(0, 2),
margin: theme.spacing(0, 2),
borderRadius: theme.shape.borderRadius,
}));
export const StyledDivider = styled(Divider)(({ theme }) => ({
'&.MuiDivider-root.MuiDivider-fullWidth': {
margin: theme.spacing(0.75, 0),
},
}));
export const StyledCheckbox = styled(Checkbox)(({ theme }) => ({
padding: theme.spacing(0.75, 1),
}));

View File

@ -1,12 +1,8 @@
import { useEffect, useState, VFC } from 'react';
import {
Box,
Checkbox,
Divider,
IconButton,
ListItemIcon,
ListItemText,
MenuItem,
MenuList,
Popover,
Tooltip,
@ -17,7 +13,14 @@ import {
import ColumnIcon from '@mui/icons-material/ViewWeek';
import CloseIcon from '@mui/icons-material/Close';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useStyles } from './ColumnsMenu.styles';
import {
StyledBoxContainer,
StyledBoxMenuHeader,
StyledCheckbox,
StyledDivider,
StyledIconButton,
StyledMenuItem,
} from './ColumnsMenu.styles';
interface IColumnsMenuProps {
allColumns: {
@ -51,7 +54,6 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
setHiddenColumns,
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const { classes } = useStyles();
const theme = useTheme();
const isTinyScreen = useMediaQuery(theme.breakpoints.down('sm'));
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
@ -104,9 +106,9 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
const menuId = `columns-menu-list-${id}`;
return (
<Box className={classes.container}>
<StyledBoxContainer>
<Tooltip title="Select columns" arrow describeChild>
<IconButton
<StyledIconButton
id={id}
aria-controls={isOpen ? menuId : undefined}
aria-haspopup="true"
@ -114,11 +116,10 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
onClick={handleClick}
type="button"
size="large"
className={classes.button}
data-loading
>
<ColumnIcon />
</IconButton>
</StyledIconButton>
</Tooltip>
<Popover
@ -136,34 +137,36 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
}}
disableScrollLock={true}
PaperProps={{
className: classes.menuContainer,
sx: theme => ({
borderRadius: theme.shape.borderRadius,
paddingBottom: theme.spacing(2),
}),
}}
>
<Box className={classes.menuHeader}>
<StyledBoxMenuHeader>
<Typography variant="body2">
<strong>Columns</strong>
</Typography>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
</Box>
</StyledBoxMenuHeader>
<MenuList>
{allColumns
.filter(({ hideInMenu }) => !hideInMenu)
.map(column => [
<ConditionallyRender
condition={dividerBefore.includes(column.id)}
show={<Divider className={classes.divider} />}
show={<StyledDivider />}
/>,
<MenuItem
<StyledMenuItem
onClick={() =>
column.toggleHidden(column.isVisible)
}
disabled={staticColumns.includes(column.id)}
className={classes.menuItem}
>
<ListItemIcon>
<Checkbox
<StyledCheckbox
edge="start"
checked={column.isVisible}
disableRipple
@ -171,7 +174,6 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
'aria-labelledby': column.id,
}}
size="medium"
className={classes.checkbox}
/>
</ListItemIcon>
<ListItemText
@ -195,14 +197,14 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
</Typography>
}
/>
</MenuItem>,
</StyledMenuItem>,
<ConditionallyRender
condition={dividerAfter.includes(column.id)}
show={<Divider className={classes.divider} />}
show={<StyledDivider />}
/>,
])}
</MenuList>
</Popover>
</Box>
</StyledBoxContainer>
);
};

View File

@ -1,9 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
mx: 'auto',
display: 'flex',
justifyContent: 'center',
},
}));

View File

@ -1,9 +1,14 @@
import { VFC } from 'react';
import { Box } from '@mui/material';
import { Box, styled } from '@mui/material';
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
import { useOptimisticUpdate } from './hooks/useOptimisticUpdate';
import { useStyles } from './FeatureToggleSwitch.styles';
import { flexRow } from 'themes/themeStyles';
const StyledBoxContainer = styled(Box)(() => ({
mx: 'auto',
...flexRow,
}));
interface IFeatureToggleSwitchProps {
featureName: string;
@ -25,7 +30,6 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
value,
onToggle,
}) => {
const { classes } = useStyles();
const [isChecked, setIsChecked, rollbackIsChecked] =
useOptimisticUpdate<boolean>(value);
@ -37,8 +41,7 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
};
return (
<Box
className={classes.container}
<StyledBoxContainer
key={`${featureName}-${environmentName}`} // Prevent animation when archiving rows
>
<PermissionSwitch
@ -50,6 +53,6 @@ export const FeatureToggleSwitch: VFC<IFeatureToggleSwitchProps> = ({
onClick={onClick}
disabled={isChecked !== value}
/>
</Box>
</StyledBoxContainer>
);
};

View File

@ -13,60 +13,4 @@ export const useStyles = makeStyles()(theme => ({
width: 'inherit',
},
},
headerClass: {
'& th': {
fontSize: theme.fontSizes.smallerBody,
lineHeight: '1rem',
},
},
bodyClass: {
overflowX: 'auto',
padding: theme.spacing(4),
},
header: {
padding: '1rem',
},
title: {
display: 'unset',
},
iconButton: {
marginRight: '1rem',
},
icon: {
color: '#000',
height: '30px',
width: '30px',
},
noTogglesFound: {
marginBottom: '0.5rem',
},
link: {
textDecoration: 'none',
color: theme.palette.primary.main,
},
actionsContainer: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
search: {
border: `1px solid ${theme.palette.grey[300]}`,
height: 35,
marginRight: '2rem',
},
button: {
whiteSpace: 'nowrap',
},
row: {
position: 'absolute',
width: '100%',
},
cell: {
alignItems: 'center',
display: 'flex',
flexShrink: 0,
'& > *': {
flexGrow: 1,
},
},
}));

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useMediaQuery, useTheme } from '@mui/material';
import { styled, useMediaQuery, useTheme } from '@mui/material';
import { Add } from '@mui/icons-material';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table';
@ -9,7 +9,6 @@ import { PageContent } from 'component/common/PageContent/PageContent';
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import { getCreateTogglePath } from 'utils/routePathHelpers';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
@ -47,6 +46,10 @@ import { FeatureTagCell } from 'component/common/Table/cells/FeatureTagCell/Feat
import { useGlobalLocalStorage } from 'hooks/useGlobalLocalStorage';
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
const StyledResponsiveButton = styled(ResponsiveButton)(() => ({
whiteSpace: 'nowrap',
}));
interface IProjectFeatureTogglesProps {
features: IProject['features'];
environments: IProject['environments'];
@ -102,7 +105,6 @@ export const ProjectFeatureToggles = ({
useGlobalLocalStorage();
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
const { uiConfig } = useUiConfig();
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
const environments = useEnvironmentsRef(
loading ? ['a', 'b', 'c'] : newEnvironments
@ -488,10 +490,8 @@ export const ProjectFeatureToggles = ({
<PageContent
isLoading={loading}
className={styles.container}
bodyClass={styles.bodyClass}
header={
<PageHeader
className={styles.title}
titleElement={`Feature toggles (${rows.length})`}
actions={
<>
@ -515,7 +515,7 @@ export const ProjectFeatureToggles = ({
setHiddenColumns={setHiddenColumns}
/>
<PageHeader.Divider sx={{ marginLeft: 0 }} />
<ResponsiveButton
<StyledResponsiveButton
onClick={() =>
navigate(getCreateTogglePath(projectId))
}
@ -523,10 +523,9 @@ export const ProjectFeatureToggles = ({
Icon={Add}
projectId={projectId}
permission={CREATE_FEATURE}
className={styles.button}
>
New feature toggle
</ResponsiveButton>
</StyledResponsiveButton>
</>
}
>

View File

@ -1,9 +1,9 @@
import useProject, {
useProjectNameOrId,
} from 'hooks/api/getters/useProject/useProject';
import { styled } from '@mui/material';
import { ProjectFeatureToggles } from './ProjectFeatureToggles/ProjectFeatureToggles';
import ProjectInfo from './ProjectInfo/ProjectInfo';
import { useStyles } from './Project.styles';
import { usePageTitle } from 'hooks/usePageTitle';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useLastViewedProject } from '../../../hooks/useLastViewedProject';
@ -11,12 +11,23 @@ import { useEffect } from 'react';
const refreshInterval = 15 * 1000;
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
}));
const StyledProjectToggles = styled('div')(() => ({
width: '100%',
minWidth: 0,
}));
const ProjectOverview = () => {
const projectId = useRequiredPathParam('projectId');
const projectName = useProjectNameOrId(projectId);
const { project, loading } = useProject(projectId, { refreshInterval });
const { members, features, health, description, environments } = project;
const { classes: styles } = useStyles();
usePageTitle(`Project overview ${projectName}`);
const { setLastViewed } = useLastViewedProject();
@ -25,7 +36,7 @@ const ProjectOverview = () => {
}, [projectId, setLastViewed]);
return (
<div className={styles.containerStyles}>
<StyledContainer>
<ProjectInfo
id={projectId}
description={description}
@ -33,14 +44,14 @@ const ProjectOverview = () => {
health={health}
featureCount={features?.length}
/>
<div className={styles.projectToggles}>
<StyledProjectToggles>
<ProjectFeatureToggles
features={features}
environments={environments}
loading={loading}
/>
</div>
</div>
</StyledProjectToggles>
</StyledContainer>
);
};

View File

@ -14,7 +14,11 @@ export const focusable = (theme: Theme) => ({
export const flexRow = {
display: 'flex',
alignItems: 'center',
};
} as const;
export const defaultBorderRadius = (theme: Theme) => ({
borderRadius: `${theme.shape.borderRadius}px`,
});
/**
* Please extract styles below into MUI fragments as shown above