Skip to content

Commit dc706e3

Browse files
committed
fix: retry failed apps
1 parent e2ad8a0 commit dc706e3

File tree

7 files changed

+83
-53
lines changed

7 files changed

+83
-53
lines changed

src/components/ApplicationGroup/AppGroup.types.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,21 @@ export interface TriggerResponseModalBodyProps {
185185
envName?: string
186186
}
187187

188-
export interface TriggerResponseModalFooterProps extends Pick<TriggerResponseModalBodyProps, 'isLoading' | 'responseList'> {
189-
onClickRetryBuild: (appsToRetry: Record<string, boolean>) => void
188+
type RetryFailedType =
189+
| {
190+
onClickRetryDeploy: BulkCDTriggerType['onClickTriggerBulkCD']
191+
skipHibernatedApps: boolean
192+
onClickRetryBuild?: never
193+
}
194+
| {
195+
onClickRetryDeploy?: never
196+
skipHibernatedApps?: never
197+
onClickRetryBuild: (appsToRetry: Record<string, boolean>) => void
198+
}
199+
200+
export type TriggerResponseModalFooterProps = Pick<TriggerResponseModalBodyProps, 'isLoading' | 'responseList'> & {
190201
closePopup: (e) => void
191-
}
202+
} & RetryFailedType
192203

193204
export interface TriggerModalRowType {
194205
rowData: ResponseRowType

src/components/ApplicationGroup/Constants.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,28 @@ export const BULK_VIRTUAL_RESPONSE_STATUS = {
6969
[BulkResponseStatus.PASS]: 'Succeeded',
7070
[BulkResponseStatus.FAIL]: 'Failed',
7171
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorised',
72+
[BulkResponseStatus.SKIP]: 'Skipped',
7273
}
7374

7475
export const BULK_CI_RESPONSE_STATUS_TEXT = {
7576
[BulkResponseStatus.PASS]: 'Build triggered',
7677
[BulkResponseStatus.FAIL]: 'Build not triggered',
7778
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorized',
79+
[BulkResponseStatus.SKIP]: 'Skipped',
7880
}
7981

8082
export const BULK_CD_RESPONSE_STATUS_TEXT = {
8183
[BulkResponseStatus.PASS]: 'Deployment triggered',
8284
[BulkResponseStatus.FAIL]: 'Deployment not triggered',
8385
[BulkResponseStatus.UNAUTHORIZE]: 'Not authorized',
86+
[BulkResponseStatus.SKIP]: 'Skipped',
8487
}
8588

8689
export const responseListOrder = {
8790
[BulkResponseStatus.FAIL]: 0,
8891
[BulkResponseStatus.UNAUTHORIZE]: 1,
89-
[BulkResponseStatus.PASS]: 2,
92+
[BulkResponseStatus.SKIP]: 2,
93+
[BulkResponseStatus.PASS]: 3,
9094
}
9195

9296
export const BULK_HIBERNATE_ERROR_MESSAGE = {

src/components/ApplicationGroup/Details/TriggerView/BulkCDTrigger.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default function BulkCDTrigger({
112112
runtimeParamsErrorState,
113113
setRuntimeParamsErrorState,
114114
}: BulkCDTriggerType) {
115-
const { deployUnhibernatedAppOnly } = useMainContext()
115+
const { fetchHelmAppStatus } = useMainContext()
116116
const [selectedApp, setSelectedApp] = useState<BulkCDDetailType>(
117117
appList.find((app) => !app.warningMessage) || appList[0],
118118
)
@@ -129,7 +129,7 @@ export default function BulkCDTrigger({
129129
const [isPartialActionAllowed, setIsPartialActionAllowed] = useState(false)
130130
const [showResistanceBox, setShowResistanceBox] = useState(false)
131131
const [currentSidebarTab, setCurrentSidebarTab] = useState<CDMaterialSidebarType>(CDMaterialSidebarType.IMAGE)
132-
const [skipHibernated, setSkipHibernated] = useState<boolean>(false)
132+
const [skipHibernatedApps, setSkipHibernatedApps] = useState<boolean>(false)
133133

134134
const location = useLocation()
135135
const history = useHistory()
@@ -356,7 +356,7 @@ export default function BulkCDTrigger({
356356
const renderHeaderSection = (): JSX.Element => {
357357
return (
358358
<div className="flex flex-align-center flex-justify dc__border-bottom bg__primary pt-16 pr-20 pb-16 pl-20">
359-
<h2 className="fs-16 fw-6 lh-1-5 m-0">Deploy to {appList[0].envName}</h2>
359+
<h2 className="fs-16 fw-6 lh-1-5 m-0 dc__truncate">Deploy to {appList[0].envName}</h2>
360360
<Button
361361
dataTestId="bulk-cd-modal-close"
362362
disabled={isLoading}
@@ -837,15 +837,13 @@ export default function BulkCDTrigger({
837837
setShowResistanceBox(false)
838838
}
839839

840-
const triggerBulkCD = () => onClickTriggerBulkCD(skipHibernated)
841-
842840
const onClickStartDeploy = (e): void => {
843841
if (isPartialActionAllowed && BulkDeployResistanceTippy && !showResistanceBox) {
844842
setShowResistanceBox(true)
845843
} else {
846844
isBulkDeploymentTriggered.current = true
847845
stopPropagation(e)
848-
triggerBulkCD()
846+
onClickTriggerBulkCD(skipHibernatedApps)
849847
setShowResistanceBox(false)
850848
}
851849
}
@@ -858,7 +856,8 @@ export default function BulkCDTrigger({
858856

859857
const renderFooterSection = (): JSX.Element => {
860858
const isDeployButtonDisabled: boolean = isDeployDisabled()
861-
const showSkipHibernatedCheckbox = stage === DeploymentNodeType.CD && !!SkipHibernatedCheckbox && deployUnhibernatedAppOnly
859+
const showSkipHibernatedCheckbox =
860+
stage === DeploymentNodeType.CD && !!SkipHibernatedCheckbox && fetchHelmAppStatus
862861
return (
863862
<div
864863
className={`dc__border-top flex ${showSkipHibernatedCheckbox ? 'dc__content-space' : 'right'} bg__primary px-20 py-16`}
@@ -869,8 +868,8 @@ export default function BulkCDTrigger({
869868
envId={appList[0].envId}
870869
envName={appList[0].envName}
871870
appIds={appList.map((app) => app.appId)}
872-
skipHibernated={skipHibernated}
873-
setSkipHibernated={setSkipHibernated}
871+
skipHibernated={skipHibernatedApps}
872+
setSkipHibernated={setSkipHibernatedApps}
874873
/>
875874
)}
876875
<div className="dc__position-rel tippy-over">
@@ -915,7 +914,8 @@ export default function BulkCDTrigger({
915914
closePopup={closeBulkCDModal}
916915
responseList={responseList}
917916
isLoading={isLoading}
918-
onClickRetryBuild={triggerBulkCD}
917+
onClickRetryDeploy={onClickTriggerBulkCD}
918+
skipHibernatedApps={skipHibernatedApps}
919919
/>
920920
) : (
921921
renderFooterSection()

src/components/ApplicationGroup/Details/TriggerView/EnvTriggerView.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
ButtonStyleType,
5656
ButtonVariantType,
5757
ComponentSizeType,
58+
API_STATUS_CODES,
5859
} from '@devtron-labs/devtron-fe-common-lib'
5960
import Tippy from '@tippyjs/react'
6061
import { BUILD_STATUS, DEFAULT_GIT_BRANCH_VALUE, NO_COMMIT_SELECTED, URLS, ViewType } from '../../../../config'
@@ -1545,18 +1546,18 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
15451546
})
15461547
} else {
15471548
const errorReason = response.reason
1548-
if (errorReason.code === 409) {
1549+
if (errorReason.code === API_STATUS_CODES.EXPECTATION_FAILED) {
15491550
const statusType = filterStatusType(
15501551
type,
1551-
BULK_CI_RESPONSE_STATUS_TEXT[BulkResponseStatus.FAIL],
1552-
BULK_VIRTUAL_RESPONSE_STATUS[BulkResponseStatus.FAIL],
1553-
BULK_CD_RESPONSE_STATUS_TEXT[BulkResponseStatus.FAIL],
1552+
BULK_CI_RESPONSE_STATUS_TEXT[BulkResponseStatus.SKIP],
1553+
BULK_VIRTUAL_RESPONSE_STATUS[BulkResponseStatus.SKIP],
1554+
BULK_CD_RESPONSE_STATUS_TEXT[BulkResponseStatus.SKIP],
15541555
)
15551556
_responseList.push({
15561557
appId: triggeredAppList[index].appId,
15571558
appName: triggeredAppList[index].appName,
15581559
statusText: statusType,
1559-
status: BulkResponseStatus.FAIL,
1560+
status: BulkResponseStatus.SKIP,
15601561
message: errorReason.errors[0].internalMessage,
15611562
})
15621563
} else if (errorReason.code === 403 || errorReason.code === 422) {

src/components/ApplicationGroup/Details/TriggerView/TriggerResponseModal.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ export const TriggerResponseModalFooter = ({
3333
closePopup,
3434
isLoading,
3535
responseList,
36+
skipHibernatedApps,
3637
onClickRetryBuild,
38+
onClickRetryDeploy,
3739
}: TriggerResponseModalFooterProps) => {
3840
const isShowRetryButton = responseList?.some((response) => response.status === BulkResponseStatus.FAIL)
3941

@@ -45,7 +47,12 @@ export const TriggerResponseModalFooter = ({
4547
appsToRetry[response.appId] = true
4648
}
4749
})
48-
onClickRetryBuild(appsToRetry)
50+
51+
if (onClickRetryBuild) {
52+
onClickRetryBuild(appsToRetry)
53+
} else {
54+
onClickRetryDeploy(skipHibernatedApps, appsToRetry)
55+
}
4956
}
5057

5158
return (

src/components/common/navigation/NavigationRoutes.tsx

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ import 'monaco-editor'
7777
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
7878
import YamlWorker from '../../../yaml.worker.js?worker'
7979
import { TAB_DATA_LOCAL_STORAGE_KEY } from '../DynamicTabs/constants'
80-
import { DEFAULT_GIT_OPS_FEATURE_FLAGS } from './constants'
80+
import { ENVIRONMENT_DATA_FALLBACK, INITIAL_ENV_DATA_STATE } from './constants'
8181
import { ParsedTabsData, ParsedTabsDataV1 } from '../DynamicTabs/types'
8282
import { SwitchThemeDialog } from '@Pages/Shared'
8383
import { SwitchThemeDialogProps } from '@Pages/Shared/SwitchThemeDialog/types'
@@ -152,17 +152,11 @@ export default function NavigationRoutes() {
152152
}
153153
const [environmentId, setEnvironmentId] = useState(null)
154154
const contextValue = useMemo(() => ({ environmentId, setEnvironmentId }), [environmentId])
155-
const [environmentDataState, setEnvironmentDataState] = useState<EnvironmentDataStateType>({
156-
isAirgapped: false,
157-
isManifestScanningEnabled: false,
158-
canOnlyViewPermittedEnvOrgLevel: false,
159-
featureGitOpsFlags: structuredClone(DEFAULT_GIT_OPS_FEATURE_FLAGS),
160-
deployUnhibernatedAppOnly: false,
161-
devtronManagedLicensingEnabled: false,
162-
})
163155

164156
const { showThemeSwitcherDialog, handleThemeSwitcherDialogVisibilityChange, appTheme } = useTheme()
165157

158+
const [environmentDataState, setEnvironmentDataState] = useState<EnvironmentDataStateType>(INITIAL_ENV_DATA_STATE)
159+
const [licenseInfoDialogType, setLicenseInfoDialogType] = useState<LicenseInfoDialogType>(null)
166160
const {
167161
userPreferences,
168162
userPreferencesError,
@@ -171,9 +165,6 @@ export default function NavigationRoutes() {
171165
handleUpdatePipelineRBACViewSelectedTab,
172166
} = useUserPreferences({ migrateUserPreferences })
173167

174-
const [licenseInfoDialogType, setLicenseInfoDialogType] = useState<LicenseInfoDialogType>(null)
175-
176-
177168
const { isAirgapped, isManifestScanningEnabled, canOnlyViewPermittedEnvOrgLevel, devtronManagedLicensingEnabled } =
178169
environmentDataState
179170

@@ -339,37 +330,33 @@ export default function NavigationRoutes() {
339330
}
340331

341332
const getEnvironmentDataValues = async (): Promise<EnvironmentDataValuesDTO> => {
342-
const fallbackResponse: EnvironmentDataValuesDTO = {
343-
isAirGapEnvironment: false,
344-
isManifestScanningEnabled: false,
345-
canOnlyViewPermittedEnvOrgLevel: false,
346-
featureGitOpsFlags: structuredClone(DEFAULT_GIT_OPS_FEATURE_FLAGS),
347-
deployUnhibernatedAppOnly: false,
348-
devtronManagedLicensingEnabled: false,
349-
}
350-
351333
if (!getEnvironmentData) {
352-
return fallbackResponse
334+
return ENVIRONMENT_DATA_FALLBACK
353335
}
354336

355337
try {
356338
const { result } = await getEnvironmentData()
357-
const parsedFeatureGitOpsFlags: typeof fallbackResponse.featureGitOpsFlags = {
339+
const parsedFeatureGitOpsFlags: typeof ENVIRONMENT_DATA_FALLBACK.featureGitOpsFlags = {
358340
isFeatureArgoCdMigrationEnabled: result.featureGitOpsFlags?.isFeatureArgoCdMigrationEnabled || false,
359341
isFeatureGitOpsEnabled: result.featureGitOpsFlags?.isFeatureGitOpsEnabled || false,
360342
isFeatureUserDefinedGitOpsEnabled:
361343
result.featureGitOpsFlags?.isFeatureUserDefinedGitOpsEnabled || false,
362344
}
363345
return {
364-
isAirGapEnvironment: result.isAirGapEnvironment,
365-
isManifestScanningEnabled: result.isManifestScanningEnabled,
366-
canOnlyViewPermittedEnvOrgLevel: result.canOnlyViewPermittedEnvOrgLevel,
346+
isAirGapEnvironment: result.isAirGapEnvironment ?? ENVIRONMENT_DATA_FALLBACK['isAirGapEnvironment'],
347+
isManifestScanningEnabled:
348+
result.isManifestScanningEnabled ?? ENVIRONMENT_DATA_FALLBACK['isManifestScanningEnabled'],
349+
canOnlyViewPermittedEnvOrgLevel:
350+
result.canOnlyViewPermittedEnvOrgLevel ??
351+
ENVIRONMENT_DATA_FALLBACK['canOnlyViewPermittedEnvOrgLevel'],
367352
featureGitOpsFlags: parsedFeatureGitOpsFlags,
368-
deployUnhibernatedAppOnly: result.deployUnhibernatedAppOnly ?? false,
369-
devtronManagedLicensingEnabled: result.devtronManagedLicensingEnabled || false,
353+
fetchHelmAppStatus: result.fetchHelmAppStatus ?? ENVIRONMENT_DATA_FALLBACK['fetchHelmAppStatus'],
354+
devtronManagedLicensingEnabled:
355+
result.devtronManagedLicensingEnabled ??
356+
ENVIRONMENT_DATA_FALLBACK['devtronManagedLicensingEnabled'],
370357
}
371358
} catch {
372-
return fallbackResponse
359+
return ENVIRONMENT_DATA_FALLBACK
373360
}
374361
}
375362

@@ -389,7 +376,7 @@ export default function NavigationRoutes() {
389376
isManifestScanningEnabled: environmentDataResponse.isManifestScanningEnabled,
390377
canOnlyViewPermittedEnvOrgLevel: environmentDataResponse.canOnlyViewPermittedEnvOrgLevel,
391378
featureGitOpsFlags: environmentDataResponse.featureGitOpsFlags,
392-
deployUnhibernatedAppOnly: environmentDataResponse.deployUnhibernatedAppOnly,
379+
fetchHelmAppStatus: environmentDataResponse.fetchHelmAppStatus,
393380
devtronManagedLicensingEnabled: environmentDataResponse.devtronManagedLicensingEnabled,
394381
})
395382

@@ -496,7 +483,7 @@ export default function NavigationRoutes() {
496483
handleOpenLicenseInfoDialog,
497484
licenseData,
498485
setLicenseData,
499-
deployUnhibernatedAppOnly: environmentDataState.deployUnhibernatedAppOnly,
486+
fetchHelmAppStatus: environmentDataState.fetchHelmAppStatus,
500487
}}
501488
>
502489
<main className={_isOnboardingPage ? 'no-nav' : ''} id={DEVTRON_BASE_MAIN_ID}>

src/components/common/navigation/constants.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,30 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { MainContext } from '@devtron-labs/devtron-fe-common-lib'
17+
import { EnvironmentDataValuesDTO, MainContext } from '@devtron-labs/devtron-fe-common-lib'
1818

19-
export const DEFAULT_GIT_OPS_FEATURE_FLAGS: MainContext['featureGitOpsFlags'] = {
19+
import { EnvironmentDataStateType } from './types'
20+
21+
const DEFAULT_GIT_OPS_FEATURE_FLAGS: MainContext['featureGitOpsFlags'] = {
2022
isFeatureArgoCdMigrationEnabled: false,
2123
isFeatureGitOpsEnabled: false,
2224
isFeatureUserDefinedGitOpsEnabled: false,
2325
}
26+
27+
const COMMON_ENV_FALLBACK: Omit<EnvironmentDataValuesDTO, 'isAirGapEnvironment'> = {
28+
isManifestScanningEnabled: false,
29+
canOnlyViewPermittedEnvOrgLevel: false,
30+
featureGitOpsFlags: structuredClone(DEFAULT_GIT_OPS_FEATURE_FLAGS),
31+
fetchHelmAppStatus: false,
32+
devtronManagedLicensingEnabled: false,
33+
}
34+
35+
export const ENVIRONMENT_DATA_FALLBACK: EnvironmentDataValuesDTO = {
36+
...COMMON_ENV_FALLBACK,
37+
isAirGapEnvironment: false,
38+
}
39+
40+
export const INITIAL_ENV_DATA_STATE: EnvironmentDataStateType = {
41+
...COMMON_ENV_FALLBACK,
42+
isAirgapped: ENVIRONMENT_DATA_FALLBACK.isAirGapEnvironment,
43+
}

0 commit comments

Comments
 (0)