Skip to content

Commit cb8a5c9

Browse files
committed
Merge branch 'develop' of https://github.com/devtron-labs/dashboard into feat/app-status-modal
2 parents c53b62b + aaf4f3a commit cb8a5c9

Some content is hidden

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

50 files changed

+1350
-1058
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ src/components/ApplicationGroup/SearchBar.tsx
3636
src/components/CIPipelineN/AdvancedConfigOptions.tsx
3737
src/components/CIPipelineN/Build.tsx
3838
src/components/CIPipelineN/CIPipeline.tsx
39-
src/components/CIPipelineN/ConditionContainer.tsx
4039
src/components/CIPipelineN/CustomImageTags.tsx
4140
src/components/CIPipelineN/CustomInputOutputVariables.tsx
4241
src/components/CIPipelineN/CustomInputVariableSelect.tsx

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "1.12.0-pre-0",
7+
"@devtron-labs/devtron-fe-common-lib": "1.12.0-pre-2",
88
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
99
"@rjsf/core": "^5.13.3",
1010
"@rjsf/utils": "^5.13.3",

src/Pages/Shared/ConfigMapSecret/ConfigMapSecretData.tsx

Lines changed: 16 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@ import {
2828
convertKeyValuePairToYAML,
2929
convertYAMLToKeyValuePair,
3030
isCodeMirrorEnabled,
31-
KeyValueConfig,
3231
KeyValueTable,
32+
KeyValueTableData,
3333
MODES,
3434
noop,
3535
OverrideMergeStrategyType,
36-
PATTERNS,
3736
SelectPickerOptionType,
3837
StyledRadioGroup,
3938
ToastManager,
@@ -57,6 +56,8 @@ import { externalTypeSecretCodeEditorDataHeaders, renderYamlInfoText } from './h
5756
import { ConfigMapSecretDataProps } from './types'
5857
import {
5958
getCMCSExpressEditComparisonDataDiffConfig,
59+
getConfigMapSecretKeyValueTableRows,
60+
getConfigMapSecretKeyValueTableValidationSchema,
6061
getExpressEditComparisonViewLHS,
6162
getLockedYamlString,
6263
} from './utils'
@@ -99,81 +100,16 @@ export const ConfigMapSecretData = ({
99100
const isSelectedTypeVolume =
100101
data.externalType === '' && data.selectedType === configMapSecretMountDataMap.volume.value
101102

102-
// METHODS & CONFIGURATIONS
103-
const config: KeyValueConfig<'k' | 'v'> = {
104-
headers: [
105-
{
106-
label: isSelectedTypeVolume ? 'File Name' : 'Key',
107-
key: 'k',
108-
},
109-
{
110-
label: isSelectedTypeVolume ? 'File Content' : 'Value',
111-
key: 'v',
112-
},
113-
],
114-
rows: data.currentData.map(({ k, v, id }) => ({
115-
data: {
116-
k: {
117-
value: k,
118-
},
119-
v: {
120-
value: typeof v === 'object' ? YAMLStringify(v) : v.toString(),
121-
},
122-
},
123-
id,
124-
})),
125-
}
126-
103+
// METHODS
127104
const onMergeStrategySelect = (newValue: SelectPickerOptionType) => {
128105
handleMergeStrategyChange(newValue.value as OverrideMergeStrategyType)
129106
}
130107

131-
const keyValueTableHandleChange =
132-
(onChange: (value: unknown) => void) => (rowId: string | number, headerKey: string, value: string) => {
133-
// - When data is changed from the YAML editor to the GUI, IDs are mapped to indices (numbers).
134-
// - When data is added via the GUI, IDs are created internally by the GUI editor as strings.
135-
const _currentData = data.currentData.reduce(
136-
(acc, currentData) => {
137-
if (currentData.id === rowId) {
138-
// If the item is found, update it with the new value and reset errors.
139-
acc.found = true
140-
acc.updatedData.push({
141-
...currentData,
142-
[headerKey]: value,
143-
})
144-
} else {
145-
// If the item is not the one we're looking for, just add it as is.
146-
acc.updatedData.push(currentData)
147-
}
148-
return acc
149-
},
150-
{ updatedData: [], found: false },
151-
)
152-
153-
// If the item is not found, it means it's a new entry added via the GUI editor.
154-
// Create a new data object and add it to the current data state.
155-
if (!_currentData.found) {
156-
_currentData.updatedData.push({
157-
k: '',
158-
v: '',
159-
[headerKey]: value,
160-
id: rowId,
161-
})
162-
}
163-
164-
// call useForm register 'onChange' method to update the form data value
165-
onChange(_currentData.updatedData)
166-
// Convert the current key-value data to YAML format and set it in the 'yaml' field.
167-
setValue('yaml', convertKeyValuePairToYAML(_currentData.updatedData), { shouldDirty: true })
168-
}
169-
170-
const keyValueHandleDelete = (onChange: (e: unknown) => void) => (rowId: string | number) => {
171-
// Create a new array by filtering out the item with the matching rowId.
172-
const _currentData = data.currentData.filter(({ id }) => id !== rowId)
108+
const keyValueTableHandleChange = (onChange: (value: unknown) => void) => (keyValueData: KeyValueTableData[]) => {
173109
// call useForm register 'onChange' method to update the form data value
174-
onChange(_currentData)
110+
onChange(keyValueData)
175111
// Convert the current key-value data to YAML format and set it in the 'yaml' field.
176-
setValue('yaml', convertKeyValuePairToYAML(_currentData), { shouldDirty: true })
112+
setValue('yaml', convertKeyValuePairToYAML(keyValueData), { shouldDirty: true })
177113
}
178114

179115
const keyValueHandleError = (err: boolean) => {
@@ -467,28 +403,21 @@ export const ConfigMapSecretData = ({
467403
isAdditionNotAllowed={secretMode || data.yamlMode || data.external}
468404
readOnly={readOnly || secretMode}
469405
isSortable
470-
config={config}
406+
headerLabel={{
407+
key: isSelectedTypeVolume ? 'File Name' : 'Key',
408+
value: isSelectedTypeVolume ? 'File Content' : 'Value',
409+
}}
410+
rows={getConfigMapSecretKeyValueTableRows(data.currentData)}
471411
placeholder={{
472-
k: 'Enter Key',
473-
v: 'Enter Value',
412+
key: 'Enter Key',
413+
value: 'Enter Value',
474414
}}
475415
onChange={keyValueTableHandleChange(onChange)}
476416
maskValue={{
477-
v: isLocked,
417+
value: isLocked,
478418
}}
479-
onDelete={keyValueHandleDelete(onChange)}
480419
showError
481-
validationSchema={(value, key) => {
482-
if (key === 'k' && value) {
483-
const isValid = new RegExp(PATTERNS.CONFIG_MAP_AND_SECRET_KEY).test(value)
484-
return isValid
485-
}
486-
return true
487-
}}
488-
errorMessages={[
489-
'Can only contain alphanumeric chars and ( - ), ( _ ), ( . )',
490-
'Spaces not allowed',
491-
]}
420+
validationSchema={getConfigMapSecretKeyValueTableValidationSchema}
492421
onError={keyValueHandleError}
493422
headerComponent={renderSecretShowHide(false)}
494423
validateEmptyKeys

src/Pages/Shared/ConfigMapSecret/utils.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ import {
3939
getConfigMapSecretPayload,
4040
getSecretDataTypeOptions,
4141
getSelectPickerOptionByValue,
42+
KeyValueTableData,
43+
KeyValueTableProps,
4244
OverrideMergeStrategyType,
45+
PATTERNS,
4346
SelectPickerOptionType,
4447
YAMLStringify,
4548
} from '@devtron-labs/devtron-fe-common-lib'
@@ -398,6 +401,30 @@ export const getConfigMapSecretDataType = (
398401
: (getSelectPickerOptionByValue(getSecretDataTypeOptions(false, true), externalType).label as string)
399402
}
400403

404+
export const getConfigMapSecretKeyValueTableRows = (data: KeyValueTableData[]): KeyValueTableProps['rows'] =>
405+
data.map(({ key, value, id }) => ({
406+
data: {
407+
key: {
408+
value: key,
409+
},
410+
value: {
411+
value: typeof value === 'object' ? YAMLStringify(value) : value.toString(),
412+
},
413+
},
414+
id,
415+
}))
416+
417+
export const getConfigMapSecretKeyValueTableValidationSchema: KeyValueTableProps['validationSchema'] = (value, key) => {
418+
if (key === 'key' && value) {
419+
const isValid = new RegExp(PATTERNS.CONFIG_MAP_AND_SECRET_KEY).test(value)
420+
return {
421+
isValid,
422+
errorMessages: ['Can only contain alphanumeric chars and ( - ), ( _ ), ( . )', 'Spaces not allowed'],
423+
}
424+
}
425+
return { isValid: true }
426+
}
427+
401428
export const shouldHidePatchOption = (configMapSecretData: CMSecretConfigData, isJob: boolean) =>
402429
isJob || configMapSecretData?.external || false
403430

src/components/ApplicationGroup/AppGroupDetailsRoute.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import EnvironmentOverview from './Details/EnvironmentOverview/EnvironmentOvervi
5757
import { EnvSelector } from './EnvSelector'
5858
import EmptyFolder from '../../assets/img/empty-folder.webp'
5959
import { AppFilterTabs, EMPTY_LIST_MESSAGING, ENV_APP_GROUP_GA_EVENTS, NO_ACCESS_TOAST_MESSAGE } from './Constants'
60-
import { ReactComponent as Settings } from '../../assets/icons/ic-settings.svg'
60+
import { ReactComponent as ICSlidersVertical } from '@Icons/ic-sliders-vertical.svg'
6161
import {
6262
deleteEnvGroup,
6363
getAppGroupList,
@@ -84,6 +84,7 @@ import EnvCDDetails from './Details/EnvCDDetails/EnvCDDetails'
8484
import '../app/details/app.scss'
8585
import { CONTEXT_NOT_AVAILABLE_ERROR, DeleteComponentsName } from '../../config/constantMessaging'
8686
import CreateAppGroup from './CreateAppGroup'
87+
import AppDetail from '@Components/app/details/appDetails/AppDetails'
8788

8889
export const AppGroupAppFilterContext = React.createContext<AppGroupAppFilterContextType>(null)
8990

@@ -422,9 +423,6 @@ export default function AppGroupDetailsRoute({ isSuperAdmin }: AppGroupAdminType
422423
<ErrorBoundary>
423424
<Suspense fallback={<Progressing pageLoader />}>
424425
<Switch>
425-
<Route path={`${path}/${URLS.APP_DETAILS}`}>
426-
<div>Env detail</div>
427-
</Route>
428426
<Route path={`${path}/${URLS.APP_OVERVIEW}`}>
429427
<EnvironmentOverview
430428
filteredAppIds={_filteredAppsIds}
@@ -435,6 +433,9 @@ export default function AppGroupDetailsRoute({ isSuperAdmin }: AppGroupAdminType
435433
description={description}
436434
/>
437435
</Route>
436+
<Route path={`${path}${URLS.DETAILS}/:appId(\\d+)?`}>
437+
<AppDetail detailsType="app-group" filteredResourceIds={_filteredAppsIds} />
438+
</Route>
438439
<Route path={`${path}/${URLS.APP_TRIGGER}`}>
439440
<EnvTriggerView filteredAppIds={_filteredAppsIds} isVirtualEnv={isVirtualEnv} />
440441
</Route>
@@ -630,6 +631,16 @@ export const EnvHeader = ({
630631
onClick: (event) => handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.OverviewClicked.action),
631632
},
632633
},
634+
{
635+
id: 'env-app-details-tab',
636+
label: 'App Details',
637+
tabType: 'navLink',
638+
props: {
639+
to: `${match.url}${URLS.DETAILS}`,
640+
onClick: (event) =>
641+
handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.EnvDetailsClicked.action),
642+
},
643+
},
633644
{
634645
id: 'build-&-deploy-tab',
635646
label: 'Build & Deploy',
@@ -664,7 +675,7 @@ export const EnvHeader = ({
664675
id: 'group-configurations-tab',
665676
label: 'Configurations',
666677
tabType: 'navLink',
667-
icon: Settings,
678+
icon: ICSlidersVertical,
668679
props: {
669680
to: `${match.url}/${CommonURLS.APP_CONFIG}`,
670681
onClick: (event) =>

src/components/ApplicationGroup/Constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ export const ENV_APP_GROUP_GA_EVENTS = {
161161
category: 'Environment',
162162
action: 'Overview Clicked',
163163
},
164+
EnvDetailsClicked: {
165+
category: 'Environment',
166+
action: 'App group App Details Clicked',
167+
},
164168
BuildDeployClicked: {
165169
category: 'Environment',
166170
action: 'Build & Deploy Clicked',

src/components/ApplicationGroup/Details/EnvironmentOverview/EnvironmentOverview.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { useHistory, useParams } from 'react-router-dom'
3333
import { HibernateModal } from './HibernateModal'
3434
import HibernateStatusListDrawer from './HibernateStatusListDrawer'
3535
import { RestartWorkloadModal } from './RestartWorkloadModal'
36-
import { Moment12HourFormat } from '../../../../config'
36+
import { Moment12HourFormat, URLS } from '../../../../config'
3737
import { importComponentFromFELibrary } from '../../../common'
3838
import { getDeploymentStatus } from '../../AppGroup.service'
3939
import {
@@ -198,9 +198,9 @@ export default function EnvironmentOverview({
198198
}
199199

200200
const getDeploymentHistoryLink = (appId: number, pipelineId: number) =>
201-
`/application-group/${envId}/cd-details/${appId}/${pipelineId}/`
201+
`${URLS.APPLICATION_GROUP}/${envId}/cd-details/${appId}/${pipelineId}/`
202202

203-
const getAppRedirectLink = (appId: number, envId: number) => `/app/${appId}/details/${envId}`
203+
const getAppRedirectLink = (appId: number, envId: number) => `${URLS.APPLICATION_GROUP}/${envId}${URLS.DETAILS}/${appId}`
204204

205205
const parseAppListData = (
206206
data: AppGroupListType,

src/components/ApplicationGroup/List/EnvironmentListView.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
ToastVariantType,
2626
} from '@devtron-labs/devtron-fe-common-lib'
2727

28+
import { URLS } from '@Config/routes'
29+
2830
import { useAppContext } from '../../common'
2931
import { EnvApp, EnvAppList, EnvironmentLinkProps, EnvironmentsListViewType } from '../AppGroup.types'
3032
import { EMPTY_LIST_MESSAGING, GROUP_LIST_HEADER, NO_ACCESS_TOAST_MESSAGE } from '../Constants'
@@ -48,7 +50,7 @@ const EnvironmentLink = ({
4850
return (
4951
<NavLink
5052
data-testid={`${namespace}-click-on-env`}
51-
to={`/application-group/${environmentId}`}
53+
to={`${URLS.APPLICATION_GROUP}/${environmentId}`}
5254
data-noapp={!appCount}
5355
onClick={handleOnLinkRedirection}
5456
>

src/components/CIPipelineN/AdvancedConfigOptions.tsx

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

17-
import React, { useContext, useEffect, useState } from 'react'
18-
import { CIBuildConfigType, CIBuildType, noop } from '@devtron-labs/devtron-fe-common-lib'
17+
import { useContext, useEffect, useState } from 'react'
18+
import { CIBuildConfigType, CIBuildType, KeyValueTableProps, noop } from '@devtron-labs/devtron-fe-common-lib'
1919
import CIConfig from '../ciConfig/CIConfig'
2020
import DockerArgs from './DockerArgs'
2121
import CustomImageTags from './CustomImageTags'
@@ -24,7 +24,6 @@ import { ComponentStates } from '../../Pages/Shared/EnvironmentOverride/Environm
2424
import { AdvancedConfigOptionsProps, CIConfigParentState } from '../ciConfig/types'
2525
import { DockerConfigOverrideKeys } from '../ciPipeline/types'
2626
import { OptionType } from '../app/types'
27-
import { DockerArgsAction, HandleDockerArgsUpdateType } from './types'
2827
import { getTargetPlatformMap } from '../ciConfig/CIConfig.utils'
2928
import { pipelineContext } from '../workflowEditor/workflowEditor'
3029
import '../ciConfig/CIConfig.scss'
@@ -83,32 +82,22 @@ export default function AdvancedConfigOptions({ ciPipeline, appId, isTemplateVie
8382
}
8483

8584
// All updates to docker args will be handled here, which will will be further merged into formData on introduction of reducer
86-
const handleDockerArgsUpdate = ({ action, argData }: HandleDockerArgsUpdateType) => {
85+
const handleDockerArgsUpdate: KeyValueTableProps['onChange'] = (args) => {
8786
setFormData((prevFormData) => {
8887
const _form = structuredClone(prevFormData)
89-
90-
switch (action) {
91-
case DockerArgsAction.ADD:
92-
_form.args.unshift({ key: '', value: '' })
93-
break
94-
95-
case DockerArgsAction.UPDATE_KEY:
96-
_form.args[argData.index]['key'] = argData.value
97-
break
98-
99-
case DockerArgsAction.UPDATE_VALUE:
100-
_form.args[argData.index]['value'] = argData.value
101-
break
102-
103-
case DockerArgsAction.DELETE:
104-
_form.args = _form.args.filter((_, index) => index !== argData.index)
105-
break
106-
}
88+
_form.args = args
10789

10890
return _form
10991
})
11092
}
11193

94+
const handleDockerArgsError: KeyValueTableProps['onError'] = (errorState) => {
95+
setFormDataErrorObj({
96+
...formDataErrorObj,
97+
dockerArgsError: { isValid: !errorState, message: 'Invalid docker build arguments' },
98+
})
99+
}
100+
112101
const updateDockerConfigOverride = (
113102
key: string,
114103
value: CIBuildConfigType | OptionType[] | boolean | string,
@@ -238,7 +227,11 @@ export default function AdvancedConfigOptions({ ciPipeline, appId, isTemplateVie
238227
)}
239228

240229
{showNonBuildpackOptions && (
241-
<DockerArgs args={formData.args} handleDockerArgsUpdate={handleDockerArgsUpdate} />
230+
<DockerArgs
231+
args={formData.args}
232+
handleDockerArgsUpdate={handleDockerArgsUpdate}
233+
handleDockerArgsError={handleDockerArgsError}
234+
/>
242235
)}
243236
</div>
244237
</div>

0 commit comments

Comments
 (0)