Skip to content

Commit 7545442

Browse files
committed
Merge branch 'develop' into feat/runtime-param
2 parents 106af46 + da93ad7 commit 7545442

File tree

75 files changed

+565
-633
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+565
-633
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.13-beta-1",
3+
"version": "0.2.20-beta-3",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Common/Api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,4 @@ export const abortPreviousRequests = <T>(
263263
*/
264264
export const getIsRequestAborted = (error) =>
265265
// The 0 code is common for aborted and blocked requests
266-
error && error.code === 0 && error.message.search('abort\|aborted')
266+
error && error.code === 0 && error.message.search('abort|aborted')

src/Common/AppStatus/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
*/
1616

1717
export { default as AppStatus } from './AppStatus'
18-
export * from './utils'
18+
export * from './utils'

src/Common/ClipboardButton/ClipboardButton.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@ export default function ClipboardButton({
4242
const [copied, setCopied] = useState<boolean>(false)
4343
const [enableTippy, setEnableTippy] = useState<boolean>(false)
4444

45-
const handleTextCopied = () => {setCopied(true)}
45+
const handleTextCopied = () => {
46+
setCopied(true)
47+
}
4648
const handleEnableTippy = () => setEnableTippy(true)
4749
const handleDisableTippy = () => setEnableTippy(false)
4850
const handleCopyContent = useCallback(
4951
(e?) => {
50-
if(e) stopPropagation(e)
52+
if (e) stopPropagation(e)
5153
copyToClipboard(content, handleTextCopied)
5254
},
5355
[content],

src/Common/CodeEditor/CodeEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const CodeEditor: React.FC<CodeEditorInterface> & CodeEditorComposition = React.
8787
cleanData = false,
8888
onBlur,
8989
onFocus,
90-
adjustEditorHeightToContent,
90+
adjustEditorHeightToContent = false,
9191
}) => {
9292
if (cleanData) {
9393
value = cleanKubeManifest(value)

src/Common/CodeEditor/types.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface InformationBarProps {
2222
children?: React.ReactNode
2323
}
2424

25-
export interface CodeEditorInterface {
25+
interface CodeEditorBaseInterface {
2626
value?: string
2727
lineDecorationsWidth?: number
2828
responseType?: string
@@ -36,7 +36,6 @@ export interface CodeEditorInterface {
3636
readOnly?: boolean
3737
noParsing?: boolean
3838
inline?: boolean
39-
height?: number | string
4039
shebang?: string | JSX.Element
4140
diffView?: boolean
4241
loading?: boolean
@@ -48,9 +47,20 @@ export interface CodeEditorInterface {
4847
isKubernetes?: boolean
4948
cleanData?: boolean
5049
chartVersion?: any
51-
adjustEditorHeightToContent?: boolean
5250
}
5351

52+
export type CodeEditorInterface = CodeEditorBaseInterface &
53+
(
54+
| {
55+
adjustEditorHeightToContent?: boolean
56+
height?: never
57+
}
58+
| {
59+
adjustEditorHeightToContent?: never
60+
height?: number | string
61+
}
62+
)
63+
5464
export interface CodeEditorHeaderInterface {
5565
children?: any
5666
className?: string

src/Common/Common.service.ts

Lines changed: 145 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import moment from 'moment'
1818
import { RuntimeParamsAPIResponseType, RuntimeParamsListItemType } from '@Shared/types'
19-
import { stringComparatorBySortOrder } from '@Shared/Helpers'
19+
import { getIsManualApprovalSpecific, sanitizeUserApprovalConfig, stringComparatorBySortOrder } from '@Shared/Helpers'
2020
import { get, post } from './Api'
2121
import { ROUTES } from './Constants'
2222
import { getUrlWithSearchParams, sortCallback } from './Helper'
@@ -34,8 +34,17 @@ import {
3434
CDMaterialFilterQuery,
3535
ImagePromotionMaterialInfo,
3636
EnvironmentListHelmResponse,
37+
UserGroupApproverType,
38+
ImageApprovalPolicyUserGroupDataType,
39+
ImageApprovalPolicyType,
40+
ImageApprovalUsersInfoDTO,
41+
UserApprovalMetadataType,
42+
UserApprovalConfigType,
43+
CDMaterialListModalServiceUtilProps,
3744
} from './Types'
3845
import { ApiResourceType } from '../Pages'
46+
import { API_TOKEN_PREFIX } from '@Shared/constants'
47+
import { DefaultUserKey } from '@Shared/types'
3948

4049
export const getTeamListMin = (): Promise<TeamList> => {
4150
// ignore active field
@@ -82,13 +91,35 @@ export function setImageTags(request, pipelineId: number, artifactId: number) {
8291
return post(`${ROUTES.IMAGE_TAGGING}/${pipelineId}/${artifactId}`, request)
8392
}
8493

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) => {
92123
if (!artifacts || !artifacts.length) return []
93124

94125
const markFirstSelected = offset === 0
@@ -132,7 +163,10 @@ const cdMaterialListModal = (
132163
vulnerable: material.vulnerable,
133164
runningOnParentCd: material.runningOnParentCd,
134165
artifactStatus: artifactStatusValue,
135-
userApprovalMetadata: material.userApprovalMetadata,
166+
userApprovalMetadata: sanitizeApprovalConfigFromApprovalMetadata(
167+
material.userApprovalMetadata,
168+
userApprovalConfig,
169+
),
136170
triggeredBy: material.triggeredBy,
137171
isVirtualEnvironment: material.isVirtualEnvironment,
138172
imageComment: material.imageComment,
@@ -177,19 +211,110 @@ const cdMaterialListModal = (
177211
return materials
178212
}
179213

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+
180303
const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResult): CDMaterialsApprovalInfo => {
181304
if (!enableApproval || !cdMaterialsResult) {
182305
return {
183306
approvalUsers: [],
184307
userApprovalConfig: null,
185308
canApproverDeploy: cdMaterialsResult?.canApproverDeploy ?? false,
309+
imageApprovalPolicyDetails: null,
186310
}
187311
}
188312

189313
return {
190314
approvalUsers: cdMaterialsResult.approvalUsers,
191-
userApprovalConfig: cdMaterialsResult.userApprovalConfig,
315+
userApprovalConfig: sanitizeUserApprovalConfig(cdMaterialsResult.userApprovalConfig),
192316
canApproverDeploy: cdMaterialsResult.canApproverDeploy ?? false,
317+
imageApprovalPolicyDetails: getImageApprovalPolicyDetailsFromMaterialResult(cdMaterialsResult),
193318
}
194319
}
195320

@@ -252,13 +377,14 @@ export const processCDMaterialServiceResponse = (
252377
}
253378
}
254379

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,
260385
disableDefaultSelection,
261-
)
386+
userApprovalConfig: cdMaterialsResult.userApprovalConfig,
387+
})
262388
const approvalInfo = processCDMaterialsApprovalInfo(
263389
stage === DeploymentNodeType.CD || stage === DeploymentNodeType.APPROVAL,
264390
cdMaterialsResult,
@@ -361,9 +487,7 @@ export function fetchChartTemplateVersions() {
361487
return get(`${ROUTES.DEPLOYMENT_TEMPLATE_LIST}?appId=-1&envId=-1`)
362488
}
363489

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`)
367491

368492
export function getEnvironmentListMinPublic(includeAllowedDeploymentTypes?: boolean) {
369493
return get(
@@ -376,9 +500,8 @@ export function getClusterListMin() {
376500
return get(URL)
377501
}
378502

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}`)
382505

383506
export function getNamespaceListMin(clusterIdsCsv: string): Promise<EnvironmentListHelmResponse> {
384507
const URL = `${ROUTES.NAMESPACE}/autocomplete?ids=${clusterIdsCsv}`

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/CustomInput/CustomInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ export const CustomInput = ({
135135

136136
{getInputError()}
137137
{helperText && (
138-
<div className="flex left top dc__gap-4 fs-11 lh-16 cn-7 mt-4">
139-
<Info className="icon-dim-16" />
140-
<div>{helperText}</div>
138+
<div className="flex left top dc__gap-4 fs-11 lh-16 cn-7 mt-4">
139+
<Info className="icon-dim-16" />
140+
<div>{helperText}</div>
141141
</div>
142142
)}
143143
</div>

0 commit comments

Comments
 (0)