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