Skip to content

Commit a61697e

Browse files
committed
feat: Enhance AppStatusModal and service functions for improved deployment status handling and data processing
1 parent 21c9226 commit a61697e

File tree

5 files changed

+194
-77
lines changed

5 files changed

+194
-77
lines changed

src/Shared/Components/AppStatusModal/AppStatusModal.component.tsx

Lines changed: 130 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,28 @@ import { GenericEmptyState } from '@Common/EmptyState'
88
import { handleUTCTime, stopPropagation, useAsync } from '@Common/Helper'
99
import { DeploymentAppTypes } from '@Common/Types'
1010
import { ComponentSizeType } from '@Shared/constants'
11+
import { AppType } from '@Shared/types'
1112

1213
import { APIResponseHandler } from '../APIResponseHandler'
1314
import { Button, ButtonComponentType, ButtonStyleType, ButtonVariantType } from '../Button'
15+
import { PROGRESSING_DEPLOYMENT_STATUS } from '../DeploymentStatusBreakdown'
1416
import { Icon } from '../Icon'
1517
import { DeploymentStatus } from '../StatusComponent'
1618
import { AppStatusBody } from './AppStatusBody'
1719
import AppStatusModalTabList from './AppStatusModalTabList'
18-
import { getAppDetails } from './service'
20+
import { getAppDetails, getDeploymentStatusWithTimeline } from './service'
1921
import { AppStatusModalProps, AppStatusModalTabType } from './types'
2022
import { getEmptyViewImageFromHelmDeploymentStatus, getShowDeploymentStatusModal } from './utils'
2123

2224
import './AppStatusModal.scss'
2325

24-
// TODO: Need to handleTabChange for appDetails view since polling is external
2526
const AppStatusModal = ({
2627
titleSegments,
2728
handleClose,
2829
type,
29-
isDeploymentTimelineLoading,
3030
appDetails: appDetailsProp,
31-
deploymentStatusDetailsBreakdownData: deploymentStatusDetailsBreakdownDataProps,
3231
processVirtualEnvironmentDeploymentData,
32+
handleUpdateDeploymentStatusDetailsBreakdownData,
3333
isConfigDriftEnabled,
3434
configDriftModal: ConfigDriftModal,
3535
appId,
@@ -39,21 +39,19 @@ const AppStatusModal = ({
3939
const [showConfigDriftModal, setShowConfigDriftModal] = useState(false)
4040
const [selectedTab, setSelectedTab] = useState<AppStatusModalTabType>(initialTab || null)
4141

42-
const abortControllerRef = useRef<AbortController>(new AbortController())
43-
const pollingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
42+
const appDetailsAbortControllerRef = useRef<AbortController>(new AbortController())
43+
const appDetailsPollingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
4444

4545
const getAppDetailsWrapper = async () => {
4646
const response = await abortPreviousRequests(
4747
() =>
4848
getAppDetails({
4949
appId,
5050
envId,
51-
abortControllerRef,
52-
deploymentStatusConfig: { showTimeline: false, processVirtualEnvironmentDeploymentData },
51+
abortControllerRef: appDetailsAbortControllerRef,
5352
}),
54-
abortControllerRef,
53+
appDetailsAbortControllerRef,
5554
)
56-
5755
return response
5856
}
5957

@@ -65,56 +63,140 @@ const AppStatusModal = ({
6563
setFetchedAppDetails,
6664
] = useAsync(getAppDetailsWrapper, [appId, envId], type === 'release')
6765

68-
const handleExternalSync = async () => {
69-
try {
70-
pollingTimeoutRef.current = setTimeout(
71-
async () => {
66+
const appDetails = type === 'release' ? fetchedAppDetails : appDetailsProp
67+
68+
const showDeploymentStatusModal = getShowDeploymentStatusModal({ type, appDetails })
69+
const deploymentStatusAbortControllerRef = useRef<AbortController>(new AbortController())
70+
const deploymentStatusPollingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)
71+
72+
const getDeploymentStatusWrapper = async () => {
73+
const response = await abortPreviousRequests(
74+
() =>
75+
getDeploymentStatusWithTimeline({
76+
abortControllerRef: deploymentStatusAbortControllerRef,
77+
appId:
78+
appDetails.appType === AppType.DEVTRON_HELM_CHART
79+
? appDetails.installedAppId
80+
: appDetails.appId,
81+
envId: appDetails.environmentId,
82+
showTimeline: selectedTab === AppStatusModalTabType.DEPLOYMENT_STATUS,
83+
virtualEnvironmentConfig: appDetails.isVirtualEnvironment
84+
? {
85+
processVirtualEnvironmentDeploymentData,
86+
wfrId: appDetails.resourceTree?.wfrId,
87+
}
88+
: null,
89+
isHelmApp: appDetails.appType === AppType.DEVTRON_HELM_CHART,
90+
}),
91+
deploymentStatusAbortControllerRef,
92+
)
93+
94+
handleUpdateDeploymentStatusDetailsBreakdownData?.(response)
95+
96+
return response
97+
}
98+
99+
const [
100+
isDeploymentTimelineLoading,
101+
deploymentStatusDetailsBreakdownData,
102+
deploymentStatusDetailsBreakdownDataError,
103+
reloadDeploymentStatusDetailsBreakdownData,
104+
setDeploymentStatusDetailsBreakdownData,
105+
] = useAsync(
106+
getDeploymentStatusWrapper,
107+
[appId, envId, showDeploymentStatusModal, selectedTab],
108+
!!showDeploymentStatusModal,
109+
)
110+
111+
const handleAppDetailsExternalSync = async () => {
112+
appDetailsPollingTimeoutRef.current = setTimeout(
113+
async () => {
114+
try {
72115
const response = await getAppDetailsWrapper()
73116
setFetchedAppDetails(response)
74-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
75-
handleExternalSync()
76-
},
77-
Number(window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL) || 30000,
78-
)
79-
} catch {
80-
// Do nothing
81-
}
117+
} catch {
118+
// Do nothing
119+
}
120+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
121+
handleAppDetailsExternalSync()
122+
},
123+
Number(window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL) || 30000,
124+
)
82125
}
83126

84-
const appDetails = type === 'release' ? fetchedAppDetails?.appDetails : appDetailsProp
85-
const deploymentStatusDetailsBreakdownData =
86-
type === 'release'
87-
? fetchedAppDetails?.deploymentStatusDetailsBreakdownData
88-
: deploymentStatusDetailsBreakdownDataProps
127+
const handleDeploymentStatusExternalSync = async () => {
128+
const isDeploymentInProgress = PROGRESSING_DEPLOYMENT_STATUS.includes(
129+
deploymentStatusDetailsBreakdownData?.deploymentStatus,
130+
)
131+
132+
const pollingIntervalFromFlag = Number(window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL) || 30000
133+
134+
deploymentStatusPollingTimeoutRef.current = setTimeout(
135+
async () => {
136+
try {
137+
const response = await getDeploymentStatusWrapper()
138+
setDeploymentStatusDetailsBreakdownData(response)
139+
} catch {
140+
// Do nothing
141+
}
142+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
143+
handleDeploymentStatusExternalSync()
144+
},
145+
isDeploymentInProgress ? 10000 : pollingIntervalFromFlag,
146+
)
147+
}
89148

90149
const areInitialAppDetailsLoadingWithAbortedError =
91150
areInitialAppDetailsLoading || getIsRequestAborted(fetchedAppDetailsError)
92151

152+
const isDeploymentStatusLoadingWithAbortedError =
153+
isDeploymentTimelineLoading || getIsRequestAborted(deploymentStatusDetailsBreakdownDataError)
154+
93155
const isTimelineRequiredAndLoading =
94-
selectedTab === AppStatusModalTabType.DEPLOYMENT_STATUS &&
95-
appDetails?.deploymentAppType !== DeploymentAppTypes.HELM &&
96-
isDeploymentTimelineLoading
156+
selectedTab === AppStatusModalTabType.DEPLOYMENT_STATUS && isDeploymentStatusLoadingWithAbortedError
97157

98158
// Adding useEffect to initiate timer for external sync and clear it on unmount
99159
useEffect(() => {
100160
if (
101161
!areInitialAppDetailsLoading &&
102162
!fetchedAppDetailsError &&
103163
fetchedAppDetails &&
104-
!pollingTimeoutRef.current
164+
!appDetailsPollingTimeoutRef.current
105165
) {
106166
// eslint-disable-next-line @typescript-eslint/no-floating-promises
107-
handleExternalSync()
167+
handleAppDetailsExternalSync()
108168
}
109169
}, [areInitialAppDetailsLoading, fetchedAppDetails, fetchedAppDetailsError])
110170

171+
useEffect(() => {
172+
if (
173+
!isDeploymentTimelineLoading &&
174+
!deploymentStatusDetailsBreakdownDataError &&
175+
deploymentStatusDetailsBreakdownData &&
176+
!deploymentStatusPollingTimeoutRef.current
177+
) {
178+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
179+
handleDeploymentStatusExternalSync()
180+
}
181+
}, [isDeploymentTimelineLoading, deploymentStatusDetailsBreakdownData, deploymentStatusDetailsBreakdownDataError])
182+
183+
const handleClearDeploymentStatusTimeout = () => {
184+
if (deploymentStatusPollingTimeoutRef.current) {
185+
clearTimeout(deploymentStatusPollingTimeoutRef.current)
186+
deploymentStatusPollingTimeoutRef.current = null
187+
}
188+
}
189+
111190
useEffect(
112191
() => () => {
113-
if (pollingTimeoutRef.current) {
114-
clearTimeout(pollingTimeoutRef.current)
192+
if (appDetailsPollingTimeoutRef.current) {
193+
clearTimeout(appDetailsPollingTimeoutRef.current)
115194
}
116195

117-
abortControllerRef.current.abort()
196+
handleClearDeploymentStatusTimeout()
197+
198+
appDetailsAbortControllerRef.current.abort()
199+
deploymentStatusAbortControllerRef.current.abort()
118200
},
119201
[],
120202
)
@@ -130,7 +212,8 @@ const AppStatusModal = ({
130212
setShowConfigDriftModal(false)
131213
}
132214

133-
const handleSelectTab = (updatedTab: AppStatusModalTabType) => {
215+
const handleSelectTab = async (updatedTab: AppStatusModalTabType) => {
216+
handleClearDeploymentStatusTimeout()
134217
setSelectedTab(updatedTab)
135218
}
136219

@@ -224,6 +307,14 @@ const AppStatusModal = ({
224307
)
225308
}
226309

310+
const timelineError =
311+
selectedTab === AppStatusModalTabType.DEPLOYMENT_STATUS ? deploymentStatusDetailsBreakdownDataError : null
312+
313+
const bodyErrorData = fetchedAppDetailsError || timelineError
314+
const bodyErrorReload = fetchedAppDetailsError
315+
? reloadInitialAppDetails
316+
: reloadDeploymentStatusDetailsBreakdownData
317+
227318
return (
228319
<Drawer position="right" width="1024px" onClose={handleClose} onEscape={handleClose}>
229320
<div
@@ -270,10 +361,10 @@ const AppStatusModal = ({
270361
progressingProps={{
271362
pageLoader: true,
272363
}}
273-
error={fetchedAppDetailsError}
364+
error={bodyErrorData}
274365
errorScreenManagerProps={{
275-
code: fetchedAppDetailsError?.code,
276-
reload: reloadInitialAppDetails,
366+
code: bodyErrorData?.code,
367+
reload: bodyErrorReload,
277368
}}
278369
>
279370
{renderContent()}

src/Shared/Components/AppStatusModal/service.ts

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,67 @@ import {
99
} from '@Shared/types'
1010

1111
import { processDeploymentStatusDetailsData } from '../DeploymentStatusBreakdown'
12-
import { GetAppDetailsParamsType } from './types'
12+
import { GetAppDetailsParamsType, GetDeploymentStatusWithTimelineParamsType } from './types'
1313

1414
export const getAppDetails = async ({
1515
appId,
1616
envId,
1717
abortControllerRef,
18-
deploymentStatusConfig,
19-
}: GetAppDetailsParamsType): Promise<{
20-
appDetails: AppDetails
21-
deploymentStatusDetailsBreakdownData: DeploymentStatusDetailsBreakdownDataType
22-
}> => {
18+
}: GetAppDetailsParamsType): Promise<AppDetails> => {
2319
try {
2420
const queryParams = getUrlWithSearchParams('', {
2521
'app-id': appId,
2622
'env-id': envId,
2723
})
2824

29-
const [appDetails, resourceTree, deploymentStatusDetails] = await Promise.all([
25+
const [appDetails, resourceTree] = await Promise.all([
3026
get<Omit<AppDetails, 'resourceTree'>>(`${ROUTES.APP_DETAIL}/v2${queryParams}`, {
3127
abortControllerRef,
3228
}),
3329
get<AppDetails['resourceTree']>(`${ROUTES.APP_DETAIL}/resource-tree${queryParams}`, {
3430
abortControllerRef,
3531
}),
36-
deploymentStatusConfig
37-
? get<DeploymentStatusDetailsType>(
38-
getUrlWithSearchParams(`${ROUTES.DEPLOYMENT_STATUS}/${appId}/${envId}`, {
39-
showTimeline: deploymentStatusConfig.showTimeline,
40-
}),
41-
)
42-
: null,
4332
])
4433

4534
return {
46-
appDetails: {
47-
...(appDetails.result || ({} as AppDetails)),
48-
resourceTree: resourceTree.result,
49-
appType: AppType.DEVTRON_APP,
50-
},
51-
deploymentStatusDetailsBreakdownData: appDetails.result?.isVirtualEnvironment
52-
? deploymentStatusConfig.processVirtualEnvironmentDeploymentData(deploymentStatusDetails.result)
53-
: processDeploymentStatusDetailsData(deploymentStatusDetails.result),
35+
...(appDetails.result || ({} as AppDetails)),
36+
resourceTree: resourceTree.result,
37+
appType: AppType.DEVTRON_APP,
38+
}
39+
} catch (error) {
40+
if (!getIsRequestAborted(error)) {
41+
showError(error)
5442
}
43+
throw error
44+
}
45+
}
46+
47+
export const getDeploymentStatusWithTimeline = async ({
48+
abortControllerRef,
49+
appId,
50+
envId,
51+
showTimeline,
52+
virtualEnvironmentConfig,
53+
isHelmApp,
54+
}: GetDeploymentStatusWithTimelineParamsType): Promise<DeploymentStatusDetailsBreakdownDataType> => {
55+
try {
56+
const baseURL = isHelmApp ? ROUTES.HELM_DEPLOYMENT_STATUS_TIMELINE_INSTALLED_APP : ROUTES.DEPLOYMENT_STATUS
57+
58+
const deploymentStatusDetailsResponse = await get<DeploymentStatusDetailsType>(
59+
getUrlWithSearchParams(`${baseURL}/${appId}/${envId}`, {
60+
showTimeline,
61+
...(virtualEnvironmentConfig && {
62+
wfrId: virtualEnvironmentConfig.wfrId,
63+
}),
64+
}),
65+
{
66+
abortControllerRef,
67+
},
68+
)
69+
70+
return virtualEnvironmentConfig
71+
? virtualEnvironmentConfig.processVirtualEnvironmentDeploymentData(deploymentStatusDetailsResponse.result)
72+
: processDeploymentStatusDetailsData(deploymentStatusDetailsResponse.result)
5573
} catch (error) {
5674
if (!getIsRequestAborted(error)) {
5775
showError(error)

0 commit comments

Comments
 (0)