1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: add strategies icons (#565)

* feat: add strategies icons with add strategy button

* fix: styling the icons

* feat: add styling for disabled button

* fix: adjust icons styling

* fix: add missing braces

* feat: remove badge from strategies icons

Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
This commit is contained in:
Youssef Khedher 2022-01-04 11:31:11 +01:00 committed by GitHub
parent 4aa7472434
commit 4f772ff2d1
4 changed files with 192 additions and 14 deletions

View File

@ -7,6 +7,7 @@ export const useStyles = makeStyles(theme => ({
position: 'relative',
width: '50px',
height: '100%',
padding: '15px 0px',
},
vertical: {
borderRadius: '1px',

View File

@ -19,6 +19,13 @@ export const useStyles = makeStyles(theme => ({
position: 'relative',
paddingBottom: '1rem',
},
header: {
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
paddingTop: '1.5rem',
},
headerTitle: {
display: 'flex',
alignItems: 'center',
@ -115,6 +122,29 @@ export const useStyles = makeStyles(theme => ({
fill: theme.palette.grey[400],
marginBottom: '1rem',
},
strategiesText: {
fontSize: '14px',
color: theme.palette.grey[700],
},
stratigiesInfoContainer: {
display: 'flex',
},
noStratigiesInfoContainer: {
top: '1px',
position: 'relative',
},
stratigiesIconsContainer: {
display: 'flex',
alignItems: 'center',
transform: 'scale(0.8)',
top: '3px',
left: '-10px',
position: 'relative',
[theme.breakpoints.down(560)]: {
marginLeft: '0px',
top: '5px',
},
},
[theme.breakpoints.down(750)]: {
accordionBodyFooter: {
flexDirection: 'column',
@ -125,7 +155,7 @@ export const useStyles = makeStyles(theme => ({
},
[theme.breakpoints.down(560)]: {
disabledIndicatorPos: {
top: '-8px',
top: '13px',
},
headerTitle: {
flexDirection: 'column',
@ -149,6 +179,46 @@ export const useStyles = makeStyles(theme => ({
padding: '0.5rem',
},
},
strategyIconContainer: {
marginRight: '5px',
},
strategyIcon: {
fill: theme.palette.grey[600],
},
container: {
display: 'flex',
alignItems: 'center',
marginLeft: '1.3rem',
[theme.breakpoints.down(560)]: {
flexDirection: 'column',
marginLeft: '0',
},
},
addStrategyButton: {
background: 'none',
textDecoration: 'none',
boxShadow: 'none',
color: theme.palette.primary.main,
fontWeight: 'normal',
'&:hover': {
background: 'none',
textDecoration: 'none',
boxShadow: 'none',
color: theme.palette.primary.main,
fontWeight: 'normal',
},
'&:disabled': {
margin: '0px 16px',
height: '35px'
},
},
separtor: {
marginLeft: '-10px',
marginRight: '9px',
[theme.breakpoints.down(560)]: {
display: 'none',
},
},
resultContainer: {
display: 'flex',
width: '100%',

View File

@ -2,24 +2,38 @@ import {
Accordion,
AccordionDetails,
AccordionSummary,
Tooltip,
} from '@material-ui/core';
import { ExpandMore } from '@material-ui/icons';
import React from 'react';
import { useParams } from 'react-router';
import { useHistory } from 'react-router-dom';
import useFeature from '../../../../../../hooks/api/getters/useFeature/useFeature';
import useFeatureMetrics from '../../../../../../hooks/api/getters/useFeatureMetrics/useFeatureMetrics';
import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle';
import { IFeatureViewParams } from '../../../../../../interfaces/params';
import { getFeatureMetrics } from '../../../../../../utils/get-feature-metrics';
import {
getFeatureStrategyIcon,
getHumanReadableStrategyName,
} from '../../../../../../utils/strategy-names';
import ConditionallyRender from '../../../../../common/ConditionallyRender';
import DisabledIndicator from '../../../../../common/DisabledIndicator/DisabledIndicator';
import EnvironmentIcon from '../../../../../common/EnvironmentIcon/EnvironmentIcon';
import PermissionButton from '../../../../../common/PermissionButton/PermissionButton';
import StringTruncator from '../../../../../common/StringTruncator/StringTruncator';
import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions';
import { useStyles } from './FeatureOverviewEnvironment.styles';
import FeatureOverviewEnvironmentBody from './FeatureOverviewEnvironmentBody/FeatureOverviewEnvironmentBody';
import FeatureOverviewEnvironmentFooter from './FeatureOverviewEnvironmentFooter/FeatureOverviewEnvironmentFooter';
import FeatureOverviewEnvironmentMetrics from './FeatureOverviewEnvironmentMetrics/FeatureOverviewEnvironmentMetrics';
interface IStrategyIconObject {
count: number;
Icon: React.ReactElement;
name: string;
}
interface IFeatureOverviewEnvironmentProps {
env: IFeatureEnvironment;
}
@ -31,6 +45,7 @@ const FeatureOverviewEnvironment = ({
const { projectId, featureId } = useParams<IFeatureViewParams>();
const { metrics } = useFeatureMetrics(projectId, featureId);
const { feature } = useFeature(projectId, featureId);
const history = useHistory();
const featureMetrics = getFeatureMetrics(feature?.environments, metrics);
const environmentMetric = featureMetrics.find(
@ -48,6 +63,29 @@ const FeatureOverviewEnvironment = ({
return `This environment is disabled, which means that none of your strategies are executing`;
};
const strategiesLink = `/projects/${projectId}/features2/${featureId}/strategies?environment=${featureEnvironment?.name}&addStrategy=true`;
const getStrategyIcons = () => {
const strategyObjects = featureEnvironment?.strategies.reduce(
(acc, current) => {
if (acc[current.name]) {
acc[current.name].count = acc[current.name].count + 1;
} else {
acc[current.name] = {
count: 1,
Icon: getFeatureStrategyIcon(current.name),
};
}
return acc;
},
{} as { [key: string]: IStrategyIconObject }
);
return Object.keys(strategyObjects).map(strategyName => {
return { ...strategyObjects[strategyName], name: strategyName };
});
};
return (
<div className={styles.featureOverviewEnvironment}>
<Accordion style={{ boxShadow: 'none' }}>
@ -55,17 +93,76 @@ const FeatureOverviewEnvironment = ({
className={styles.accordionHeader}
expandIcon={<ExpandMore />}
>
<div className={styles.headerTitle} data-loading>
<EnvironmentIcon
enabled={env.enabled}
className={styles.headerIcon}
/>
Feature toggle execution for&nbsp;
<StringTruncator
text={env.name}
className={styles.truncator}
maxWidth="100"
/>
<div className={styles.header} data-loading>
<div className={styles.headerTitle}>
<EnvironmentIcon
enabled={env.enabled}
className={styles.headerIcon}
/>
Feature toggle execution for&nbsp;
<StringTruncator
text={env.name}
className={styles.truncator}
maxWidth="100"
/>
</div>
<div className={styles.container}>
<PermissionButton
permission={UPDATE_FEATURE}
onClick={() => history.push(strategiesLink)}
className={styles.addStrategyButton}
>
Add strategy
</PermissionButton>
<span className={styles.separtor}>|</span>
<ConditionallyRender
condition={
featureEnvironment?.strategies.length !== 0
}
show={
<div
className={
styles.stratigiesIconsContainer
}
>
{getStrategyIcons()?.map(
({ name, Icon }) => (
<Tooltip
title={getHumanReadableStrategyName(
name
)}
arrow
>
<div
className={
styles.strategyIconContainer
}
>
<Icon
className={
styles.strategyIcon
}
/>
</div>
</Tooltip>
)
)}
</div>
}
elseShow={
<div
className={
styles.noStratigiesInfoContainer
}
>
<p className={styles.strategiesText}>
No strategies defined on this toggle
</p>
</div>
}
/>
</div>
<ConditionallyRender
condition={!env.enabled}
show={

View File

@ -1,4 +1,4 @@
import { Link, useParams, useHistory } from 'react-router-dom';
import { useParams, useHistory } from 'react-router-dom';
import { IFeatureViewParams } from '../../../../../../../interfaces/params';
import ConditionallyRender from '../../../../../../common/ConditionallyRender';
import NoItemsStrategies from '../../../../../../common/NoItems/NoItemsStrategies/NoItemsStrategies';
@ -6,6 +6,9 @@ import FeatureOverviewEnvironmentStrategies from '../FeatureOverviewEnvironmentS
import { useStyles } from '../FeatureOverviewEnvironment.styles';
import { IFeatureEnvironment } from '../../../../../../../interfaces/featureToggle';
import { UPDATE_FEATURE } from '../../../../../../providers/AccessProvider/permissions';
import ResponsiveButton from '../../../../../../common/ResponsiveButton/ResponsiveButton';
import { Add } from '@material-ui/icons';
interface IFeatureOverviewEnvironmentBodyProps {
getOverviewText: () => string;
@ -39,7 +42,14 @@ const FeatureOverviewEnvironmentBody = ({
show={
<>
<div className={styles.linkContainer}>
<Link to={strategiesLink}>Edit strategies</Link>
<ResponsiveButton
Icon={Add}
onClick={() => history.push(strategiesLink)}
maxWidth="700px"
permission={UPDATE_FEATURE}
>
Add strategy
</ResponsiveButton>
</div>
<FeatureOverviewEnvironmentStrategies
strategies={featureEnvironment?.strategies}