mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
feat: Add transition condition UI for release plan milestones (#10768)
This commit is contained in:
parent
247dd3af51
commit
a922801690
@ -69,7 +69,7 @@ export const EnvironmentAccordionBody = ({
|
||||
const { releasePlans } = useFeatureReleasePlans(
|
||||
projectId,
|
||||
featureId,
|
||||
featureEnvironment,
|
||||
featureEnvironment?.name,
|
||||
);
|
||||
const { trackEvent } = usePlausibleTracker();
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ const FeatureOverviewWithReleasePlans: FC<
|
||||
const { releasePlans } = useFeatureReleasePlans(
|
||||
projectId,
|
||||
featureId,
|
||||
environment,
|
||||
environment?.name,
|
||||
);
|
||||
const envAddStrategySuggestionEnabled = useUiFlag(
|
||||
'envAddStrategySuggestion',
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import Add from '@mui/icons-material/Add';
|
||||
import { Button, styled } from '@mui/material';
|
||||
import type { MilestoneStatus } from './ReleasePlanMilestoneStatus.tsx';
|
||||
import { MilestoneTransitionDisplay } from './MilestoneTransitionDisplay.tsx';
|
||||
|
||||
const StyledAutomationContainer = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'status',
|
||||
@ -51,6 +52,9 @@ interface IMilestoneAutomationSectionProps {
|
||||
status?: MilestoneStatus;
|
||||
onAddAutomation?: () => void;
|
||||
automationForm?: React.ReactNode;
|
||||
transitionCondition?: {
|
||||
intervalMinutes: number;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export const MilestoneAutomationSection = ({
|
||||
@ -58,6 +62,7 @@ export const MilestoneAutomationSection = ({
|
||||
status,
|
||||
onAddAutomation,
|
||||
automationForm,
|
||||
transitionCondition,
|
||||
}: IMilestoneAutomationSectionProps) => {
|
||||
if (!showAutomation) return null;
|
||||
|
||||
@ -65,6 +70,10 @@ export const MilestoneAutomationSection = ({
|
||||
<StyledAutomationContainer status={status}>
|
||||
{automationForm ? (
|
||||
automationForm
|
||||
) : transitionCondition ? (
|
||||
<MilestoneTransitionDisplay
|
||||
intervalMinutes={transitionCondition.intervalMinutes}
|
||||
/>
|
||||
) : (
|
||||
<StyledAddAutomationButton
|
||||
onClick={onAddAutomation}
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
import BoltIcon from '@mui/icons-material/Bolt';
|
||||
import { styled } from '@mui/material';
|
||||
import { formatDuration, intervalToDuration } from 'date-fns';
|
||||
|
||||
const StyledDisplayContainer = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const StyledIcon = styled(BoltIcon)(({ theme }) => ({
|
||||
color: theme.palette.common.white,
|
||||
fontSize: 18,
|
||||
flexShrink: 0,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
borderRadius: '50%',
|
||||
padding: theme.spacing(0.25),
|
||||
}));
|
||||
|
||||
const StyledText = styled('span')(({ theme }) => ({
|
||||
color: theme.palette.text.primary,
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
}));
|
||||
|
||||
interface IMilestoneTransitionDisplayProps {
|
||||
intervalMinutes: number;
|
||||
}
|
||||
|
||||
const formatInterval = (minutes: number): string => {
|
||||
if (minutes === 0) return '0 minutes';
|
||||
|
||||
const duration = intervalToDuration({
|
||||
start: 0,
|
||||
end: minutes * 60 * 1000,
|
||||
});
|
||||
|
||||
return formatDuration(duration, {
|
||||
format: ['days', 'hours', 'minutes'],
|
||||
delimiter: ', ',
|
||||
});
|
||||
};
|
||||
|
||||
export const MilestoneTransitionDisplay = ({
|
||||
intervalMinutes,
|
||||
}: IMilestoneTransitionDisplayProps) => {
|
||||
return (
|
||||
<StyledDisplayContainer>
|
||||
<StyledIcon />
|
||||
<StyledText>
|
||||
Proceed to the next milestone after{' '}
|
||||
{formatInterval(intervalMinutes)}
|
||||
</StyledText>
|
||||
</StyledDisplayContainer>
|
||||
);
|
||||
};
|
||||
@ -118,6 +118,7 @@ export const ReleasePlanMilestone = ({
|
||||
status={status}
|
||||
onAddAutomation={onAddAutomation}
|
||||
automationForm={automationForm}
|
||||
transitionCondition={milestone.transitionCondition}
|
||||
/>
|
||||
</StyledMilestoneContainer>
|
||||
);
|
||||
@ -174,6 +175,7 @@ export const ReleasePlanMilestone = ({
|
||||
status={status}
|
||||
onAddAutomation={onAddAutomation}
|
||||
automationForm={automationForm}
|
||||
transitionCondition={milestone.transitionCondition}
|
||||
/>
|
||||
</StyledMilestoneContainer>
|
||||
);
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { useReleasePlans } from '../useReleasePlans/useReleasePlans.js';
|
||||
import { useFeature } from '../useFeature/useFeature.js';
|
||||
import type { IFeatureEnvironment } from 'interfaces/featureToggle';
|
||||
|
||||
export const useFeatureReleasePlans = (
|
||||
projectId: string,
|
||||
featureId: string,
|
||||
environment?: IFeatureEnvironment | string,
|
||||
environmentName?: string,
|
||||
) => {
|
||||
const featureReleasePlansEnabled = useUiFlag('featureReleasePlans');
|
||||
const envName =
|
||||
typeof environment === 'string' ? environment : environment?.name;
|
||||
const {
|
||||
releasePlans: releasePlansFromHook,
|
||||
refetch: refetchReleasePlans,
|
||||
...rest
|
||||
} = useReleasePlans(projectId, featureId, envName);
|
||||
const { refetchFeature } = useFeature(projectId, featureId);
|
||||
} = useReleasePlans(projectId, featureId, environmentName);
|
||||
const { feature, refetchFeature } = useFeature(projectId, featureId);
|
||||
|
||||
const releasePlans = featureReleasePlansEnabled
|
||||
? typeof environment === 'object'
|
||||
? environment?.releasePlans || []
|
||||
: []
|
||||
: releasePlansFromHook;
|
||||
let releasePlans = releasePlansFromHook;
|
||||
|
||||
if (featureReleasePlansEnabled) {
|
||||
const matchingEnvironment = feature?.environments?.find(
|
||||
(env) => env.name === environmentName,
|
||||
);
|
||||
releasePlans = matchingEnvironment?.releasePlans || [];
|
||||
}
|
||||
|
||||
const refetch = featureReleasePlansEnabled
|
||||
? refetchFeature
|
||||
|
||||
@ -35,6 +35,9 @@ export interface IReleasePlanMilestone {
|
||||
name: string;
|
||||
releasePlanDefinitionId: string;
|
||||
strategies: IReleasePlanMilestoneStrategy[];
|
||||
transitionCondition?: {
|
||||
intervalMinutes: number;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export interface IReleasePlanMilestoneStrategy extends IFeatureStrategy {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user