Skip to content

Commit a13f089

Browse files
committed
feat: add reloadWorkflowStatus prop to BulkBuildImageModal and update related components
1 parent dfffa8f commit a13f089

File tree

4 files changed

+146
-117
lines changed

4 files changed

+146
-117
lines changed

src/components/ApplicationGroup/Details/TriggerView/EnvTriggerView.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,7 @@ const EnvTriggerView = ({ filteredAppIds, isVirtualEnv }: AppGroupDetailDefaultT
11511151
workflows={filteredWorkflows}
11521152
reloadWorkflows={getWorkflowsData}
11531153
filteredCIPipelineMap={filteredCIPipelines}
1154+
reloadWorkflowStatus={getWorkflowStatusData}
11541155
/>
11551156
)
11561157
}

src/components/app/details/triggerView/BuildImageModal/BulkBuildImageModal.tsx

Lines changed: 33 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {
44
API_STATUS_CODES,
55
ApiQueuingWithBatch,
66
Button,
7-
CIMaterialType,
8-
CommonNodeAttr,
97
ComponentSizeType,
108
DocLink,
119
Drawer,
@@ -17,7 +15,6 @@ import {
1715
PromiseAllStatusType,
1816
RuntimePluginVariables,
1917
showError,
20-
SourceTypeMap,
2118
stopPropagation,
2219
stringComparatorBySortOrder,
2320
ToastManager,
@@ -44,141 +41,58 @@ import { importComponentFromFELibrary } from '@Components/common'
4441
import { SOURCE_NOT_CONFIGURED } from '@Config/constants'
4542

4643
import { getModuleConfigured } from '../../appDetails/appDetails.service'
47-
import { CI_MATERIAL_EMPTY_STATE_MESSAGING, IGNORE_CACHE_INFO } from '../Constants'
44+
import { IGNORE_CACHE_INFO } from '../Constants'
4845
import BuildImageHeader from './BuildImageHeader'
4946
import GitInfoMaterial from './GitInfoMaterial'
5047
import { getCIMaterials, triggerBuild } from './service'
5148
import { BulkBuildImageModalProps, GitInfoMaterialProps } from './types'
52-
import { getCanNodeHaveMaterial, getIsRegexBranchNotAvailable, getTriggerBuildPayload } from './utils'
49+
import {
50+
getBulkCIDataPromiseGetterList,
51+
getBulkCIErrorMessage,
52+
getBulkCIWarningMessage,
53+
getCanNodeHaveMaterial,
54+
getTriggerBuildPayload,
55+
} from './utils'
5356

54-
const getRuntimeParams = importComponentFromFELibrary('getRuntimeParams', null, 'function')
5557
const validateRuntimeParameters = importComponentFromFELibrary(
5658
'validateRuntimeParameters',
5759
() => ({ isValid: true, cellError: {} }),
5860
'function',
5961
)
6062

6163
const BulkBuildImageModal = ({
62-
handleClose,
64+
handleClose: handleCloseProp,
6365
workflows,
6466
reloadWorkflows,
6567
filteredCIPipelineMap,
68+
reloadWorkflowStatus,
6669
}: BulkBuildImageModalProps) => {
6770
const [selectedAppIdState, setSelectedAppIdState] = useState<number | null>(null)
6871
const [showWebhookModal, setShowWebhookModal] = useState(false)
6972
const [isBuildTriggerLoading, setIsBuildTriggerLoading] = useState(false)
7073
const [responseList, setResponseList] = useState<ResponseRowType[]>([])
7174

72-
const [blobStorageConfigurationLoading, blobStorageConfiguration] = useAsync(
73-
() => getModuleConfigured(ModuleNameMap.BLOB_STORAGE),
74-
[],
75+
const [blobStorageConfigurationLoading, blobStorageConfiguration] = useAsync(() =>
76+
getModuleConfigured(ModuleNameMap.BLOB_STORAGE),
7577
)
7678

7779
const blobStorageNotConfigured = !blobStorageConfigurationLoading && !blobStorageConfiguration?.result?.enabled
7880

79-
const getWarningMessage = (ciNode: CommonNodeAttr): string => {
80-
if (ciNode.isLinkedCD) {
81-
return 'Uses another environment as image source'
82-
}
83-
84-
if (ciNode.isLinkedCI) {
85-
return 'Has linked build pipeline'
86-
}
87-
88-
if (ciNode.type === WorkflowNodeType.WEBHOOK) {
89-
return 'Has webhook build pipeline'
90-
}
91-
92-
return ''
93-
}
94-
95-
const getErrorMessage = (
96-
_appId: number,
97-
_ciNode: CommonNodeAttr,
98-
filteredCIPipelines: BulkCIDetailType['filteredCIPipelines'],
99-
materialList: CIMaterialType[],
100-
): string => {
101-
const selectedCIPipeline = filteredCIPipelines?.find((_ci) => _ci.id === +_ciNode.id)
102-
103-
if (_ciNode.inputMaterialList?.length > 0) {
104-
if (getIsRegexBranchNotAvailable(selectedCIPipeline, materialList)) {
105-
return 'Primary branch is not set'
106-
}
107-
if (selectedCIPipeline?.ciMaterial) {
108-
const invalidInputMaterial = _ciNode.inputMaterialList.find(
109-
(_mat) =>
110-
_mat.isBranchError ||
111-
_mat.isRepoError ||
112-
_mat.isDockerFileError ||
113-
_mat.isMaterialSelectionError ||
114-
(_mat.type === SourceTypeMap.WEBHOOK && _mat.history.length === 0),
115-
)
116-
117-
if (invalidInputMaterial) {
118-
if (invalidInputMaterial.isRepoError) {
119-
return invalidInputMaterial.repoErrorMsg
120-
}
121-
if (invalidInputMaterial.isDockerFileError) {
122-
return invalidInputMaterial.dockerFileErrorMsg
123-
}
124-
if (invalidInputMaterial.isBranchError) {
125-
return invalidInputMaterial.branchErrorMsg
126-
}
127-
if (invalidInputMaterial.isMaterialSelectionError) {
128-
return invalidInputMaterial.materialSelectionErrorMsg
129-
}
130-
return CI_MATERIAL_EMPTY_STATE_MESSAGING.NoMaterialFound
131-
}
132-
}
133-
}
134-
return ''
135-
}
136-
13781
const initialDataAbortControllerRef = useRef<AbortController>(new AbortController())
13882

83+
const selectedWorkflows = workflows.filter(
84+
(workflow) =>
85+
workflow.isSelected &&
86+
workflow.nodes.some((node) => node.type === WorkflowNodeType.CI || node.type === WorkflowNodeType.WEBHOOK),
87+
)
88+
13989
// Returns map of appId to BulkCIDetailType
14090
const getInitialAppList = async (appId?: number): Promise<Record<number, BulkCIDetailType>> => {
141-
const validWorkflows = workflows.filter(
142-
(workflow) =>
143-
workflow.isSelected &&
144-
(!appId || workflow.appId === appId) &&
145-
workflow.nodes.some(
146-
(node) => node.type === WorkflowNodeType.CI || node.type === WorkflowNodeType.WEBHOOK,
147-
),
148-
)
149-
150-
const { ciMaterialPromiseList, runtimeParamsPromiseList } = validWorkflows.reduce(
151-
(acc, workflow) => {
152-
const currentNode = workflow.nodes.find(
153-
(node) => node.type === WorkflowNodeType.CI || node.type === WorkflowNodeType.WEBHOOK,
154-
)
155-
156-
if (!getCanNodeHaveMaterial(currentNode)) {
157-
acc.ciMaterialPromiseList.push(() => [])
158-
acc.runtimeParamsPromiseList.push(() => [])
159-
160-
return acc
161-
}
91+
const validWorkflows = selectedWorkflows.filter((workflow) => !appId || workflow.appId === appId)
16292

163-
acc.ciMaterialPromiseList.push(() =>
164-
getCIMaterials({
165-
ciNodeId: currentNode.id,
166-
abortControllerRef: initialDataAbortControllerRef,
167-
isCINodePresent: !!currentNode,
168-
selectedWorkflow: workflow,
169-
}),
170-
)
171-
172-
// TODO: Check runtime param page should show error state in case of its error
173-
if (getRuntimeParams) {
174-
acc.runtimeParamsPromiseList.push(() => getRuntimeParams(currentNode.id))
175-
} else {
176-
acc.runtimeParamsPromiseList.push(() => [])
177-
}
178-
179-
return acc
180-
},
181-
{ ciMaterialPromiseList: [], runtimeParamsPromiseList: [] },
93+
const { ciMaterialPromiseList, runtimeParamsPromiseList } = getBulkCIDataPromiseGetterList(
94+
validWorkflows,
95+
initialDataAbortControllerRef,
18296
)
18397

18498
if (ciMaterialPromiseList.length === 0) {
@@ -187,7 +101,6 @@ const BulkBuildImageModal = ({
187101

188102
const ciMaterialList =
189103
await ApiQueuingWithBatch<Awaited<ReturnType<typeof getCIMaterials>>>(ciMaterialPromiseList)
190-
// TODO: Add show regex modal logic later
191104
const runtimeParamsList = await ApiQueuingWithBatch<RuntimePluginVariables[]>(runtimeParamsPromiseList)
192105

193106
return validWorkflows.reduce<Record<number, BulkCIDetailType>>((acc, workflow, index) => {
@@ -225,8 +138,8 @@ const BulkBuildImageModal = ({
225138
isValid: runtimeParamsList[index].status !== PromiseAllStatusType.REJECTED,
226139
cellError: {},
227140
},
228-
warningMessage: getWarningMessage(node),
229-
errorMessage: getErrorMessage(
141+
warningMessage: getBulkCIWarningMessage(node),
142+
errorMessage: getBulkCIErrorMessage(
230143
workflow.appId,
231144
node,
232145
filteredCIPipelineMap.get(String(workflow.appId)),
@@ -288,6 +201,13 @@ const BulkBuildImageModal = ({
288201
setShowWebhookModal(false)
289202
}
290203

204+
const handleClose = () => {
205+
if (responseList.length) {
206+
reloadWorkflowStatus()
207+
}
208+
handleCloseProp()
209+
}
210+
291211
const validateBulkRuntimeParams = (): boolean => {
292212
const currentAppList = structuredClone(sortedAppList)
293213
const updatedAppInfoMap = structuredClone(appInfoMap)
@@ -451,7 +371,6 @@ const BulkBuildImageModal = ({
451371
if (responseList.length) {
452372
return (
453373
<TriggerResponseModalFooter
454-
// TODO: Refetch workflows after triggering build
455374
closePopup={handleClose}
456375
responseList={responseList}
457376
isLoading={isBuildTriggerLoading}
@@ -551,8 +470,8 @@ const BulkBuildImageModal = ({
551470
const renderContent = () => {
552471
if (isLoadingAppInfoMap || isBuildTriggerLoading) {
553472
const message = isBuildTriggerLoading
554-
? BULK_CI_BUILD_STATUS(sortedAppList.length)
555-
: BULK_CI_MATERIAL_STATUS(sortedAppList.length)
473+
? BULK_CI_BUILD_STATUS(selectedWorkflows.length)
474+
: BULK_CI_MATERIAL_STATUS(selectedWorkflows.length)
556475

557476
return <GenericEmptyState {...message} SvgImage={MechanicalOperation} contentClassName="text-center" />
558477
}

src/components/app/details/triggerView/BuildImageModal/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export type GitInfoMaterialProps = Pick<BuildImageModalProps, 'appId' | 'isJobVi
7777
)
7878

7979
export interface BulkBuildImageModalProps
80-
extends Pick<BuildImageModalProps, 'handleClose' | 'workflows' | 'reloadWorkflows'> {
80+
extends Pick<BuildImageModalProps, 'handleClose' | 'workflows' | 'reloadWorkflows' | 'reloadWorkflowStatus'> {
8181
filteredCIPipelineMap: Map<string, TriggerViewState['filteredCIPipelines']>
8282
}
8383

src/components/app/details/triggerView/BuildImageModal/utils.ts

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1-
import { CIMaterialType, CommonNodeAttr, WorkflowNodeType } from '@devtron-labs/devtron-fe-common-lib'
1+
import {
2+
APIOptions,
3+
CIMaterialType,
4+
CommonNodeAttr,
5+
RuntimePluginVariables,
6+
SourceTypeMap,
7+
WorkflowNodeType,
8+
WorkflowType,
9+
} from '@devtron-labs/devtron-fe-common-lib'
210

11+
import { BulkCIDetailType } from '@Components/ApplicationGroup/AppGroup.types'
312
import { CIPipelineBuildType } from '@Components/ciPipeline/types'
413
import { importComponentFromFELibrary } from '@Components/common'
514
import { CI_CONFIGURED_GIT_MATERIAL_ERROR } from '@Config/constantMessaging'
615
import { DEFAULT_GIT_BRANCH_VALUE } from '@Config/constants'
716

17+
import { CI_MATERIAL_EMPTY_STATE_MESSAGING } from '../Constants'
818
import { BuildImageModalProps, CIPipelineMaterialDTO } from '../types'
19+
import { getCIMaterials } from './service'
920
import { GetTriggerBuildPayloadProps, TriggerBuildPayloadType } from './types'
1021

1122
const getRuntimeParamsPayload = importComponentFromFELibrary('getRuntimeParamsPayload', null, 'function')
23+
const getRuntimeParams = importComponentFromFELibrary('getRuntimeParams', null, 'function')
1224

1325
export const getIsRegexBranchNotAvailable = (
1426
selectedCIPipeline: BuildImageModalProps['filteredCIPipelines'][number],
@@ -41,7 +53,6 @@ export const getTriggerBuildPayload = ({
4153

4254
const history = material.history.filter((historyItem) => historyItem.isSelected)
4355
if (!history.length) {
44-
// FIXME: Will include/exclude impact this?
4556
history.push(material.history[0])
4657
}
4758

@@ -84,3 +95,101 @@ export const getTriggerBuildPayload = ({
8495

8596
export const getCanNodeHaveMaterial = (node: CommonNodeAttr): boolean =>
8697
!!node && node.type !== WorkflowNodeType.WEBHOOK && !node.isLinkedCD && !node.isLinkedCI
98+
99+
export const getBulkCIWarningMessage = (ciNode: CommonNodeAttr): string => {
100+
if (ciNode.isLinkedCD) {
101+
return 'Uses another environment as image source'
102+
}
103+
104+
if (ciNode.isLinkedCI) {
105+
return 'Has linked build pipeline'
106+
}
107+
108+
if (ciNode.type === WorkflowNodeType.WEBHOOK) {
109+
return 'Has webhook build pipeline'
110+
}
111+
112+
return ''
113+
}
114+
115+
export const getBulkCIErrorMessage = (
116+
_appId: number,
117+
_ciNode: CommonNodeAttr,
118+
filteredCIPipelines: BulkCIDetailType['filteredCIPipelines'],
119+
materialList: CIMaterialType[],
120+
): string => {
121+
const selectedCIPipeline = filteredCIPipelines?.find((_ci) => _ci.id === +_ciNode.id)
122+
123+
if (materialList?.length > 0) {
124+
if (getIsRegexBranchNotAvailable(selectedCIPipeline, materialList)) {
125+
return 'Primary branch is not set'
126+
}
127+
if (selectedCIPipeline?.ciMaterial) {
128+
const invalidInputMaterial = materialList.find(
129+
(_mat) =>
130+
_mat.isBranchError ||
131+
_mat.isRepoError ||
132+
_mat.isDockerFileError ||
133+
_mat.isMaterialSelectionError ||
134+
(_mat.type === SourceTypeMap.WEBHOOK && _mat.history.length === 0),
135+
)
136+
137+
if (invalidInputMaterial) {
138+
if (invalidInputMaterial.isRepoError) {
139+
return invalidInputMaterial.repoErrorMsg
140+
}
141+
if (invalidInputMaterial.isDockerFileError) {
142+
return invalidInputMaterial.dockerFileErrorMsg
143+
}
144+
if (invalidInputMaterial.isBranchError) {
145+
return invalidInputMaterial.branchErrorMsg
146+
}
147+
if (invalidInputMaterial.isMaterialSelectionError) {
148+
return invalidInputMaterial.materialSelectionErrorMsg
149+
}
150+
return CI_MATERIAL_EMPTY_STATE_MESSAGING.NoMaterialFound
151+
}
152+
}
153+
}
154+
return ''
155+
}
156+
157+
export const getBulkCIDataPromiseGetterList = (
158+
validWorkflows: WorkflowType[],
159+
initialDataAbortControllerRef: APIOptions['abortControllerRef'],
160+
): {
161+
ciMaterialPromiseList: (() => Promise<CIMaterialType[]>)[]
162+
runtimeParamsPromiseList: (() => Promise<RuntimePluginVariables[]>)[]
163+
} =>
164+
validWorkflows.reduce(
165+
(acc, workflow) => {
166+
const currentNode = workflow.nodes.find(
167+
(node) => node.type === WorkflowNodeType.CI || node.type === WorkflowNodeType.WEBHOOK,
168+
)
169+
170+
if (!getCanNodeHaveMaterial(currentNode)) {
171+
acc.ciMaterialPromiseList.push(() => [])
172+
acc.runtimeParamsPromiseList.push(() => [])
173+
174+
return acc
175+
}
176+
177+
acc.ciMaterialPromiseList.push(() =>
178+
getCIMaterials({
179+
ciNodeId: currentNode.id,
180+
abortControllerRef: initialDataAbortControllerRef,
181+
isCINodePresent: !!currentNode,
182+
selectedWorkflow: workflow,
183+
}),
184+
)
185+
186+
if (getRuntimeParams) {
187+
acc.runtimeParamsPromiseList.push(() => getRuntimeParams(currentNode.id))
188+
} else {
189+
acc.runtimeParamsPromiseList.push(() => [])
190+
}
191+
192+
return acc
193+
},
194+
{ ciMaterialPromiseList: [], runtimeParamsPromiseList: [] },
195+
)

0 commit comments

Comments
 (0)