mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
Segment preview (#1194)
* segment preview * fix: loading and font size inconsistencies * update segment accordion styles
This commit is contained in:
parent
672a3f0b92
commit
b7de1fba52
@ -26,9 +26,6 @@ export const useStyles = makeStyles()(theme => ({
|
||||
'&:before': {
|
||||
opacity: '0 !important',
|
||||
},
|
||||
'&:first-of-type, &:last-of-type': {
|
||||
borderRadius: theme.shape.borderRadiusMedium,
|
||||
},
|
||||
},
|
||||
accordionEdit: {
|
||||
backgroundColor: '#F6F6FA',
|
||||
|
@ -48,7 +48,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
fontWeight: theme.fontWeight.bold,
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
},
|
||||
description: {
|
||||
color: '#fff',
|
||||
|
@ -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),
|
||||
},
|
||||
}));
|
81
frontend/src/component/common/SegmentItem/SegmentItem.tsx
Normal file
81
frontend/src/component/common/SegmentItem/SegmentItem.tsx
Normal 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>
|
||||
);
|
||||
};
|
@ -26,6 +26,7 @@ const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.activityIndicators.primary,
|
||||
border: `1px solid ${theme.palette.primary.border}`,
|
||||
borderRadius: theme.shape.borderRadiusLarge,
|
||||
padding: theme.spacing(0.75, 1.5),
|
||||
}));
|
||||
|
||||
export const StrategySeparator = ({ text }: IStrategySeparatorProps) => {
|
||||
|
@ -16,7 +16,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'auto 1fr',
|
||||
gridGap: '.5rem',
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
},
|
||||
icon: {
|
||||
color: theme.palette.primary.main,
|
||||
|
@ -3,5 +3,7 @@ import { makeStyles } from 'tss-react/mui';
|
||||
export const useStyles = makeStyles()(theme => ({
|
||||
divider: {
|
||||
border: `1px dashed ${theme.palette.divider}`,
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
}));
|
||||
|
@ -12,10 +12,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
gap: '0.5rem',
|
||||
},
|
||||
and: {
|
||||
color: theme.palette.grey[600],
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
border: '1px solid',
|
||||
borderColor: theme.palette.grey[300],
|
||||
padding: theme.spacing(0.75, 1),
|
||||
display: 'block',
|
||||
marginTop: 'auto',
|
||||
@ -23,6 +20,8 @@ export const useStyles = makeStyles()(theme => ({
|
||||
alignItems: 'center',
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
lineHeight: 1,
|
||||
color: theme.palette.text.primary,
|
||||
backgroundColor: theme.palette.secondaryContainer,
|
||||
},
|
||||
selectedSegmentsLabel: {
|
||||
color: theme.palette.text.secondary,
|
||||
|
@ -3,7 +3,7 @@ import { ISegment } from 'interfaces/segment';
|
||||
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentList.styles';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
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 {
|
||||
segments: ISegment[];
|
||||
@ -48,16 +48,10 @@ export const FeatureStrategySegmentList = ({
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(preview && preview.constraints.length === 0)}
|
||||
show={() => <p>This segment has no constraints.</p>}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(preview)}
|
||||
show={() => (
|
||||
<ConstraintAccordionList
|
||||
constraints={preview!.constraints}
|
||||
/>
|
||||
<SegmentItem segment={preview as ISegment} isExpanded />
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
|
@ -19,7 +19,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
},
|
||||
},
|
||||
header: {
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
fontWeight: 'normal',
|
||||
margin: 0,
|
||||
marginBottom: '0.5rem',
|
||||
|
@ -31,7 +31,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
percentage: {
|
||||
color: theme.palette.primary.main,
|
||||
textAlign: 'right',
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
},
|
||||
percentageCircle: {
|
||||
margin: '0 1rem',
|
||||
|
@ -19,7 +19,7 @@ const SeparatorContainer = styled('div')(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const SeparatorContent = styled('span')(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
textAlign: 'center',
|
||||
padding: '0 1rem',
|
||||
background: theme.palette.secondaryContainer,
|
||||
|
@ -28,7 +28,7 @@ export const useStyles = makeStyles()(theme => ({
|
||||
alignItems: 'center',
|
||||
},
|
||||
header: {
|
||||
fontSize: theme.fontSizes.subHeader,
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
fontWeight: 'normal',
|
||||
margin: 0,
|
||||
},
|
||||
|
@ -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',
|
||||
},
|
||||
},
|
||||
}));
|
@ -1,10 +1,8 @@
|
||||
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 { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||
import { SegmentItem } from '../../../../common/SegmentItem/SegmentItem';
|
||||
|
||||
interface IFeatureOverviewSegmentProps {
|
||||
strategyId: string;
|
||||
@ -13,7 +11,6 @@ interface IFeatureOverviewSegmentProps {
|
||||
export const FeatureOverviewSegment = ({
|
||||
strategyId,
|
||||
}: IFeatureOverviewSegmentProps) => {
|
||||
const { classes: styles } = useStyles();
|
||||
const { segments } = useSegments(strategyId);
|
||||
|
||||
if (!segments || segments.length === 0) {
|
||||
@ -28,21 +25,9 @@ export const FeatureOverviewSegment = ({
|
||||
condition={index > 0}
|
||||
show={<StrategySeparator text="AND" />}
|
||||
/>
|
||||
<div className={styles.container}>
|
||||
<DonutLarge color="secondary" sx={{ mr: 1 }} /> Segment:{' '}
|
||||
<Link
|
||||
to={segmentPath(segment.id)}
|
||||
className={styles.link}
|
||||
>
|
||||
{segment.name}
|
||||
</Link>
|
||||
</div>
|
||||
<SegmentItem segment={segment} />
|
||||
</Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const segmentPath = (segmentId: number): string => {
|
||||
return `/segments/edit/${segmentId}`;
|
||||
};
|
||||
|
@ -76,21 +76,6 @@ export const FeatureView = () => {
|
||||
|
||||
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) {
|
||||
return <FeatureNotFound />;
|
||||
}
|
||||
@ -168,7 +153,15 @@ export const FeatureView = () => {
|
||||
indicatorColor="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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,21 +80,6 @@ const Project = () => {
|
||||
/* 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 (
|
||||
<div ref={ref}>
|
||||
<div className={styles.header}>
|
||||
@ -135,7 +120,15 @@ const Project = () => {
|
||||
indicatorColor="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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,7 +36,6 @@ export default createTheme({
|
||||
},
|
||||
fontSizes: {
|
||||
mainHeader: '1.25rem',
|
||||
subHeader: '1.1rem',
|
||||
bodySize: '1rem',
|
||||
smallBody: `${14 / 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: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'& > .MuiAccordionSummary-content.Mui-expanded': {
|
||||
margin: '12px 0',
|
||||
},
|
||||
'&.Mui-expanded': {
|
||||
minHeight: '0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -5,7 +5,6 @@ declare module '@mui/material/styles' {
|
||||
*/
|
||||
fontSizes: {
|
||||
mainHeader: string;
|
||||
subHeader: string;
|
||||
bodySize: string;
|
||||
smallBody: string;
|
||||
smallerBody: string;
|
||||
|
Loading…
Reference in New Issue
Block a user