mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-24 20:06:55 +01:00
refactor: simplify components
This commit is contained in:
parent
d9503de15c
commit
5869c7e04f
@ -340,15 +340,12 @@ const CreateMilestoneProgression: FC<{
|
||||
<MilestoneAutomationSection status={status}>
|
||||
<MilestoneTransitionDisplay
|
||||
intervalMinutes={milestone.transitionCondition.intervalMinutes}
|
||||
onSave={async (payload) => {
|
||||
onUpdateChangeRequestSubmit?.(milestone.id, payload);
|
||||
}}
|
||||
onDelete={() => onDeleteChangeRequestSubmit?.(milestone.id)}
|
||||
milestoneName={milestone.name}
|
||||
status={status}
|
||||
projectId={projectId}
|
||||
environment={environmentName}
|
||||
featureName={featureName}
|
||||
sourceMilestoneId={milestone.id}
|
||||
onUpdate={onUpdate || (() => {})}
|
||||
onChangeRequestSubmit={onUpdateChangeRequestSubmit}
|
||||
hasPendingUpdate={false}
|
||||
hasPendingDelete={false}
|
||||
/>
|
||||
@ -467,15 +464,12 @@ const UpdateMilestoneProgression: FC<{
|
||||
<MilestoneAutomationSection status={status}>
|
||||
<MilestoneTransitionDisplay
|
||||
intervalMinutes={milestone.transitionCondition.intervalMinutes}
|
||||
onSave={async (payload) => {
|
||||
onUpdateChangeRequestSubmit?.(milestone.id, payload);
|
||||
}}
|
||||
onDelete={() => onDeleteChangeRequestSubmit?.(milestone.id)}
|
||||
milestoneName={milestone.name}
|
||||
status={status}
|
||||
projectId={projectId}
|
||||
environment={environmentName}
|
||||
featureName={featureName}
|
||||
sourceMilestoneId={milestone.id}
|
||||
onUpdate={onUpdate || (() => {})}
|
||||
onChangeRequestSubmit={onUpdateChangeRequestSubmit}
|
||||
hasPendingUpdate={false}
|
||||
hasPendingDelete={false}
|
||||
/>
|
||||
@ -682,15 +676,12 @@ const ConsolidatedProgressionChanges: FC<{
|
||||
<MilestoneAutomationSection status={status}>
|
||||
<MilestoneTransitionDisplay
|
||||
intervalMinutes={displayMilestone.transitionCondition.intervalMinutes}
|
||||
onSave={async (payload) => {
|
||||
onUpdateChangeRequestSubmit?.(displayMilestone.id, payload);
|
||||
}}
|
||||
onDelete={() => onDeleteChangeRequestSubmit?.(displayMilestone.id)}
|
||||
milestoneName={displayMilestone.name}
|
||||
status={status}
|
||||
projectId={projectId}
|
||||
environment={environmentName}
|
||||
featureName={featureName}
|
||||
sourceMilestoneId={displayMilestone.id}
|
||||
onUpdate={onUpdate || (() => {})}
|
||||
onChangeRequestSubmit={onUpdateChangeRequestSubmit}
|
||||
hasPendingUpdate={false}
|
||||
hasPendingDelete={Boolean(deleteChange)}
|
||||
/>
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { Button, styled } from '@mui/material';
|
||||
import BoltIcon from '@mui/icons-material/Bolt';
|
||||
import { useMilestoneProgressionForm } from '../hooks/useMilestoneProgressionForm.js';
|
||||
import { useMilestoneProgressionsApi } from 'hooks/api/actions/useMilestoneProgressionsApi/useMilestoneProgressionsApi';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { MilestoneProgressionTimeInput } from './MilestoneProgressionTimeInput.tsx';
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import type { CreateMilestoneProgressionSchema } from 'openapi';
|
||||
|
||||
const StyledFormContainer = styled('div')(({ theme }) => ({
|
||||
@ -60,74 +55,27 @@ const StyledErrorMessage = styled('span')(({ theme }) => ({
|
||||
interface IMilestoneProgressionFormProps {
|
||||
sourceMilestoneId: string;
|
||||
targetMilestoneId: string;
|
||||
projectId: string;
|
||||
environment: string;
|
||||
featureName: string;
|
||||
onSave: () => void;
|
||||
onSubmit: (payload: CreateMilestoneProgressionSchema) => Promise<void>;
|
||||
onCancel: () => void;
|
||||
onChangeRequestSubmit?: (
|
||||
progressionPayload: CreateMilestoneProgressionSchema,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export const MilestoneProgressionForm = ({
|
||||
sourceMilestoneId,
|
||||
targetMilestoneId,
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
onSave,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
onChangeRequestSubmit,
|
||||
}: IMilestoneProgressionFormProps) => {
|
||||
const form = useMilestoneProgressionForm(
|
||||
sourceMilestoneId,
|
||||
targetMilestoneId,
|
||||
);
|
||||
const { createMilestoneProgression } = useMilestoneProgressionsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleChangeRequestSubmit = () => {
|
||||
const progressionPayload = form.getProgressionPayload();
|
||||
onChangeRequestSubmit?.(progressionPayload);
|
||||
};
|
||||
|
||||
const handleDirectSubmit = async () => {
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
await createMilestoneProgression(
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
form.getProgressionPayload(),
|
||||
);
|
||||
setToastData({
|
||||
type: 'success',
|
||||
text: 'Automation configured successfully',
|
||||
});
|
||||
onSave();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (isSubmitting) return;
|
||||
|
||||
if (!form.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isChangeRequestConfigured(environment) && onChangeRequestSubmit) {
|
||||
handleChangeRequestSubmit();
|
||||
} else {
|
||||
await handleDirectSubmit();
|
||||
}
|
||||
await onSubmit(form.getProgressionPayload());
|
||||
};
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent) => {
|
||||
@ -150,7 +98,6 @@ export const MilestoneProgressionForm = ({
|
||||
timeUnit={form.timeUnit}
|
||||
onTimeValueChange={form.handleTimeValueChange}
|
||||
onTimeUnitChange={form.handleTimeUnitChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</StyledTopRow>
|
||||
<StyledButtonGroup>
|
||||
@ -161,7 +108,6 @@ export const MilestoneProgressionForm = ({
|
||||
variant='outlined'
|
||||
onClick={onCancel}
|
||||
size='small'
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
@ -170,9 +116,8 @@ export const MilestoneProgressionForm = ({
|
||||
color='primary'
|
||||
onClick={handleSubmit}
|
||||
size='small'
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? 'Saving...' : 'Save'}
|
||||
Save
|
||||
</Button>
|
||||
</StyledButtonGroup>
|
||||
</StyledFormContainer>
|
||||
|
||||
@ -3,16 +3,11 @@ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
import { Button, IconButton, styled } from '@mui/material';
|
||||
import { Badge } from 'component/common/Badge/Badge';
|
||||
import type { MilestoneStatus } from './ReleasePlanMilestoneStatus.tsx';
|
||||
import { useState } from 'react';
|
||||
import { useMilestoneProgressionsApi } from 'hooks/api/actions/useMilestoneProgressionsApi/useMilestoneProgressionsApi';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { MilestoneProgressionTimeInput } from '../MilestoneProgressionForm/MilestoneProgressionTimeInput.tsx';
|
||||
import {
|
||||
useMilestoneProgressionForm,
|
||||
getTimeValueAndUnitFromMinutes,
|
||||
} from '../hooks/useMilestoneProgressionForm.js';
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import type { UpdateMilestoneProgressionSchema } from 'openapi';
|
||||
|
||||
const StyledDisplayContainer = styled('div')(({ theme }) => ({
|
||||
@ -62,50 +57,32 @@ const StyledButtonGroup = styled('div')(({ theme }) => ({
|
||||
|
||||
interface IMilestoneTransitionDisplayProps {
|
||||
intervalMinutes: number;
|
||||
onSave: (payload: UpdateMilestoneProgressionSchema) => Promise<void>;
|
||||
onDelete: () => void;
|
||||
milestoneName: string;
|
||||
status?: MilestoneStatus;
|
||||
projectId: string;
|
||||
environment: string;
|
||||
featureName: string;
|
||||
sourceMilestoneId: string;
|
||||
onUpdate: () => void;
|
||||
onChangeRequestSubmit?: (
|
||||
sourceMilestoneId: string,
|
||||
payload: UpdateMilestoneProgressionSchema,
|
||||
) => void;
|
||||
hasPendingUpdate?: boolean;
|
||||
hasPendingDelete?: boolean;
|
||||
}
|
||||
|
||||
export const MilestoneTransitionDisplay = ({
|
||||
intervalMinutes,
|
||||
onSave,
|
||||
onDelete,
|
||||
milestoneName,
|
||||
status,
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
sourceMilestoneId,
|
||||
onUpdate,
|
||||
onChangeRequestSubmit,
|
||||
hasPendingUpdate = false,
|
||||
hasPendingDelete = false,
|
||||
}: IMilestoneTransitionDisplayProps) => {
|
||||
const { updateMilestoneProgression } = useMilestoneProgressionsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||
|
||||
const initial = getTimeValueAndUnitFromMinutes(intervalMinutes);
|
||||
const form = useMilestoneProgressionForm(
|
||||
sourceMilestoneId,
|
||||
sourceMilestoneId, // We don't need targetMilestone for edit, just reuse source
|
||||
'', // sourceMilestoneId not needed for display
|
||||
'', // targetMilestoneId not needed for display
|
||||
{
|
||||
timeValue: initial.value,
|
||||
timeUnit: initial.unit,
|
||||
},
|
||||
);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const currentIntervalMinutes = form.getIntervalMinutes();
|
||||
const hasChanged = currentIntervalMinutes !== intervalMinutes;
|
||||
@ -113,7 +90,7 @@ export const MilestoneTransitionDisplay = ({
|
||||
const showDraftBadge = hasPendingUpdate || hasPendingDelete;
|
||||
|
||||
const handleSave = async () => {
|
||||
if (isSubmitting || !hasChanged) return;
|
||||
if (!hasChanged) return;
|
||||
|
||||
const payload: UpdateMilestoneProgressionSchema = {
|
||||
transitionCondition: {
|
||||
@ -121,32 +98,9 @@ export const MilestoneTransitionDisplay = ({
|
||||
},
|
||||
};
|
||||
|
||||
if (isChangeRequestConfigured(environment) && onChangeRequestSubmit) {
|
||||
onChangeRequestSubmit(sourceMilestoneId, payload);
|
||||
// Reset the form after submitting to change request
|
||||
handleReset();
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
await updateMilestoneProgression(
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
sourceMilestoneId,
|
||||
payload,
|
||||
);
|
||||
setToastData({
|
||||
type: 'success',
|
||||
text: 'Automation updated successfully',
|
||||
});
|
||||
onUpdate();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
await onSave(payload);
|
||||
// Reset the form after save
|
||||
handleReset();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
@ -177,7 +131,6 @@ export const MilestoneTransitionDisplay = ({
|
||||
timeUnit={form.timeUnit}
|
||||
onTimeValueChange={form.handleTimeValueChange}
|
||||
onTimeUnitChange={form.handleTimeUnitChange}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</StyledContentGroup>
|
||||
<StyledButtonGroup>
|
||||
@ -187,9 +140,8 @@ export const MilestoneTransitionDisplay = ({
|
||||
color='primary'
|
||||
onClick={handleSave}
|
||||
size='small'
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? 'Saving...' : 'Save'}
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
{showDraftBadge && (
|
||||
@ -202,7 +154,6 @@ export const MilestoneTransitionDisplay = ({
|
||||
size='small'
|
||||
aria-label={`Delete automation for ${milestoneName}`}
|
||||
sx={{ padding: 0.5 }}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<DeleteOutlineIcon fontSize='small' />
|
||||
</IconButton>
|
||||
|
||||
@ -12,6 +12,10 @@ import { MilestoneTransitionDisplay } from '../ReleasePlanMilestone/MilestoneTra
|
||||
import { ReleasePlanMilestone } from '../ReleasePlanMilestone/ReleasePlanMilestone.tsx';
|
||||
import type { MilestoneStatus } from '../ReleasePlanMilestone/ReleasePlanMilestoneStatus.tsx';
|
||||
import { MilestoneProgressionForm } from '../MilestoneProgressionForm/MilestoneProgressionForm.tsx';
|
||||
import { useMilestoneProgressionsApi } from 'hooks/api/actions/useMilestoneProgressionsApi/useMilestoneProgressionsApi';
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
|
||||
const StyledConnection = styled('div', {
|
||||
shouldForwardProp: (prop) => prop !== 'isCompleted',
|
||||
@ -124,12 +128,71 @@ export const ReleasePlanMilestoneItem = ({
|
||||
featureName,
|
||||
onUpdate,
|
||||
}: IReleasePlanMilestoneItemProps) => {
|
||||
const { createMilestoneProgression, updateMilestoneProgression } =
|
||||
useMilestoneProgressionsApi();
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
const isNotLastMilestone = index < milestones.length - 1;
|
||||
const isProgressionFormOpen = progressionFormOpenIndex === index;
|
||||
const nextMilestoneId = milestones[index + 1]?.id || '';
|
||||
const handleOpenProgressionForm = () => onSetProgressionFormOpenIndex(index);
|
||||
const handleCloseProgressionForm = () => onSetProgressionFormOpenIndex(null);
|
||||
|
||||
// Unified handler for creating progression
|
||||
const handleCreateProgression = async (
|
||||
payload: CreateMilestoneProgressionSchema,
|
||||
) => {
|
||||
if (isChangeRequestConfigured(environment)) {
|
||||
onProgressionChangeRequestSubmit(payload);
|
||||
handleCloseProgressionForm();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await createMilestoneProgression(
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
payload,
|
||||
);
|
||||
setToastData({
|
||||
type: 'success',
|
||||
text: 'Automation configured successfully',
|
||||
});
|
||||
await onProgressionSave();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
// Unified handler for updating progression
|
||||
const handleUpdateProgression = async (
|
||||
payload: UpdateMilestoneProgressionSchema,
|
||||
) => {
|
||||
if (isChangeRequestConfigured(environment)) {
|
||||
onUpdateProgressionChangeRequestSubmit(milestone.id, payload);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await updateMilestoneProgression(
|
||||
projectId,
|
||||
environment,
|
||||
featureName,
|
||||
milestone.id,
|
||||
payload,
|
||||
);
|
||||
setToastData({
|
||||
type: 'success',
|
||||
text: 'Automation updated successfully',
|
||||
});
|
||||
await onUpdate();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
const status: MilestoneStatus =
|
||||
milestone.id === activeMilestoneId
|
||||
? environmentIsDisabled
|
||||
@ -168,27 +231,16 @@ export const ReleasePlanMilestoneItem = ({
|
||||
<MilestoneProgressionForm
|
||||
sourceMilestoneId={milestone.id}
|
||||
targetMilestoneId={nextMilestoneId}
|
||||
projectId={projectId}
|
||||
environment={environment}
|
||||
featureName={featureName}
|
||||
onSave={onProgressionSave}
|
||||
onSubmit={handleCreateProgression}
|
||||
onCancel={handleCloseProgressionForm}
|
||||
onChangeRequestSubmit={(payload) =>
|
||||
onProgressionChangeRequestSubmit(payload)
|
||||
}
|
||||
/>
|
||||
) : effectiveTransitionCondition ? (
|
||||
<MilestoneTransitionDisplay
|
||||
intervalMinutes={effectiveTransitionCondition.intervalMinutes}
|
||||
onSave={handleUpdateProgression}
|
||||
onDelete={() => onDeleteProgression(milestone)}
|
||||
milestoneName={milestone.name}
|
||||
status={status}
|
||||
projectId={projectId}
|
||||
environment={environment}
|
||||
featureName={featureName}
|
||||
sourceMilestoneId={milestone.id}
|
||||
onUpdate={onUpdate}
|
||||
onChangeRequestSubmit={onUpdateProgressionChangeRequestSubmit}
|
||||
hasPendingUpdate={hasPendingUpdate}
|
||||
hasPendingDelete={hasPendingDelete}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user