Skip to content

Commit 01cf4db

Browse files
authored
Merge pull request #2727 from devtron-labs/feat/feasible-pipelines
feat: add util for getting workflows which can be triggered
2 parents 68da4c8 + 205f584 commit 01cf4db

File tree

8 files changed

+114
-63
lines changed

8 files changed

+114
-63
lines changed

.eslintignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ src/App.tsx
1010
src/Pages/GlobalConfigurations/Authorization/APITokens/__tests__/ApiTokens.test.tsx
1111
src/components/AppSelector/ChartSelector.tsx
1212
src/components/ApplicationGroup/AppGroup.service.ts
13-
src/components/ApplicationGroup/AppGroup.types.ts
1413
src/components/ApplicationGroup/AppGroup.utils.ts
1514
src/components/ApplicationGroup/AppGroupAppFilter.components.tsx
16-
src/components/ApplicationGroup/AppGroupAppFilter.tsx
1715
src/components/ApplicationGroup/AppGroupDetailsRoute.tsx
1816
src/components/ApplicationGroup/AppGroupRoute.tsx
1917
src/components/ApplicationGroup/Constants.ts

src/components/ApplicationGroup/AppGroup.types.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,39 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Dispatch, SetStateAction } from 'react'
18+
import { MultiValue } from 'react-select'
19+
1720
import {
1821
ACTION_STATE,
22+
AppInfoListType,
23+
ApprovalConfigDataType,
1924
CDModalTabType,
25+
CommonNodeAttr,
2026
DeploymentNodeType,
27+
DeploymentStrategyTypeWithDefault,
2128
FilterConditionsListType,
29+
GVKType,
2230
MODAL_TYPE,
31+
PipelineIdsVsDeploymentStrategyMap,
2332
ResponseType,
33+
RuntimePluginVariables,
34+
UseUrlFiltersReturnType,
2435
WorkflowNodeType,
2536
WorkflowType,
26-
AppInfoListType,
27-
GVKType,
28-
UseUrlFiltersReturnType,
29-
CommonNodeAttr,
30-
ApprovalConfigDataType,
31-
RuntimePluginVariables,
32-
PipelineIdsVsDeploymentStrategyMap,
3337
} from '@devtron-labs/devtron-fe-common-lib'
34-
import { CDMaterialProps, RuntimeParamsErrorState } from '../app/details/triggerView/types'
35-
import { EditDescRequest, NodeType, Nodes, OptionType } from '../app/types'
36-
import { MultiValue } from 'react-select'
37-
import { AppFilterTabs, BulkResponseStatus } from './Constants'
38-
import { WorkloadCheckType } from '../v2/appDetails/sourceInfo/scaleWorkloads/scaleWorkloadsModal.type'
38+
39+
import { TIME_STAMP_ORDER } from '@Components/app/details/triggerView/Constants'
40+
import { CDMaterialProps, RuntimeParamsErrorState, WebhookPayloadType } from '@Components/app/details/triggerView/types'
3941
import {
4042
AppConfigState,
4143
EnvConfigurationsNavProps,
4244
EnvConfigurationState,
4345
} from '@Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types'
44-
import { WebhookPayloadType } from '@Components/app/details/triggerView/types'
45-
import { TIME_STAMP_ORDER } from '@Components/app/details/triggerView/Constants'
46+
47+
import { EditDescRequest, Nodes, NodeType, OptionType } from '../app/types'
48+
import { WorkloadCheckType } from '../v2/appDetails/sourceInfo/scaleWorkloads/scaleWorkloadsModal.type'
49+
import { AppFilterTabs, BulkResponseStatus } from './Constants'
4650

4751
interface BulkTriggerAppDetailType {
4852
workFlowId: string
@@ -157,6 +161,9 @@ export interface BulkCDTriggerType extends BulkRuntimeParamsType {
157161
setLoading: React.Dispatch<React.SetStateAction<boolean>>
158162
isVirtualEnv?: boolean
159163
uniqueReleaseTags: string[]
164+
feasiblePipelineIds: Set<number>
165+
bulkDeploymentStrategy: DeploymentStrategyTypeWithDefault
166+
setBulkDeploymentStrategy: Dispatch<SetStateAction<DeploymentStrategyTypeWithDefault>>
160167
}
161168

162169
export interface ProcessWorkFlowStatusType {

src/components/ApplicationGroup/AppGroupAppFilter.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
*/
1616

1717
import { useEffect, useRef, useState } from 'react'
18-
import ReactSelect, { SelectInstance } from 'react-select'
1918
import ReactGA from 'react-ga4'
20-
import { useAppGroupAppFilterContext } from './AppGroupDetailsRoute'
21-
import { appGroupAppSelectorStyle } from './AppGroup.utils'
22-
import { AppGroupAppFilterContextType, FilterParentType } from './AppGroup.types'
23-
import { AppFilterTabs } from './Constants'
24-
import { MenuList, Option, ValueContainer } from './AppGroupAppFilter.components'
19+
import ReactSelect, { SelectInstance } from 'react-select'
20+
2521
import { OptionType, ReactSelectInputAction, useRegisterShortcut } from '@devtron-labs/devtron-fe-common-lib'
22+
2623
import { setAppGroupFilterInLocalStorage } from '@Components/common'
2724

28-
export default function AppGroupAppFilter() {
25+
import { AppGroupAppFilterContextType, FilterParentType } from './AppGroup.types'
26+
import { appGroupAppSelectorStyle } from './AppGroup.utils'
27+
import { MenuList, Option, ValueContainer } from './AppGroupAppFilter.components'
28+
import { useAppGroupAppFilterContext } from './AppGroupDetailsRoute'
29+
import { AppFilterTabs } from './Constants'
30+
31+
const AppGroupAppFilter = () => {
2932
const {
3033
resourceId,
3134
appListOptions,
@@ -171,3 +174,5 @@ export default function AppGroupAppFilter() {
171174
/>
172175
)
173176
}
177+
178+
export default AppGroupAppFilter

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ import { BulkCDDetailType, BulkCDTriggerType } from '../../AppGroup.types'
7474
import { BULK_CD_DEPLOYMENT_STATUS, BULK_CD_MATERIAL_STATUS, BULK_CD_MESSAGING, BUTTON_TITLE } from '../../Constants'
7575
import { BULK_ERROR_MESSAGES } from './constants'
7676
import TriggerResponseModalBody, { TriggerResponseModalFooter } from './TriggerResponseModal'
77-
import { getIsImageApprovedByDeployerSelected, getIsNonApprovedImageSelected, getSelectedAppListForBulkStrategy } from './utils'
77+
import {
78+
getIsImageApprovedByDeployerSelected,
79+
getIsNonApprovedImageSelected,
80+
getSelectedAppListForBulkStrategy,
81+
} from './utils'
7882

7983
const DeploymentWindowInfoBar = importComponentFromFELibrary('DeploymentWindowInfoBar')
8084
const BulkDeployResistanceTippy = importComponentFromFELibrary('BulkDeployResistanceTippy')
@@ -111,13 +115,16 @@ const BulkCDTrigger = ({
111115
updateBulkInputMaterial,
112116
// NOTE: Should trigger the bulk cd here only but since its also calling another parent function not refactoring right now
113117
onClickTriggerBulkCD,
118+
feasiblePipelineIds,
114119
responseList,
115120
isLoading,
116121
setLoading,
117122
isVirtualEnv,
118123
uniqueReleaseTags,
119124
runtimeParams,
120125
setRuntimeParams,
126+
bulkDeploymentStrategy,
127+
setBulkDeploymentStrategy,
121128
runtimeParamsErrorState,
122129
setRuntimeParamsErrorState,
123130
}: BulkCDTriggerType) => {
@@ -139,7 +146,6 @@ const BulkCDTrigger = ({
139146
const [showResistanceBox, setShowResistanceBox] = useState(false)
140147
const [currentSidebarTab, setCurrentSidebarTab] = useState<CDMaterialSidebarType>(CDMaterialSidebarType.IMAGE)
141148
const [skipHibernatedApps, setSkipHibernatedApps] = useState<boolean>(false)
142-
const [bulkDeploymentStrategy, setBulkDeploymentStrategy] = useState<DeploymentStrategyTypeWithDefault>('DEFAULT')
143149
const [showStrategyFeasibilityPage, setShowStrategyFeasibilityPage] = useState<boolean>(false)
144150
const [pipelineIdVsStrategyMap, setPipelineIdVsStrategyMap] = useState<PipelineIdsVsDeploymentStrategyMap>({})
145151

@@ -1002,7 +1008,7 @@ const BulkCDTrigger = ({
10021008
bulkDeploymentStrategy={bulkDeploymentStrategy}
10031009
pipelineIdVsStrategyMap={pipelineIdVsStrategyMap}
10041010
setPipelineIdVsStrategyMap={setPipelineIdVsStrategyMap}
1005-
appList={getSelectedAppListForBulkStrategy(appList)}
1011+
appList={getSelectedAppListForBulkStrategy(appList, feasiblePipelineIds)}
10061012
/>
10071013
) : (
10081014
<>

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

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
ComponentSizeType,
5858
API_STATUS_CODES,
5959
PipelineIdsVsDeploymentStrategyMap,
60+
DeploymentStrategyTypeWithDefault,
6061
} from '@devtron-labs/devtron-fe-common-lib'
6162
import Tippy from '@tippyjs/react'
6263
import { BUILD_STATUS, DEFAULT_GIT_BRANCH_VALUE, NO_COMMIT_SELECTED, URLS, ViewType } from '../../../../config'
@@ -129,6 +130,7 @@ import { RenderCDMaterialContentProps } from './types'
129130
import { WebhookReceivedPayloadModal } from '@Components/app/details/triggerView/WebhookReceivedPayloadModal'
130131
import { getExternalCIConfig } from '@Components/ciPipeline/Webhook/webhook.service'
131132
import { shouldRenderWebhookAddImageModal } from '@Components/app/details/triggerView/TriggerView.utils'
133+
import { getSelectedCDNode } from './utils'
132134

133135
const ApprovalMaterialModal = importComponentFromFELibrary('ApprovalMaterialModal')
134136
const getCIBlockState: (...props) => Promise<BlockedStateData> = importComponentFromFELibrary(
@@ -198,6 +200,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
198200
const [runtimeParamsErrorState, setRuntimeParamsErrorState] = useState<Record<string, RuntimeParamsErrorState>>({})
199201
const [isBulkTriggerLoading, setIsBulkTriggerLoading] = useState<boolean>(false)
200202
const [selectedWebhookNode, setSelectedWebhookNode] = useState<{ appId: number; id: number }>(null)
203+
const [bulkDeploymentStrategy, setBulkDeploymentStrategy] = useState<DeploymentStrategyTypeWithDefault>('DEFAULT')
201204

202205
const enableRoutePrompt = isBranchChangeLoading || isBulkTriggerLoading
203206
usePrompt({ shouldPrompt: enableRoutePrompt })
@@ -1437,6 +1440,26 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
14371440
return true
14381441
}
14391442

1443+
// Helper to get selected CD nodes
1444+
const getSelectedCDNodesWithArtifacts = (selectedWorkflows: WorkflowType[]): { node: CommonNodeAttr; wf: WorkflowType }[] =>
1445+
selectedWorkflows
1446+
.filter((wf) => wf.isSelected)
1447+
.map((wf) => {
1448+
const _cdNode = wf.nodes.find(
1449+
(node) => node.type === WorkflowNodeType.CD && node.environmentId === +envId,
1450+
)
1451+
if (!_cdNode) return null
1452+
1453+
const _selectedNode: CommonNodeAttr | undefined = getSelectedCDNode(bulkTriggerType, _cdNode)
1454+
1455+
const selectedArtifacts = _selectedNode?.[materialType]?.filter((artifact) => artifact.isSelected) ?? []
1456+
if (selectedArtifacts.length > 0) {
1457+
return { node: _selectedNode, wf }
1458+
}
1459+
return null
1460+
})
1461+
.filter(Boolean)
1462+
14401463
const onClickTriggerBulkCD = (
14411464
skipIfHibernated: boolean,
14421465
pipelineIdVsStrategyMap: PipelineIdsVsDeploymentStrategyMap,
@@ -1452,27 +1475,14 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
14521475
const nodeList: CommonNodeAttr[] = []
14531476
const triggeredAppList: { appId: number; envId?: number; appName: string }[] = []
14541477

1455-
for (const _wf of filteredWorkflows) {
1456-
if (_wf.isSelected && (!appsToRetry || appsToRetry[_wf.appId])) {
1457-
const _cdNode = _wf.nodes.find(
1458-
(node) => node.type === WorkflowNodeType.CD && node.environmentId === +envId,
1459-
)
1460-
let _selectedNode: CommonNodeAttr
1461-
if (bulkTriggerType === DeploymentNodeType.PRECD) {
1462-
_selectedNode = _cdNode.preNode
1463-
} else if (bulkTriggerType === DeploymentNodeType.CD) {
1464-
_selectedNode = _cdNode
1465-
} else if (bulkTriggerType === DeploymentNodeType.POSTCD) {
1466-
_selectedNode = _cdNode.postNode
1467-
}
1468-
1469-
if (_selectedNode?.[materialType]?.length) {
1470-
nodeList.push(_selectedNode)
1471-
_appIdMap.set(_selectedNode.id, _wf.appId.toString())
1472-
triggeredAppList.push({ appId: _wf.appId, appName: _wf.name, envId: _selectedNode.environmentId })
1473-
}
1474-
}
1475-
}
1478+
const eligibleNodes = getSelectedCDNodesWithArtifacts(
1479+
filteredWorkflows.filter((wf) => !appsToRetry || appsToRetry[wf.appId]),
1480+
)
1481+
eligibleNodes.forEach(({ node: eligibleNode, wf }) => {
1482+
nodeList.push(eligibleNode)
1483+
_appIdMap.set(eligibleNode.id, wf.appId.toString())
1484+
triggeredAppList.push({ appId: wf.appId, appName: wf.name, envId: eligibleNode.environmentId })
1485+
})
14761486

14771487
const _CDTriggerPromiseFunctionList = []
14781488
nodeList.forEach((node, index) => {
@@ -1484,9 +1494,11 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
14841494
ciArtifact = artifact
14851495
}
14861496
})
1487-
if (ciArtifact) {
1488-
const pipelineId = Number(node.id)
1489-
const strategy = pipelineIdVsStrategyMap[pipelineId]
1497+
const pipelineId = Number(node.id)
1498+
const strategy = pipelineIdVsStrategyMap[pipelineId]
1499+
1500+
// skip app if bulkDeploymentStrategy is not default and strategy is not configured for app
1501+
if (ciArtifact && (bulkDeploymentStrategy === 'DEFAULT' || !!strategy)) {
14901502
_CDTriggerPromiseFunctionList.push(() =>
14911503
triggerCDNode({
14921504
pipelineId,
@@ -1497,7 +1509,8 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
14971509
? { runtimeParamsPayload: getRuntimeParamsPayload(runtimeParams[currentAppId] ?? []) }
14981510
: {}),
14991511
skipIfHibernated,
1500-
...(strategy ? { strategy } : {}),
1512+
// strategy DEFAULT means custom chart
1513+
...(strategy && strategy !== 'DEFAULT' ? { strategy } : {}),
15011514
}),
15021515
)
15031516
} else {
@@ -2067,12 +2080,15 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
20672080

20682081
const { uniqueReleaseTags } = bulkCDDetailTypeResponse
20692082

2083+
const feasiblePipelineIds = new Set(getSelectedCDNodesWithArtifacts(filteredWorkflows).map(({ node }) => +node.id))
2084+
20702085
// Have to look for its each prop carefully
20712086
// No need to send uniqueReleaseTags will get those in BulkCDTrigger itself
20722087
return (
20732088
<BulkCDTrigger
20742089
stage={bulkTriggerType}
20752090
appList={_selectedAppWorkflowList}
2091+
feasiblePipelineIds={feasiblePipelineIds}
20762092
closePopup={hideBulkCDModal}
20772093
updateBulkInputMaterial={updateBulkCDInputMaterial}
20782094
onClickTriggerBulkCD={onClickTriggerBulkCD}
@@ -2085,7 +2101,9 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
20852101
setRuntimeParams={setRuntimeParams}
20862102
runtimeParamsErrorState={runtimeParamsErrorState}
20872103
setRuntimeParamsErrorState={setRuntimeParamsErrorState}
2088-
/>
2104+
bulkDeploymentStrategy={bulkDeploymentStrategy}
2105+
setBulkDeploymentStrategy={setBulkDeploymentStrategy}
2106+
/>
20892107
)
20902108
}
20912109

src/components/ApplicationGroup/Details/TriggerView/utils.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { CommonNodeAttr, DeploymentNodeType } from '@devtron-labs/devtron-fe-common-lib'
18+
1719
import { getIsMaterialApproved } from '@Components/app/details/triggerView/cdMaterials.utils'
1820

1921
import { BulkCDDetailType, BulkCIDetailType } from '../../AppGroup.types'
@@ -46,5 +48,20 @@ export const getIsImageApprovedByDeployerSelected = (appList: BulkCDDetailType[]
4648
)
4749
})
4850

49-
export const getSelectedAppListForBulkStrategy = (appList: BulkCDDetailType[]) =>
50-
appList.map((app) => ({ pipelineId: +app.cdPipelineId, appName: app.name }))
51+
export const getSelectedCDNode = (bulkTriggerType: DeploymentNodeType, _cdNode: CommonNodeAttr) => {
52+
if (bulkTriggerType === DeploymentNodeType.PRECD) {
53+
return _cdNode.preNode
54+
}
55+
if (bulkTriggerType === DeploymentNodeType.CD) {
56+
return _cdNode
57+
}
58+
if (bulkTriggerType === DeploymentNodeType.POSTCD) {
59+
return _cdNode.postNode
60+
}
61+
return null
62+
}
63+
64+
export const getSelectedAppListForBulkStrategy = (appList: BulkCDDetailType[], feasiblePipelineIds: Set<number>) =>
65+
appList
66+
.map((app) => ({ pipelineId: +app.cdPipelineId, appName: app.name }))
67+
.filter(({ pipelineId }) => feasiblePipelineIds.has(pipelineId))

src/css/colorPalette.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,9 @@ $black: 0, 0, 0;
247247
--shadow-modal: 0px 1px 1px 0px rgba(#{$black}, 0.04), 0px 2px 8px 0px rgba(#{$black}, 0.04), 0px 3px 17px 0px rgba(#{$black}, 0.04), 0px 4px 30px 0px rgba(#{$black}, 0.13);
248248
--shadow-overlay: 0px 1px 1px 0px rgba(#{$black}, 0.04), 0px 2px 6px 0px rgba(#{$black}, 0.04), 0px 4px 12px 0px rgba(#{$black}, 0.1);
249249
--shadow-drawer: 0px 1px 1px 0px rgba(#{$black}, 0.04), 0px 2px 8px 0px rgba(#{$black}, 0.04), 0px 3px 17px 0px rgba(#{$black}, 0.04), 0px 4px 30px 0px rgba(#{$black}, 0.13);
250-
--shadow-card-primary: 0px 1px 2px 0px rgba(1, 87, 173, 0.1);
251-
--shadow-card-secondary: 0px 0px 8px 0px rgba(#{$black}, 0.1);
252-
--shadow-card-tertiary: 0 8px 12px 0 rgba(30, 35, 96, 0.1), 0 1px 4px 0 rgba(#{$black}, 0.1);
250+
--shadow-10: 0px 0px 4px 0px var(--black-20);
251+
--shadow-20: 0px 0px 7px 0px var(--black-20);
252+
--shadow-30: 0px 0px 10px 0px var(--black-20);
253253

254254
&.theme {
255255
&__light {

src/css/themeUtils.scss

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,16 @@
116116
}
117117

118118
&__card {
119-
&--primary {
120-
box-shadow: var(--shadow-card-primary);
119+
&--10 {
120+
box-shadow: var(--shadow-10);
121121
}
122122

123-
&--secondary {
124-
box-shadow: var(--shadow-card-secondary);
123+
&--20 {
124+
box-shadow: var(--shadow-20);
125125
}
126126

127-
&--tertiary {
128-
box-shadow: var(--shadow-card-tertiary);
127+
&--30 {
128+
box-shadow: var(--shadow-10);
129129
}
130130
}
131131
}

0 commit comments

Comments
 (0)