mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-15 17:50:48 +02:00
Fix/strategy constraints (#283)
* feat: redesign strategy cards * fix: add version check to constraints * fix: use flags * fix: update icon and add tooltips * fix: remove console logs Co-authored-by: Ivar Conradi Østhus <ivarconr@gmail.com>
This commit is contained in:
parent
367b5c8d85
commit
e8de5bd816
6
frontend/src/assets/icons/reorder.svg
Normal file
6
frontend/src/assets/icons/reorder.svg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.64645 19.3536C9.84171 19.5488 10.1583 19.5488 10.3536 19.3536L13.5355 16.1716C13.7308 15.9763 13.7308 15.6597 13.5355 15.4645C13.3403 15.2692 13.0237 15.2692 12.8284 15.4645L10 18.2929L7.17157 15.4645C6.97631 15.2692 6.65973 15.2692 6.46447 15.4645C6.2692 15.6597 6.2692 15.9763 6.46447 16.1716L9.64645 19.3536ZM9.5 1L9.5 19L10.5 19L10.5 1L9.5 1Z" fill="white"/>
|
||||||
|
<path d="M19.3536 10.3536C19.5488 10.1583 19.5488 9.84171 19.3536 9.64645L16.1716 6.46447C15.9763 6.2692 15.6597 6.2692 15.4645 6.46447C15.2692 6.65973 15.2692 6.97631 15.4645 7.17157L18.2929 10L15.4645 12.8284C15.2692 13.0237 15.2692 13.3403 15.4645 13.5355C15.6597 13.7308 15.9763 13.7308 16.1716 13.5355L19.3536 10.3536ZM1 10.5L19 10.5V9.5L1 9.5V10.5Z" fill="white"/>
|
||||||
|
<path d="M0.646446 9.64645C0.451185 9.84171 0.451185 10.1583 0.646446 10.3536L3.82843 13.5355C4.02369 13.7308 4.34027 13.7308 4.53553 13.5355C4.7308 13.3403 4.7308 13.0237 4.53553 12.8284L1.70711 10L4.53553 7.17157C4.7308 6.97631 4.7308 6.65973 4.53553 6.46446C4.34027 6.2692 4.02369 6.2692 3.82843 6.46446L0.646446 9.64645ZM19 9.5L1 9.5L1 10.5L19 10.5L19 9.5Z" fill="white"/>
|
||||||
|
<path d="M10.3536 0.646446C10.1583 0.451185 9.84171 0.451185 9.64645 0.646446L6.46447 3.82843C6.2692 4.02369 6.2692 4.34027 6.46447 4.53553C6.65973 4.7308 6.97631 4.7308 7.17157 4.53553L10 1.70711L12.8284 4.53553C13.0237 4.7308 13.3403 4.7308 13.5355 4.53553C13.7308 4.34027 13.7308 4.02369 13.5355 3.82843L10.3536 0.646446ZM10.5 19L10.5 1L9.5 1L9.5 19L10.5 19Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -1,8 +1,20 @@
|
|||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
|
|
||||||
export const useStyles = makeStyles({
|
export const useStyles = makeStyles(theme => ({
|
||||||
strategyCard: {
|
strategyCard: {
|
||||||
width: '250px',
|
width: '337px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
[theme.breakpoints.down('xs')]: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
[theme.breakpoints.down('1250')]: {
|
||||||
|
width: '300px',
|
||||||
|
},
|
||||||
|
[theme.breakpoints.down('1035')]: {
|
||||||
|
width: '280px',
|
||||||
|
},
|
||||||
|
[theme.breakpoints.down('860')]: {
|
||||||
|
width: '380px',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
|
@ -5,7 +5,7 @@ import { Typography } from '@material-ui/core';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
||||||
@ -19,7 +19,9 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
|||||||
return (
|
return (
|
||||||
<Typography className={commonStyles.textCenter}>
|
<Typography className={commonStyles.textCenter}>
|
||||||
The strategy definition "{strategy.name}" does not exist.{' '}
|
The strategy definition "{strategy.name}" does not exist.{' '}
|
||||||
<Link to={`/strategies/create?name=${strategy.name}`}>Create a strategy named {strategy.name}</Link>
|
<Link to={`/strategies/create?name=${strategy.name}`}>
|
||||||
|
Create a strategy named {strategy.name}
|
||||||
|
</Link>
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
if (strategyDefinition.name === 'Loading') return null;
|
if (strategyDefinition.name === 'Loading') return null;
|
||||||
@ -42,7 +44,7 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
|||||||
case 'list':
|
case 'list':
|
||||||
/* eslint-disable-next-line */
|
/* eslint-disable-next-line */
|
||||||
const paramList = param
|
const paramList = param
|
||||||
? param.split(",").filter(listItem => listItem)
|
? param.split(',').filter(listItem => listItem)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -51,7 +53,10 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
|||||||
condition={paramList.length > 0}
|
condition={paramList.length > 0}
|
||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<StrategyCardList list={paramList} valuesName={paramDefinition.name} />
|
<StrategyCardList
|
||||||
|
list={paramList}
|
||||||
|
valuesName={paramDefinition.name}
|
||||||
|
/>
|
||||||
<div className={commonStyles.divider} />
|
<div className={commonStyles.divider} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@ -64,29 +69,28 @@ const StrategyCardContentCustom = ({ strategy, strategyDefinition }) => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
key={paramDefinition.name}
|
key={paramDefinition.name}
|
||||||
condition={param || param === false}
|
condition={param || param === false}
|
||||||
show={<StrategyCardField title={paramDefinition.name} value={param} />}
|
show={
|
||||||
|
<StrategyCardField
|
||||||
|
title={paramDefinition.name}
|
||||||
|
value={param}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderCustomSections = () =>
|
const renderCustomSections = () =>
|
||||||
strategyDefinition.parameters.map(paramDefinition => getSection(paramDefinition));
|
strategyDefinition.parameters.map(paramDefinition =>
|
||||||
|
getSection(paramDefinition)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
{renderCustomSections()}
|
{renderCustomSections()}
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<div className={commonStyles.divider} />
|
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@ import React from 'react';
|
|||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from '@material-ui/core';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
||||||
|
|
||||||
const StrategyCardContentDefault = ({ strategy }) => {
|
const StrategyCardContentDefault = ({ strategy }) => {
|
||||||
@ -13,18 +12,11 @@ const StrategyCardContentDefault = ({ strategy }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
|
<div className={commonStyles.divider} />
|
||||||
<Typography className={commonStyles.textCenter}>
|
<Typography className={commonStyles.textCenter}>
|
||||||
The default strategy is either on or off for all users.
|
The default strategy is on for all users.
|
||||||
</Typography>
|
</Typography>
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<div className={commonStyles.divider} />
|
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,10 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints';
|
||||||
import StrategyCardField from '../common/StrategyCardField/StrategyCardField';
|
import StrategyCardField from '../common/StrategyCardField/StrategyCardField';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
|
||||||
|
|
||||||
const StrategyCardContentFlexible = ({ strategy }) => {
|
const StrategyCardContentFlexible = ({ strategy }) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
@ -18,16 +17,9 @@ const StrategyCardContentFlexible = ({ strategy }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardPercentage percentage={rolloutPercentage} />
|
<StrategyCardPercentage percentage={rolloutPercentage} />
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<div className={commonStyles.divider} />
|
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={commonStyles.divider} />
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardField title="Sticky on" value={stickyField} />
|
<StrategyCardField title="Sticky on" value={stickyField} />
|
||||||
|
@ -2,10 +2,9 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
|
||||||
|
|
||||||
const StrategyCardContentGradRandom = ({ strategy }) => {
|
const StrategyCardContentGradRandom = ({ strategy }) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
@ -15,16 +14,9 @@ const StrategyCardContentGradRandom = ({ strategy }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardPercentage percentage={rolloutPercentage} />
|
<StrategyCardPercentage percentage={rolloutPercentage} />
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<div className={commonStyles.divider} />
|
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
||||||
@ -15,16 +15,14 @@ const StrategyCardContentList = ({ strategy, parameter, valuesName }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
|
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={list.length > 0}
|
condition={list.length > 0}
|
||||||
show={<StrategyCardList list={list} valuesName={valuesName} />}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<div className={commonStyles.divider} />
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
<StrategyCardList list={list} valuesName={valuesName} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -2,11 +2,10 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
import StrategyCardPercentage from '../common/StrategyCardPercentage/StrageyCardPercentage';
|
||||||
import StrategyCardConstraints from '../common/StrategyCardConstraints/StrategyCardConstraints';
|
import StrategyCardConstraints from '../common/StrategyCardConstraints';
|
||||||
import StrategyCardField from '../common/StrategyCardField/StrategyCardField';
|
import StrategyCardField from '../common/StrategyCardField/StrategyCardField';
|
||||||
|
|
||||||
import { useCommonStyles } from '../../../../../../common.styles';
|
import { useCommonStyles } from '../../../../../../common.styles';
|
||||||
import ConditionallyRender from '../../../../../common/ConditionallyRender';
|
|
||||||
|
|
||||||
const StrategyCardContentRollout = ({ strategy }) => {
|
const StrategyCardContentRollout = ({ strategy }) => {
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
@ -17,16 +16,9 @@ const StrategyCardContentRollout = ({ strategy }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<StrategyCardConstraints constraints={constraints} />
|
||||||
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardPercentage percentage={rolloutPercentage} />
|
<StrategyCardPercentage percentage={rolloutPercentage} />
|
||||||
<ConditionallyRender
|
|
||||||
condition={constraints && constraints.length > 0}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<div className={commonStyles.divider} />
|
|
||||||
<StrategyCardConstraints constraints={constraints} />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={commonStyles.divider} />
|
<div className={commonStyles.divider} />
|
||||||
<StrategyCardField title="Group id" value={groupId} />
|
<StrategyCardField title="Group id" value={groupId} />
|
||||||
|
@ -1,55 +1,122 @@
|
|||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from '@material-ui/core';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { useStyles } from './StrategyCardConstraints.styles.js';
|
import { useStyles } from './StrategyCardConstraints.styles.js';
|
||||||
import { useCommonStyles } from '../../../../../../../common.styles.js';
|
import ConditionallyRender from '../../../../../../common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { C } from '../../../../../../common/flags.js';
|
||||||
|
|
||||||
const StrategyCardConstraints = ({ constraints }) => {
|
const StrategyCardConstraints = ({ constraints, flags }) => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const commonStyles = useCommonStyles();
|
|
||||||
|
|
||||||
const renderConstraintValues = constraint =>
|
const isEnterprise = () => {
|
||||||
constraint.values.map(value => (
|
if (!flags) return false;
|
||||||
<Typography variant="body2" key={value} className={styles.constraintValue}>
|
if (flags[C]) {
|
||||||
{value}
|
return true;
|
||||||
</Typography>
|
}
|
||||||
));
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const renderConstraints = () =>
|
const renderConstraintValues = constraint => {
|
||||||
constraints.map((constraint, i) => (
|
const multiple = constraint.values.length > 1;
|
||||||
<div key={`${constraint.contextName}-${i}`} className={styles.constraintContainer}>
|
return constraint.values.map((value, index) => {
|
||||||
<div className={styles.constraintDisplayContainer}>
|
const notLastItem = index !== constraint.values.length - 1;
|
||||||
<Typography variant="body2" className={styles.label}>
|
return (
|
||||||
context
|
<ConditionallyRender
|
||||||
</Typography>
|
key={value}
|
||||||
<Typography variant="body2">{constraint.contextName}</Typography>
|
condition={multiple && notLastItem}
|
||||||
</div>
|
show={<span>'{value}',</span>}
|
||||||
<div className={styles.constraintDisplayContainer}>
|
elseShow={<span>'{value}'</span>}
|
||||||
<Typography variant="body2" className={styles.label}>
|
/>
|
||||||
operator
|
);
|
||||||
</Typography>
|
});
|
||||||
<Typography variant="body2">{constraint.operator}</Typography>
|
};
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classnames(commonStyles.flexColumn, styles.constraintValuesContainer)}>
|
const renderConstraints = () => {
|
||||||
<Typography variant="body2" className={styles.label}>
|
return constraints.map((constraint, i) => (
|
||||||
values
|
<div key={`${constraint.contextName}-${constraint.operator}`}>
|
||||||
</Typography>
|
<ConditionallyRender
|
||||||
<div className={classnames(commonStyles.flexRow, commonStyles.flexWrap)}>
|
condition={i > 0}
|
||||||
{renderConstraintValues(constraint)}
|
show={<span>and</span>}
|
||||||
</div>
|
/>
|
||||||
</div>
|
<pre
|
||||||
|
key={`${constraint.contextName}-${i}`}
|
||||||
|
className={classnames(styles.constraintContainer)}
|
||||||
|
>
|
||||||
|
<span>{constraint.contextName}</span>
|
||||||
|
|
||||||
|
<span>{constraint.operator}</span>
|
||||||
|
|
||||||
|
{renderConstraintValues(constraint)}
|
||||||
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography className={styles.title} variant="subtitle1">
|
<Typography className={styles.title} variant="subtitle1">
|
||||||
Constraints
|
Constraints
|
||||||
</Typography>
|
</Typography>
|
||||||
{renderConstraints()}
|
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={constraints && constraints.length > 0}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
<Typography variant="body2">
|
||||||
|
The following pre-conditions must be fulfilled for
|
||||||
|
this strategy to be executed
|
||||||
|
</Typography>
|
||||||
|
<div className={styles.constraints}>
|
||||||
|
{renderConstraints()}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<>
|
||||||
|
<Typography variant="body2">
|
||||||
|
No pre-conditions defined for this strategy.
|
||||||
|
</Typography>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={isEnterprise()}
|
||||||
|
show={
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
className={styles.placeholderText}
|
||||||
|
>
|
||||||
|
Constraints allow you fine grained control
|
||||||
|
over how to execute your strategies.
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className={styles.link}
|
||||||
|
href="https://docs.getunleash.io/docs/advanced/strategy_constraints"
|
||||||
|
>
|
||||||
|
Learn more
|
||||||
|
</a>
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
className={styles.placeholderText}
|
||||||
|
>
|
||||||
|
Constraints are only available as an
|
||||||
|
enterprise feature.{' '}
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className={styles.link}
|
||||||
|
href="https://docs.getunleash.io/docs/advanced/strategy_constraints"
|
||||||
|
>
|
||||||
|
Learn more
|
||||||
|
</a>
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,34 +1,27 @@
|
|||||||
import { makeStyles } from '@material-ui/styles';
|
import { makeStyles } from '@material-ui/styles';
|
||||||
|
|
||||||
export const useStyles = makeStyles(theme => ({
|
export const useStyles = makeStyles(theme => ({
|
||||||
|
constraints: {
|
||||||
|
marginTop: '1rem',
|
||||||
|
},
|
||||||
constraintContainer: {
|
constraintContainer: {
|
||||||
backgroundColor: theme.palette.cards.container.bg,
|
backgroundColor: theme.palette.cards.container.bg,
|
||||||
margin: '0.5rem 0',
|
margin: '0.5rem 0',
|
||||||
borderRadius: theme.borders.radius.main,
|
borderRadius: theme.borders.radius.main,
|
||||||
padding: '0.8rem',
|
padding: '0.8rem',
|
||||||
overflow: 'scroll',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
|
'& span': {
|
||||||
|
marginRight: '0.4rem',
|
||||||
|
fontSize: '0.9rem',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
verticalSpacer: {
|
placeholderText: {
|
||||||
margin: '0 0.25rem',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontWeight: theme.fontWeight.semi,
|
|
||||||
},
|
|
||||||
constraintDisplayContainer: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
width: '50%',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
fontWeight: theme.fontWeight.bold,
|
|
||||||
},
|
|
||||||
constraintValuesContainer: {
|
|
||||||
marginTop: '0.25rem',
|
marginTop: '0.25rem',
|
||||||
},
|
},
|
||||||
constraintValue: {
|
link: {
|
||||||
marginRight: '0.25rem',
|
display: 'block',
|
||||||
|
marginTop: '0.2rem',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import StrategyCardConstraints from './StrategyCardConstraints';
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
flags: state.uiConfig.toJS().flags,
|
||||||
|
constraints: ownProps.constraints,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(StrategyCardConstraints);
|
@ -8,9 +8,7 @@ const StrategyCardField = ({ title, value }) => {
|
|||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
return (
|
return (
|
||||||
<div className={styles.fieldContainer}>
|
<div className={styles.fieldContainer}>
|
||||||
<Typography variant="body1" className={styles.fieldTitle}>
|
<Typography variant="body1">{title}</Typography>
|
||||||
{title}
|
|
||||||
</Typography>
|
|
||||||
<Typography className={styles.fieldValue} variant="body1">
|
<Typography className={styles.fieldValue} variant="body1">
|
||||||
{value}
|
{value}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -6,9 +6,6 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
margin: '0.4rem 0',
|
margin: '0.4rem 0',
|
||||||
},
|
},
|
||||||
fieldTitle: {
|
|
||||||
fontWeight: theme.fontWeight.semi,
|
|
||||||
},
|
|
||||||
fieldValue: {
|
fieldValue: {
|
||||||
maxWidth: '50%',
|
maxWidth: '50%',
|
||||||
},
|
},
|
||||||
|
@ -10,9 +10,15 @@ const StrategyCardList = ({ list, valuesName }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.strategyList}>
|
<div className={styles.strategyList}>
|
||||||
<Typography className={styles.strategyListHeader}>List of {valuesName}</Typography>
|
<Typography className={styles.strategyListHeader}>
|
||||||
|
List of {valuesName}
|
||||||
|
</Typography>
|
||||||
{list.map(listItem => (
|
{list.map(listItem => (
|
||||||
<Chip key={listItem} label={listItem} className={styles.strategyListChip} />
|
<Chip
|
||||||
|
key={listItem}
|
||||||
|
label={listItem}
|
||||||
|
className={styles.strategyListChip}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,6 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
margin: '0.25rem',
|
margin: '0.25rem',
|
||||||
},
|
},
|
||||||
strategyListHeader: {
|
strategyListHeader: {
|
||||||
fontWeight: theme.fontWeight.semi,
|
|
||||||
marginBottom: '0.5rem',
|
marginBottom: '0.5rem',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -5,11 +5,7 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
},
|
},
|
||||||
title: {
|
|
||||||
fontWeight: theme.fontWeight.semi,
|
|
||||||
},
|
|
||||||
percentage: {
|
percentage: {
|
||||||
color: theme.palette.success.main,
|
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { CardHeader, Typography, IconButton, Icon } from '@material-ui/core';
|
import {
|
||||||
|
CardHeader,
|
||||||
|
Typography,
|
||||||
|
IconButton,
|
||||||
|
Icon,
|
||||||
|
Tooltip,
|
||||||
|
} from '@material-ui/core';
|
||||||
|
|
||||||
import { useStyles } from './StrategyCardHeader.styles.js';
|
import { useStyles } from './StrategyCardHeader.styles.js';
|
||||||
|
import { ReactComponent as ReorderIcon } from '../../../../../assets/icons/reorder.svg';
|
||||||
|
|
||||||
const StrategyCardHeader = ({ name, connectDragSource, removeStrategy, editStrategy }) => {
|
const StrategyCardHeader = ({
|
||||||
|
name,
|
||||||
|
connectDragSource,
|
||||||
|
removeStrategy,
|
||||||
|
editStrategy,
|
||||||
|
}) => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -16,23 +28,36 @@ const StrategyCardHeader = ({ name, connectDragSource, removeStrategy, editStrat
|
|||||||
}}
|
}}
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
<Typography variant="subtitle1" className={styles.strategyCardHeaderTitle}>
|
<Typography
|
||||||
|
variant="subtitle1"
|
||||||
|
className={styles.strategyCardHeaderTitle}
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={styles.strategyCardHeaderActions}>
|
<div className={styles.strategyCardHeaderActions}>
|
||||||
<IconButton onClick={editStrategy}>
|
<Tooltip title="Edit strategy">
|
||||||
<Icon className={styles.strateyCardHeaderIcon}>edit</Icon>
|
<IconButton onClick={editStrategy}>
|
||||||
</IconButton>
|
<Icon className={styles.strateyCardHeaderIcon}>
|
||||||
|
edit
|
||||||
|
</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
{connectDragSource(
|
{connectDragSource(
|
||||||
<span>
|
<span>
|
||||||
<IconButton>
|
<Tooltip title="Drag and drop strategy to reorder. This only affects the order of which your strategies are evaluated.">
|
||||||
<Icon className={styles.strateyCardHeaderIcon}>reorder</Icon>
|
<IconButton>
|
||||||
</IconButton>
|
<ReorderIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<IconButton onClick={removeStrategy}>
|
<Tooltip title="Delete strategy">
|
||||||
<Icon className={styles.strateyCardHeaderIcon}>delete</Icon>
|
<IconButton onClick={removeStrategy}>
|
||||||
</IconButton>
|
<Icon className={styles.strateyCardHeaderIcon}>
|
||||||
|
delete
|
||||||
|
</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,21 @@ import { makeStyles } from '@material-ui/styles';
|
|||||||
export const useStyles = makeStyles(theme => ({
|
export const useStyles = makeStyles(theme => ({
|
||||||
strategyCardHeaderContent: {
|
strategyCardHeaderContent: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
},
|
},
|
||||||
strategyCardHeader: {
|
strategyCardHeader: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
|
||||||
background: `linear-gradient(${theme.palette.cards.gradient.top}, ${theme.palette.cards.gradient.bottom})`,
|
background: `linear-gradient(${theme.palette.cards.gradient.top}, ${theme.palette.cards.gradient.bottom})`,
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
textAlign: 'center',
|
textAlign: 'left',
|
||||||
width: '100%',
|
|
||||||
},
|
},
|
||||||
strategyCardHeaderTitle: {
|
strategyCardHeaderTitle: {
|
||||||
fontWeight: 'bold',
|
fontSize: theme.fontSizes.subHeader,
|
||||||
fontSize: theme.fontSizes.mainHeader,
|
|
||||||
marginBottom: '0.7rem',
|
|
||||||
},
|
},
|
||||||
strategyCardHeaderActions: {
|
strategyCardHeaderActions: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
},
|
},
|
||||||
strateyCardHeaderIcon: {
|
strateyCardHeaderIcon: {
|
||||||
|
@ -187,16 +187,20 @@ const StrategiesList = props => {
|
|||||||
className={styles.infoCard}
|
className={styles.infoCard}
|
||||||
onClose={() => setShowAlert(false)}
|
onClose={() => setShowAlert(false)}
|
||||||
>
|
>
|
||||||
Strategies allow you fine grained control over how to
|
<div style={{ maxWidth: '800px' }}>
|
||||||
activate your features, and are composable blocks that
|
Activation strategies defines how you enable the new
|
||||||
are executed in an OR fashion. As an example, you can
|
feature to your users. Changes to the activation
|
||||||
have a gradual rollout that targets 80% of users in a
|
strategies does not require redeployment of the
|
||||||
region of the world (using the enterprise feature of
|
code.
|
||||||
constraints), and another gradual rollout that targets
|
<br />
|
||||||
20% of the users in another region. If you don't add a
|
<br />
|
||||||
strategy, the default strategy is activated which means
|
Multiple activation strategies are composable blocks
|
||||||
that the feature will be strictly on/off for your entire
|
that is executed in an OR fashion.
|
||||||
userbase.
|
<br />
|
||||||
|
E.g. A gradual rollout activation strategy allows
|
||||||
|
you to gradually enable to feature to a subset of
|
||||||
|
your users without redeploy to production.
|
||||||
|
</div>
|
||||||
</Alert>
|
</Alert>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
background-color: #f2f9fc;
|
background-color: #f2f9fc;
|
||||||
overflow: "visible";
|
overflow: 'visible';
|
||||||
}
|
}
|
||||||
|
|
||||||
.paragraph {
|
.paragraph {
|
||||||
@ -156,3 +156,11 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.strategyListCards {
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: none;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user