Skip to content

Commit

Permalink
Disable and enable strategies - frontend (#3582)
Browse files Browse the repository at this point in the history
Signed-off-by: andreas-unleash <andreas@getunleash.ai>
Co-authored-by: andreas-unleash <andreas@getunleash.ai>
  • Loading branch information
Tymek and andreas-unleash committed Apr 26, 2023
1 parent 1e3f652 commit 3bb09c5
Show file tree
Hide file tree
Showing 28 changed files with 722 additions and 168 deletions.
@@ -1,25 +1,14 @@
import { FC, ReactNode } from 'react';
import {
hasNameField,
IChange,
IChangeRequest,
IChangeRequestFeature,
} from '../../../changeRequest.types';
import { objectId } from 'utils/objectId';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Alert, Box, styled } from '@mui/material';

import {
StrategyTooltipLink,
StrategyDiff,
} from 'component/changeRequest/ChangeRequest/StrategyTooltipLink/StrategyTooltipLink';
import { StrategyExecution } from '../../../../feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
import { ToggleStatusChange } from './ToggleStatusChange';
import {
StrategyAddedChange,
StrategyDeletedChange,
StrategyEditedChange,
} from './StrategyChange';
import { StrategyChange } from './StrategyChange';
import { VariantPatch } from './VariantPatch/VariantPatch';

const StyledSingleChangeBox = styled(Box, {
Expand Down Expand Up @@ -74,6 +63,7 @@ export const Change: FC<{
const lastIndex = feature.defaultChange
? feature.changes.length + 1
: feature.changes.length;

return (
<StyledSingleChangeBox
key={objectId(change)}
Expand All @@ -98,50 +88,17 @@ export const Change: FC<{
discard={discard}
/>
)}
{change.action === 'addStrategy' && (
<>
<StrategyAddedChange discard={discard}>
<StrategyTooltipLink change={change}>
<StrategyDiff
change={change}
feature={feature.name}
environmentName={changeRequest.environment}
project={changeRequest.project}
/>
</StrategyTooltipLink>
</StrategyAddedChange>
<StrategyExecution strategy={change.payload} />
</>
)}
{change.action === 'deleteStrategy' && (
<StrategyDeletedChange discard={discard}>
{hasNameField(change.payload) && (
<StrategyTooltipLink change={change}>
<StrategyDiff
change={change}
feature={feature.name}
environmentName={changeRequest.environment}
project={changeRequest.project}
/>
</StrategyTooltipLink>
)}
</StrategyDeletedChange>
)}
{change.action === 'updateStrategy' && (
<>
<StrategyEditedChange discard={discard}>
<StrategyTooltipLink change={change}>
<StrategyDiff
change={change}
feature={feature.name}
environmentName={changeRequest.environment}
project={changeRequest.project}
/>
</StrategyTooltipLink>
</StrategyEditedChange>
<StrategyExecution strategy={change.payload} />
</>
)}
{change.action === 'addStrategy' ||
change.action === 'deleteStrategy' ||
change.action === 'updateStrategy' ? (
<StrategyChange
discard={discard}
change={change}
featureName={feature.name}
environmentName={changeRequest.environment}
projectId={changeRequest.project}
/>
) : null}
{change.action === 'patchVariant' && (
<VariantPatch
feature={feature.name}
Expand Down
@@ -1,13 +1,29 @@
import { Box, styled, Typography } from '@mui/material';
import { FC, ReactNode } from 'react';
import { VFC, FC, ReactNode } from 'react';
import { Box, styled, Tooltip, Typography } from '@mui/material';
import BlockIcon from '@mui/icons-material/Block';
import TrackChangesIcon from '@mui/icons-material/TrackChanges';
import {
StrategyDiff,
StrategyTooltipLink,
} from '../../StrategyTooltipLink/StrategyTooltipLink';
import { StrategyExecution } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution';
import {
IChangeRequestAddStrategy,
IChangeRequestDeleteStrategy,
IChangeRequestUpdateStrategy,
} from 'component/changeRequest/changeRequest.types';
import { useCurrentStrategy } from './hooks/useCurrentStrategy';
import { Badge } from 'component/common/Badge/Badge';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { flexRow } from 'themes/themeStyles';

export const ChangeItemWrapper = styled(Box)({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
});

export const ChangeItemCreateEditWrapper = styled(Box)(({ theme }) => ({
const ChangeItemCreateEditWrapper = styled(Box)(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
Expand All @@ -20,55 +36,175 @@ const ChangeItemInfo: FC = styled(Box)(({ theme }) => ({
gap: theme.spacing(1),
}));

export const StrategyAddedChange: FC<{ discard?: ReactNode }> = ({
children,
discard,
}) => {
const hasNameField = (payload: unknown): payload is { name: string } =>
typeof payload === 'object' && payload !== null && 'name' in payload;

const DisabledEnabledState: VFC<{ disabled: boolean }> = ({ disabled }) => {
if (disabled) {
return (
<Tooltip
title="This strategy will not be taken into account when evaluating feature toggle."
arrow
sx={{ cursor: 'pointer' }}
>
<Badge color="disabled" icon={<BlockIcon />}>
Disabled
</Badge>
</Tooltip>
);
}

return (
<ChangeItemCreateEditWrapper>
<ChangeItemInfo>
<Typography
sx={theme => ({
color: theme.palette.success.dark,
})}
>
+ Adding strategy:
</Typography>
{children}
</ChangeItemInfo>
{discard}
</ChangeItemCreateEditWrapper>
<Tooltip
title="This was disabled before and with this change it will be taken into account when evaluating feature toggle."
arrow
sx={{ cursor: 'pointer' }}
>
<Badge color="success" icon={<TrackChangesIcon />}>
Enabled
</Badge>
</Tooltip>
);
};

export const StrategyEditedChange: FC<{ discard?: ReactNode }> = ({
children,
discard,
}) => {
return (
<ChangeItemCreateEditWrapper>
<ChangeItemInfo>
<Typography>Editing strategy:</Typography>
{children}
</ChangeItemInfo>
{discard}
</ChangeItemCreateEditWrapper>
);
const EditHeader: VFC<{
wasDisabled?: boolean;
willBeDisabled?: boolean;
}> = ({ wasDisabled = false, willBeDisabled = false }) => {
if (wasDisabled && willBeDisabled) {
return (
<Typography color="action.disabled">
Editing disabled strategy
</Typography>
);
}

if (!wasDisabled && willBeDisabled) {
return <Typography color="error.dark">Editing strategy</Typography>;
}

if (wasDisabled && !willBeDisabled) {
return <Typography color="success.dark">Editing strategy</Typography>;
}

return <Typography>Editing strategy:</Typography>;
};

export const StrategyDeletedChange: FC<{ discard?: ReactNode }> = ({
discard,
children,
}) => {
export const StrategyChange: VFC<{
discard?: ReactNode;
change:
| IChangeRequestAddStrategy
| IChangeRequestDeleteStrategy
| IChangeRequestUpdateStrategy;
environmentName: string;
featureName: string;
projectId: string;
}> = ({ discard, change, featureName, environmentName, projectId }) => {
const currentStrategy = useCurrentStrategy(
change,
projectId,
featureName,
environmentName
);

return (
<ChangeItemWrapper>
<ChangeItemInfo>
<Typography sx={theme => ({ color: theme.palette.error.main })}>
- Deleting strategy
</Typography>
{children}
</ChangeItemInfo>
{discard}
</ChangeItemWrapper>
<>
{change.action === 'addStrategy' && (
<>
<ChangeItemCreateEditWrapper>
<ChangeItemInfo>
<Typography
color={
change.payload?.disabled
? 'action.disabled'
: 'success.dark'
}
>
+ Adding strategy:
</Typography>
<StrategyTooltipLink change={change}>
<StrategyDiff
change={change}
currentStrategy={currentStrategy}
/>
</StrategyTooltipLink>
<ConditionallyRender
condition={Boolean(
change.payload?.disabled === true
)}
show={<DisabledEnabledState disabled={true} />}
/>
</ChangeItemInfo>
{discard}
</ChangeItemCreateEditWrapper>
<StrategyExecution strategy={change.payload} />
</>
)}
{change.action === 'deleteStrategy' && (
<ChangeItemWrapper>
<ChangeItemInfo>
<Typography
sx={theme => ({ color: theme.palette.error.main })}
>
- Deleting strategy
</Typography>
{hasNameField(change.payload) && (
<StrategyTooltipLink change={change}>
<StrategyDiff
change={change}
currentStrategy={currentStrategy}
/>
</StrategyTooltipLink>
)}
</ChangeItemInfo>
{discard}
</ChangeItemWrapper>
)}
{change.action === 'updateStrategy' && (
<>
<ChangeItemCreateEditWrapper>
<ChangeItemInfo>
<EditHeader
wasDisabled={currentStrategy?.disabled}
willBeDisabled={change.payload?.disabled}
/>
<StrategyTooltipLink
change={change}
previousTitle={currentStrategy?.title}
>
<StrategyDiff
change={change}
currentStrategy={currentStrategy}
/>
</StrategyTooltipLink>
</ChangeItemInfo>
{discard}
</ChangeItemCreateEditWrapper>
<StrategyExecution strategy={change.payload} />
<ConditionallyRender
condition={
change.payload?.disabled !==
currentStrategy?.disabled
}
show={
<Typography
sx={{
marginTop: theme => theme.spacing(2),
paddingLeft: theme => theme.spacing(3),
paddingRight: theme => theme.spacing(3),
...flexRow,
gap: theme => theme.spacing(1),
}}
>
This strategy will be{' '}
<DisabledEnabledState
disabled={change.payload?.disabled || false}
/>
</Typography>
}
/>
</>
)}
</>
);
};
@@ -0,0 +1,25 @@
import {
IChangeRequestAddStrategy,
IChangeRequestDeleteStrategy,
IChangeRequestUpdateStrategy,
} from 'component/changeRequest/changeRequest.types';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';

export const useCurrentStrategy = (
change:
| IChangeRequestAddStrategy
| IChangeRequestUpdateStrategy
| IChangeRequestDeleteStrategy,
project: string,
feature: string,
environmentName: string
) => {
const currentFeature = useFeature(project, feature);
const currentStrategy = currentFeature.feature?.environments
.find(environment => environment.name === environmentName)
?.strategies.find(
strategy =>
'id' in change.payload && strategy.id === change.payload.id
);
return currentStrategy;
};

0 comments on commit 3bb09c5

Please sign in to comment.