mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-03 01:18:43 +02:00
Update UI for strategies - segmentation and for mobile devices (#1189)
* fix: strategies rwd ui updates * rwd updates to strategies * add item numbers to strategies * update strategy segmentation styles
This commit is contained in:
parent
367d8a6a5a
commit
0b93776db6
@ -8,8 +8,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: theme.spacing(1),
|
||||
[theme.breakpoints.down(650)]: {
|
||||
marginBottom: '1rem',
|
||||
[theme.breakpoints.down(710)]: {
|
||||
marginRight: 0,
|
||||
},
|
||||
},
|
||||
@ -17,8 +16,8 @@ export const useStyles = makeStyles()(theme => ({
|
||||
fill: '#fff',
|
||||
},
|
||||
accordion: {
|
||||
border: `1px solid ${theme.palette.grey[400]}`,
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
backgroundColor: '#fff',
|
||||
boxShadow: 'none',
|
||||
margin: 0,
|
||||
@ -27,6 +26,9 @@ export const useStyles = makeStyles()(theme => ({
|
||||
'&:before': {
|
||||
opacity: '0 !important',
|
||||
},
|
||||
'&:first-of-type, &:last-of-type': {
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
},
|
||||
},
|
||||
accordionEdit: {
|
||||
backgroundColor: '#F6F6FA',
|
||||
@ -34,7 +36,10 @@ export const useStyles = makeStyles()(theme => ({
|
||||
headerMetaInfo: {
|
||||
display: 'flex',
|
||||
alignItems: 'stretch',
|
||||
[theme.breakpoints.down(710)]: { flexDirection: 'column' },
|
||||
[theme.breakpoints.down(710)]: {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
},
|
||||
},
|
||||
headerContainer: {
|
||||
display: 'flex',
|
||||
@ -76,6 +81,9 @@ export const useStyles = makeStyles()(theme => ({
|
||||
minWidth: '152px',
|
||||
paddingRight: '0.5rem',
|
||||
},
|
||||
[theme.breakpoints.down(710)]: {
|
||||
paddingRight: 0,
|
||||
},
|
||||
},
|
||||
editingBadge: {
|
||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||
|
@ -1,18 +1,12 @@
|
||||
import { styled } from '@mui/material';
|
||||
import { Box, styled, useTheme } from '@mui/material';
|
||||
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||
|
||||
interface IStrategySeparatorProps {
|
||||
text: 'AND' | 'OR';
|
||||
}
|
||||
|
||||
const StyledContainer = styled('div')(({ theme }) => ({
|
||||
height: theme.spacing(1),
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}));
|
||||
|
||||
const StyledContent = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(0.75, 1.5),
|
||||
padding: theme.spacing(0.75, 1),
|
||||
color: theme.palette.text.primary,
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
backgroundColor: theme.palette.secondaryContainer,
|
||||
@ -20,26 +14,38 @@ const StyledContent = styled('div')(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
zIndex: theme.zIndex.fab,
|
||||
top: '50%',
|
||||
left: theme.spacing(3),
|
||||
left: theme.spacing(2),
|
||||
transform: 'translateY(-50%)',
|
||||
lineHeight: 1,
|
||||
}));
|
||||
|
||||
const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
backgroundColor: theme.palette.secondary.light,
|
||||
backgroundColor: theme.palette.activityIndicators.primary,
|
||||
border: `1px solid ${theme.palette.primary.border}`,
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
}));
|
||||
|
||||
export const StrategySeparator = ({ text }: IStrategySeparatorProps) => (
|
||||
<StyledContainer>
|
||||
<ConditionallyRender
|
||||
condition={text === 'AND'}
|
||||
show={() => <StyledContent>{text}</StyledContent>}
|
||||
elseShow={() => (
|
||||
<StyledCenteredContent>{text}</StyledCenteredContent>
|
||||
)}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
export const StrategySeparator = ({ text }: IStrategySeparatorProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
height: theme.spacing(text === 'AND' ? 1 : 1.5),
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={text === 'AND'}
|
||||
show={() => <StyledContent>{text}</StyledContent>}
|
||||
elseShow={() => (
|
||||
<StyledCenteredContent>{text}</StyledCenteredContent>
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingTop: theme.spacing(2),
|
||||
},
|
||||
title: {
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
|
@ -161,7 +161,7 @@ export const FeatureStrategyEmpty = ({
|
||||
display: 'grid',
|
||||
width: '100%',
|
||||
gap: 2,
|
||||
gridTemplateColumns: '1fr 1fr',
|
||||
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },
|
||||
}}
|
||||
>
|
||||
<PresetCard
|
||||
|
@ -40,7 +40,14 @@ export const PresetCard: FC<IPresetCardProps> = ({
|
||||
{children}
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ ml: 'auto', mt: 'auto', pt: 1 }}>
|
||||
<Box
|
||||
sx={{
|
||||
ml: 'auto',
|
||||
mt: 'auto',
|
||||
pt: 1,
|
||||
mr: { xs: 'auto', sm: 0 },
|
||||
}}
|
||||
>
|
||||
<PermissionButton
|
||||
permission={CREATE_FEATURE_STRATEGY}
|
||||
projectId={projectId}
|
||||
|
@ -1,11 +1,6 @@
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
export const useStyles = makeStyles()(theme => ({
|
||||
title: {
|
||||
margin: 0,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
fontWeight: theme.fontWeight.bold,
|
||||
},
|
||||
divider: {
|
||||
border: `1px dashed ${theme.palette.divider}`,
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/Fe
|
||||
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.styles';
|
||||
import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs/SegmentDocs';
|
||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||
import { Divider } from '@mui/material';
|
||||
import { Divider, Typography } from '@mui/material';
|
||||
|
||||
interface IFeatureStrategySegmentProps {
|
||||
segments: ISegment[];
|
||||
@ -53,7 +53,9 @@ export const FeatureStrategySegment = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className={styles.title}>Segmentation</h3>
|
||||
<Typography component="h3" sx={{ m: 0 }} variant="h3">
|
||||
Segmentation
|
||||
</Typography>
|
||||
{atStrategySegmentsLimit && <SegmentDocsStrategyWarning />}
|
||||
<p>Add a predefined segment to constrain this feature toggle:</p>
|
||||
<AutocompleteBox
|
||||
|
@ -16,11 +16,13 @@ export const useStyles = makeStyles()(theme => ({
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
border: '1px solid',
|
||||
borderColor: theme.palette.grey[300],
|
||||
paddingInline: '0.4rem',
|
||||
marginBlock: '0.2rem',
|
||||
display: 'grid',
|
||||
padding: theme.spacing(0.75, 1),
|
||||
display: 'block',
|
||||
marginTop: 'auto',
|
||||
marginBottom: 'auto',
|
||||
alignItems: 'center',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
lineHeight: 1,
|
||||
},
|
||||
selectedSegmentsLabel: {
|
||||
color: theme.palette.text.secondary,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Box, styled } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||
import { MoveListItem, useDragItem } from 'hooks/useDragItem';
|
||||
@ -13,6 +14,18 @@ interface IStrategyDraggableItemProps {
|
||||
onDragAndDrop: MoveListItem;
|
||||
}
|
||||
|
||||
const StyledIndexLabel = styled('div')(({ theme }) => ({
|
||||
fontSize: theme.typography.fontSize,
|
||||
color: theme.palette.text.secondary,
|
||||
position: 'absolute',
|
||||
display: 'none',
|
||||
right: 'calc(100% + 6px)',
|
||||
top: theme.spacing(2.5),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'block',
|
||||
},
|
||||
}));
|
||||
|
||||
export const StrategyDraggableItem = ({
|
||||
strategy,
|
||||
index,
|
||||
@ -23,17 +36,20 @@ export const StrategyDraggableItem = ({
|
||||
const ref = useDragItem(index, onDragAndDrop);
|
||||
|
||||
return (
|
||||
<div key={strategy.id} ref={ref}>
|
||||
<Box key={strategy.id} ref={ref}>
|
||||
<ConditionallyRender
|
||||
condition={index > 0}
|
||||
show={<StrategySeparator text="OR" />}
|
||||
/>
|
||||
<StrategyItem
|
||||
strategy={strategy}
|
||||
environmentId={environmentName}
|
||||
otherEnvironments={otherEnvironments}
|
||||
isDraggable
|
||||
/>
|
||||
</div>
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<StyledIndexLabel>{index + 1}</StyledIndexLabel>
|
||||
<StrategyItem
|
||||
strategy={strategy}
|
||||
environmentId={environmentName}
|
||||
otherEnvironments={otherEnvironments}
|
||||
isDraggable
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
container: {
|
||||
width: '100%',
|
||||
padding: theme.spacing(2, 3),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
chip: {
|
||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
valueContainer: {
|
||||
padding: theme.spacing(2, 3),
|
||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
},
|
||||
valueSeparator: {
|
||||
color: theme.palette.grey[700],
|
||||
|
@ -17,6 +17,9 @@ export const useStyles = makeStyles()(theme => ({
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
},
|
||||
headerDraggable: {
|
||||
paddingLeft: theme.spacing(1),
|
||||
},
|
||||
icon: {
|
||||
fill: theme.palette.inactiveIcon,
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { DragIndicator, Edit } from '@mui/icons-material';
|
||||
import { styled, useTheme, IconButton } from '@mui/material';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import { IFeatureEnvironment } from 'interfaces/featureToggle';
|
||||
import { IFeatureStrategy } from 'interfaces/strategy';
|
||||
import {
|
||||
@ -52,7 +53,11 @@ export const StrategyItem = ({
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.header}>
|
||||
<div
|
||||
className={classNames(styles.header, {
|
||||
[styles.headerDraggable]: isDraggable,
|
||||
})}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(isDraggable)}
|
||||
show={() => (
|
||||
@ -60,6 +65,7 @@ export const StrategyItem = ({
|
||||
<DragIndicator
|
||||
titleAccess="Drag to reorder"
|
||||
cursor="grab"
|
||||
sx={{ color: 'neutral.main' }}
|
||||
/>
|
||||
</DragIcon>
|
||||
)}
|
||||
|
@ -28,9 +28,13 @@ export const useStyles = makeStyles()(theme => ({
|
||||
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
|
||||
borderBottomRightRadius: theme.shape.borderRadiusLarge,
|
||||
borderBottom: `4px solid ${theme.palette.primary.light}`,
|
||||
|
||||
[theme.breakpoints.down('md')]: {
|
||||
padding: theme.spacing(2, 1),
|
||||
},
|
||||
},
|
||||
accordionDetailsDisabled: {
|
||||
borderBottom: `4px solid ${theme.palette.dividerAlternative}`,
|
||||
borderBottom: `4px solid ${theme.palette.neutral.border}`,
|
||||
},
|
||||
accordionBody: {
|
||||
width: '100%',
|
||||
|
@ -85,18 +85,18 @@ const FeatureOverviewEnvironment = ({
|
||||
maxWidth="100"
|
||||
maxLength={15}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={!env.enabled}
|
||||
show={
|
||||
<Chip
|
||||
size="small"
|
||||
variant="outlined"
|
||||
label="Disabled"
|
||||
sx={{ ml: 1 }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<ConditionallyRender
|
||||
condition={!env.enabled}
|
||||
show={
|
||||
<Chip
|
||||
size="small"
|
||||
variant="outlined"
|
||||
label="Disabled"
|
||||
sx={{ ml: 1 }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.container}>
|
||||
<FeatureStrategyMenu
|
||||
|
@ -14,7 +14,7 @@ const SeparatorContainer = styled('div')(({ theme }) => ({
|
||||
transform: 'translateY(-50%)',
|
||||
height: 2,
|
||||
width: '100%',
|
||||
backgroundColor: theme.palette.divider,
|
||||
backgroundColor: theme.palette.dividerAlternative,
|
||||
},
|
||||
}));
|
||||
|
||||
@ -25,7 +25,7 @@ const SeparatorContent = styled('span')(({ theme }) => ({
|
||||
background: theme.palette.secondaryContainer,
|
||||
position: 'relative',
|
||||
maxWidth: '80%',
|
||||
color: theme.palette.text.secondary,
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const SectionSeparator: FC = ({ children }) => (
|
||||
|
@ -3,6 +3,8 @@ import { Link } from 'react-router-dom';
|
||||
import { DonutLarge } from '@mui/icons-material';
|
||||
import { useStyles } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.styles';
|
||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||
|
||||
interface IFeatureOverviewSegmentProps {
|
||||
strategyId: string;
|
||||
@ -20,8 +22,12 @@ export const FeatureOverviewSegment = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{segments.map(segment => (
|
||||
{segments.map((segment, index) => (
|
||||
<Fragment key={segment.id}>
|
||||
<ConditionallyRender
|
||||
condition={index > 0}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
<div className={styles.container}>
|
||||
<DonutLarge color="secondary" sx={{ mr: 1 }} /> Segment:{' '}
|
||||
<Link
|
||||
|
@ -81,9 +81,9 @@ const RolloutSlider = ({
|
||||
<div className={classes.slider}>
|
||||
<Typography
|
||||
id="discrete-slider-always"
|
||||
variant="subtitle2"
|
||||
variant="h3"
|
||||
gutterBottom
|
||||
component="h2"
|
||||
component="h3"
|
||||
>
|
||||
{name}
|
||||
</Typography>
|
||||
|
@ -26,6 +26,10 @@ export default createTheme({
|
||||
fontSize: '1.5rem',
|
||||
lineHeight: 1.875,
|
||||
},
|
||||
h3: {
|
||||
fontSize: '1rem',
|
||||
fontWeight: '700',
|
||||
},
|
||||
caption: {
|
||||
fontSize: `${12 / 16}rem`,
|
||||
},
|
||||
@ -128,6 +132,7 @@ export default createTheme({
|
||||
recent: colors.green[100],
|
||||
inactive: colors.orange[200],
|
||||
abandoned: colors.red[200],
|
||||
primary: colors.purple[100],
|
||||
},
|
||||
inactiveIcon: colors.grey[600],
|
||||
},
|
||||
|
@ -46,13 +46,14 @@ declare module '@mui/material/styles' {
|
||||
background: string;
|
||||
};
|
||||
/**
|
||||
* For 'Seen' column on feature toggles list.
|
||||
* For 'Seen' column on feature toggles list and other.
|
||||
*/
|
||||
activityIndicators: {
|
||||
unknown: string;
|
||||
recent: string;
|
||||
inactive: string;
|
||||
abandoned: string;
|
||||
primary: string;
|
||||
};
|
||||
dividerAlternative: string;
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user