mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +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 ![image](https://github.com/user-attachments/assets/8511c6a3-c83e-4eee-aa18-9affe4a9ac1d) ### Remove release plan ![image](https://github.com/user-attachments/assets/ed13f9ac-140c-40c9-a1a2-3c066c89c09a) ### Start milestone ![image](https://github.com/user-attachments/assets/ac8e5408-e877-470c-a98b-295b41444bfa) ![image](https://github.com/user-attachments/assets/abf19a55-89df-4dd8-8738-9dfcd63949b7)
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