Skip to content

Commit 2185577

Browse files
committed
Merge branch 'main' of https://github.com/devtron-labs/devtron-fe-common-lib into chore/sync-main-rc-44
2 parents 8606e70 + 12f9a58 commit 2185577

15 files changed

Lines changed: 775 additions & 185 deletions

package-lock.json

Lines changed: 93 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Common/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export const URLS = {
6969
LOGIN: '/login',
7070
LOGIN_SSO: '/login/sso',
7171
APP_LIST: 'list',
72+
APP: '/app',
7273
CREATE_JOB: 'create-job',
7374
GETTING_STARTED: 'getting-started',
7475
STACK_MANAGER_ABOUT: '/stack-manager/about',
@@ -223,6 +224,7 @@ export const ROUTES = {
223224
LICENSE_DATA: 'license/data',
224225
ENV: 'env',
225226
APP_METADATA: 'app-metadata',
227+
RESOURCE_CONFLICTS_LIST: 'app/:appId/cd-pipeline/:pipelineId/history/:wfrId/helm-ownership-conflicts',
226228
} as const
227229

228230
export enum KEY_VALUE {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[id*="table__resource-conflict-details"] {
2+
.generic-table__row {
3+
.generic-table__cell {
4+
display: flex;
5+
align-items: center;
6+
padding: 10px 0;
7+
}
8+
}
9+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { useMemo } from 'react'
2+
3+
import { FiltersTypeEnum, PaginationEnum, Table, TableViewWrapperProps } from '../Table'
4+
import { RowsType } from '../Table/types'
5+
import { CONFLICTED_RESOURCES_COLUMNS } from './constants'
6+
import { ConflictedResourcesTableProps, ResourceConflictItemType } from './types'
7+
8+
import './ConflictedResourcesTable.scss'
9+
10+
const Wrapper = ({ children }: TableViewWrapperProps<unknown, FiltersTypeEnum.STATE>) => (
11+
<div className="dc__overflow-hidden flexbox-col flex-grow-1">{children}</div>
12+
)
13+
const filter = () => true
14+
15+
const ConflictedResourcesTable = ({ resourceConflictDetails }: ConflictedResourcesTableProps) => {
16+
const rows: RowsType<ResourceConflictItemType> = useMemo(
17+
() =>
18+
(resourceConflictDetails || []).map<RowsType<ResourceConflictItemType>[number]>((resource) => ({
19+
data: resource,
20+
id: resource.id,
21+
})),
22+
[resourceConflictDetails],
23+
)
24+
25+
return (
26+
<Table<ResourceConflictItemType, FiltersTypeEnum.STATE>
27+
id="table__resource-conflict-details"
28+
columns={CONFLICTED_RESOURCES_COLUMNS}
29+
rows={rows}
30+
emptyStateConfig={{
31+
noRowsConfig: {
32+
title: 'No resource found',
33+
},
34+
noRowsForFilterConfig: {
35+
title: 'No results',
36+
subTitle: "We couldn't find any matching results",
37+
},
38+
}}
39+
paginationVariant={PaginationEnum.NOT_PAGINATED}
40+
additionalFilterProps={{
41+
initialSortKey: 'name' satisfies keyof ResourceConflictItemType,
42+
}}
43+
filtersVariant={FiltersTypeEnum.STATE}
44+
ViewWrapper={Wrapper}
45+
filter={filter}
46+
/>
47+
)
48+
}
49+
50+
export default ConflictedResourcesTable
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useState } from 'react'
2+
import { useHistory, useParams } from 'react-router-dom'
3+
4+
import { URLS } from '@Common/Constants'
5+
import { showError } from '@Common/Helper'
6+
7+
import { ButtonStyleType } from '../Button'
8+
import { ConfirmationModal, ConfirmationModalVariantType } from '../ConfirmationModal'
9+
import { Icon } from '../Icon'
10+
import { resourceConflictRedeploy } from './service'
11+
import { ResourceConflictDeployDialogProps, ResourceConflictDeployDialogURLParamsType } from './types'
12+
13+
const ResourceConflictDeployDialog = ({ appName, environmentName, handleClose }: ResourceConflictDeployDialogProps) => {
14+
const history = useHistory()
15+
const { appId, envId, pipelineId, triggerId } = useParams<ResourceConflictDeployDialogURLParamsType>()
16+
const [isLoading, setIsLoading] = useState(false)
17+
18+
const handleDeploy = async () => {
19+
setIsLoading(true)
20+
try {
21+
await resourceConflictRedeploy({
22+
pipelineId,
23+
triggerId,
24+
appId,
25+
})
26+
setIsLoading(false)
27+
history.push(`${URLS.APP}/${appId}/details/${envId}`)
28+
} catch (error) {
29+
showError(error)
30+
setIsLoading(false)
31+
}
32+
}
33+
34+
return (
35+
<ConfirmationModal
36+
variant={ConfirmationModalVariantType.custom}
37+
Icon={<Icon name="ic-warning" color={null} size={48} />}
38+
title="Take resource ownership and redeploy"
39+
subtitle={`Ensure the resources belong to the '${appName}' application and the '${environmentName}' environment to avoid destructive changes.`}
40+
handleClose={handleClose}
41+
buttonConfig={{
42+
secondaryButtonConfig: {
43+
text: 'Cancel',
44+
onClick: handleClose,
45+
},
46+
primaryButtonConfig: {
47+
isLoading,
48+
text: 'Re-deploy',
49+
onClick: handleDeploy,
50+
style: ButtonStyleType.warning,
51+
},
52+
}}
53+
/>
54+
)
55+
}
56+
57+
export default ResourceConflictDeployDialog
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { useState } from 'react'
2+
import { useHistory, useParams } from 'react-router-dom'
3+
4+
import { useQuery } from '@Common/API'
5+
import { URLS } from '@Common/Constants'
6+
import { Drawer } from '@Common/Drawer'
7+
import { showError, stopPropagation } from '@Common/Helper'
8+
import { ComponentSizeType } from '@Shared/constants'
9+
10+
import { APIResponseHandler } from '../APIResponseHandler'
11+
import { Button, ButtonStyleType, ButtonVariantType } from '../Button'
12+
import { Icon } from '../Icon'
13+
import ConflictedResourcesTable from './ConflictedResourcesTable'
14+
import { getResourceConflictDetails, resourceConflictRedeploy } from './service'
15+
import {
16+
ResourceConflictDeployDialogURLParamsType,
17+
ResourceConflictDetailsModalProps,
18+
ResourceConflictItemType,
19+
} from './types'
20+
21+
const ResourceConflictDetailsModal = ({ appName, environmentName, handleClose }: ResourceConflictDetailsModalProps) => {
22+
const { appId, envId, pipelineId, triggerId } = useParams<ResourceConflictDeployDialogURLParamsType>()
23+
const history = useHistory()
24+
25+
const {
26+
isFetching: isLoadingResourceData,
27+
data: resourceConflictDetails,
28+
refetch: refetchResourceConflictDetails,
29+
error: resourceConflictDetailsError,
30+
} = useQuery<ResourceConflictItemType[], ResourceConflictItemType[], [string, string, string, string], false>({
31+
queryKey: ['getResourceConflictDetails', pipelineId, triggerId, appId],
32+
queryFn: ({ signal }) => getResourceConflictDetails({ pipelineId, triggerId, appId, signal }),
33+
})
34+
35+
const [isDeploying, setIsDeploying] = useState(false)
36+
37+
const handleDeploy = async () => {
38+
setIsDeploying(true)
39+
try {
40+
await resourceConflictRedeploy({
41+
pipelineId,
42+
triggerId,
43+
appId,
44+
})
45+
setIsDeploying(false)
46+
history.push(`${URLS.APP}/${appId}/details/${envId}`)
47+
} catch (error) {
48+
showError(error)
49+
setIsDeploying(false)
50+
}
51+
}
52+
53+
return (
54+
<Drawer width="800px" onClose={handleClose} onEscape={handleClose} position="right">
55+
<div
56+
className="flexbox-col dc__content-space h-100 bg__modal--primary shadow__modal dc__overflow-auto"
57+
onClick={stopPropagation}
58+
>
59+
<div className="flexbox-col dc__overflow-auto flex-grow-1">
60+
<div className="px-20 py-12 flexbox dc__content-space dc__align-items-center border__primary--bottom">
61+
<h2 className="m-0 fs-16 fw-6 lh-24 cn-9">Resources with conflict</h2>
62+
63+
<Button
64+
dataTestId="header-close-button"
65+
ariaLabel="Close"
66+
showAriaLabelInTippy={false}
67+
onClick={handleClose}
68+
variant={ButtonVariantType.borderLess}
69+
style={ButtonStyleType.negativeGrey}
70+
icon={<Icon name="ic-close-large" color={null} />}
71+
size={ComponentSizeType.xs}
72+
/>
73+
</div>
74+
75+
<div className="flexbox-col flex-grow-1 dc__overflow-auto w-100">
76+
<APIResponseHandler
77+
isLoading={isLoadingResourceData}
78+
progressingProps={{
79+
pageLoader: true,
80+
}}
81+
error={resourceConflictDetailsError}
82+
errorScreenManagerProps={{
83+
code: resourceConflictDetailsError?.code,
84+
reload: refetchResourceConflictDetails,
85+
on404Redirect: handleClose,
86+
}}
87+
>
88+
<ConflictedResourcesTable resourceConflictDetails={resourceConflictDetails} />
89+
</APIResponseHandler>
90+
</div>
91+
</div>
92+
93+
<div className="flexbox dc__align-items-center dc__content-space dc__gap-20 py-16 px-20 border__primary--top dc__no-shrink">
94+
<div className="flexbox dc__gap-8">
95+
<Icon name="ic-warning" size={20} color={null} />
96+
<div className="flexbox-col">
97+
<span className="cn-9 fs-13 fw-6 lh-1-5">Take resource ownership and redeploy</span>
98+
<span>
99+
Ensure all resources strictly belong to the {appName} application and the&nbsp;
100+
{environmentName}
101+
environment. Any resource outside this Helm release may cause incorrect associations and
102+
potentially destructive changes.
103+
</span>
104+
</div>
105+
</div>
106+
<div className="dc__no-shrink">
107+
<Button
108+
dataTestId="footer-redeploy-button"
109+
variant={ButtonVariantType.primary}
110+
style={ButtonStyleType.warning}
111+
size={ComponentSizeType.large}
112+
text="Re-deploy"
113+
startIcon={<Icon name="ic-rocket-launch" color={null} />}
114+
isLoading={isDeploying}
115+
disabled={!resourceConflictDetails?.length}
116+
onClick={handleDeploy}
117+
/>
118+
</div>
119+
</div>
120+
</div>
121+
</Drawer>
122+
)
123+
}
124+
125+
export default ResourceConflictDetailsModal

src/Shared/Components/CICDHistory/Sidebar.tsx

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ import {
4141
HistorySummaryCardType,
4242
SidebarType,
4343
} from './types'
44-
import { getHistoryItemStatusIconFromWorkflowStages, getTriggerStatusIcon, getWorkflowNodeStatusTitle } from './utils'
44+
import {
45+
getHistoryItemStatusIconFromWorkflowStages,
46+
getSortedTriggerHistory,
47+
getTriggerStatusIcon,
48+
getWorkflowNodeStatusTitle,
49+
} from './utils'
4550

4651
/**
4752
* @description To be shown on deployment history or when we don't have workflowExecutionStages
@@ -378,30 +383,28 @@ const Sidebar = React.memo(
378383
{fetchIdData === FetchIdDataStatus.SUCCESS && (
379384
<ViewAllCardsTile handleViewAllHistory={handleViewAllHistory} />
380385
)}
381-
{Array.from(triggerHistory)
382-
.sort(([a], [b]) => b - a)
383-
.map(([triggerId, triggerDetails], index) => (
384-
<HistorySummaryCard
385-
dataTestId={`deployment-history-${index}`}
386-
key={triggerId}
387-
id={triggerId}
388-
status={triggerDetails.status}
389-
startedOn={triggerDetails.startedOn}
390-
triggeredBy={triggerDetails.triggeredBy}
391-
triggeredByEmail={triggerDetails.triggeredByEmail}
392-
ciMaterials={triggerDetails.ciMaterials}
393-
gitTriggers={triggerDetails.gitTriggers}
394-
artifact={triggerDetails.artifact}
395-
stage={triggerDetails.stage}
396-
type={type}
397-
runSource={triggerDetails.runSource}
398-
renderRunSource={renderRunSource}
399-
resourceId={resourceId}
400-
workflowExecutionStages={triggerDetails.workflowExecutionStages}
401-
podName={triggerDetails.podName}
402-
namespace={triggerDetails.namespace}
403-
/>
404-
))}
386+
{getSortedTriggerHistory(triggerHistory).map(([triggerId, triggerDetails], index) => (
387+
<HistorySummaryCard
388+
dataTestId={`deployment-history-${index}`}
389+
key={triggerId}
390+
id={triggerId}
391+
status={triggerDetails.status}
392+
startedOn={triggerDetails.startedOn}
393+
triggeredBy={triggerDetails.triggeredBy}
394+
triggeredByEmail={triggerDetails.triggeredByEmail}
395+
ciMaterials={triggerDetails.ciMaterials}
396+
gitTriggers={triggerDetails.gitTriggers}
397+
artifact={triggerDetails.artifact}
398+
stage={triggerDetails.stage}
399+
type={type}
400+
runSource={triggerDetails.runSource}
401+
renderRunSource={renderRunSource}
402+
resourceId={resourceId}
403+
workflowExecutionStages={triggerDetails.workflowExecutionStages}
404+
podName={triggerDetails.podName}
405+
namespace={triggerDetails.namespace}
406+
/>
407+
))}
405408
{hasMore && (fetchIdData === FetchIdDataStatus.SUSPEND || !fetchIdData) && (
406409
<DetectBottom callback={reloadNextAfterBottom} />
407410
)}

0 commit comments

Comments
 (0)