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