1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-18 00:19:49 +01:00

task: Add buttons for deleting/editing a constraint (#522)

* task: Add buttons for deleting/editing a constraint

* task: Improve look and feel of constraints buttons

- Make constraints fill their container
- Move constraint buttons to material ui buttons
- Move constraint buttons to top right of their container

* fix: adjust positioning

* fix: added project id to permissin button

* fix: add correct permission

* fix: update create feature path

Co-authored-by: Simon Hornby <simon@getunleash.ai>
Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
This commit is contained in:
sighphyre 2021-11-26 17:07:05 +02:00 committed by GitHub
parent 3e53a64fcf
commit b85b326104
7 changed files with 99 additions and 30 deletions

View File

@ -82,7 +82,9 @@ describe('feature toggle', () => {
cy.get('[data-test=NAVIGATE_TO_CREATE_FEATURE').click();
cy.intercept('POST', '/api/admin/features').as('createFeature');
cy.intercept('POST', '/api/admin/projects/default/features').as(
'createFeature'
);
cy.get("[data-test='CF_NAME_ID'").type(featureToggleName);
cy.get("[data-test='CF_DESC_ID'").type('hellowrdada');

View File

@ -33,6 +33,7 @@
"test": "react-scripts test",
"prepare": "yarn run build",
"e2e": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,AUTH_TOKEN=$AUTH_TOKEN",
"e2e:heroku": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=false,AUTH_TOKEN=$AUTH_TOKEN",
"e2e:enterprise": "yarn run cypress open --config baseUrl='http://localhost:3000' --env PASSWORD_AUTH=true,ENTERPRISE=true,AUTH_TOKEN=$AUTH_TOKEN"
},
"devDependencies": {

View File

@ -11,11 +11,21 @@ export const useStyles = makeStyles(theme => ({
alignItems: 'center',
justifyContent: 'center',
padding: '0.1rem 0.5rem',
border: `1px solid ${theme.palette.grey[300]}`,
borderRadius: '5px',
fontSize: theme.fontSizes.smallBody,
backgroundColor: theme.palette.grey[200],
margin: '0.5rem 0',
position: 'relative',
borderRadius: '5px',
},
constraintBtn: {
color: theme.palette.primary.main,
fontWeight: 'normal',
marginBottom: '0.5rem',
},
btnContainer: {
position: 'absolute',
top: '6px',
right: 0,
},
column: {
flexDirection: 'column',

View File

@ -1,31 +1,75 @@
import { Delete, Edit } from '@material-ui/icons';
import classnames from 'classnames';
import { useParams } from 'react-router';
import { IFeatureViewParams } from '../../../interfaces/params';
import { IConstraint } from '../../../interfaces/strategy';
import FeatureStrategiesSeparator from '../../feature/FeatureView2/FeatureStrategies/FeatureStrategiesEnvironments/FeatureStrategiesSeparator/FeatureStrategiesSeparator';
import { UPDATE_FEATURE } from '../../providers/AccessProvider/permissions';
import ConditionallyRender from '../ConditionallyRender';
import PermissionIconButton from '../PermissionIconButton/PermissionIconButton';
import StringTruncator from '../StringTruncator/StringTruncator';
import { useStyles } from './Constraint.styles';
interface IConstraintProps {
constraint: IConstraint;
className?: string;
deleteCallback?: () => void;
editCallback?: () => void;
}
const Constraint = ({ constraint, className, ...rest }: IConstraintProps) => {
const Constraint = ({
constraint,
deleteCallback,
editCallback,
className,
...rest
}: IConstraintProps) => {
const styles = useStyles();
const { projectId } = useParams<IFeatureViewParams>();
const classes = classnames(styles.constraint, {
[styles.column]: constraint.values.length > 2,
});
const editable = !!(deleteCallback && editCallback);
return (
<div className={classes + ' ' + className} {...rest}>
<StringTruncator text={constraint.contextName} maxWidth="125" />
<FeatureStrategiesSeparator
text={constraint.operator}
maxWidth="none"
<div className={classes + ' ' + className} {...rest}>
<StringTruncator text={constraint.contextName} maxWidth="125" />
<FeatureStrategiesSeparator
text={constraint.operator}
maxWidth="none"
/>
<span className={styles.values}>
{constraint.values.join(', ')}
</span>
</div>
<ConditionallyRender
condition={editable}
show={
<div className={styles.btnContainer}>
<PermissionIconButton
onClick={editCallback}
tooltip="Edit strategy"
permission={UPDATE_FEATURE}
projectId={projectId}
>
<Edit />
</PermissionIconButton>
<PermissionIconButton
onClick={deleteCallback}
tooltip="Delete strategy"
permission={UPDATE_FEATURE}
projectId={projectId}
>
<Delete />
</PermissionIconButton>
</div>
}
/>
<span className={styles.values}>
{constraint.values.join(', ')}
</span>
</div>
);
};

View File

@ -5,7 +5,7 @@ import AccessContext from '../../../contexts/AccessContext';
interface IPermissionIconButtonProps extends OverridableComponent<any> {
permission: string;
Icon: React.ElementType;
Icon?: React.ElementType;
tooltip: string;
onClick?: (e: any) => void;
projectId?: string;

View File

@ -7,7 +7,8 @@ export const useStyles = makeStyles(theme => ({
marginBottom: '0.5rem',
},
accordionContainer: {
width: '80%',
width: '100%',
paddingRight: '37px',
[theme.breakpoints.down(800)]: {
width: '100%',
},
@ -20,7 +21,4 @@ export const useStyles = makeStyles(theme => ({
marginTop: '0.5rem',
fontSize: theme.fontSizes.smallBody,
},
constraintBody: {
maxWidth: '350px',
},
}));

View File

@ -12,7 +12,6 @@ import { useContext, useState } from 'react';
import ConditionallyRender from '../../../../../common/ConditionallyRender';
import useUiConfig from '../../../../../../hooks/api/getters/useUiConfig/useUiConfig';
import { C } from '../../../../../common/flags';
import { Button } from '@material-ui/core';
import { useStyles } from './FeatureStrategyAccordionBody.styles';
import Dialogue from '../../../../../common/Dialogue';
import DefaultStrategy from '../../common/DefaultStrategy/DefaultStrategy';
@ -20,6 +19,9 @@ import { ADD_CONSTRAINT_ID } from '../../../../../../testIds';
import AccessContext from '../../../../../../contexts/AccessContext';
import { UPDATE_FEATURE } from '../../../../../providers/AccessProvider/permissions';
import Constraint from '../../../../../common/Constraint/Constraint';
import PermissionButton from '../../../../../common/PermissionButton/PermissionButton';
import { useParams } from 'react-router';
import { IFeatureViewParams } from '../../../../../../interfaces/params';
interface IFeatureStrategyAccordionBodyProps {
strategy: IFeatureStrategy;
@ -40,6 +42,7 @@ const FeatureStrategyAccordionBody: React.FC<IFeatureStrategyAccordionBodyProps>
setStrategyConstraints,
}) => {
const styles = useStyles();
const { projectId } = useParams<IFeatureViewParams>();
const [constraintError, setConstraintError] = useState({});
const { strategies } = useStrategies();
const { uiConfig } = useUiConfig();
@ -106,13 +109,25 @@ const FeatureStrategyAccordionBody: React.FC<IFeatureStrategyAccordionBodyProps>
return (
<Constraint
constraint={constraint}
editCallback={() => {
setShowConstraints(true);
}}
deleteCallback={() => {
removeConstraint(index);
}}
key={`${constraint.contextName}-${index}`}
className={styles.constraintBody}
/>
);
});
};
const removeConstraint = (index: number) => {
const updatedConstraints = [...constraints];
updatedConstraints.splice(index, 1);
updateConstraints(updatedConstraints);
};
const closeConstraintDialog = () => {
setShowConstraints(false);
const filteredConstraints = constraints.filter(constraint => {
@ -137,18 +152,17 @@ const FeatureStrategyAccordionBody: React.FC<IFeatureStrategyAccordionBodyProps>
Constraints
</p>
{renderConstraints()}
<ConditionallyRender
condition={hasAccess(UPDATE_FEATURE)}
show={
<Button
className={styles.addConstraintBtn}
onClick={toggleConstraints}
data-test={ADD_CONSTRAINT_ID}
>
+ Edit constraints
</Button>
}
/>
<PermissionButton
className={styles.addConstraintBtn}
onClick={toggleConstraints}
variant={'text'}
data-test={ADD_CONSTRAINT_ID}
permission={UPDATE_FEATURE}
projectId={projectId}
>
+ Add constraints
</PermissionButton>
</>
}
/>