mirror of
https://github.com/Unleash/unleash.git
synced 2025-10-27 11:02:16 +01:00
refactor: better type safety
This commit is contained in:
parent
e1d21adc9f
commit
a3e4c1095d
@ -15,7 +15,10 @@ import {
|
||||
Deleted,
|
||||
} from './Change.styles.tsx';
|
||||
import type { ChangeMilestoneProgressionSchema } from 'openapi';
|
||||
import { MilestoneListRenderer } from './MilestoneListRenderer.tsx';
|
||||
import {
|
||||
ReadonlyMilestoneListRenderer,
|
||||
EditableMilestoneListRenderer,
|
||||
} from './MilestoneListRenderer.tsx';
|
||||
import { applyProgressionChanges } from './applyProgressionChanges.js';
|
||||
import { EventDiff } from 'component/events/EventDiff/EventDiff';
|
||||
|
||||
@ -72,11 +75,11 @@ export const ConsolidatedProgressionChanges: FC<{
|
||||
feature: IChangeRequestFeature;
|
||||
currentReleasePlan?: IReleasePlan;
|
||||
changeRequestState: ChangeRequestState;
|
||||
onUpdateChangeRequestSubmit?: (
|
||||
onUpdateChangeRequestSubmit: (
|
||||
sourceMilestoneId: string,
|
||||
payload: ChangeMilestoneProgressionSchema,
|
||||
) => Promise<void>;
|
||||
onDeleteChangeRequestSubmit?: (sourceMilestoneId: string) => Promise<void>;
|
||||
onDeleteChangeRequestSubmit: (sourceMilestoneId: string) => Promise<void>;
|
||||
}> = ({
|
||||
feature,
|
||||
currentReleasePlan,
|
||||
@ -113,6 +116,9 @@ export const ConsolidatedProgressionChanges: FC<{
|
||||
basePlan,
|
||||
);
|
||||
|
||||
const readonly =
|
||||
changeRequestState === 'Applied' || changeRequestState === 'Cancelled';
|
||||
|
||||
return (
|
||||
<StyledTabs>
|
||||
<ChangeItemWrapper>
|
||||
@ -137,16 +143,25 @@ export const ConsolidatedProgressionChanges: FC<{
|
||||
</div>
|
||||
</ChangeItemWrapper>
|
||||
<TabPanel>
|
||||
<MilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
changeRequestState={changeRequestState}
|
||||
milestonesWithAutomation={milestonesWithAutomation}
|
||||
milestonesWithDeletedAutomation={
|
||||
milestonesWithDeletedAutomation
|
||||
}
|
||||
onUpdateAutomation={onUpdateChangeRequestSubmit}
|
||||
onDeleteAutomation={onDeleteChangeRequestSubmit}
|
||||
/>
|
||||
{readonly ? (
|
||||
<ReadonlyMilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
milestonesWithAutomation={milestonesWithAutomation}
|
||||
milestonesWithDeletedAutomation={
|
||||
milestonesWithDeletedAutomation
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<EditableMilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
milestonesWithAutomation={milestonesWithAutomation}
|
||||
milestonesWithDeletedAutomation={
|
||||
milestonesWithDeletedAutomation
|
||||
}
|
||||
onUpdateAutomation={onUpdateChangeRequestSubmit}
|
||||
onDeleteAutomation={onDeleteChangeRequestSubmit}
|
||||
/>
|
||||
)}
|
||||
</TabPanel>
|
||||
<TabPanel variant='diff'>
|
||||
<EventDiff
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { styled } from '@mui/material';
|
||||
import type { IReleasePlan } from 'interfaces/releasePlans';
|
||||
import type { ChangeMilestoneProgressionSchema } from 'openapi';
|
||||
import type { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
|
||||
import { ReleasePlanMilestone } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/ReleasePlanMilestone';
|
||||
import { MilestoneAutomationSection } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneAutomationSection.tsx';
|
||||
import { MilestoneTransitionDisplay } from 'component/feature/FeatureView/FeatureOverview/ReleasePlan/ReleasePlanMilestone/MilestoneTransitionDisplay.tsx';
|
||||
@ -15,29 +14,26 @@ const StyledConnection = styled('div')(({ theme }) => ({
|
||||
marginLeft: theme.spacing(3.25),
|
||||
}));
|
||||
|
||||
interface MilestoneListRendererProps {
|
||||
interface MilestoneListRendererCoreProps {
|
||||
plan: IReleasePlan;
|
||||
changeRequestState: ChangeRequestState;
|
||||
milestonesWithAutomation?: Set<string>;
|
||||
milestonesWithDeletedAutomation?: Set<string>;
|
||||
onUpdateAutomation?: (
|
||||
readonly: boolean;
|
||||
milestonesWithAutomation: Set<string>;
|
||||
milestonesWithDeletedAutomation: Set<string>;
|
||||
onUpdateAutomation: (
|
||||
sourceMilestoneId: string,
|
||||
payload: ChangeMilestoneProgressionSchema,
|
||||
) => Promise<void>;
|
||||
onDeleteAutomation?: (sourceMilestoneId: string) => void;
|
||||
onDeleteAutomation: (sourceMilestoneId: string) => void;
|
||||
}
|
||||
|
||||
export const MilestoneListRenderer = ({
|
||||
const MilestoneListRendererCore = ({
|
||||
plan,
|
||||
changeRequestState,
|
||||
milestonesWithAutomation = new Set(),
|
||||
milestonesWithDeletedAutomation = new Set(),
|
||||
readonly,
|
||||
milestonesWithAutomation,
|
||||
milestonesWithDeletedAutomation,
|
||||
onUpdateAutomation,
|
||||
onDeleteAutomation,
|
||||
}: MilestoneListRendererProps) => {
|
||||
// TODO: Split into read and write model at the type level to avoid having optional handlers
|
||||
const readonly =
|
||||
changeRequestState === 'Applied' || changeRequestState === 'Cancelled';
|
||||
}: MilestoneListRendererCoreProps) => {
|
||||
const status: MilestoneStatus = 'not-started';
|
||||
|
||||
return (
|
||||
@ -70,14 +66,14 @@ export const MilestoneListRenderer = ({
|
||||
}
|
||||
targetMilestoneId={nextMilestoneId}
|
||||
onSave={async (payload) => {
|
||||
await onUpdateAutomation?.(
|
||||
await onUpdateAutomation(
|
||||
milestone.id,
|
||||
payload,
|
||||
);
|
||||
return { shouldReset: true };
|
||||
}}
|
||||
onDelete={() =>
|
||||
onDeleteAutomation?.(milestone.id)
|
||||
onDeleteAutomation(milestone.id)
|
||||
}
|
||||
milestoneName={milestone.name}
|
||||
status={status}
|
||||
@ -102,3 +98,56 @@ export const MilestoneListRenderer = ({
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface ReadonlyMilestoneListRendererProps {
|
||||
plan: IReleasePlan;
|
||||
milestonesWithAutomation?: Set<string>;
|
||||
milestonesWithDeletedAutomation?: Set<string>;
|
||||
}
|
||||
|
||||
export const ReadonlyMilestoneListRenderer = ({
|
||||
plan,
|
||||
milestonesWithAutomation = new Set(),
|
||||
milestonesWithDeletedAutomation = new Set(),
|
||||
}: ReadonlyMilestoneListRendererProps) => {
|
||||
return (
|
||||
<MilestoneListRendererCore
|
||||
plan={plan}
|
||||
readonly={true}
|
||||
milestonesWithAutomation={milestonesWithAutomation}
|
||||
milestonesWithDeletedAutomation={milestonesWithDeletedAutomation}
|
||||
onUpdateAutomation={async () => {}}
|
||||
onDeleteAutomation={() => {}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface EditableMilestoneListRendererProps {
|
||||
plan: IReleasePlan;
|
||||
milestonesWithAutomation?: Set<string>;
|
||||
milestonesWithDeletedAutomation?: Set<string>;
|
||||
onUpdateAutomation: (
|
||||
sourceMilestoneId: string,
|
||||
payload: ChangeMilestoneProgressionSchema,
|
||||
) => Promise<void>;
|
||||
onDeleteAutomation: (sourceMilestoneId: string) => void;
|
||||
}
|
||||
|
||||
export const EditableMilestoneListRenderer = ({
|
||||
plan,
|
||||
milestonesWithAutomation = new Set(),
|
||||
milestonesWithDeletedAutomation = new Set(),
|
||||
onUpdateAutomation,
|
||||
onDeleteAutomation,
|
||||
}: EditableMilestoneListRendererProps) => {
|
||||
return (
|
||||
<MilestoneListRendererCore
|
||||
plan={plan}
|
||||
readonly={false}
|
||||
milestonesWithAutomation={milestonesWithAutomation}
|
||||
milestonesWithDeletedAutomation={milestonesWithDeletedAutomation}
|
||||
onUpdateAutomation={onUpdateAutomation}
|
||||
onDeleteAutomation={onDeleteAutomation}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -10,7 +10,10 @@ import { EventDiff } from 'component/events/EventDiff/EventDiff';
|
||||
import { Tab, TabList, TabPanel, Tabs } from './ChangeTabComponents.tsx';
|
||||
import { Action, ChangeItemInfo, ChangeItemWrapper } from './Change.styles.tsx';
|
||||
import { styled } from '@mui/material';
|
||||
import { MilestoneListRenderer } from './MilestoneListRenderer.tsx';
|
||||
import {
|
||||
ReadonlyMilestoneListRenderer,
|
||||
EditableMilestoneListRenderer,
|
||||
} from './MilestoneListRenderer.tsx';
|
||||
import { applyProgressionChanges } from './applyProgressionChanges.ts';
|
||||
|
||||
const StyledTabs = styled(Tabs)(({ theme }) => ({
|
||||
@ -24,11 +27,11 @@ interface ProgressionChangeProps {
|
||||
currentReleasePlan?: IReleasePlan;
|
||||
actions?: ReactNode;
|
||||
changeRequestState: ChangeRequestState;
|
||||
onUpdateChangeRequestSubmit?: (
|
||||
onUpdateChangeRequestSubmit: (
|
||||
sourceMilestoneId: string,
|
||||
payload: ChangeMilestoneProgressionSchema,
|
||||
) => Promise<void>;
|
||||
onDeleteChangeRequestSubmit?: (sourceMilestoneId: string) => void;
|
||||
onDeleteChangeRequestSubmit: (sourceMilestoneId: string) => void;
|
||||
}
|
||||
|
||||
export const ProgressionChange: FC<ProgressionChangeProps> = ({
|
||||
@ -62,6 +65,9 @@ export const ProgressionChange: FC<ProgressionChangeProps> = ({
|
||||
(milestone) => milestone.id === sourceId,
|
||||
);
|
||||
|
||||
const readonly =
|
||||
changeRequestState === 'Applied' || changeRequestState === 'Cancelled';
|
||||
|
||||
return (
|
||||
<StyledTabs>
|
||||
<ChangeItemWrapper>
|
||||
@ -80,15 +86,23 @@ export const ProgressionChange: FC<ProgressionChangeProps> = ({
|
||||
</div>
|
||||
</ChangeItemWrapper>
|
||||
<TabPanel>
|
||||
<MilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
changeRequestState={changeRequestState}
|
||||
milestonesWithAutomation={
|
||||
new Set([sourceId].filter(Boolean))
|
||||
}
|
||||
onUpdateAutomation={onUpdateChangeRequestSubmit}
|
||||
onDeleteAutomation={onDeleteChangeRequestSubmit}
|
||||
/>
|
||||
{readonly ? (
|
||||
<ReadonlyMilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
milestonesWithAutomation={
|
||||
new Set([sourceId].filter(Boolean))
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<EditableMilestoneListRenderer
|
||||
plan={modifiedPlan}
|
||||
milestonesWithAutomation={
|
||||
new Set([sourceId].filter(Boolean))
|
||||
}
|
||||
onUpdateAutomation={onUpdateChangeRequestSubmit}
|
||||
onDeleteAutomation={onDeleteChangeRequestSubmit}
|
||||
/>
|
||||
)}
|
||||
</TabPanel>
|
||||
<TabPanel variant='diff'>
|
||||
<EventDiff
|
||||
|
||||
@ -8,7 +8,7 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { calculateMilestoneStatus } from './milestoneStatusUtils.js';
|
||||
import { usePendingProgressionChanges } from './usePendingProgressionChanges.js';
|
||||
import { getPendingProgressionData } from './pendingProgressionChanges.js';
|
||||
import { MilestoneAutomation } from './MilestoneAutomation.tsx';
|
||||
|
||||
const StyledConnection = styled('div', {
|
||||
@ -130,7 +130,7 @@ export const ReleasePlanMilestoneItem = ({
|
||||
);
|
||||
|
||||
const { pendingProgressionChange, effectiveTransitionCondition } =
|
||||
usePendingProgressionChanges(milestone, getPendingProgressionChange);
|
||||
getPendingProgressionData(milestone, getPendingProgressionChange);
|
||||
|
||||
const shouldShowAutomation =
|
||||
isNotLastMilestone && milestoneProgressionsEnabled;
|
||||
|
||||
@ -9,7 +9,7 @@ interface PendingProgressionChangeResult {
|
||||
effectiveTransitionCondition: IReleasePlanMilestone['transitionCondition'];
|
||||
}
|
||||
|
||||
export const usePendingProgressionChanges = (
|
||||
export const getPendingProgressionData = (
|
||||
milestone: IReleasePlanMilestone,
|
||||
getPendingProgressionChange: IReleasePlanMilestoneItemProps['getPendingProgressionChange'],
|
||||
): PendingProgressionChangeResult => {
|
||||
Loading…
Reference in New Issue
Block a user