@@ -32,8 +32,18 @@ import {
32
32
CDMaterialFilterQuery ,
33
33
ImagePromotionMaterialInfo ,
34
34
EnvironmentListHelmResponse ,
35
+ UserGroupApproverType ,
36
+ ImageApprovalPolicyUserGroupDataType ,
37
+ ImageApprovalPolicyType ,
38
+ ImageApprovalUsersInfoDTO ,
39
+ UserApprovalMetadataType ,
40
+ UserApprovalConfigType ,
41
+ CDMaterialListModalServiceUtilProps ,
35
42
} from './Types'
36
43
import { ApiResourceType } from '../Pages'
44
+ import { getIsManualApprovalSpecific , sanitizeUserApprovalConfig , stringComparatorBySortOrder } from '@Shared/Helpers'
45
+ import { API_TOKEN_PREFIX } from '@Shared/constants'
46
+ import { DefaultUserKey } from '@Shared/types'
37
47
38
48
export const getTeamListMin = ( ) : Promise < TeamList > => {
39
49
// ignore active field
@@ -80,7 +90,35 @@ export function setImageTags(request, pipelineId: number, artifactId: number) {
80
90
return post ( `${ ROUTES . IMAGE_TAGGING } /${ pipelineId } /${ artifactId } ` , request )
81
91
}
82
92
83
- const cdMaterialListModal = ( artifacts : any [ ] , offset : number , artifactId ?: number , artifactStatus ?: string , disableDefaultSelection ?: boolean ) => {
93
+ const sanitizeApprovalConfigFromApprovalMetadata = (
94
+ approvalMetadata : UserApprovalMetadataType ,
95
+ userApprovalConfig : UserApprovalConfigType ,
96
+ ) : UserApprovalMetadataType => {
97
+ if ( ! approvalMetadata ) {
98
+ return null
99
+ }
100
+
101
+ const approvedUsersData = approvalMetadata . approvedUsersData || [ ]
102
+ const unsanitizedApprovalConfig = approvalMetadata . approvalConfig || userApprovalConfig
103
+
104
+ return {
105
+ ...approvalMetadata ,
106
+ approvedUsersData : approvedUsersData . map ( ( userData ) => ( {
107
+ ...userData ,
108
+ userGroups : userData . userGroups ?. filter ( ( group ) => ! ! group ?. identifier && ! ! group ?. name ) ?? [ ] ,
109
+ } ) ) ,
110
+ approvalConfig : sanitizeUserApprovalConfig ( unsanitizedApprovalConfig ) ,
111
+ }
112
+ }
113
+
114
+ const cdMaterialListModal = ( {
115
+ artifacts,
116
+ offset,
117
+ artifactId,
118
+ artifactStatus,
119
+ disableDefaultSelection,
120
+ userApprovalConfig,
121
+ } : CDMaterialListModalServiceUtilProps ) => {
84
122
if ( ! artifacts || ! artifacts . length ) return [ ]
85
123
86
124
const markFirstSelected = offset === 0
@@ -124,7 +162,10 @@ const cdMaterialListModal = (artifacts: any[], offset: number, artifactId?: numb
124
162
vulnerable : material . vulnerable ,
125
163
runningOnParentCd : material . runningOnParentCd ,
126
164
artifactStatus : artifactStatusValue ,
127
- userApprovalMetadata : material . userApprovalMetadata ,
165
+ userApprovalMetadata : sanitizeApprovalConfigFromApprovalMetadata (
166
+ material . userApprovalMetadata ,
167
+ userApprovalConfig ,
168
+ ) ,
128
169
triggeredBy : material . triggeredBy ,
129
170
isVirtualEnvironment : material . isVirtualEnvironment ,
130
171
imageComment : material . imageComment ,
@@ -169,19 +210,110 @@ const cdMaterialListModal = (artifacts: any[], offset: number, artifactId?: numb
169
210
return materials
170
211
}
171
212
213
+ const getImageApprovalPolicyDetailsFromMaterialResult = ( cdMaterialsResult ) : ImageApprovalPolicyType => {
214
+ const approvalUsers : string [ ] = cdMaterialsResult . approvalUsers || [ ]
215
+ const userApprovalConfig = sanitizeUserApprovalConfig ( cdMaterialsResult . userApprovalConfig )
216
+ const isPolicyConfigured = getIsManualApprovalSpecific ( userApprovalConfig )
217
+ const imageApprovalUsersInfo : ImageApprovalUsersInfoDTO = cdMaterialsResult . imageApprovalUsersInfo || { }
218
+
219
+ const approvalUsersMap = approvalUsers . reduce (
220
+ ( acc , user ) => {
221
+ acc [ user ] = true
222
+ return acc
223
+ } ,
224
+ { } as Record < string , true > ,
225
+ )
226
+
227
+ const specificUsersAPIToken = userApprovalConfig . specificUsers . identifiers
228
+ . filter ( ( user ) => user . startsWith ( API_TOKEN_PREFIX ) )
229
+ . sort ( stringComparatorBySortOrder )
230
+ const specificUsersEmails = userApprovalConfig . specificUsers . identifiers
231
+ . filter ( ( user ) => ! user . startsWith ( API_TOKEN_PREFIX ) && user !== DefaultUserKey . system )
232
+ . sort ( stringComparatorBySortOrder )
233
+
234
+ const specificUsersData : ImageApprovalPolicyType [ 'specificUsersData' ] = {
235
+ dataStore : userApprovalConfig . specificUsers . identifiers . reduce (
236
+ ( acc , email ) => {
237
+ acc [ email ] = {
238
+ email,
239
+ hasAccess : approvalUsersMap [ email ] ?? false ,
240
+ }
241
+ return acc
242
+ } ,
243
+ { } as Record < string , UserGroupApproverType > ,
244
+ ) ,
245
+ requiredCount : userApprovalConfig . specificUsers . requiredCount ,
246
+ emails : specificUsersEmails . concat ( specificUsersAPIToken ) ,
247
+ }
248
+
249
+ const validGroups = userApprovalConfig . userGroups . map ( ( group ) => group . identifier )
250
+
251
+ // Have moved from Object.keys(imageApprovalUsersInfo) to approvalUsers since backend is not filtering out the users without approval
252
+ // TODO: This check should be on BE. Need to remove this once BE is updated
253
+ const usersList = approvalUsers . filter ( ( user ) => user !== DefaultUserKey . system )
254
+ const groupIdentifierToUsersMap = usersList . reduce (
255
+ ( acc , user ) => {
256
+ const userGroups = imageApprovalUsersInfo [ user ] || [ ]
257
+ userGroups . forEach ( ( group ) => {
258
+ if ( ! acc [ group . identifier ] ) {
259
+ acc [ group . identifier ] = { }
260
+ }
261
+ acc [ group . identifier ] [ user ] = true
262
+ } )
263
+ return acc
264
+ } ,
265
+ { } as Record < string , Record < string , true > > ,
266
+ )
267
+
268
+ return {
269
+ isPolicyConfigured,
270
+ specificUsersData,
271
+ userGroupData : userApprovalConfig . userGroups . reduce (
272
+ ( acc , group ) => {
273
+ const identifier = group . identifier
274
+ // No need of handling api tokens here since they are not part of user groups
275
+ const users = Object . keys ( groupIdentifierToUsersMap [ identifier ] || { } ) . sort ( stringComparatorBySortOrder )
276
+
277
+ acc [ identifier ] = {
278
+ dataStore : users . reduce (
279
+ ( acc , user ) => {
280
+ acc [ user ] = {
281
+ email : user ,
282
+ // As of now it will always be true, but UI has handled it in a way that can support false as well
283
+ hasAccess : approvalUsersMap [ user ] ?? false ,
284
+ }
285
+ return acc
286
+ } ,
287
+ { } as Record < string , UserGroupApproverType > ,
288
+ ) ,
289
+ requiredCount : group . requiredCount ,
290
+ emails : users ,
291
+ }
292
+
293
+ return acc
294
+ } ,
295
+ { } as Record < string , ImageApprovalPolicyUserGroupDataType > ,
296
+ ) ,
297
+ // Not sorting since would change them in approval info modal to name
298
+ validGroups,
299
+ }
300
+ }
301
+
172
302
const processCDMaterialsApprovalInfo = ( enableApproval : boolean , cdMaterialsResult ) : CDMaterialsApprovalInfo => {
173
303
if ( ! enableApproval || ! cdMaterialsResult ) {
174
304
return {
175
305
approvalUsers : [ ] ,
176
306
userApprovalConfig : null ,
177
307
canApproverDeploy : cdMaterialsResult ?. canApproverDeploy ?? false ,
308
+ imageApprovalPolicyDetails : null ,
178
309
}
179
310
}
180
311
181
312
return {
182
313
approvalUsers : cdMaterialsResult . approvalUsers ,
183
- userApprovalConfig : cdMaterialsResult . userApprovalConfig ,
314
+ userApprovalConfig : sanitizeUserApprovalConfig ( cdMaterialsResult . userApprovalConfig ) ,
184
315
canApproverDeploy : cdMaterialsResult . canApproverDeploy ?? false ,
316
+ imageApprovalPolicyDetails : getImageApprovalPolicyDetailsFromMaterialResult ( cdMaterialsResult ) ,
185
317
}
186
318
}
187
319
@@ -237,13 +369,14 @@ export const processCDMaterialServiceResponse = (
237
369
}
238
370
}
239
371
240
- const materials = cdMaterialListModal (
241
- cdMaterialsResult . ci_artifacts ,
242
- offset ?? 0 ,
243
- cdMaterialsResult . latest_wf_artifact_id ,
244
- cdMaterialsResult . latest_wf_artifact_status ,
372
+ const materials = cdMaterialListModal ( {
373
+ artifacts : cdMaterialsResult . ci_artifacts ,
374
+ offset : offset ?? 0 ,
375
+ artifactId : cdMaterialsResult . latest_wf_artifact_id ,
376
+ artifactStatus : cdMaterialsResult . latest_wf_artifact_status ,
245
377
disableDefaultSelection,
246
- )
378
+ userApprovalConfig : cdMaterialsResult . userApprovalConfig ,
379
+ } )
247
380
const approvalInfo = processCDMaterialsApprovalInfo (
248
381
stage === DeploymentNodeType . CD || stage === DeploymentNodeType . APPROVAL ,
249
382
cdMaterialsResult ,
@@ -366,8 +499,8 @@ export const getResourceGroupListRaw = (clusterId: string): Promise<ResponseType
366
499
}
367
500
368
501
export function getNamespaceListMin ( clusterIdsCsv : string ) : Promise < EnvironmentListHelmResponse > {
369
- const URL = `${ ROUTES . NAMESPACE } /autocomplete?ids=${ clusterIdsCsv } `
370
- return get ( URL )
502
+ const URL = `${ ROUTES . NAMESPACE } /autocomplete?ids=${ clusterIdsCsv } `
503
+ return get ( URL )
371
504
}
372
505
export function getWebhookEventsForEventId ( eventId : string | number ) {
373
506
const URL = `${ ROUTES . GIT_HOST_EVENT } /${ eventId } `
0 commit comments