Skip to content

Commit 6433a45

Browse files
authored
Merge pull request #443 from devtron-labs/feat/runtime-params
feat: Runtime Params
2 parents d25e0f7 + 77cac08 commit 6433a45

32 files changed

+561
-52
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": "1.2.16",
3+
"version": "1.2.17",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Assets/Icon/ic-cloud-upload.svg

Lines changed: 3 additions & 0 deletions
Loading

src/Assets/Icon/ic-var-initial.svg

Lines changed: 25 additions & 0 deletions
Loading

src/Common/CIPipeline.Types.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { DynamicDataTableCellValidationState } from '@Shared/Components'
18+
1719
export interface MaterialType {
1820
name: string
1921
type: string
@@ -97,11 +99,34 @@ export enum RefVariableStageType {
9799
POST_CI = 'POST_CI',
98100
}
99101

102+
export interface FilePropertyType {
103+
allowedExtensions: string[]
104+
maxUploadSize: number
105+
}
106+
107+
export interface ConstraintType {
108+
fileProperty: FilePropertyType
109+
}
110+
111+
export interface ValueConstraintType {
112+
choices?: string[]
113+
blockCustomValue?: boolean
114+
constraint?: ConstraintType
115+
}
116+
117+
export enum VariableTypeFormat {
118+
STRING = 'STRING',
119+
NUMBER = 'NUMBER',
120+
BOOL = 'BOOL',
121+
DATE = 'DATE',
122+
FILE = 'FILE',
123+
}
124+
100125
export interface VariableType {
101126
id: number
102127
name: string
103128
value: string
104-
format: string
129+
format: VariableTypeFormat
105130
description: string
106131
defaultValue: string
107132
allowEmptyValue: boolean
@@ -110,6 +135,12 @@ export interface VariableType {
110135
refVariableName: string
111136
refVariableStage?: RefVariableStageType
112137
variableStepIndexInPlugin?: number
138+
fileMountDir: string
139+
fileReferenceId?: number
140+
valueConstraintId?: number
141+
valueConstraint?: ValueConstraintType
142+
isRuntimeArg: boolean
143+
refVariableUsed: boolean
113144
}
114145

115146
interface CommandArgsMap {
@@ -260,11 +291,30 @@ export interface ErrorObj {
260291
isValid: boolean
261292
message: string | null
262293
}
294+
295+
export enum InputOutputVariablesHeaderKeys {
296+
VARIABLE = 'variable',
297+
FORMAT = 'format',
298+
VALUE = 'val',
299+
}
300+
301+
export type InputOutputVariablesErrorObj = Record<InputOutputVariablesHeaderKeys, DynamicDataTableCellValidationState>
302+
263303
export interface TaskErrorObj {
264304
isValid: boolean
265305
name: ErrorObj
266-
inlineStepDetail?: { inputVariables?: ErrorObj[]; outputVariables?: ErrorObj[] }
267-
pluginRefStepDetail?: { inputVariables?: ErrorObj[]; outputVariables?: ErrorObj[] }
306+
inlineStepDetail?: {
307+
inputVariables?: Record<number, InputOutputVariablesErrorObj>
308+
outputVariables?: Record<number, InputOutputVariablesErrorObj>
309+
isInputVariablesValid?: boolean
310+
isOutputVariablesValid?: boolean
311+
}
312+
pluginRefStepDetail?: {
313+
inputVariables?: Record<number, InputOutputVariablesErrorObj>
314+
outputVariables?: Record<number, InputOutputVariablesErrorObj>
315+
isInputVariablesValid?: boolean
316+
isOutputVariablesValid?: boolean
317+
}
268318
}
269319
export interface FormErrorObjectType {
270320
name: ErrorObj

src/Common/Common.service.ts

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { MutableRefObject } from 'react'
1718
import moment from 'moment'
18-
import { RuntimeParamsAPIResponseType, RuntimeParamsListItemType } from '@Shared/types'
19+
import { RuntimeParamsAPIResponseType, RuntimePluginVariables } from '@Shared/types'
1920
import { getIsManualApprovalSpecific, sanitizeUserApprovalConfig, stringComparatorBySortOrder } from '@Shared/Helpers'
20-
import { get, post } from './Api'
21-
import { GitProviderType, ROUTES } from './Constants'
22-
import { getUrlWithSearchParams, sortCallback } from './Helper'
21+
import { get, getIsRequestAborted, post } from './Api'
22+
import { API_STATUS_CODES, GitProviderType, ROUTES } from './Constants'
23+
import { getUrlWithSearchParams, showError, sortCallback } from './Helper'
2324
import {
2425
TeamList,
2526
ResponseType,
@@ -41,10 +42,15 @@ import {
4142
UserApprovalMetadataType,
4243
UserApprovalConfigType,
4344
CDMaterialListModalServiceUtilProps,
45+
GlobalVariableDTO,
46+
GlobalVariableOptionType,
4447
} from './Types'
4548
import { ApiResourceType } from '../Pages'
4649
import { API_TOKEN_PREFIX } from '@Shared/constants'
4750
import { DefaultUserKey } from '@Shared/types'
51+
import { RefVariableType } from './CIPipeline.Types'
52+
import { ServerErrors } from './ServerError'
53+
import { ToastManager, ToastVariantType } from '@Shared/Services'
4854

4955
export const getTeamListMin = (): Promise<TeamList> => {
5056
// ignore active field
@@ -318,10 +324,8 @@ const processCDMaterialsApprovalInfo = (enableApproval: boolean, cdMaterialsResu
318324
}
319325
}
320326

321-
export const parseRuntimeParams = (response: RuntimeParamsAPIResponseType): RuntimeParamsListItemType[] =>
322-
Object.entries(response?.envVariables || {})
323-
.map(([key, value], index) => ({ key, value, id: index }))
324-
.sort((a, b) => stringComparatorBySortOrder(a.key, b.key))
327+
export const parseRuntimeParams = (response: RuntimeParamsAPIResponseType): RuntimePluginVariables[] =>
328+
(response?.runtimePluginVariables ?? []).map((variable) => ({ ...variable, defaultValue: variable.value }))
325329

326330
const processCDMaterialsMetaInfo = (cdMaterialsResult): CDMaterialsMetaInfo => {
327331
if (!cdMaterialsResult) {
@@ -520,10 +524,59 @@ export function getWebhookEventsForEventId(eventId: string | number) {
520524
*/
521525
export const getGitBranchUrl = (gitUrl: string, branchName: string): string | null => {
522526
if (!gitUrl) return null
523-
const trimmedGitUrl = gitUrl.trim().replace(/\.git$/, '').replace(/\/$/, '') // Remove any trailing slash
527+
const trimmedGitUrl = gitUrl
528+
.trim()
529+
.replace(/\.git$/, '')
530+
.replace(/\/$/, '') // Remove any trailing slash
524531
if (trimmedGitUrl.includes(GitProviderType.GITLAB)) return `${trimmedGitUrl}/-/tree/${branchName}`
525532
else if (trimmedGitUrl.includes(GitProviderType.GITHUB)) return `${trimmedGitUrl}/tree/${branchName}`
526533
else if (trimmedGitUrl.includes(GitProviderType.BITBUCKET)) return `${trimmedGitUrl}/branch/${branchName}`
527534
else if (trimmedGitUrl.includes(GitProviderType.AZURE)) return `${trimmedGitUrl}/src/branch/${branchName}`
528535
return null
529536
}
537+
538+
export const getGlobalVariables = async ({
539+
appId,
540+
isCD = false,
541+
abortControllerRef,
542+
}: {
543+
appId: number
544+
isCD?: boolean
545+
abortControllerRef?: MutableRefObject<AbortController>
546+
}): Promise<GlobalVariableOptionType[]> => {
547+
try {
548+
const { result } = await get<GlobalVariableDTO[]>(
549+
getUrlWithSearchParams(ROUTES.PLUGIN_GLOBAL_VARIABLES, { appId }),
550+
{
551+
abortControllerRef,
552+
},
553+
)
554+
const variableList = (result ?? [])
555+
.filter((item) => (isCD ? item.stageType !== 'ci' : item.stageType === 'ci'))
556+
.map<GlobalVariableOptionType>((variable) => {
557+
const { name, ...updatedVariable } = variable
558+
559+
return {
560+
...updatedVariable,
561+
label: name,
562+
value: name,
563+
description: updatedVariable.description || '',
564+
variableType: RefVariableType.GLOBAL,
565+
}
566+
})
567+
568+
return variableList
569+
} catch (err) {
570+
if (!getIsRequestAborted(err)) {
571+
if (err instanceof ServerErrors && err.code === API_STATUS_CODES.PERMISSION_DENIED) {
572+
ToastManager.showToast({
573+
variant: ToastVariantType.notAuthorized,
574+
description: 'You are not authorized to access global variables',
575+
})
576+
} else {
577+
showError(err)
578+
}
579+
}
580+
throw err
581+
}
582+
}

src/Common/Constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ export const DOCUMENTATION = {
3333
}
3434

3535
export const PATTERNS = {
36+
NATURAL_NUMBERS: /^\d*\.?\d*$/,
3637
KUBERNETES_KEY_PREFIX: /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/,
3738
KUBERNETES_KEY_NAME: /^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$/,
3839
START_END_ALPHANUMERIC: /^([Az09].*[A-Za-z0-9])$|[A-Za-z0-9]$/,
3940
ALPHANUMERIC_WITH_SPECIAL_CHAR: /^[A-Za-z0-9._-]+$/, // allow alphanumeric,(.) ,(-),(_)
4041
ESCAPED_CHARACTERS: /[.*+?^${}()|[\]\\]/g,
42+
NUMBERS_WITH_SCOPE_VARIABLES: /^(\d+(\.\d+)?|@{{[a-zA-Z0-9-]+}})$/,
4143
}
4244

4345
export const URLS = {
@@ -121,6 +123,8 @@ export const ROUTES = {
121123
CONFIG_DATA: 'config/data',
122124
K8S_RESOURCE: 'k8s/resource',
123125
K8S_RESOURCE_LIST: 'k8s/resource/list',
126+
FILE_UPLOAD: 'file/upload',
127+
PLUGIN_GLOBAL_VARIABLES: 'plugin/global/list/global-variable',
124128
CONFIG_COMPARE_SECRET: 'config/compare/secret',
125129
}
126130

src/Common/Helper.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,3 +1033,10 @@ export const getIframeWithDefaultAttributes = (iframeString: string, defaultName
10331033

10341034
return iframeString
10351035
}
1036+
1037+
export const getGoLangFormattedDateWithTimezone = (dateFormat: string) => {
1038+
const now = moment()
1039+
const formattedDate = now.format(dateFormat)
1040+
const timezone = now.format('Z').replace(/([+/-])(\d{2})[:.](\d{2})/, '$1$2$3')
1041+
return formattedDate.replace('Z', timezone)
1042+
}

src/Common/TippyCustomized.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,19 @@ export const TippyCustomized = (props: TippyCustomizedProps) => {
4343
}
4444

4545
const closeTippy = (e) => {
46-
stopPropagation(e)
47-
if (tippyRef.current?.hide) {
48-
tippyRef.current.hide()
49-
tippyRef.current = null
46+
if (!props.disableClose) {
47+
stopPropagation(e)
48+
if (tippyRef.current?.hide) {
49+
tippyRef.current.hide()
50+
tippyRef.current = null
5051

51-
if (props.onClose) {
52-
props.onClose()
52+
if (props.onClose) {
53+
props.onClose()
54+
}
5355
}
56+
setShowHeadingInfo(false)
57+
document.removeEventListener('keydown', closeOnEsc)
5458
}
55-
setShowHeadingInfo(false)
56-
document.removeEventListener('keydown', closeOnEsc)
5759
}
5860

5961
const toggleHeadingInfo = (e) => {

src/Common/Types.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,35 @@
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
1616

1717
import React, { ReactNode, CSSProperties, ReactElement, MutableRefObject } from 'react'
1818
import { TippyProps } from '@tippyjs/react'
1919
import { Placement } from 'tippy.js'
2020
import { UserGroupDTO } from '@Pages/GlobalConfigurations'
2121
import { ImageComment, ReleaseTag } from './ImageTags.Types'
22-
import { MandatoryPluginBaseStateType, RegistryType, RuntimeParamsListItemType, Severity } from '../Shared'
22+
import {
23+
MandatoryPluginBaseStateType,
24+
RegistryType,
25+
RuntimePluginVariables,
26+
Severity,
27+
} from '../Shared'
2328
import {
2429
ACTION_STATE,
25-
ConsequenceType,
2630
DEPLOYMENT_WINDOW_TYPE,
2731
DockerConfigOverrideType,
32+
RefVariableType,
2833
SortingOrder,
2934
TaskErrorObj,
35+
VariableTypeFormat,
3036
} from '.'
3137

3238
/**
@@ -125,6 +131,7 @@ export interface TippyCustomizedProps extends Pick<TippyProps, 'appendTo'> {
125131
documentationLink?: string
126132
documentationLinkText?: string
127133
children: React.ReactElement<any>
134+
disableClose?: boolean
128135
}
129136

130137
export interface InfoIconTippyProps
@@ -697,7 +704,7 @@ export interface CDMaterialsMetaInfo {
697704
* This is the ID of user that has request the material
698705
*/
699706
requestedUserId: number
700-
runtimeParams: RuntimeParamsListItemType[]
707+
runtimeParams: RuntimePluginVariables[]
701708
}
702709

703710
export interface ImagePromotionMaterialInfo {
@@ -1013,3 +1020,16 @@ export interface WidgetEventDetails {
10131020
age: string
10141021
lastSeen: string
10151022
}
1023+
1024+
export interface GlobalVariableDTO {
1025+
name: string
1026+
format: VariableTypeFormat
1027+
description: string
1028+
stageType: 'cd' | 'post-cd' | 'ci'
1029+
}
1030+
1031+
export type GlobalVariableOptionType = Omit<GlobalVariableDTO, 'name'> & {
1032+
label: string
1033+
value: string
1034+
variableType: Extract<RefVariableType, RefVariableType.GLOBAL>
1035+
}

0 commit comments

Comments
 (0)