mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +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:
		
							parent
							
								
									4aa7472434
								
							
						
					
					
						commit
						4f772ff2d1
					
				@ -7,6 +7,7 @@ export const useStyles = makeStyles(theme => ({
 | 
			
		||||
        position: 'relative',
 | 
			
		||||
        width: '50px',
 | 
			
		||||
        height: '100%',
 | 
			
		||||
        padding: '15px 0px',
 | 
			
		||||
    },
 | 
			
		||||
    vertical: {
 | 
			
		||||
        borderRadius: '1px',
 | 
			
		||||
 | 
			
		||||
@ -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%',
 | 
			
		||||
 | 
			
		||||
@ -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 
 | 
			
		||||
                        <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 
 | 
			
		||||
                            <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={
 | 
			
		||||
 | 
			
		||||
@ -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}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user