1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-14 00:19:16 +01:00

Segment preview (#1194)

* segment preview

* fix: loading and font size inconsistencies

* update segment accordion styles
This commit is contained in:
Tymoteusz Czech 2022-08-04 14:44:18 +02:00 committed by GitHub
parent 672a3f0b92
commit b7de1fba52
19 changed files with 171 additions and 93 deletions

View File

@ -26,9 +26,6 @@ export const useStyles = makeStyles()(theme => ({
'&:before': { '&:before': {
opacity: '0 !important', opacity: '0 !important',
}, },
'&:first-of-type, &:last-of-type': {
borderRadius: theme.shape.borderRadiusMedium,
},
}, },
accordionEdit: { accordionEdit: {
backgroundColor: '#F6F6FA', backgroundColor: '#F6F6FA',

View File

@ -48,7 +48,7 @@ export const useStyles = makeStyles()(theme => ({
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',
fontWeight: theme.fontWeight.bold, fontWeight: theme.fontWeight.bold,
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
}, },
description: { description: {
color: '#fff', color: '#fff',

View File

@ -0,0 +1,45 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
width: '100%',
padding: theme.spacing(2, 3),
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
fontSize: theme.fontSizes.smallBody,
border: `1px solid ${theme.palette.dividerAlternative}`,
position: 'relative',
borderRadius: '5px',
},
link: {
textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': {
textDecoration: 'underline',
},
},
accordion: {
border: `1px solid ${theme.palette.dividerAlternative}`,
borderRadius: theme.shape.borderRadiusMedium,
backgroundColor: '#fff',
boxShadow: 'none',
margin: 0,
},
accordionRoot: {
transition: 'all 0.1s ease',
},
accordionExpanded: {
backgroundColor: theme.palette.neutral.light,
},
previewButton: {
paddingTop: 0,
paddingBottom: 0,
marginLeft: 'auto',
fontSize: theme.fontSizes.smallBody,
},
summary: {
fontSize: theme.fontSizes.smallBody,
margin: theme.spacing(0.5, 0),
},
}));

View File

@ -0,0 +1,81 @@
import { useState, VFC } from 'react';
import { Link } from 'react-router-dom';
import { DonutLarge } from '@mui/icons-material';
import { ISegment } from 'interfaces/segment';
import {
Accordion,
AccordionDetails,
AccordionSummary,
Button,
Typography,
} from '@mui/material';
import { ConstraintAccordionList } from '../ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { useStyles } from './SegmentItem.styles';
interface ISegmentItemProps {
segment: ISegment;
isExpanded?: boolean;
}
export const SegmentItem: VFC<ISegmentItemProps> = ({
segment,
isExpanded,
}) => {
const { classes } = useStyles();
const [isOpen, setIsOpen] = useState(isExpanded || false);
return (
<Accordion
expanded={isOpen}
className={classes.accordion}
classes={{
root: classes.accordionRoot,
expanded: classes.accordionExpanded,
}}
>
<AccordionSummary
id={`segment-accordion-${segment.id}`}
className={classes.summary}
>
<DonutLarge color="secondary" sx={{ mr: 1 }} />
Segment:
<Link
to={`/segments/edit/${segment.id}`}
className={classes.link}
>
{segment.name}
</Link>
<ConditionallyRender
condition={!isExpanded}
show={
<Button
size="small"
variant="outlined"
onClick={() => setIsOpen(value => !value)}
className={classes.previewButton}
>
{isOpen ? 'Close preview' : 'Preview'}
</Button>
}
/>
</AccordionSummary>
<AccordionDetails sx={{ pt: 0 }}>
<ConditionallyRender
condition={segment!.constraints?.length > 0}
show={
<ConstraintAccordionList
constraints={segment!.constraints}
showLabel={false}
/>
}
elseShow={
<Typography>
This segment has no constraints.
</Typography>
}
/>
</AccordionDetails>
</Accordion>
);
};

View File

@ -26,6 +26,7 @@ const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({
backgroundColor: theme.palette.activityIndicators.primary, backgroundColor: theme.palette.activityIndicators.primary,
border: `1px solid ${theme.palette.primary.border}`, border: `1px solid ${theme.palette.primary.border}`,
borderRadius: theme.shape.borderRadiusLarge, borderRadius: theme.shape.borderRadiusLarge,
padding: theme.spacing(0.75, 1.5),
})); }));
export const StrategySeparator = ({ text }: IStrategySeparatorProps) => { export const StrategySeparator = ({ text }: IStrategySeparatorProps) => {

View File

@ -16,7 +16,7 @@ export const useStyles = makeStyles()(theme => ({
display: 'grid', display: 'grid',
gridTemplateColumns: 'auto 1fr', gridTemplateColumns: 'auto 1fr',
gridGap: '.5rem', gridGap: '.5rem',
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
}, },
icon: { icon: {
color: theme.palette.primary.main, color: theme.palette.primary.main,

View File

@ -3,5 +3,7 @@ import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({ export const useStyles = makeStyles()(theme => ({
divider: { divider: {
border: `1px dashed ${theme.palette.divider}`, border: `1px dashed ${theme.palette.divider}`,
marginTop: theme.spacing(1),
marginBottom: theme.spacing(2),
}, },
})); }));

View File

@ -12,10 +12,7 @@ export const useStyles = makeStyles()(theme => ({
gap: '0.5rem', gap: '0.5rem',
}, },
and: { and: {
color: theme.palette.grey[600],
fontSize: theme.fontSizes.smallerBody, fontSize: theme.fontSizes.smallerBody,
border: '1px solid',
borderColor: theme.palette.grey[300],
padding: theme.spacing(0.75, 1), padding: theme.spacing(0.75, 1),
display: 'block', display: 'block',
marginTop: 'auto', marginTop: 'auto',
@ -23,6 +20,8 @@ export const useStyles = makeStyles()(theme => ({
alignItems: 'center', alignItems: 'center',
borderRadius: theme.shape.borderRadius, borderRadius: theme.shape.borderRadius,
lineHeight: 1, lineHeight: 1,
color: theme.palette.text.primary,
backgroundColor: theme.palette.secondaryContainer,
}, },
selectedSegmentsLabel: { selectedSegmentsLabel: {
color: theme.palette.text.secondary, color: theme.palette.text.secondary,

View File

@ -3,7 +3,7 @@ import { ISegment } from 'interfaces/segment';
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList.styles'; import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList.styles';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip'; import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
import { ConstraintAccordionList } from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList'; import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
interface IFeatureStrategySegmentListProps { interface IFeatureStrategySegmentListProps {
segments: ISegment[]; segments: ISegment[];
@ -48,16 +48,10 @@ export const FeatureStrategySegmentList = ({
</Fragment> </Fragment>
))} ))}
</div> </div>
<ConditionallyRender
condition={Boolean(preview && preview.constraints.length === 0)}
show={() => <p>This segment has no constraints.</p>}
/>
<ConditionallyRender <ConditionallyRender
condition={Boolean(preview)} condition={Boolean(preview)}
show={() => ( show={() => (
<ConstraintAccordionList <SegmentItem segment={preview as ISegment} isExpanded />
constraints={preview!.constraints}
/>
)} )}
/> />
</> </>

View File

@ -19,7 +19,7 @@ export const useStyles = makeStyles()(theme => ({
}, },
}, },
header: { header: {
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
fontWeight: 'normal', fontWeight: 'normal',
margin: 0, margin: 0,
marginBottom: '0.5rem', marginBottom: '0.5rem',

View File

@ -31,7 +31,7 @@ export const useStyles = makeStyles()(theme => ({
percentage: { percentage: {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textAlign: 'right', textAlign: 'right',
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
}, },
percentageCircle: { percentageCircle: {
margin: '0 1rem', margin: '0 1rem',

View File

@ -19,7 +19,7 @@ const SeparatorContainer = styled('div')(({ theme }) => ({
})); }));
const SeparatorContent = styled('span')(({ theme }) => ({ const SeparatorContent = styled('span')(({ theme }) => ({
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
textAlign: 'center', textAlign: 'center',
padding: '0 1rem', padding: '0 1rem',
background: theme.palette.secondaryContainer, background: theme.palette.secondaryContainer,

View File

@ -28,7 +28,7 @@ export const useStyles = makeStyles()(theme => ({
alignItems: 'center', alignItems: 'center',
}, },
header: { header: {
fontSize: theme.fontSizes.subHeader, fontSize: theme.fontSizes.bodySize,
fontWeight: 'normal', fontWeight: 'normal',
margin: 0, margin: 0,
}, },

View File

@ -1,22 +0,0 @@
import { makeStyles } from 'tss-react/mui';
export const useStyles = makeStyles()(theme => ({
container: {
width: '100%',
padding: theme.spacing(2, 3),
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
fontSize: theme.fontSizes.smallBody,
border: `1px solid ${theme.palette.dividerAlternative}`,
position: 'relative',
borderRadius: '5px',
},
link: {
textDecoration: 'none',
marginLeft: theme.spacing(1),
'&:hover': {
textDecoration: 'underline',
},
},
}));

View File

@ -1,10 +1,8 @@
import { Fragment } from 'react'; import { Fragment } from 'react';
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 { useSegments } from 'hooks/api/getters/useSegments/useSegments';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
import { SegmentItem } from '../../../../common/SegmentItem/SegmentItem';
interface IFeatureOverviewSegmentProps { interface IFeatureOverviewSegmentProps {
strategyId: string; strategyId: string;
@ -13,7 +11,6 @@ interface IFeatureOverviewSegmentProps {
export const FeatureOverviewSegment = ({ export const FeatureOverviewSegment = ({
strategyId, strategyId,
}: IFeatureOverviewSegmentProps) => { }: IFeatureOverviewSegmentProps) => {
const { classes: styles } = useStyles();
const { segments } = useSegments(strategyId); const { segments } = useSegments(strategyId);
if (!segments || segments.length === 0) { if (!segments || segments.length === 0) {
@ -28,21 +25,9 @@ export const FeatureOverviewSegment = ({
condition={index > 0} condition={index > 0}
show={<StrategySeparator text="AND" />} show={<StrategySeparator text="AND" />}
/> />
<div className={styles.container}> <SegmentItem segment={segment} />
<DonutLarge color="secondary" sx={{ mr: 1 }} /> Segment:{' '}
<Link
to={segmentPath(segment.id)}
className={styles.link}
>
{segment.name}
</Link>
</div>
</Fragment> </Fragment>
))} ))}
</> </>
); );
}; };
const segmentPath = (segmentId: number): string => {
return `/segments/edit/${segmentId}`;
};

View File

@ -76,21 +76,6 @@ export const FeatureView = () => {
const activeTab = tabData.find(tab => tab.path === pathname) ?? tabData[0]; const activeTab = tabData.find(tab => tab.path === pathname) ?? tabData[0];
const renderTabs = () => {
return tabData.map((tab, index) => {
return (
<Tab
data-loading
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
className={styles.tabButton}
/>
);
});
};
if (status === 404) { if (status === 404) {
return <FeatureNotFound />; return <FeatureNotFound />;
} }
@ -168,7 +153,15 @@ export const FeatureView = () => {
indicatorColor="primary" indicatorColor="primary"
textColor="primary" textColor="primary"
> >
{renderTabs()} {tabData.map(tab => (
<Tab
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
className={styles.tabButton}
/>
))}
</Tabs> </Tabs>
</div> </div>
</div> </div>

View File

@ -80,21 +80,6 @@ const Project = () => {
/* eslint-disable-next-line */ /* eslint-disable-next-line */
}, []); }, []);
const renderTabs = () => {
return tabs.map(tab => {
return (
<Tab
data-loading
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
className={styles.tabButton}
/>
);
});
};
return ( return (
<div ref={ref}> <div ref={ref}>
<div className={styles.header}> <div className={styles.header}>
@ -135,7 +120,15 @@ const Project = () => {
indicatorColor="primary" indicatorColor="primary"
textColor="primary" textColor="primary"
> >
{renderTabs()} {tabs.map(tab => (
<Tab
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
className={styles.tabButton}
/>
))}
</Tabs> </Tabs>
</div> </div>
</div> </div>

View File

@ -36,7 +36,6 @@ export default createTheme({
}, },
fontSizes: { fontSizes: {
mainHeader: '1.25rem', mainHeader: '1.25rem',
subHeader: '1.1rem',
bodySize: '1rem', bodySize: '1rem',
smallBody: `${14 / 16}rem`, smallBody: `${14 / 16}rem`,
smallerBody: `${12 / 16}rem`, smallerBody: `${12 / 16}rem`,
@ -260,12 +259,24 @@ export default createTheme({
}, },
}, },
}, },
MuiAccordion: {
styleOverrides: {
root: ({ theme }) => ({
'&:first-of-type, &:last-of-type': {
borderRadius: theme.shape.borderRadiusMedium,
},
}),
},
},
MuiAccordionSummary: { MuiAccordionSummary: {
styleOverrides: { styleOverrides: {
root: { root: {
'& > .MuiAccordionSummary-content.Mui-expanded': { '& > .MuiAccordionSummary-content.Mui-expanded': {
margin: '12px 0', margin: '12px 0',
}, },
'&.Mui-expanded': {
minHeight: '0',
},
}, },
}, },
}, },

View File

@ -5,7 +5,6 @@ declare module '@mui/material/styles' {
*/ */
fontSizes: { fontSizes: {
mainHeader: string; mainHeader: string;
subHeader: string;
bodySize: string; bodySize: string;
smallBody: string; smallBody: string;
smallerBody: string; smallerBody: string;