Skip to content

Commit fd34959

Browse files
committed
fix: review comments
1 parent c02b976 commit fd34959

File tree

11 files changed

+97
-63
lines changed

11 files changed

+97
-63
lines changed

src/Common/Helper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,7 @@ const getAppTypeCategory = (appType: AppType) => {
11241124
export const getAIAnalyticsEvents = (context: string, appType?: AppType) =>
11251125
`AI_${appType ? `${getAppTypeCategory(appType)}_` : ''}${context}`
11261126

1127-
export const findRight = <T,>(arr: T[], predicate: (item: T) => boolean): T => {
1127+
export const findRight = <T,>(arr: T[], predicate: (item: T) => boolean): T | null => {
11281128
for (let i = arr.length - 1; i >= 0; i--) {
11291129
if (predicate(arr[i])) {
11301130
return arr[i]

src/Shared/Components/AppStatusModal/AppStatusBody.tsx

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ComponentProps, PropsWithChildren, ReactNode } from 'react'
1+
import { ComponentProps, ReactNode } from 'react'
22

33
import { getAIAnalyticsEvents } from '@Common/Helper'
44
import { Tooltip } from '@Common/Tooltip'
@@ -13,7 +13,7 @@ import { ShowMoreText } from '../ShowMoreText'
1313
import { AppStatus, DeploymentStatus, StatusType } from '../StatusComponent'
1414
import AppStatusContent from './AppStatusContent'
1515
import { APP_STATUS_CUSTOM_MESSAGES } from './constants'
16-
import { AppStatusBodyProps, AppStatusModalTabType } from './types'
16+
import { AppStatusBodyProps, AppStatusModalTabType, StatusHeadingContainerProps } from './types'
1717
import { getAppStatusMessageFromAppDetails } from './utils'
1818

1919
const InfoCardItem = ({ heading, value, isLast = false }: { heading: string; value: ReactNode; isLast?: boolean }) => (
@@ -37,17 +37,7 @@ const InfoCardItem = ({ heading, value, isLast = false }: { heading: string; val
3737
</div>
3838
)
3939

40-
const StatusHeadingContainer = ({
41-
children,
42-
type,
43-
appId,
44-
envId,
45-
actionItem,
46-
}: PropsWithChildren<Pick<AppStatusBodyProps, 'type'>> & {
47-
appId: number
48-
envId?: number
49-
actionItem?: ReactNode
50-
}) => (
40+
const StatusHeadingContainer = ({ children, type, appId, envId, actionItem }: StatusHeadingContainerProps) => (
5141
<div className="flexbox dc__content-space w-100">
5242
{children}
5343

@@ -96,7 +86,7 @@ export const AppStatusBody = ({
9686

9787
return [
9888
{
99-
id: `app-status-block${1}`,
89+
id: 'app-status-row',
10090
heading: type !== 'stack-manager' ? 'Application Status' : 'Status',
10191
value: (
10292
<StatusHeadingContainer
@@ -129,7 +119,7 @@ export const AppStatusBody = ({
129119
...(message
130120
? [
131121
{
132-
id: `app-status-block${2}`,
122+
id: 'app-status-primary-message',
133123
heading: 'Message',
134124
value: message,
135125
},
@@ -138,7 +128,7 @@ export const AppStatusBody = ({
138128
...(customMessage
139129
? [
140130
{
141-
id: `app-status-block${3}`,
131+
id: 'app-status-secondary-message',
142132
heading: 'Message',
143133
value: customMessage,
144134
},
@@ -152,7 +142,7 @@ export const AppStatusBody = ({
152142
? getAppStatusInfoCardItems()
153143
: [
154144
{
155-
id: `deployment-status-block-${1}`,
145+
id: 'deployment-status-row',
156146
heading: 'Deployment Status',
157147
value: (
158148
<StatusHeadingContainer type={type} appId={appDetails.appId} envId={appDetails.environmentId}>

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { Drawer } from '@Common/Drawer'
77
import { GenericEmptyState } from '@Common/EmptyState'
88
import { handleUTCTime, stopPropagation, useAsync } from '@Common/Helper'
99
import { DeploymentAppTypes, ImageType } from '@Common/Types'
10-
import { ComponentSizeType } from '@Shared/constants'
10+
import {
11+
APP_DETAILS_FALLBACK_POLLING_INTERVAL,
12+
ComponentSizeType,
13+
PROGRESSING_DEPLOYMENT_STATUS_POLLING_INTERVAL,
14+
} from '@Shared/constants'
1115
import { AppType } from '@Shared/types'
1216

1317
import { APIResponseHandler } from '../APIResponseHandler'
@@ -56,6 +60,10 @@ const AppStatusModal = ({
5660
return response
5761
}
5862

63+
/**
64+
* Fetching logic for app details is we initially call from useAsync then through useEffect initiate polling
65+
* Since the dependency of useAsync is empty array, it will only be called once and then we will call the polling method is triggered based on the polling interval set in the environment variables.
66+
*/
5967
const [
6068
areInitialAppDetailsLoading,
6169
fetchedAppDetails,
@@ -100,6 +108,12 @@ const AppStatusModal = ({
100108
return response
101109
}
102110

111+
/**
112+
* Fetching logic for deployment status is we initially call from useAsync then through useEffect initiate polling
113+
* Now on tab switch we need to clear the previous timeout and set a new one reason being tab would have changed and in polling method that would not be reflected since closure is created
114+
* So we re-trigger useAsync to get the new data and set a new timeout
115+
* resetOnChange is there so that user don't see the change in icon in tabs
116+
*/
103117
const [
104118
isDeploymentTimelineLoading,
105119
deploymentStatusDetailsBreakdownData,
@@ -122,7 +136,7 @@ const AppStatusModal = ({
122136
// eslint-disable-next-line @typescript-eslint/no-floating-promises
123137
handleAppDetailsExternalSync()
124138
},
125-
Number(window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL) || 30000,
139+
Number(window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL) || APP_DETAILS_FALLBACK_POLLING_INTERVAL,
126140
)
127141
}
128142

@@ -136,7 +150,7 @@ const AppStatusModal = ({
136150
appDetails.appType !== AppType.DEVTRON_HELM_CHART
137151
? window._env_.DEVTRON_APP_DETAILS_POLLING_INTERVAL
138152
: window._env_.HELM_APP_DETAILS_POLLING_INTERVAL,
139-
) || 30000
153+
) || APP_DETAILS_FALLBACK_POLLING_INTERVAL
140154

141155
deploymentStatusPollingTimeoutRef.current = setTimeout(
142156
async () => {
@@ -149,7 +163,7 @@ const AppStatusModal = ({
149163
// eslint-disable-next-line @typescript-eslint/no-floating-promises
150164
handleDeploymentStatusExternalSync()
151165
},
152-
isDeploymentInProgress ? 10000 : pollingIntervalFromFlag,
166+
isDeploymentInProgress ? PROGRESSING_DEPLOYMENT_STATUS_POLLING_INTERVAL : pollingIntervalFromFlag,
153167
)
154168
}
155169

src/Shared/Components/AppStatusModal/AppStatusModalTabList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const AppStatusModalTabList = ({
7979
// Could have achieved via onDataLoad but, have done this through useEffect to avoid abrupt shift in case some tabs went missing after polling
8080
useEffect(() => {
8181
if (tabGroups.length && !selectedTab) {
82-
handleSelectTab(tabGroups[0]?.id as AppStatusModalTabType)
82+
handleSelectTab(tabGroups[0].id as AppStatusModalTabType)
8383
}
8484
}, [])
8585

src/Shared/Components/AppStatusModal/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FunctionComponent } from 'react'
1+
import { FunctionComponent, PropsWithChildren, ReactNode } from 'react'
22

33
import { APIOptions } from '@Common/Types'
44
import {
@@ -92,3 +92,9 @@ export interface AppStatusModalTabListProps extends Pick<AppStatusModalProps, 'a
9292
selectedTab: AppStatusModalTabType
9393
deploymentStatusDetailsBreakdownData: DeploymentStatusDetailsBreakdownDataType
9494
}
95+
96+
export interface StatusHeadingContainerProps extends PropsWithChildren<Pick<AppStatusBodyProps, 'type'>> {
97+
appId: number
98+
envId?: number
99+
actionItem?: ReactNode
100+
}

src/Shared/Components/AppStatusModal/utils.tsx

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,30 +84,19 @@ export const getShowDeploymentStatusModal = ({
8484
type,
8585
appDetails,
8686
}: Pick<AppStatusModalProps, 'type' | 'appDetails'>): boolean => {
87-
if (!appDetails) {
88-
return false
89-
}
90-
91-
const isHelmOrDevtronApp =
92-
appDetails.appType === AppType.DEVTRON_APP || appDetails.appType === AppType.DEVTRON_HELM_CHART
93-
94-
if (type === 'stack-manager' || !isHelmOrDevtronApp) {
87+
if (
88+
!appDetails ||
89+
type === 'stack-manager' ||
90+
(appDetails.appType !== AppType.DEVTRON_APP && appDetails.appType !== AppType.DEVTRON_HELM_CHART)
91+
) {
9592
return false
9693
}
9794

9895
if (appDetails.appType === AppType.DEVTRON_HELM_CHART) {
99-
if (!appDetails.lastDeployedTime || appDetails.deploymentAppType === DeploymentAppTypes.HELM) {
100-
return false
101-
}
102-
103-
return true
104-
}
105-
106-
if (appDetails.releaseMode === ReleaseMode.MIGRATE_EXTERNAL_APPS && !appDetails.isPipelineTriggered) {
107-
return false
96+
return !!appDetails.lastDeployedTime && appDetails.deploymentAppType !== DeploymentAppTypes.HELM
10897
}
10998

110-
return true
99+
return appDetails.releaseMode !== ReleaseMode.MIGRATE_EXTERNAL_APPS || appDetails.isPipelineTriggered
111100
}
112101

113102
export const getEmptyViewImageFromHelmDeploymentStatus = (

src/Shared/Components/CICDHistory/DeploymentStatusDetailRow.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,18 @@ export const DeploymentStatusDetailRow = ({
7878

7979
return (
8080
<div className="px-8 py-12">
81-
<div>
82-
{statusBreakDownType.subSteps?.map((items, index) => (
83-
// eslint-disable-next-line react/no-array-index-key
84-
<div className="flex left lh-20 mb-8" key={`item-${index}`}>
81+
{statusBreakDownType.subSteps?.map((items, index) => (
82+
// eslint-disable-next-line react/no-array-index-key
83+
<div key={`item-${index}`}>
84+
<div className="flex left lh-20 mb-8">
8585
{renderDeploymentTimelineIcon(items.icon)}
8686
<span className="ml-12">{items.message}</span>
8787
</div>
88-
))}
89-
</div>
88+
</div>
89+
))}
9090
{statusBreakDownType.resourceDetails?.length ? (
9191
<div className="pl-32">
92-
<div className="app-status-row dc__border-bottom pt-8 pb-8">
92+
<div className="app-status-row dc__border-bottom py-8">
9393
{MANIFEST_STATUS_HEADERS.map((headerKey, index) => (
9494
// eslint-disable-next-line react/no-array-index-key
9595
<div className="fs-13 fw-6 cn-7" key={`header_${index}`}>

src/Shared/Components/DeploymentStatusBreakdown/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export enum WorkflowRunnerStatusDTO {
2020
DEGRADED = 'Degraded',
2121
}
2222

23-
export interface HandleUpdateTimelineDataForTimedOutOrUnableToFetchStatusParamsType {
23+
export interface ProcessUnableToFetchOrTimedOutStatusType {
2424
timelineData: DeploymentStatusBreakdownItemType
2525
timelineStatusType: DeploymentStatusTimelineType
2626
deploymentStatus: typeof DEPLOYMENT_STATUS.UNABLE_TO_FETCH | typeof DEPLOYMENT_STATUS.TIMED_OUT

src/Shared/Components/DeploymentStatusBreakdown/utils.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
SUCCESSFUL_DEPLOYMENT_STATUS,
2020
WFR_STATUS_DTO_TO_DEPLOYMENT_STATUS_MAP,
2121
} from './constants'
22-
import { HandleUpdateTimelineDataForTimedOutOrUnableToFetchStatusParamsType } from './types'
22+
import { ProcessUnableToFetchOrTimedOutStatusType } from './types'
2323

2424
const getDefaultDeploymentStatusTimeline = (
2525
data?: DeploymentStatusDetailsType,
@@ -94,13 +94,13 @@ const getPredicate =
9494
}
9595
}
9696

97-
const handleUpdateTimelineDataForTimedOutOrUnableToFetchStatus = ({
97+
const processUnableToFetchOrTimedOutStatus = ({
9898
timelineData,
9999
timelineStatusType,
100100
deploymentStatus,
101101
statusLastFetchedAt,
102102
statusFetchCount,
103-
}: HandleUpdateTimelineDataForTimedOutOrUnableToFetchStatusParamsType) => {
103+
}: ProcessUnableToFetchOrTimedOutStatusType) => {
104104
timelineData.icon = deploymentStatus === DEPLOYMENT_STATUS.UNABLE_TO_FETCH ? 'disconnect' : 'timed_out'
105105
timelineData.displaySubText = 'Unknown'
106106
timelineData.isCollapsed = false
@@ -149,7 +149,7 @@ const processKubeCTLApply = (
149149
}
150150

151151
if (element.status === TIMELINE_STATUS.KUBECTL_APPLY_STARTED) {
152-
timelineData.resourceDetails = element.resourceDetails?.filter(
152+
timelineData.resourceDetails = (element.resourceDetails || []).filter(
153153
(item) => item.resourcePhase === tableData.currentPhase,
154154
)
155155

@@ -176,7 +176,7 @@ const processKubeCTLApply = (
176176
deploymentStatus === DEPLOYMENT_STATUS.TIMED_OUT ||
177177
deploymentStatus === DEPLOYMENT_STATUS.UNABLE_TO_FETCH
178178
) {
179-
handleUpdateTimelineDataForTimedOutOrUnableToFetchStatus({
179+
processUnableToFetchOrTimedOutStatus({
180180
timelineData,
181181
timelineStatusType: TIMELINE_STATUS.KUBECTL_APPLY,
182182
deploymentStatus,
@@ -202,6 +202,24 @@ const processKubeCTLApply = (
202202
}
203203
}
204204

205+
/**
206+
* @description
207+
* This function processes the deployment status details data and returns a breakdown of the deployment status.
208+
* Cases it handles:
209+
* 1. If timelines are not present, say the case of helm deployment, we will parse the wfrStatus and put the status and basic deployment info [triggeredBy, deploymentStartedOn, deploymentFinishedOn] into the breakdown data and return it.
210+
* 2. In case of gitops:
211+
* - There are five timelines in chronological order:
212+
* - Deployment Initiated
213+
* - Git commit
214+
* - ArgoCD Sync
215+
* - Kubectl Apply
216+
* - App Health
217+
* - Basic flow is we traverse the timelines in order, if find the last status for that specific timeline from response by traversing the timelines in reverse order.
218+
* - If element is found, we will parse the status and set the icon, display text, time, etc. for that timeline and set the next timeline to inprogress.
219+
* - If element is not found, we will parse on basis of factors like:
220+
* - If this timeline is not inprogress and deploymentStatus is progressing, we will set the current timeline to waiting.
221+
* - In similar fashion based on the deploymentStatus we will set the icon and display text for the timeline.
222+
*/
205223
export const processDeploymentStatusDetailsData = (
206224
data?: DeploymentStatusDetailsType,
207225
): DeploymentStatusDetailsBreakdownDataType => {
@@ -229,6 +247,8 @@ export const processDeploymentStatusDetailsData = (
229247
}
230248

231249
const isProgressing = PROGRESSING_DEPLOYMENT_STATUS.includes(deploymentStatus)
250+
// This key will be used since argocd sync is manual or auto based on flag on BE.
251+
// And in old data as well this timeline won't be present so in KUBECTL_APPLY timeline we will set the icon to success
232252
const isArgoCDSyncAvailable = data.timelines.some((timeline) =>
233253
timeline.status.includes(TIMELINE_STATUS.ARGOCD_SYNC),
234254
)
@@ -263,7 +283,7 @@ export const processDeploymentStatusDetailsData = (
263283
deploymentStatus === DEPLOYMENT_STATUS.TIMED_OUT) &&
264284
timelineData.icon === 'inprogress'
265285
) {
266-
handleUpdateTimelineDataForTimedOutOrUnableToFetchStatus({
286+
processUnableToFetchOrTimedOutStatus({
267287
timelineData,
268288
timelineStatusType,
269289
deploymentStatus,

src/Shared/Components/TabGroup/TabGroup.types.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,35 @@ type TabTooltipProps =
9393
tooltipProps?: never
9494
}
9595

96+
/**
97+
* Represents the properties for defining an icon in a tab group.
98+
* This type allows for three configurations:
99+
*
100+
* 1. **Icon as a functional component or string**:
101+
* - Use the `icon` property to specify either a functional component that renders an SVG or a string representing the name of the icon.
102+
* - The `iconElement` property must not be provided in this case.
103+
*
104+
* 2. **Icon as a JSX element**:
105+
* - Use the `iconElement` property to specify a JSX element representing the icon.
106+
* - The `icon` property must not be provided in this case.
107+
*
108+
* 3. **No icon**:
109+
* - Neither `icon` nor `iconElement` is provided, resulting in no icon being displayed.
110+
*
111+
*/
96112
type TabGroupIconProp =
97113
| {
98114
/**
99-
* Icon to be displayed in the tab.
100-
* This can either be a functional component that renders a SVG
101-
* or a string representing the name of the icon to be rendered by the Icon component.
115+
* A functional component rendering an SVG or a string representing the icon name. Mutually exclusive with `iconElement`.
102116
*/
103117
icon: React.FunctionComponent<React.SVGProps<SVGSVGElement>> | IconName
104118
iconElement?: never
105119
}
106120
| {
121+
icon?: never
107122
/**
108-
* Icon to be displayed in the tab.
109-
* This can either be a functional component that renders a SVG
110-
* or a string representing the name of the icon to be rendered by the Icon component.
123+
* A JSX element representing the icon. Mutually exclusive with `icon`.
111124
*/
112-
icon?: never
113125
iconElement: JSX.Element
114126
}
115127
| {

src/Shared/constants.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,6 @@ export const DEPLOYMENT_STAGE_TO_NODE_MAP: Readonly<Record<DeploymentStageType,
577577
[DeploymentStageType.POST]: DeploymentNodeType.POSTCD,
578578
[DeploymentStageType.PRE]: DeploymentNodeType.PRECD,
579579
}
580+
581+
export const APP_DETAILS_FALLBACK_POLLING_INTERVAL = 30000
582+
export const PROGRESSING_DEPLOYMENT_STATUS_POLLING_INTERVAL = 10000

0 commit comments

Comments
 (0)