Skip to content

Commit 8e1e76a

Browse files
committed
feat: implement bulk CI material handling and enhance UI components for better user experience
1 parent 1f68821 commit 8e1e76a

File tree

10 files changed

+132
-83
lines changed

10 files changed

+132
-83
lines changed

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@
4343
height: 100%;
4444
justify-content: space-between;
4545

46+
.bulk-ci-trigger {
47+
.material-list {
48+
.material-list__item {
49+
padding: 10px;
50+
border-radius: 4px;
51+
border: 1px solid var(--N200);
52+
margin-bottom: 6px;
53+
54+
&.material-selected {
55+
box-shadow: none;
56+
border-color: var(--B500);
57+
background-color: var(--bg-primary);
58+
}
59+
}
60+
}
61+
62+
.main-content {
63+
.select-material--regex-body {
64+
height: auto;
65+
}
66+
67+
.material-history {
68+
width: auto;
69+
}
70+
}
71+
}
72+
4673
.tippy-over {
4774
.tippy-box {
4875
top: 47px;
@@ -51,6 +78,7 @@
5178

5279
.response-list-container {
5380
overflow: auto;
81+
5482
.response-row {
5583
display: grid;
5684
grid-template-columns: repeat(2, 200px) auto;
@@ -61,4 +89,4 @@
6189
}
6290
}
6391
}
64-
}
92+
}

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

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
APIResponseHandler,
1414
Button,
1515
Checkbox,
16-
CIMaterialType,
1716
CIPipelineNodeType,
1817
CommonNodeAttr,
1918
ComponentSizeType,
@@ -35,8 +34,6 @@ import {
3534
WorkflowNodeType,
3635
} from '@devtron-labs/devtron-fe-common-lib'
3736

38-
import { getCIMaterialList } from '@Components/app/service'
39-
import { handleSourceNotConfigured } from '@Components/ApplicationGroup/AppGroup.utils'
4037
import { EnvironmentList } from '@Components/CIPipelineN/EnvironmentList'
4138
import { getCIPipelineURL, importComponentFromFELibrary } from '@Components/common'
4239
import { BUILD_STATUS, SOURCE_NOT_CONFIGURED } from '@Config/constants'
@@ -46,7 +43,7 @@ import { IGNORE_CACHE_INFO, TRIGGER_VIEW_GA_EVENTS } from '../Constants'
4643
import { BuildImageModalProps, CIMaterialRouterProps } from '../types'
4744
import BuildImageHeader from './BuildImageHeader'
4845
import GitInfoMaterial from './GitInfoMaterial'
49-
import { triggerBuild } from './service'
46+
import { getCIMaterials, triggerBuild } from './service'
5047
import { GitInfoMaterialProps } from './types'
5148
import { getTriggerBuildPayload } from './utils'
5249

@@ -58,10 +55,6 @@ const validateRuntimeParameters = importComponentFromFELibrary(
5855
'function',
5956
)
6057

61-
/**
62-
* TODO:
63-
* - On save/change of branch call plugin state api and update the state of workflow
64-
*/
6558
const BuildImageModal = ({
6659
handleClose,
6760
isJobView,
@@ -87,49 +80,21 @@ const BuildImageModal = ({
8780
const [isBuildTriggerLoading, setIsBuildTriggerLoading] = useState<boolean>(false)
8881
const [showWebhookModal, setShowWebhookModal] = useState<boolean>(false)
8982

90-
const selectedWorkflow = workflows?.find((workflow) =>
91-
workflow.nodes.some((node) => node.type === WorkflowNodeType.CI && Number(node.id) === +ciNodeId),
83+
// Workflows will be present since this modal is only opened when workflows are loaded
84+
const selectedWorkflow = workflows.find((workflow) =>
85+
workflow.nodes.some((node) => node.type === WorkflowNodeType.CI && +node.id === +ciNodeId),
9286
)
9387
const workflowId = selectedWorkflow?.id
94-
// Workflows will be present since this modal is only opened when workflows are loaded
9588
const ciNode = selectedWorkflow?.nodes.find((node) => node.type === CIPipelineNodeType.CI && node.id === ciNodeId)
9689
const appId = appIdProp || selectedWorkflow?.appId
9790
const filteredCIPipelines = filteredCIPipelinesProp || filteredCIPipelineMap?.get(String(appId)) || []
9891

99-
// TODO: Add as much type as possible to selectedCIPipeline
10092
const selectedCIPipeline = (filteredCIPipelines || []).find((_ci) => _ci.id === +ciNodeId)
10193

10294
usePrompt({
10395
shouldPrompt: isBuildTriggerLoading,
10496
})
10597

106-
const getMaterialList = async (): Promise<CIMaterialType[]> => {
107-
const { result: materialListResponse } = await getCIMaterialList(
108-
{
109-
pipelineId: ciNodeId,
110-
},
111-
materialListAbortControllerRef.current.signal,
112-
)
113-
114-
const configuredMaterialList = new Map<number, Set<number>>()
115-
if (ciNode) {
116-
const gitMaterials = new Map<number, string[]>()
117-
materialListResponse?.forEach((material) => {
118-
gitMaterials[material.gitMaterialId] = [material.gitMaterialName.toLowerCase(), material.value]
119-
})
120-
121-
configuredMaterialList[selectedWorkflow.name] = new Set<number>()
122-
123-
handleSourceNotConfigured(
124-
configuredMaterialList,
125-
selectedWorkflow,
126-
materialListResponse || [],
127-
!gitMaterials[selectedWorkflow.ciConfiguredGitMaterialId],
128-
)
129-
}
130-
return materialListResponse
131-
}
132-
13398
const [areRuntimeParamsLoading, runtimeParams, runtimeParamsError, reloadRuntimeParams, setRuntimeParams] =
13499
useAsync<GitInfoMaterialProps['runtimeParams']>(
135100
() => getRuntimeParams(ciNodeId, true),
@@ -138,7 +103,13 @@ const BuildImageModal = ({
138103
)
139104

140105
const [isMaterialListLoading, _materialList, materialListError, reloadMaterialList, setMaterialList] = useAsync(
141-
getMaterialList,
106+
() =>
107+
getCIMaterials({
108+
ciNodeId,
109+
abortControllerRef: materialListAbortControllerRef,
110+
isCINodePresent: !!ciNode,
111+
selectedWorkflow,
112+
}),
142113
[ciNodeId],
143114
!!ciNodeId,
144115
)
@@ -159,7 +130,6 @@ const BuildImageModal = ({
159130
return () => materialListAbortControllerRef.current.abort()
160131
}, [])
161132

162-
// TODO: Maybe extract component for storage module for bulk view as well
163133
const isBlobStorageConfigured = !!blobStorageModuleRes?.result?.enabled
164134

165135
const handleReload = () => {

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

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
} from '@devtron-labs/devtron-fe-common-lib'
2828

2929
import { ReactComponent as MechanicalOperation } from '@Images/ic-mechanical-operation.svg'
30-
import { getCIMaterialList } from '@Components/app/service'
3130
import { BulkCIDetailType, ResponseRowType } from '@Components/ApplicationGroup/AppGroup.types'
3231
import {
3332
BULK_CI_BUILD_STATUS,
@@ -48,7 +47,7 @@ import { getModuleConfigured } from '../../appDetails/appDetails.service'
4847
import { CI_MATERIAL_EMPTY_STATE_MESSAGING, IGNORE_CACHE_INFO } from '../Constants'
4948
import BuildImageHeader from './BuildImageHeader'
5049
import GitInfoMaterial from './GitInfoMaterial'
51-
import { triggerBuild } from './service'
50+
import { getCIMaterials, triggerBuild } from './service'
5251
import { BulkBuildImageModalProps, GitInfoMaterialProps } from './types'
5352
import { getCanNodeHaveMaterial, getIsRegexBranchNotAvailable, getTriggerBuildPayload } from './utils'
5453

@@ -162,12 +161,12 @@ const BulkBuildImageModal = ({
162161
}
163162

164163
acc.ciMaterialPromiseList.push(() =>
165-
getCIMaterialList(
166-
{
167-
pipelineId: currentNode.id,
168-
},
169-
initialDataAbortControllerRef.current.signal,
170-
),
164+
getCIMaterials({
165+
ciNodeId: currentNode.id,
166+
abortControllerRef: initialDataAbortControllerRef,
167+
isCINodePresent: !!currentNode,
168+
selectedWorkflow: workflow,
169+
}),
171170
)
172171

173172
// TODO: Check runtime param page should show error state in case of its error
@@ -187,7 +186,7 @@ const BulkBuildImageModal = ({
187186
}
188187

189188
const ciMaterialList =
190-
await ApiQueuingWithBatch<Awaited<ReturnType<typeof getCIMaterialList>>>(ciMaterialPromiseList)
189+
await ApiQueuingWithBatch<Awaited<ReturnType<typeof getCIMaterials>>>(ciMaterialPromiseList)
191190
// TODO: Add show regex modal logic later
192191
const runtimeParamsList = await ApiQueuingWithBatch<RuntimePluginVariables[]>(runtimeParamsPromiseList)
193192

@@ -202,9 +201,8 @@ const BulkBuildImageModal = ({
202201
}
203202

204203
const currentMaterial =
205-
(ciMaterialList[index].status === PromiseAllStatusType.FULFILLED
206-
? ciMaterialList[index].value?.result
207-
: []) || []
204+
(ciMaterialList[index].status === PromiseAllStatusType.FULFILLED ? ciMaterialList[index].value : []) ||
205+
[]
208206
const runtimeParams =
209207
runtimeParamsList[index].status === PromiseAllStatusType.FULFILLED ? runtimeParamsList[index].value : []
210208

@@ -593,13 +591,13 @@ const BulkBuildImageModal = ({
593591
}
594592

595593
return (
596-
<Drawer position="right" minWidth="1024px" maxWidth="1200px" onClose={handleClose} onEscape={handleClose}>
594+
<Drawer position="right" width="1080px" onClose={handleClose} onEscape={handleClose}>
597595
<div
598596
className="flexbox-col dc__content-space h-100 bg__modal--primary shadow__modal dc__overflow-auto bulk-ci-trigger-container"
599597
onClick={stopPropagation}
600598
>
601599
<div
602-
className="flexbox-col dc__content-space h-100 bg__modal--primary shadow__modal dc__overflow-auto"
600+
className="flexbox-col dc__content-space h-100 bg__modal--primary shadow__modal dc__overflow-auto bulk-ci-trigger"
603601
onClick={stopPropagation}
604602
>
605603
<div className="flexbox-col dc__overflow-auto flex-grow-1">

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ const GitInfoMaterial = ({
134134
},
135135
null,
136136
)
137+
// Not added source not configured check here since ideally this should not be even called at that moment and we are not adding a new material
137138

138139
if (!newSelectedMaterialItem.result.length) {
139140
throw new Error('Unable to fetch material details')

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ const TriggerBuildSidebar = ({
126126
)
127127

128128
const renderCacheSection = (currentAppDetails: BulkCIDetailType): JSX.Element | null => {
129-
if (!getCanNodeHaveMaterial(currentAppDetails.node)) {
129+
if (getCanNodeHaveMaterial(currentAppDetails.node)) {
130130
if (currentAppDetails.node.status?.toLowerCase() === BUILD_STATUS.NOT_TRIGGERED) {
131131
return renderTippy(
132132
BULK_CI_MESSAGING.isFirstTrigger.infoText,
@@ -179,8 +179,8 @@ const TriggerBuildSidebar = ({
179179

180180
return appList.map((app) => (
181181
<div
182-
className={`material-list pr-12 pl-12 pb-12 ${
183-
app.appId === appId ? 'bg__tertiary' : 'dc__border-bottom-n1 cursor'
182+
className={`material-list px-12 pb-12 dc__border-bottom-n1 ${
183+
app.appId === appId ? 'bg__tertiary' : 'bg__primary'
184184
}`}
185185
key={`app-${app.appId}`}
186186
>
@@ -191,9 +191,9 @@ const TriggerBuildSidebar = ({
191191
}
192192

193193
return (
194-
<div className="material-list dc__overflow-hidden flexbox-col flex-grow-1 mh-0">
194+
<div className="material-list dc__overflow-hidden flexbox-col flex-grow-1 mh-0 border__primary--right">
195195
{RuntimeParamTabs ? (
196-
<div className="flex pt-12 pb-12 pl-16 pr-16 dc__gap-4">
196+
<div className="flex pt-12 pb-12 pl-16 pr-16 dc__gap-4 dc__border-bottom">
197197
<RuntimeParamTabs
198198
tabs={sidebarTabs}
199199
initialTab={currentSidebarTab}
@@ -209,7 +209,7 @@ const TriggerBuildSidebar = ({
209209
</div>
210210
)}
211211

212-
{renderContent()}
212+
<div className="flexbox-col dc__overflow-auto flex-grow-1">{renderContent()}</div>
213213
</div>
214214
)
215215
}

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import {
77
ToastVariantType,
88
} from '@devtron-labs/devtron-fe-common-lib'
99

10-
import { triggerCINode } from '@Components/app/service'
10+
import { getCIMaterialList, triggerCINode } from '@Components/app/service'
11+
import { handleSourceNotConfigured } from '@Components/ApplicationGroup/AppGroup.utils'
1112
import { NO_TASKS_CONFIGURED_ERROR } from '@Config/constantMessaging'
1213

13-
import { TriggerBuildProps } from './types'
14+
import { GetCIMaterialsProps, TriggerBuildProps } from './types'
1415

1516
export const triggerBuild = async ({ payload, redirectToCIPipeline }: TriggerBuildProps) => {
1617
try {
@@ -57,3 +58,35 @@ export const triggerBuild = async ({ payload, redirectToCIPipeline }: TriggerBui
5758
throw errors
5859
}
5960
}
61+
62+
export const getCIMaterials = async ({
63+
ciNodeId,
64+
abortControllerRef,
65+
isCINodePresent,
66+
selectedWorkflow,
67+
}: GetCIMaterialsProps) => {
68+
const { result: materialListResponse } = await getCIMaterialList(
69+
{
70+
pipelineId: ciNodeId,
71+
},
72+
abortControllerRef,
73+
)
74+
75+
const configuredMaterialList = new Map<number, Set<number>>()
76+
if (isCINodePresent) {
77+
const gitMaterials = new Map<number, string[]>()
78+
materialListResponse?.forEach((material) => {
79+
gitMaterials[material.gitMaterialId] = [material.gitMaterialName.toLowerCase(), material.value]
80+
})
81+
82+
configuredMaterialList[selectedWorkflow.name] = new Set<number>()
83+
84+
handleSourceNotConfigured(
85+
configuredMaterialList,
86+
selectedWorkflow,
87+
materialListResponse || [],
88+
!gitMaterials[selectedWorkflow.ciConfiguredGitMaterialId],
89+
)
90+
}
91+
return materialListResponse
92+
}

src/components/app/details/triggerView/MaterialSource.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export default function MaterialSource({
9595
}
9696

9797
return (
98-
<div className="flexbox-col flex-grow-1 dc__overflow-auto">
98+
<div className="flexbox-col flex-grow-1">
9999
{material.map((mat, index) => {
100100
return (
101101
<div

src/components/app/details/triggerView/TriggerView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
ToastVariantType,
2929
getEnvironmentListMinPublic,
3030
DocLink,
31+
DEFAULT_ENV,
3132
} from '@devtron-labs/devtron-fe-common-lib'
3233
import ReactGA from 'react-ga4'
3334
import { withRouter, Route, Switch } from 'react-router-dom'
@@ -51,7 +52,7 @@ import { AppNotConfigured } from '../appDetails/AppDetails'
5152
import { getHostURLConfiguration } from '../../../../services/service'
5253
import { ReactComponent as CloseIcon } from '../../../../assets/icons/ic-close.svg'
5354
import { TriggerViewContext } from './config'
54-
import { DEFAULT_ENV, TRIGGER_VIEW_PARAMS, TRIGGER_VIEW_GA_EVENTS } from './Constants'
55+
import { TRIGGER_VIEW_PARAMS, TRIGGER_VIEW_GA_EVENTS } from './Constants'
5556
import {
5657
APP_DETAILS,
5758
} from '../../../../config/constantMessaging'
@@ -279,7 +280,6 @@ class TriggerView extends Component<TriggerViewProps, TriggerViewState> {
279280
}
280281

281282
openCIMaterialModal = (ciNodeId: string) => {
282-
// TODO: Check if match.url support fw/bw navigation
283283
this.props.history.push(`${this.props.match.url}${URLS.BUILD}/${ciNodeId}`)
284284
}
285285

0 commit comments

Comments
 (0)