Skip to content

Commit

Permalink
Splitted strategy button (#4025)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tymek committed Jun 21, 2023
1 parent 71d242a commit 02ca605
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 79 deletions.
Expand Up @@ -20,6 +20,7 @@ export interface IPermissionButtonProps extends Omit<ButtonProps, 'title'> {
projectId?: string;
environmentId?: string;
tooltipProps?: Omit<ITooltipResolverProps, 'children'>;
hideLockIcon?: boolean;
}

interface IPermissionBaseButtonProps extends IPermissionButtonProps {
Expand Down Expand Up @@ -68,6 +69,7 @@ const BasePermissionButton: React.FC<IPermissionBaseButtonProps> =
projectId,
environmentId,
tooltipProps,
hideLockIcon,
...rest
},
ref
Expand All @@ -92,7 +94,7 @@ const BasePermissionButton: React.FC<IPermissionBaseButtonProps> =
endIcon={
<>
<ConditionallyRender
condition={!access}
condition={!access && !hideLockIcon}
show={<Lock titleAccess="Locked" />}
elseShow={
Boolean(rest.endIcon) &&
Expand Down
Expand Up @@ -15,6 +15,8 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { getFeatureStrategyIcon } from 'utils/strategyNames';
import { AddFromTemplateCard } from './AddFromTemplateCard/AddFromTemplateCard';
import { FeatureStrategyMenu } from '../FeatureStrategyMenu/FeatureStrategyMenu';
import { LegacyFeatureStrategyMenu } from '../FeatureStrategyMenu/LegacyFeatureStrategyMenu';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

interface IFeatureStrategyEmptyProps {
projectId: string;
Expand Down Expand Up @@ -76,6 +78,9 @@ export const FeatureStrategyEmpty = ({
onChangeRequestAddStrategyClose,
} = useChangeRequestAddStrategy(projectId, featureId, 'addStrategy');

const { uiConfig } = useUiConfig();
const strategySplittedButton = uiConfig?.flags?.strategySplittedButton;

const onAfterAddStrategy = (multiple = false) => {
refetchFeature();
refetchFeatureImmutable();
Expand Down Expand Up @@ -166,12 +171,26 @@ export const FeatureStrategyEmpty = ({
justifyContent: 'center',
}}
>
<FeatureStrategyMenu
label="Add your first strategy"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
matchWidth={canCopyFromOtherEnvironment}
<ConditionallyRender
condition={Boolean(strategySplittedButton)}
show={
<FeatureStrategyMenu
label="Add your first strategy"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
matchWidth={canCopyFromOtherEnvironment}
/>
}
elseShow={
<LegacyFeatureStrategyMenu
label="Add your first strategy"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
matchWidth={canCopyFromOtherEnvironment}
/>
}
/>
<ConditionallyRender
condition={canCopyFromOtherEnvironment}
Expand All @@ -186,55 +205,67 @@ export const FeatureStrategyEmpty = ({
}
/>
</Box>
<Box sx={{ width: '100%', mt: 3 }}>
<SectionSeparator>
Or use a strategy template
</SectionSeparator>
</Box>
<Box
sx={{
display: 'grid',
width: '100%',
gap: 2,
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },
}}
>
<AddFromTemplateCard
title="Standard strategy"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
onAfterAddStrategy={onAfterAddStrategy}
Icon={getFeatureStrategyIcon('default')}
strategy={{
name: 'default',
parameters: {},
constraints: [],
}}
>
The standard strategy is strictly on/off for your entire
userbase.
</AddFromTemplateCard>
<AddFromTemplateCard
title="Gradual rollout"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
onAfterAddStrategy={onAfterAddStrategy}
Icon={getFeatureStrategyIcon('flexibleRollout')}
strategy={{
name: 'flexibleRollout',
parameters: {
rollout: '50',
stickiness: 'default',
groupId: feature.name,
},
constraints: [],
}}
>
Roll out to a percentage of your userbase.
</AddFromTemplateCard>
</Box>
<ConditionallyRender
condition={strategySplittedButton === false}
show={
<>
<Box sx={{ width: '100%', mt: 3 }}>
<SectionSeparator>
Or use a strategy template
</SectionSeparator>
</Box>
<Box
sx={{
display: 'grid',
width: '100%',
gap: 2,
gridTemplateColumns: {
xs: '1fr',
sm: '1fr 1fr',
},
}}
>
<AddFromTemplateCard
title="Standard strategy"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
onAfterAddStrategy={onAfterAddStrategy}
Icon={getFeatureStrategyIcon('default')}
strategy={{
name: 'default',
parameters: {},
constraints: [],
}}
>
The standard strategy is strictly on/off for
your entire userbase.
</AddFromTemplateCard>
<AddFromTemplateCard
title="Gradual rollout"
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
onAfterAddStrategy={onAfterAddStrategy}
Icon={getFeatureStrategyIcon(
'flexibleRollout'
)}
strategy={{
name: 'flexibleRollout',
parameters: {
rollout: '50',
stickiness: 'default',
groupId: feature.name,
},
constraints: [],
}}
>
Roll out to a percentage of your userbase.
</AddFromTemplateCard>
</Box>
</>
}
/>
</StyledContainer>
</>
);
Expand Down
@@ -1,10 +1,13 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import PermissionButton, {
IPermissionButtonProps,
} from 'component/common/PermissionButton/PermissionButton';
import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import { Popover } from '@mui/material';
import { Popover, styled } from '@mui/material';
import { FeatureStrategyMenuCards } from './FeatureStrategyMenuCards/FeatureStrategyMenuCards';
import { formatCreateStrategyPath } from '../FeatureStrategyCreate/FeatureStrategyCreate';
import { MoreVert } from '@mui/icons-material';

interface IFeatureStrategyMenuProps {
label: string;
Expand All @@ -13,17 +16,30 @@ interface IFeatureStrategyMenuProps {
environmentId: string;
variant?: IPermissionButtonProps['variant'];
matchWidth?: boolean;
size?: IPermissionButtonProps['size'];
}

const StyledAdditionalMenuButton = styled(PermissionButton)(({ theme }) => ({
minWidth: 0,
width: theme.spacing(4.5),
alignItems: 'center',
justifyContent: 'center',
align: 'center',
flexDirection: 'column',
marginLeft: theme.spacing(1),
}));

export const FeatureStrategyMenu = ({
label,
projectId,
featureId,
environmentId,
variant,
size,
matchWidth,
}: IFeatureStrategyMenuProps) => {
const [anchor, setAnchor] = useState<Element>();
const navigate = useNavigate();
const isPopoverOpen = Boolean(anchor);
const popoverId = isPopoverOpen ? 'FeatureStrategyMenuPopover' : undefined;

Expand All @@ -35,25 +51,55 @@ export const FeatureStrategyMenu = ({
setAnchor(event.currentTarget);
};

const createStrategyPath = formatCreateStrategyPath(
projectId,
featureId,
environmentId,
'flexibleRollout',
true
);

return (
<div onClick={event => event.stopPropagation()}>
<PermissionButton
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={onClick}
onClick={() => navigate(createStrategyPath)}
aria-labelledby={popoverId}
variant={variant}
size={size}
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
>
{label}
</PermissionButton>

<StyledAdditionalMenuButton
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={onClick}
aria-labelledby={popoverId}
variant="outlined"
size={size}
hideLockIcon
tooltipProps={{
title: 'More strategies',
}}
>
<MoreVert sx={theme => ({ margin: theme.spacing(0.25, 0) })} />
</StyledAdditionalMenuButton>
<Popover
id={popoverId}
open={isPopoverOpen}
anchorEl={anchor}
onClose={onClose}
onClick={onClose}
PaperProps={{
sx: theme => ({
paddingBottom: theme.spacing(1),
}),
}}
>
<FeatureStrategyMenuCards
projectId={projectId}
Expand Down
@@ -0,0 +1,70 @@
import React, { useState } from 'react';
import PermissionButton, {
IPermissionButtonProps,
} from 'component/common/PermissionButton/PermissionButton';
import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
import { Popover } from '@mui/material';
import { FeatureStrategyMenuCards } from './FeatureStrategyMenuCards/FeatureStrategyMenuCards';

interface IFeatureStrategyMenuProps {
label: string;
projectId: string;
featureId: string;
environmentId: string;
variant?: IPermissionButtonProps['variant'];
matchWidth?: boolean;
}

/**
* Remove when removing feature flag strategySplittedButton
* @deprecated
*/
export const LegacyFeatureStrategyMenu = ({
label,
projectId,
featureId,
environmentId,
variant,
matchWidth,
}: IFeatureStrategyMenuProps) => {
const [anchor, setAnchor] = useState<Element>();
const isPopoverOpen = Boolean(anchor);
const popoverId = isPopoverOpen ? 'FeatureStrategyMenuPopover' : undefined;

const onClose = () => {
setAnchor(undefined);
};

const onClick = (event: React.SyntheticEvent) => {
setAnchor(event.currentTarget);
};

return (
<div onClick={event => event.stopPropagation()}>
<PermissionButton
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
onClick={onClick}
aria-labelledby={popoverId}
variant={variant}
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
>
{label}
</PermissionButton>
<Popover
id={popoverId}
open={isPopoverOpen}
anchorEl={anchor}
onClose={onClose}
onClick={onClose}
>
<FeatureStrategyMenuCards
projectId={projectId}
featureId={featureId}
environmentId={environmentId}
/>
</Popover>
</div>
);
};

0 comments on commit 02ca605

Please sign in to comment.