mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	chore: release plan changes in change request view (#9225)
https://linear.app/unleash/issue/2-3169/add-release-plan-ui-representation-in-change-request-ui Adds visual representations for release plan change requests. ### Add release plan  ### Remove release plan  ### Start milestone  
This commit is contained in:
		
							parent
							
								
									9a8607b07e
								
							
						
					
					
						commit
						9fa7f5aa7b
					
				| @ -14,6 +14,7 @@ import { EnvironmentStrategyExecutionOrder } from './EnvironmentStrategyExecutio | |||||||
| import { ArchiveFeatureChange } from './ArchiveFeatureChange'; | import { ArchiveFeatureChange } from './ArchiveFeatureChange'; | ||||||
| import { DependencyChange } from './DependencyChange'; | import { DependencyChange } from './DependencyChange'; | ||||||
| import { Link } from 'react-router-dom'; | import { Link } from 'react-router-dom'; | ||||||
|  | import { ReleasePlanChange } from './ReleasePlanChange'; | ||||||
| 
 | 
 | ||||||
| const StyledSingleChangeBox = styled(Box, { | const StyledSingleChangeBox = styled(Box, { | ||||||
|     shouldForwardProp: (prop: string) => !prop.startsWith('$'), |     shouldForwardProp: (prop: string) => !prop.startsWith('$'), | ||||||
| @ -192,6 +193,18 @@ export const FeatureChange: FC<{ | |||||||
|                         actions={actions} |                         actions={actions} | ||||||
|                     /> |                     /> | ||||||
|                 )} |                 )} | ||||||
|  |                 {(change.action === 'addReleasePlan' || | ||||||
|  |                     change.action === 'deleteReleasePlan' || | ||||||
|  |                     change.action === 'startMilestone') && ( | ||||||
|  |                     <ReleasePlanChange | ||||||
|  |                         actions={actions} | ||||||
|  |                         change={change} | ||||||
|  |                         featureName={feature.name} | ||||||
|  |                         environmentName={changeRequest.environment} | ||||||
|  |                         projectId={changeRequest.project} | ||||||
|  |                         changeRequestState={changeRequest.state} | ||||||
|  |                     /> | ||||||
|  |                 )} | ||||||
|             </ChangeInnerBox> |             </ChangeInnerBox> | ||||||
|         </StyledSingleChangeBox> |         </StyledSingleChangeBox> | ||||||
|     ); |     ); | ||||||
|  | |||||||
| @ -0,0 +1,277 @@ | |||||||
|  | import type React from 'react'; | ||||||
|  | import type { FC, ReactNode } from 'react'; | ||||||
|  | import { Box, styled, Typography } from '@mui/material'; | ||||||
|  | import type { | ||||||
|  |     ChangeRequestState, | ||||||
|  |     IChangeRequestAddReleasePlan, | ||||||
|  |     IChangeRequestDeleteReleasePlan, | ||||||
|  |     IChangeRequestStartMilestone, | ||||||
|  | } from 'component/changeRequest/changeRequest.types'; | ||||||
|  | import { useReleasePlanTemplate } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplate'; | ||||||
|  | import { useReleasePlans } from 'hooks/api/getters/useReleasePlans/useReleasePlans'; | ||||||
|  | import { TooltipLink } from 'component/common/TooltipLink/TooltipLink'; | ||||||
|  | import EventDiff from 'component/events/EventDiff/EventDiff'; | ||||||
|  | import { ReleasePlan } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlan'; | ||||||
|  | import { ReleasePlanMilestone } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone'; | ||||||
|  | 
 | ||||||
|  | export const ChangeItemWrapper = styled(Box)({ | ||||||
|  |     display: 'flex', | ||||||
|  |     justifyContent: 'space-between', | ||||||
|  |     alignItems: 'center', | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const ChangeItemCreateEditDeleteWrapper = styled(Box)(({ theme }) => ({ | ||||||
|  |     display: 'grid', | ||||||
|  |     gridTemplateColumns: 'auto auto', | ||||||
|  |     justifyContent: 'space-between', | ||||||
|  |     gap: theme.spacing(1), | ||||||
|  |     alignItems: 'center', | ||||||
|  |     marginBottom: theme.spacing(2), | ||||||
|  |     width: '100%', | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const ChangeItemInfo: FC<{ children?: React.ReactNode }> = styled(Box)( | ||||||
|  |     ({ theme }) => ({ | ||||||
|  |         display: 'flex', | ||||||
|  |         gap: theme.spacing(1), | ||||||
|  |     }), | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | const ViewDiff = styled('span')(({ theme }) => ({ | ||||||
|  |     color: theme.palette.primary.main, | ||||||
|  |     marginLeft: theme.spacing(1), | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const StyledCodeSection = styled('div')(({ theme }) => ({ | ||||||
|  |     overflowX: 'auto', | ||||||
|  |     '& code': { | ||||||
|  |         wordWrap: 'break-word', | ||||||
|  |         whiteSpace: 'pre-wrap', | ||||||
|  |         fontFamily: 'monospace', | ||||||
|  |         lineHeight: 1.5, | ||||||
|  |         fontSize: theme.fontSizes.smallBody, | ||||||
|  |     }, | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const DeleteReleasePlan: FC<{ | ||||||
|  |     change: IChangeRequestDeleteReleasePlan; | ||||||
|  |     environmentName: string; | ||||||
|  |     featureName: string; | ||||||
|  |     projectId: string; | ||||||
|  |     changeRequestState: ChangeRequestState; | ||||||
|  |     actions?: ReactNode; | ||||||
|  | }> = ({ | ||||||
|  |     change, | ||||||
|  |     environmentName, | ||||||
|  |     featureName, | ||||||
|  |     projectId, | ||||||
|  |     changeRequestState, | ||||||
|  |     actions, | ||||||
|  | }) => { | ||||||
|  |     const { releasePlans } = useReleasePlans( | ||||||
|  |         projectId, | ||||||
|  |         featureName, | ||||||
|  |         environmentName, | ||||||
|  |     ); | ||||||
|  |     const currentReleasePlan = releasePlans[0]; | ||||||
|  | 
 | ||||||
|  |     const releasePlan = | ||||||
|  |         changeRequestState === 'Applied' && change.payload.snapshot | ||||||
|  |             ? change.payload.snapshot | ||||||
|  |             : currentReleasePlan; | ||||||
|  | 
 | ||||||
|  |     if (!releasePlan) return; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |             <ChangeItemCreateEditDeleteWrapper> | ||||||
|  |                 <ChangeItemInfo> | ||||||
|  |                     <Typography | ||||||
|  |                         sx={(theme) => ({ | ||||||
|  |                             color: theme.palette.error.main, | ||||||
|  |                         })} | ||||||
|  |                     > | ||||||
|  |                         - Deleting release plan: | ||||||
|  |                     </Typography> | ||||||
|  |                     <Typography>{releasePlan.name}</Typography> | ||||||
|  |                 </ChangeItemInfo> | ||||||
|  |                 <div>{actions}</div> | ||||||
|  |             </ChangeItemCreateEditDeleteWrapper> | ||||||
|  |             <ReleasePlan plan={releasePlan} readonly /> | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const StartMilestone: FC<{ | ||||||
|  |     change: IChangeRequestStartMilestone; | ||||||
|  |     environmentName: string; | ||||||
|  |     featureName: string; | ||||||
|  |     projectId: string; | ||||||
|  |     changeRequestState: ChangeRequestState; | ||||||
|  |     actions?: ReactNode; | ||||||
|  | }> = ({ | ||||||
|  |     change, | ||||||
|  |     environmentName, | ||||||
|  |     featureName, | ||||||
|  |     projectId, | ||||||
|  |     changeRequestState, | ||||||
|  |     actions, | ||||||
|  | }) => { | ||||||
|  |     const { releasePlans } = useReleasePlans( | ||||||
|  |         projectId, | ||||||
|  |         featureName, | ||||||
|  |         environmentName, | ||||||
|  |     ); | ||||||
|  |     const currentReleasePlan = releasePlans[0]; | ||||||
|  | 
 | ||||||
|  |     const releasePlan = | ||||||
|  |         changeRequestState === 'Applied' && change.payload.snapshot | ||||||
|  |             ? change.payload.snapshot | ||||||
|  |             : currentReleasePlan; | ||||||
|  | 
 | ||||||
|  |     if (!releasePlan) return; | ||||||
|  | 
 | ||||||
|  |     const previousMilestone = releasePlan.milestones.find( | ||||||
|  |         (milestone) => milestone.id === releasePlan.activeMilestoneId, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     const newMilestone = releasePlan.milestones.find( | ||||||
|  |         (milestone) => milestone.id === change.payload.milestoneId, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (!newMilestone) return; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |             <ChangeItemCreateEditDeleteWrapper> | ||||||
|  |                 <ChangeItemInfo> | ||||||
|  |                     <Typography color='success.dark'> | ||||||
|  |                         + Start milestone: | ||||||
|  |                     </Typography> | ||||||
|  |                     <Typography>{newMilestone.name}</Typography> | ||||||
|  |                     <TooltipLink | ||||||
|  |                         tooltip={ | ||||||
|  |                             <StyledCodeSection> | ||||||
|  |                                 <EventDiff | ||||||
|  |                                     entry={{ | ||||||
|  |                                         preData: previousMilestone, | ||||||
|  |                                         data: newMilestone, | ||||||
|  |                                     }} | ||||||
|  |                                 /> | ||||||
|  |                             </StyledCodeSection> | ||||||
|  |                         } | ||||||
|  |                         tooltipProps={{ | ||||||
|  |                             maxWidth: 500, | ||||||
|  |                             maxHeight: 600, | ||||||
|  |                         }} | ||||||
|  |                     > | ||||||
|  |                         <ViewDiff>View Diff</ViewDiff> | ||||||
|  |                     </TooltipLink> | ||||||
|  |                 </ChangeItemInfo> | ||||||
|  |                 <div>{actions}</div> | ||||||
|  |             </ChangeItemCreateEditDeleteWrapper> | ||||||
|  |             <ReleasePlanMilestone readonly milestone={newMilestone} /> | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const AddReleasePlan: FC<{ | ||||||
|  |     change: IChangeRequestAddReleasePlan; | ||||||
|  |     environmentName: string; | ||||||
|  |     featureName: string; | ||||||
|  |     actions?: ReactNode; | ||||||
|  | }> = ({ change, environmentName, featureName, actions }) => { | ||||||
|  |     const { template } = useReleasePlanTemplate(change.payload.templateId); | ||||||
|  | 
 | ||||||
|  |     if (!template) return; | ||||||
|  | 
 | ||||||
|  |     const tentativeReleasePlan = { | ||||||
|  |         ...template, | ||||||
|  |         environment: environmentName, | ||||||
|  |         featureName, | ||||||
|  |         milestones: template.milestones.map((milestone) => ({ | ||||||
|  |             ...milestone, | ||||||
|  |             releasePlanDefinitionId: template.id, | ||||||
|  |             strategies: (milestone.strategies || []).map((strategy) => ({ | ||||||
|  |                 ...strategy, | ||||||
|  |                 parameters: { | ||||||
|  |                     ...strategy.parameters, | ||||||
|  |                     ...(strategy.parameters.groupId && { | ||||||
|  |                         groupId: String(strategy.parameters.groupId).replaceAll( | ||||||
|  |                             '{{featureName}}', | ||||||
|  |                             featureName, | ||||||
|  |                         ), | ||||||
|  |                     }), | ||||||
|  |                 }, | ||||||
|  |                 milestoneId: milestone.id, | ||||||
|  |             })), | ||||||
|  |         })), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |             <ChangeItemCreateEditDeleteWrapper> | ||||||
|  |                 <ChangeItemInfo> | ||||||
|  |                     <Typography color='success.dark'> | ||||||
|  |                         + Adding release plan: | ||||||
|  |                     </Typography> | ||||||
|  |                     <Typography>{template.name}</Typography> | ||||||
|  |                 </ChangeItemInfo> | ||||||
|  |                 <div>{actions}</div> | ||||||
|  |             </ChangeItemCreateEditDeleteWrapper> | ||||||
|  |             <ReleasePlan plan={tentativeReleasePlan} readonly /> | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const ReleasePlanChange: FC<{ | ||||||
|  |     actions?: ReactNode; | ||||||
|  |     change: | ||||||
|  |         | IChangeRequestAddReleasePlan | ||||||
|  |         | IChangeRequestDeleteReleasePlan | ||||||
|  |         | IChangeRequestStartMilestone; | ||||||
|  |     environmentName: string; | ||||||
|  |     featureName: string; | ||||||
|  |     projectId: string; | ||||||
|  |     changeRequestState: ChangeRequestState; | ||||||
|  | }> = ({ | ||||||
|  |     actions, | ||||||
|  |     change, | ||||||
|  |     featureName, | ||||||
|  |     environmentName, | ||||||
|  |     projectId, | ||||||
|  |     changeRequestState, | ||||||
|  | }) => { | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |             {change.action === 'addReleasePlan' && ( | ||||||
|  |                 <AddReleasePlan | ||||||
|  |                     change={change} | ||||||
|  |                     environmentName={environmentName} | ||||||
|  |                     featureName={featureName} | ||||||
|  |                     actions={actions} | ||||||
|  |                 /> | ||||||
|  |             )} | ||||||
|  |             {change.action === 'deleteReleasePlan' && ( | ||||||
|  |                 <DeleteReleasePlan | ||||||
|  |                     change={change} | ||||||
|  |                     environmentName={environmentName} | ||||||
|  |                     featureName={featureName} | ||||||
|  |                     projectId={projectId} | ||||||
|  |                     changeRequestState={changeRequestState} | ||||||
|  |                     actions={actions} | ||||||
|  |                 /> | ||||||
|  |             )} | ||||||
|  |             {change.action === 'startMilestone' && ( | ||||||
|  |                 <StartMilestone | ||||||
|  |                     change={change} | ||||||
|  |                     environmentName={environmentName} | ||||||
|  |                     featureName={featureName} | ||||||
|  |                     projectId={projectId} | ||||||
|  |                     changeRequestState={changeRequestState} | ||||||
|  |                     actions={actions} | ||||||
|  |                 /> | ||||||
|  |             )} | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
| @ -3,6 +3,7 @@ import type { ISegment } from 'interfaces/segment'; | |||||||
| import type { IFeatureStrategy } from '../../interfaces/strategy'; | import type { IFeatureStrategy } from '../../interfaces/strategy'; | ||||||
| import type { IUser } from '../../interfaces/user'; | import type { IUser } from '../../interfaces/user'; | ||||||
| import type { SetStrategySortOrderSchema } from '../../openapi'; | import type { SetStrategySortOrderSchema } from '../../openapi'; | ||||||
|  | import type { IReleasePlan } from 'interfaces/releasePlans'; | ||||||
| 
 | 
 | ||||||
| type BaseChangeRequest = { | type BaseChangeRequest = { | ||||||
|     id: number; |     id: number; | ||||||
| @ -126,7 +127,10 @@ type ChangeRequestPayload = | |||||||
|     | IChangeRequestDeleteSegment |     | IChangeRequestDeleteSegment | ||||||
|     | SetStrategySortOrderSchema |     | SetStrategySortOrderSchema | ||||||
|     | IChangeRequestArchiveFeature |     | IChangeRequestArchiveFeature | ||||||
|     | ChangeRequestAddDependency; |     | ChangeRequestAddDependency | ||||||
|  |     | ChangeRequestAddReleasePlan | ||||||
|  |     | ChangeRequestDeleteReleasePlan | ||||||
|  |     | ChangeRequestStartMilestone; | ||||||
| 
 | 
 | ||||||
| export interface IChangeRequestAddStrategy extends IChangeRequestChangeBase { | export interface IChangeRequestAddStrategy extends IChangeRequestChangeBase { | ||||||
|     action: 'addStrategy'; |     action: 'addStrategy'; | ||||||
| @ -167,6 +171,22 @@ export interface IChangeRequestDeleteDependency | |||||||
|     action: 'deleteDependency'; |     action: 'deleteDependency'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface IChangeRequestAddReleasePlan extends IChangeRequestChangeBase { | ||||||
|  |     action: 'addReleasePlan'; | ||||||
|  |     payload: ChangeRequestAddReleasePlan; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface IChangeRequestDeleteReleasePlan | ||||||
|  |     extends IChangeRequestChangeBase { | ||||||
|  |     action: 'deleteReleasePlan'; | ||||||
|  |     payload: ChangeRequestDeleteReleasePlan; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface IChangeRequestStartMilestone extends IChangeRequestChangeBase { | ||||||
|  |     action: 'startMilestone'; | ||||||
|  |     payload: ChangeRequestStartMilestone; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface IChangeRequestReorderStrategy | export interface IChangeRequestReorderStrategy | ||||||
|     extends IChangeRequestChangeBase { |     extends IChangeRequestChangeBase { | ||||||
|     action: 'reorderStrategy'; |     action: 'reorderStrategy'; | ||||||
| @ -211,7 +231,10 @@ export type IFeatureChange = | |||||||
|     | IChangeRequestReorderStrategy |     | IChangeRequestReorderStrategy | ||||||
|     | IChangeRequestArchiveFeature |     | IChangeRequestArchiveFeature | ||||||
|     | IChangeRequestAddDependency |     | IChangeRequestAddDependency | ||||||
|     | IChangeRequestDeleteDependency; |     | IChangeRequestDeleteDependency | ||||||
|  |     | IChangeRequestAddReleasePlan | ||||||
|  |     | IChangeRequestDeleteReleasePlan | ||||||
|  |     | IChangeRequestStartMilestone; | ||||||
| 
 | 
 | ||||||
| export type ISegmentChange = | export type ISegmentChange = | ||||||
|     | IChangeRequestUpdateSegment |     | IChangeRequestUpdateSegment | ||||||
| @ -230,6 +253,20 @@ type ChangeRequestAddDependency = { | |||||||
|     variants?: string[]; |     variants?: string[]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | type ChangeRequestAddReleasePlan = { | ||||||
|  |     templateId: string; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | type ChangeRequestDeleteReleasePlan = { | ||||||
|  |     planId: string; | ||||||
|  |     snapshot?: IReleasePlan; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | type ChangeRequestStartMilestone = { | ||||||
|  |     milestoneId: string; | ||||||
|  |     snapshot?: IReleasePlan; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export type ChangeRequestAddStrategy = Pick< | export type ChangeRequestAddStrategy = Pick< | ||||||
|     IFeatureStrategy, |     IFeatureStrategy, | ||||||
|     | 'parameters' |     | 'parameters' | ||||||
| @ -264,4 +301,7 @@ export type ChangeRequestAction = | |||||||
|     | 'deleteSegment' |     | 'deleteSegment' | ||||||
|     | 'archiveFeature' |     | 'archiveFeature' | ||||||
|     | 'addDependency' |     | 'addDependency' | ||||||
|     | 'deleteDependency'; |     | 'deleteDependency' | ||||||
|  |     | 'addReleasePlan' | ||||||
|  |     | 'deleteReleasePlan' | ||||||
|  |     | 'startMilestone'; | ||||||
|  | |||||||
| @ -16,13 +16,17 @@ import { ReleasePlanRemoveDialog } from './ReleasePlanRemoveDialog'; | |||||||
| import { ReleasePlanMilestone } from './ReleasePlanMilestone/ReleasePlanMilestone'; | import { ReleasePlanMilestone } from './ReleasePlanMilestone/ReleasePlanMilestone'; | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| 
 | 
 | ||||||
| const StyledContainer = styled('div')(({ theme }) => ({ | const StyledContainer = styled('div', { | ||||||
|  |     shouldForwardProp: (prop) => prop !== 'readonly', | ||||||
|  | })<{ readonly?: boolean }>(({ theme, readonly }) => ({ | ||||||
|     padding: theme.spacing(2), |     padding: theme.spacing(2), | ||||||
|     borderRadius: theme.shape.borderRadiusMedium, |     borderRadius: theme.shape.borderRadiusMedium, | ||||||
|     '& + &': { |     '& + &': { | ||||||
|         marginTop: theme.spacing(2), |         marginTop: theme.spacing(2), | ||||||
|     }, |     }, | ||||||
|     background: theme.palette.background.paper, |     background: readonly | ||||||
|  |         ? theme.palette.background.elevation1 | ||||||
|  |         : theme.palette.background.paper, | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
| const StyledHeader = styled('div')(({ theme }) => ({ | const StyledHeader = styled('div')(({ theme }) => ({ | ||||||
| @ -66,12 +70,14 @@ const StyledConnection = styled('div')(({ theme }) => ({ | |||||||
| 
 | 
 | ||||||
| interface IReleasePlanProps { | interface IReleasePlanProps { | ||||||
|     plan: IReleasePlan; |     plan: IReleasePlan; | ||||||
|     environmentIsDisabled: boolean; |     environmentIsDisabled?: boolean; | ||||||
|  |     readonly?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const ReleasePlan = ({ | export const ReleasePlan = ({ | ||||||
|     plan, |     plan, | ||||||
|     environmentIsDisabled, |     environmentIsDisabled, | ||||||
|  |     readonly, | ||||||
| }: IReleasePlanProps) => { | }: IReleasePlanProps) => { | ||||||
|     const { |     const { | ||||||
|         id, |         id, | ||||||
| @ -134,7 +140,7 @@ export const ReleasePlan = ({ | |||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <StyledContainer> |         <StyledContainer readonly={readonly}> | ||||||
|             <StyledHeader> |             <StyledHeader> | ||||||
|                 <StyledHeaderTitleContainer> |                 <StyledHeaderTitleContainer> | ||||||
|                     <StyledHeaderTitleLabel> |                     <StyledHeaderTitleLabel> | ||||||
| @ -145,22 +151,25 @@ export const ReleasePlan = ({ | |||||||
|                         {description} |                         {description} | ||||||
|                     </StyledHeaderDescription> |                     </StyledHeaderDescription> | ||||||
|                 </StyledHeaderTitleContainer> |                 </StyledHeaderTitleContainer> | ||||||
|                 <PermissionIconButton |                 {!readonly && ( | ||||||
|                     onClick={() => setRemoveOpen(true)} |                     <PermissionIconButton | ||||||
|                     permission={DELETE_FEATURE_STRATEGY} |                         onClick={() => setRemoveOpen(true)} | ||||||
|                     environmentId={environment} |                         permission={DELETE_FEATURE_STRATEGY} | ||||||
|                     projectId={projectId} |                         environmentId={environment} | ||||||
|                     tooltipProps={{ |                         projectId={projectId} | ||||||
|                         title: 'Remove release plan', |                         tooltipProps={{ | ||||||
|                     }} |                             title: 'Remove release plan', | ||||||
|                 > |                         }} | ||||||
|                     <Delete /> |                     > | ||||||
|                 </PermissionIconButton> |                         <Delete /> | ||||||
|  |                     </PermissionIconButton> | ||||||
|  |                 )} | ||||||
|             </StyledHeader> |             </StyledHeader> | ||||||
|             <StyledBody> |             <StyledBody> | ||||||
|                 {milestones.map((milestone, index) => ( |                 {milestones.map((milestone, index) => ( | ||||||
|                     <div key={milestone.id}> |                     <div key={milestone.id}> | ||||||
|                         <ReleasePlanMilestone |                         <ReleasePlanMilestone | ||||||
|  |                             readonly={readonly} | ||||||
|                             milestone={milestone} |                             milestone={milestone} | ||||||
|                             status={ |                             status={ | ||||||
|                                 milestone.id === activeMilestoneId |                                 milestone.id === activeMilestoneId | ||||||
|  | |||||||
| @ -58,14 +58,16 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ | |||||||
| 
 | 
 | ||||||
| interface IReleasePlanMilestoneProps { | interface IReleasePlanMilestoneProps { | ||||||
|     milestone: IReleasePlanMilestone; |     milestone: IReleasePlanMilestone; | ||||||
|     status: MilestoneStatus; |     status?: MilestoneStatus; | ||||||
|     onStartMilestone: (milestone: IReleasePlanMilestone) => void; |     onStartMilestone?: (milestone: IReleasePlanMilestone) => void; | ||||||
|  |     readonly?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const ReleasePlanMilestone = ({ | export const ReleasePlanMilestone = ({ | ||||||
|     milestone, |     milestone, | ||||||
|     status, |     status = 'not-started', | ||||||
|     onStartMilestone, |     onStartMilestone, | ||||||
|  |     readonly, | ||||||
| }: IReleasePlanMilestoneProps) => { | }: IReleasePlanMilestoneProps) => { | ||||||
|     const [expanded, setExpanded] = useState(false); |     const [expanded, setExpanded] = useState(false); | ||||||
| 
 | 
 | ||||||
| @ -75,10 +77,14 @@ export const ReleasePlanMilestone = ({ | |||||||
|                 <StyledAccordionSummary> |                 <StyledAccordionSummary> | ||||||
|                     <StyledTitleContainer> |                     <StyledTitleContainer> | ||||||
|                         <StyledTitle>{milestone.name}</StyledTitle> |                         <StyledTitle>{milestone.name}</StyledTitle> | ||||||
|                         <ReleasePlanMilestoneStatus |                         {!readonly && onStartMilestone && ( | ||||||
|                             status={status} |                             <ReleasePlanMilestoneStatus | ||||||
|                             onStartMilestone={() => onStartMilestone(milestone)} |                                 status={status} | ||||||
|                         /> |                                 onStartMilestone={() => | ||||||
|  |                                     onStartMilestone(milestone) | ||||||
|  |                                 } | ||||||
|  |                             /> | ||||||
|  |                         )} | ||||||
|                     </StyledTitleContainer> |                     </StyledTitleContainer> | ||||||
|                     <StyledSecondaryLabel>No strategies</StyledSecondaryLabel> |                     <StyledSecondaryLabel>No strategies</StyledSecondaryLabel> | ||||||
|                 </StyledAccordionSummary> |                 </StyledAccordionSummary> | ||||||
| @ -94,10 +100,12 @@ export const ReleasePlanMilestone = ({ | |||||||
|             <StyledAccordionSummary expandIcon={<ExpandMore />}> |             <StyledAccordionSummary expandIcon={<ExpandMore />}> | ||||||
|                 <StyledTitleContainer> |                 <StyledTitleContainer> | ||||||
|                     <StyledTitle>{milestone.name}</StyledTitle> |                     <StyledTitle>{milestone.name}</StyledTitle> | ||||||
|                     <ReleasePlanMilestoneStatus |                     {!readonly && onStartMilestone && ( | ||||||
|                         status={status} |                         <ReleasePlanMilestoneStatus | ||||||
|                         onStartMilestone={() => onStartMilestone(milestone)} |                             status={status} | ||||||
|                     /> |                             onStartMilestone={() => onStartMilestone(milestone)} | ||||||
|  |                         /> | ||||||
|  |                     )} | ||||||
|                 </StyledTitleContainer> |                 </StyledTitleContainer> | ||||||
|                 <StyledSecondaryLabel> |                 <StyledSecondaryLabel> | ||||||
|                     {milestone.strategies.length === 1 |                     {milestone.strategies.length === 1 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user