Skip to content

Commit b0c7234

Browse files
committed
Merge branch 'develop' of github.com:devtron-labs/devtron-fe-common-lib into feat/disable-editor-search
2 parents 886ff49 + da93ad7 commit b0c7234

File tree

18 files changed

+375
-93
lines changed

18 files changed

+375
-93
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "0.2.17",
3+
"version": "0.2.21",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Common/Common.service.ts

Lines changed: 142 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,18 @@ import {
3232
CDMaterialFilterQuery,
3333
ImagePromotionMaterialInfo,
3434
EnvironmentListHelmResponse,
35+
UserGroupApproverType,
36+
ImageApprovalPolicyUserGroupDataType,
37+
ImageApprovalPolicyType,
38+
ImageApprovalUsersInfoDTO,
39+
UserApprovalMetadataType,
40+
UserApprovalConfigType,
41+
CDMaterialListModalServiceUtilProps,
3542
} from './Types'
3643
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'
3747

3848
export const getTeamListMin = (): Promise<TeamList> => {
3949
// ignore active field
@@ -80,13 +90,35 @@ export function setImageTags(request, pipelineId: number, artifactId: number) {
8090
return post(`${ROUTES.IMAGE_TAGGING}/${pipelineId}/${artifactId}`, request)
8191
}
8292

83-
const cdMaterialListModal = (
84-
artifacts: any[],
85-
offset: number,
86-
artifactId?: number,
87-
artifactStatus?: string,
88-
disableDefaultSelection?: boolean,
89-
) => {
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) => {
90122
if (!artifacts || !artifacts.length) return []
91123

92124
const markFirstSelected = offset === 0
@@ -130,7 +162,10 @@ const cdMaterialListModal = (
130162
vulnerable: material.vulnerable,
131163
runningOnParentCd: material.runningOnParentCd,
132164
artifactStatus: artifactStatusValue,
133-
userApprovalMetadata: material.userApprovalMetadata,
165+
userApprovalMetadata: sanitizeApprovalConfigFromApprovalMetadata(
166+
material.userApprovalMetadata,
167+
userApprovalConfig,
168+
),
134169
triggeredBy: material.triggeredBy,
135170
isVirtualEnvironment: material.isVirtualEnvironment,
136171
imageComment: material.imageComment,
@@ -175,19 +210,110 @@ const cdMaterialListModal = (
175210
return materials
176211
}
177212

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+
178302
const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResult): CDMaterialsApprovalInfo => {
179303
if (!enableApproval || !cdMaterialsResult) {
180304
return {
181305
approvalUsers: [],
182306
userApprovalConfig: null,
183307
canApproverDeploy: cdMaterialsResult?.canApproverDeploy ?? false,
308+
imageApprovalPolicyDetails: null,
184309
}
185310
}
186311

187312
return {
188313
approvalUsers: cdMaterialsResult.approvalUsers,
189-
userApprovalConfig: cdMaterialsResult.userApprovalConfig,
314+
userApprovalConfig: sanitizeUserApprovalConfig(cdMaterialsResult.userApprovalConfig),
190315
canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
316+
imageApprovalPolicyDetails: getImageApprovalPolicyDetailsFromMaterialResult(cdMaterialsResult),
191317
}
192318
}
193319

@@ -243,13 +369,14 @@ export const processCDMaterialServiceResponse = (
243369
}
244370
}
245371

246-
const materials = cdMaterialListModal(
247-
cdMaterialsResult.ci_artifacts,
248-
offset ?? 0,
249-
cdMaterialsResult.latest_wf_artifact_id,
250-
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,
251377
disableDefaultSelection,
252-
)
378+
userApprovalConfig: cdMaterialsResult.userApprovalConfig,
379+
})
253380
const approvalInfo = processCDMaterialsApprovalInfo(
254381
stage === DeploymentNodeType.CD || stage === DeploymentNodeType.APPROVAL,
255382
cdMaterialsResult,

src/Common/Constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export const ROUTES = {
107107
PLUGIN_GLOBAL_LIST_V2: 'plugin/global/list/v2',
108108
PLUGIN_GLOBAL_LIST_TAGS: 'plugin/global/list/tags',
109109
DEPLOYMENT_CHARTS_LIST: 'deployment/template/fetch',
110+
USER_LIST_MIN: 'user/list/min',
110111
CONFIG_DATA: 'config/data',
111112
}
112113

src/Common/Types.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import React, { ReactNode, CSSProperties } from 'react'
1818
import { Placement } from 'tippy.js'
1919
import { ImageComment, ReleaseTag } from './ImageTags.Types'
2020
import { ACTION_STATE, DEPLOYMENT_WINDOW_TYPE, DockerConfigOverrideType, SortingOrder, TaskErrorObj } from '.'
21+
import { UserGroupDTO } from '@Pages/GlobalConfigurations'
2122
import { RegistryType, Severity } from '../Shared'
2223

2324
/**
@@ -320,24 +321,75 @@ export enum DeploymentNodeType {
320321
APPROVAL = 'APPROVAL',
321322
}
322323

323-
export interface UserApprovalConfigType {
324+
export enum ManualApprovalType {
325+
specific = 'SPECIFIC',
326+
any = 'ANY',
327+
notConfigured = 'NOT_CONFIGURED',
328+
}
329+
330+
export interface UserGroupApproverType {
331+
email: string
332+
hasAccess: boolean
333+
}
334+
335+
export interface ImageApprovalPolicyUserGroupDataType {
336+
// Mapping email to data
337+
dataStore: Record<string, UserGroupApproverType>
324338
requiredCount: number
339+
emails: string[]
325340
}
326341

342+
export interface ImageApprovalPolicyType {
343+
isPolicyConfigured: boolean
344+
specificUsersData: ImageApprovalPolicyUserGroupDataType
345+
userGroupData: Record<string, ImageApprovalPolicyUserGroupDataType>
346+
// Assuming name of groups are unique
347+
validGroups: string[]
348+
}
349+
350+
export type ImageApprovalUsersInfoDTO = Record<string, Pick<UserGroupDTO, 'identifier' | 'name'>[]>
351+
352+
// TODO: Need to verify this change for all impacting areas
353+
export interface UserApprovalConfigType {
354+
type: ManualApprovalType
355+
requiredCount: number
356+
specificUsers: {
357+
identifiers: string[]
358+
// FIXME: Remove this ? check later when time permits
359+
requiredCount?: number
360+
}
361+
userGroups: (Pick<UserGroupDTO, 'identifier'> & {
362+
requiredCount: number
363+
})[]
364+
}
365+
366+
export type UserApprovalConfigPayloadType =
367+
| ({
368+
type: ManualApprovalType.any
369+
} & Pick<UserApprovalConfigType, 'requiredCount'>)
370+
| ({
371+
type: ManualApprovalType.specific
372+
} & Pick<UserApprovalConfigType, 'userGroups' | 'specificUsers'>)
373+
| {
374+
type: ManualApprovalType.notConfigured
375+
}
376+
327377
interface ApprovalUserDataType {
328378
dataId: number
329379
userActionTime: string
330380
userComment: string
331381
userEmail: string
332382
userId: number
333383
userResponse: number
384+
userGroups?: Pick<UserGroupDTO, 'identifier' | 'name'>[]
334385
}
335386

336387
export interface UserApprovalMetadataType {
337388
approvalRequestId: number
338389
approvalRuntimeState: number
339390
approvedUsersData: ApprovalUserDataType[]
340391
requestedUserData: ApprovalUserDataType
392+
approvalConfig?: UserApprovalConfigType
341393
}
342394

343395
export enum FilterStates {
@@ -397,6 +449,15 @@ export interface ArtifactReleaseMappingType {
397449
version: string
398450
}
399451

452+
export interface CDMaterialListModalServiceUtilProps {
453+
artifacts: any[],
454+
offset: number,
455+
artifactId?: number,
456+
artifactStatus?: string,
457+
disableDefaultSelection?: boolean,
458+
userApprovalConfig?: UserApprovalConfigType,
459+
}
460+
400461
export interface CDMaterialType {
401462
index: number
402463
id: string
@@ -618,6 +679,10 @@ export interface CDMaterialsApprovalInfo {
618679
approvalUsers: string[]
619680
userApprovalConfig: UserApprovalConfigType
620681
canApproverDeploy: boolean
682+
/**
683+
* Only available incase of approvals do'nt use in cd materials or any other flow since approvalUsers are not present there
684+
*/
685+
imageApprovalPolicyDetails: ImageApprovalPolicyType
621686
}
622687

623688
export interface CDMaterialsMetaInfo {

src/Pages/CDPipeline/types.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BuildStageType, FormType } from '@Common/CIPipeline.Types'
2-
import { DeploymentAppTypes } from '@Common/Types'
2+
import { DeploymentAppTypes, UserApprovalConfigType } from '@Common/Types'
33
import { DeploymentStrategy } from '@Shared/Components'
44
import { EnvListMinDTO } from '@Shared/types'
55

@@ -61,9 +61,7 @@ export interface CDFormType {
6161
preStageConfigMapSecretNames: { configMaps: ConfigSecretType[]; secrets: ConfigSecretType[] }
6262
postStageConfigMapSecretNames: { configMaps: ConfigSecretType[]; secrets: ConfigSecretType[] }
6363
requiredApprovals: string
64-
userApprovalConfig?: {
65-
requiredCount: number
66-
}
64+
userApprovalConfig?: UserApprovalConfigType
6765
isClusterCdActive: boolean
6866
deploymentAppCreated: boolean
6967
clusterId: string

src/Pages/GlobalConfigurations/Authorization/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@
1515
*/
1616

1717
export * from './constants'
18-
export type { UserListFilterParams, UserRoleGroup } from './types'
18+
export type { UserListFilterParams, UserRoleGroup, UserGroupDTO, UserGroupType } from './types'
1919
export * from './shared'
20+
export * from './service'
21+
export { getUserAndApiTokenOption } from './utils'

0 commit comments

Comments
 (0)