mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
chore: list release templates in strategy popover (#8703)
https://linear.app/unleash/issue/2-2817/expand-the-strategy-dropdown-with-release-plan-templates Does what it says on the tin, lists release plan templates in the strategy popover. I think we should improve this popover soon, at least behind the `flagOverviewRedesign` flag, but not in this PR. 
This commit is contained in:
parent
da805f2036
commit
044e61454b
@ -140,12 +140,9 @@ export const TOPICS: ITutorialTopic[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
target: `a[href="${basePath}/projects/${PROJECT}/features/demoApp.step2/strategies/create?environmentId=${ENVIRONMENT}&strategyName=default&defaultStrategy=false"]`,
|
||||
target: `a[href="${basePath}/projects/${PROJECT}/features/demoApp.step2/strategies/create?environmentId=${ENVIRONMENT}&strategyName=flexibleRollout&defaultStrategy=true"]`,
|
||||
content: (
|
||||
<Description>
|
||||
Select the <Badge as='span'>Standard</Badge> strategy
|
||||
type.
|
||||
</Description>
|
||||
<Description>Select the default strategy.</Description>
|
||||
),
|
||||
placement: 'right',
|
||||
optional: true,
|
||||
@ -480,6 +477,15 @@ export const TOPICS: ITutorialTopic[] = [
|
||||
</Description>
|
||||
),
|
||||
},
|
||||
{
|
||||
target: `a[href="${basePath}/projects/${PROJECT}/features/demoApp.step4/strategies/create?environmentId=${ENVIRONMENT}&strategyName=flexibleRollout&defaultStrategy=true"]`,
|
||||
content: (
|
||||
<Description>Select the default strategy.</Description>
|
||||
),
|
||||
placement: 'right',
|
||||
optional: true,
|
||||
backCloseModal: true,
|
||||
},
|
||||
{
|
||||
target: 'button[data-testid="STRATEGY_TARGETING_TAB"]',
|
||||
content: (
|
||||
|
@ -0,0 +1,88 @@
|
||||
import { getFeatureStrategyIcon } from 'utils/strategyNames';
|
||||
import StringTruncator from 'component/common/StringTruncator/StringTruncator';
|
||||
import { Link, styled } from '@mui/material';
|
||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
|
||||
|
||||
const StyledIcon = styled('div')(({ theme }) => ({
|
||||
width: theme.spacing(4),
|
||||
height: 'auto',
|
||||
'& > svg': {
|
||||
fill: theme.palette.primary.main,
|
||||
},
|
||||
'& > div': {
|
||||
height: theme.spacing(2),
|
||||
marginLeft: '-.75rem',
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledDescription = styled('div')(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallBody,
|
||||
}));
|
||||
|
||||
const StyledName = styled(StringTruncator)(({ theme }) => ({
|
||||
fontWeight: theme.fontWeight.bold,
|
||||
}));
|
||||
|
||||
const StyledCard = styled(Link)(({ theme }) => ({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '3rem 1fr',
|
||||
width: '20rem',
|
||||
padding: theme.spacing(2),
|
||||
color: 'inherit',
|
||||
textDecoration: 'inherit',
|
||||
lineHeight: 1.25,
|
||||
borderWidth: '1px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: theme.palette.divider,
|
||||
borderRadius: theme.spacing(1),
|
||||
'&:hover, &:focus': {
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
interface IFeatureReleasePlanCardProps {
|
||||
projectId: string;
|
||||
featureId: string;
|
||||
environmentId: string;
|
||||
releasePlanTemplate: IReleasePlanTemplate;
|
||||
}
|
||||
|
||||
export const FeatureReleasePlanCard = ({
|
||||
projectId,
|
||||
featureId,
|
||||
environmentId,
|
||||
releasePlanTemplate,
|
||||
}: IFeatureReleasePlanCardProps) => {
|
||||
const Icon = getFeatureStrategyIcon('releasePlanTemplate');
|
||||
const { trackEvent } = usePlausibleTracker();
|
||||
|
||||
const addReleasePlan = () => {
|
||||
trackEvent('release-plans', {
|
||||
props: {
|
||||
eventType: 'add',
|
||||
name: releasePlanTemplate.name,
|
||||
},
|
||||
});
|
||||
console.log('TODO: call and implement addReleasePlan');
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledCard onClick={addReleasePlan}>
|
||||
<StyledIcon>
|
||||
<Icon />
|
||||
</StyledIcon>
|
||||
<div>
|
||||
<StyledName
|
||||
text={releasePlanTemplate.name}
|
||||
maxWidth='200'
|
||||
maxLength={25}
|
||||
/>
|
||||
<StyledDescription>
|
||||
{releasePlanTemplate.description}
|
||||
</StyledDescription>
|
||||
</div>
|
||||
</StyledCard>
|
||||
);
|
||||
};
|
@ -10,6 +10,7 @@ import { FeatureStrategyMenuCards } from './FeatureStrategyMenuCards/FeatureStra
|
||||
import { formatCreateStrategyPath } from '../FeatureStrategyCreate/FeatureStrategyCreate';
|
||||
import MoreVert from '@mui/icons-material/MoreVert';
|
||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
interface IFeatureStrategyMenuProps {
|
||||
label: string;
|
||||
@ -51,6 +52,7 @@ export const FeatureStrategyMenu = ({
|
||||
const { trackEvent } = usePlausibleTracker();
|
||||
const isPopoverOpen = Boolean(anchor);
|
||||
const popoverId = isPopoverOpen ? 'FeatureStrategyMenuPopover' : undefined;
|
||||
const flagOverviewRedesignEnabled = useUiFlag('flagOverviewRedesign');
|
||||
|
||||
const onClose = () => {
|
||||
setAnchor(undefined);
|
||||
@ -77,6 +79,48 @@ export const FeatureStrategyMenu = ({
|
||||
true,
|
||||
);
|
||||
|
||||
if (flagOverviewRedesignEnabled) {
|
||||
return (
|
||||
<StyledStrategyMenu onClick={(event) => event.stopPropagation()}>
|
||||
<PermissionButton
|
||||
data-testid='ADD_STRATEGY_BUTTON'
|
||||
permission={CREATE_FEATURE_STRATEGY}
|
||||
projectId={projectId}
|
||||
environmentId={environmentId}
|
||||
onClick={openMoreStrategies}
|
||||
aria-labelledby={popoverId}
|
||||
variant={variant}
|
||||
size={size}
|
||||
sx={{ minWidth: matchWidth ? '282px' : 'auto' }}
|
||||
disabled={Boolean(disableReason)}
|
||||
tooltipProps={{
|
||||
title: disableReason ? disableReason : undefined,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</PermissionButton>
|
||||
<Popover
|
||||
id={popoverId}
|
||||
open={isPopoverOpen}
|
||||
anchorEl={anchor}
|
||||
onClose={onClose}
|
||||
onClick={onClose}
|
||||
PaperProps={{
|
||||
sx: (theme) => ({
|
||||
paddingBottom: theme.spacing(1),
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<FeatureStrategyMenuCards
|
||||
projectId={projectId}
|
||||
featureId={featureId}
|
||||
environmentId={environmentId}
|
||||
/>
|
||||
</Popover>
|
||||
</StyledStrategyMenu>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledStrategyMenu onClick={(event) => event.stopPropagation()}>
|
||||
<PermissionButton
|
||||
|
@ -2,6 +2,8 @@ import { List, ListItem, styled, Typography } from '@mui/material';
|
||||
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
|
||||
import { FeatureStrategyMenuCard } from '../FeatureStrategyMenuCard/FeatureStrategyMenuCard';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates';
|
||||
import { FeatureReleasePlanCard } from '../FeatureReleasePlanCard/FeatureReleasePlanCard';
|
||||
|
||||
interface IFeatureStrategyMenuCardsProps {
|
||||
projectId: string;
|
||||
@ -20,6 +22,7 @@ export const FeatureStrategyMenuCards = ({
|
||||
environmentId,
|
||||
}: IFeatureStrategyMenuCardsProps) => {
|
||||
const { strategies } = useStrategies();
|
||||
const { templates } = useReleasePlanTemplates();
|
||||
|
||||
const preDefinedStrategies = strategies.filter(
|
||||
(strategy) => !strategy.deprecated && !strategy.editable,
|
||||
@ -39,7 +42,7 @@ export const FeatureStrategyMenuCards = ({
|
||||
<List dense>
|
||||
<>
|
||||
<StyledTypography color='textSecondary'>
|
||||
{environmentId} environment default strategy
|
||||
Default strategy for {environmentId} environment
|
||||
</StyledTypography>
|
||||
<ListItem key={defaultStrategy.name}>
|
||||
<FeatureStrategyMenuCard
|
||||
@ -51,6 +54,26 @@ export const FeatureStrategyMenuCards = ({
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
<ConditionallyRender
|
||||
condition={templates.length > 0}
|
||||
show={
|
||||
<>
|
||||
<StyledTypography color='textSecondary'>
|
||||
Release templates
|
||||
</StyledTypography>
|
||||
{templates.map((template) => (
|
||||
<ListItem key={template.id}>
|
||||
<FeatureReleasePlanCard
|
||||
projectId={projectId}
|
||||
featureId={featureId}
|
||||
environmentId={environmentId}
|
||||
releasePlanTemplate={template}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<StyledTypography color='textSecondary'>
|
||||
Predefined strategy types
|
||||
</StyledTypography>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import useUiConfig from '../useUiConfig/useUiConfig';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { useConditionalSWR } from '../useConditionalSWR/useConditionalSWR';
|
||||
@ -12,12 +11,11 @@ const ENDPOINT = 'api/admin/release-plan-templates';
|
||||
const DEFAULT_DATA: IReleasePlanTemplate[] = [];
|
||||
|
||||
export const useReleasePlanTemplates = () => {
|
||||
const { isAdmin } = useContext(AccessContext);
|
||||
const { isEnterprise } = useUiConfig();
|
||||
const signalsEnabled = useUiFlag('releasePlans');
|
||||
const releasePlansEnabled = useUiFlag('releasePlans');
|
||||
|
||||
const { data, error, mutate } = useConditionalSWR<IReleasePlanTemplate[]>(
|
||||
isEnterprise() && isAdmin && signalsEnabled,
|
||||
isEnterprise() && releasePlansEnabled,
|
||||
DEFAULT_DATA,
|
||||
formatApiPath(ENDPOINT),
|
||||
fetcher,
|
||||
|
@ -73,7 +73,8 @@ export type CustomEvents =
|
||||
| 'order-environments'
|
||||
| 'unleash-ai-chat'
|
||||
| 'project-navigation'
|
||||
| 'productivity-report';
|
||||
| 'productivity-report'
|
||||
| 'release-plans';
|
||||
|
||||
export const usePlausibleTracker = () => {
|
||||
const plausible = useContext(PlausibleContext);
|
||||
|
@ -6,6 +6,7 @@ import LanguageIcon from '@mui/icons-material/Language';
|
||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||
import CodeIcon from '@mui/icons-material/Code';
|
||||
import { ReactComponent as RolloutIcon } from 'assets/icons/rollout.svg';
|
||||
import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
|
||||
|
||||
export const formatStrategyName = (strategyName: string): string => {
|
||||
return formattedStrategyNames[strategyName] ?? strategyName;
|
||||
@ -31,6 +32,8 @@ export const getFeatureStrategyIcon = (strategyName: string) => {
|
||||
return PeopleIcon;
|
||||
case 'applicationHostname':
|
||||
return LocationOnIcon;
|
||||
case 'releasePlanTemplate':
|
||||
return FormatListNumberedIcon;
|
||||
default:
|
||||
return CodeIcon;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user