Skip to content

Commit aaf4f3a

Browse files
authored
Merge pull request #2670 from devtron-labs/feat/app-env-details
feat: add app details page in app group
2 parents 9d99d4d + 38b4b19 commit aaf4f3a

File tree

23 files changed

+417
-373
lines changed

23 files changed

+417
-373
lines changed

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-1",
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/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
>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { generatePath, useHistory, useParams, useRouteMatch } from 'react-router-dom'
2+
import { GroupBase } from 'react-select'
3+
4+
import {
5+
AppEnvironment,
6+
BaseURLParams,
7+
EnvAppsMetaDTO,
8+
SelectPicker,
9+
SelectPickerOptionType,
10+
} from '@devtron-labs/devtron-fe-common-lib'
11+
12+
import { AppEnvDropdownProps, AppEnvSelectorProps } from './appDetails.type'
13+
import { getEnvOptions } from './utils'
14+
15+
const AppEnvDropdown = ({ isAppView = false, options, value }: AppEnvDropdownProps) => {
16+
const { push } = useHistory()
17+
const { path } = useRouteMatch()
18+
const { appId, envId } = useParams<Pick<BaseURLParams, 'appId' | 'envId'>>()
19+
20+
const handleOnChange = (option: SelectPickerOptionType) => {
21+
const newUrl = generatePath(path, {
22+
appId: isAppView ? appId : option.value,
23+
envId: isAppView ? option.value : envId,
24+
})
25+
push(newUrl)
26+
}
27+
28+
return (
29+
<>
30+
<div style={{ width: 'clamp( 100px, 30%, 100px )', height: '100%', position: 'relative' }}>
31+
<svg
32+
viewBox="0 0 200 40"
33+
preserveAspectRatio="none"
34+
style={{ width: '100%', height: '100%', display: 'flex' }}
35+
>
36+
<path d="M0 20 L200 20 Z" strokeWidth="1" stroke="var(--B500)" />
37+
<path d="M0 10 L0, 30" strokeWidth="2" stroke="var(--B500)" />
38+
</svg>
39+
<div
40+
className="bcb-5 br-10 cn-0 pl-8 pr-8"
41+
style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}
42+
>
43+
{isAppView ? 'ENV' : 'APP'}
44+
</div>
45+
</div>
46+
<div data-testid="app-deployed-env-name" className="app-details__selector w-200 dc__zi-12">
47+
<SelectPicker
48+
inputId="app-environment-select"
49+
placeholder={`Select ${isAppView ? 'Environment' : 'Application'}`}
50+
options={options}
51+
value={value}
52+
onChange={handleOnChange}
53+
closeMenuOnSelect
54+
isSearchable
55+
classNamePrefix="app-environment-select"
56+
/>
57+
</div>
58+
</>
59+
)
60+
}
61+
62+
const AppSelector = ({ applications }: { applications: EnvAppsMetaDTO['apps'] }) => {
63+
const { appId } = useParams<Pick<BaseURLParams, 'appId'>>()
64+
65+
const appIdVsNameMap = (applications ?? []).reduce((agg, curr) => {
66+
// eslint-disable-next-line no-param-reassign
67+
agg[curr.appId] = curr.appName
68+
return agg
69+
}, {})
70+
71+
const appOptions = (applications ?? []).map((app) => ({
72+
label: app.appName,
73+
value: app.appId,
74+
}))
75+
76+
return (
77+
<AppEnvDropdown options={appOptions} value={appId ? { label: appIdVsNameMap[+appId], value: +appId } : null} />
78+
)
79+
}
80+
81+
const EnvSelector = ({ environments }: { environments: AppEnvironment[] }) => {
82+
const { envId } = useParams<Pick<BaseURLParams, 'envId'>>()
83+
84+
const envIdVsNameMap = (environments ?? []).reduce((agg, curr) => {
85+
// eslint-disable-next-line no-param-reassign
86+
agg[curr.environmentId] = curr.environmentName
87+
return agg
88+
}, {})
89+
90+
const isolatedEnvOptions = (environments ?? []).filter((env) => env.isVirtualEnvironment).map(getEnvOptions)
91+
92+
const envOptions: Array<GroupBase<SelectPickerOptionType<number>> | SelectPickerOptionType<number>> = [
93+
...(environments ?? []).filter((env) => !env.isVirtualEnvironment).map(getEnvOptions),
94+
...(isolatedEnvOptions.length
95+
? [
96+
{
97+
label: 'Isolated Environments',
98+
options: isolatedEnvOptions,
99+
},
100+
]
101+
: []),
102+
]
103+
104+
return (
105+
<AppEnvDropdown
106+
isAppView
107+
options={envOptions}
108+
value={envId ? { label: envIdVsNameMap[+envId], value: +envId } : null}
109+
/>
110+
)
111+
}
112+
113+
const AppEnvSelector = ({ isAppView, environments, applications }: AppEnvSelectorProps) =>
114+
isAppView ? <EnvSelector environments={environments} /> : <AppSelector applications={applications} />
115+
116+
export default AppEnvSelector

0 commit comments

Comments
 (0)