Skip to content

Commit e4977bf

Browse files
Merge pull request #1332 from devtron-labs/feat/modal-app-details-env-filter
Feat: modal app details env filter
2 parents 5656a94 + 26bae40 commit e4977bf

File tree

12 files changed

+336
-120
lines changed

12 files changed

+336
-120
lines changed

src/components/ApplicationGroup/AppGroup.service.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,19 @@ export const getAppGroupList = (envId: number): Promise<AppGroupList> => {
194194
return get(`${Routes.APP_LIST_GROUP}/${envId}`)
195195
}
196196

197-
export const getEnvGroupList = (envId: number): Promise<EnvGroupListResponse> => {
198-
return get(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUPS}`)
197+
export const getEnvGroupList = (envId: number, filterParentType?:string): Promise<EnvGroupListResponse> => {
198+
let filterParentTypeQuery = ''
199+
if (filterParentType) {
200+
filterParentTypeQuery = `?groupType=${filterParentType}`
201+
}
202+
return get(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUPS}${filterParentTypeQuery}`)
199203
}
200204

201205
export const getEnvGroup = (envId: number, groupId: number): Promise<EnvGroupResponse> => {
202206
return get(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${groupId}`)
203207
}
204208

205-
export const createEnvGroup = (envId: string, data: EnvGroupListType, isEdit: boolean): Promise<EnvGroupResponse> => {
209+
export const createEnvGroup = (envId: string, data, isEdit: boolean): Promise<EnvGroupResponse> => {
206210
if (isEdit) {
207211
return put(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}`, data)
208212
}
@@ -213,6 +217,10 @@ export const appGroupPermission = (envId: string, data: CheckPermissionType): Pr
213217
return post(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${Routes.PERMISSION}`, data)
214218
}
215219

216-
export const deleteEnvGroup = (envId: string, groupId: string): Promise<EnvGroupResponse> => {
217-
return trash(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${groupId}`)
220+
export const deleteEnvGroup = (envId: string, groupId: string, filterParentType?:string): Promise<EnvGroupResponse> => {
221+
let filterParentTypeQuery = ''
222+
if (filterParentType) {
223+
filterParentTypeQuery = `?groupType=${filterParentType}`
224+
}
225+
return trash(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${groupId}${filterParentTypeQuery}`)
218226
}

src/components/ApplicationGroup/AppGroup.types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ export interface CreateGroupType {
311311
selectedAppGroup: GroupOptionType
312312
unAuthorizedApps?: Map<string, boolean>
313313
closePopup: (e, groupId?: number) => void
314+
filterParentType: FilterParentType
314315
}
315316

316317
export interface ApplistEnvType {
@@ -384,6 +385,6 @@ export interface SearchBarType {
384385
}
385386

386387
export enum FilterParentType {
387-
app = 'app',
388-
env = 'env',
388+
app = 'env-group',
389+
env = 'app-group',
389390
}

src/components/ApplicationGroup/AppGroupDetailsRoute.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ export default function AppGroupDetailsRoute({ isSuperAdmin }: AppGroupAdminType
393393
appList={allAppsList}
394394
selectedAppGroup={clickedGroup}
395395
closePopup={closeCreateGroup}
396+
filterParentType={FilterParentType.env}
396397
/>
397398
)}
398399
{showDeleteGroup && isPopupBox && (
@@ -446,7 +447,7 @@ export function EnvHeader({
446447
openCreateGroup,
447448
openDeleteGroup,
448449
isSuperAdmin,
449-
filterParentType: FilterParentType.env
450+
filterParentType: FilterParentType.env,
450451
}),
451452
[
452453
appListOptions,
@@ -521,7 +522,6 @@ export function EnvHeader({
521522
onClickTabPreventDefault(event, 'active')
522523
}
523524

524-
525525
const renderEnvDetailsTabs = () => {
526526
return (
527527
<ul role="tablist" className="tab-list">
@@ -530,7 +530,9 @@ export function EnvHeader({
530530
activeClassName="active"
531531
to={`${match.url}/${URLS.APP_OVERVIEW}`}
532532
className="tab-list__tab-link"
533-
onClick={(event) => handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.OverviewClicked.action)}
533+
onClick={(event) =>
534+
handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.OverviewClicked.action)
535+
}
534536
>
535537
Overview
536538
</NavLink>
@@ -541,7 +543,9 @@ export function EnvHeader({
541543
to={`${match.url}/${URLS.APP_TRIGGER}`}
542544
className="tab-list__tab-link"
543545
data-testid="group-build-deploy"
544-
onClick={(event) => handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.BuildDeployClicked.action)}
546+
onClick={(event) =>
547+
handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.BuildDeployClicked.action)
548+
}
545549
>
546550
Build & Deploy
547551
</NavLink>
@@ -573,7 +577,9 @@ export function EnvHeader({
573577
to={`${match.url}/${URLS.APP_CONFIG}`}
574578
className="tab-list__tab-link flex"
575579
data-testid="group-configuration"
576-
onClick={(event) => handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.ConfigurationClicked.action)}
580+
onClick={(event) =>
581+
handleEventRegistration(event, ENV_APP_GROUP_GA_EVENTS.ConfigurationClicked.action)
582+
}
577583
>
578584
<Settings className="tab-list__icon icon-dim-16 fcn-9 mr-4" />
579585
Configurations

src/components/ApplicationGroup/Constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,16 @@ export enum AppFilterTabs {
160160

161161
export enum CreateGroupTabs {
162162
'SELECTED_APPS' = 'selectedApps',
163+
'SELECTED_ENV' = 'selectedEnv',
163164
'ALL_APPS' = 'allApps',
165+
'ALL_ENV' = 'allEnv',
164166
}
165167

166168
export const CREATE_GROUP_TABS = {
167169
selectedApps: 'Selected applications',
168170
allApps: 'Add/Remove applications',
171+
selectedEnv: 'Selected environments',
172+
allEnv: 'Add/Remove environments',
169173
}
170174

171175
export const GetBranchChangeStatus = (statusText: string): BulkResponseStatus => {

src/components/ApplicationGroup/CreateAppGroup.tsx

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,31 @@ import { ReactComponent as Close } from '../../assets/icons/ic-close.svg'
1212
import { ReactComponent as Error } from '../../assets/icons/ic-warning.svg'
1313
import { ReactComponent as CheckIcon } from '../../assets/icons/ic-check.svg'
1414
import { ReactComponent as Abort } from '../../assets/icons/ic-abort.svg'
15-
import { CreateGroupType, CreateTypeOfAppListType } from './AppGroup.types'
15+
import { CreateGroupType, CreateTypeOfAppListType, FilterParentType } from './AppGroup.types'
1616
import SearchBar from './SearchBar'
1717
import { CreateGroupTabs, CREATE_GROUP_TABS } from './Constants'
1818
import { toast } from 'react-toastify'
1919
import { createEnvGroup } from './AppGroup.service'
2020
import { useParams } from 'react-router-dom'
2121
import Tippy from '@tippyjs/react'
22+
import { filter } from 'rxjs'
2223

23-
export default function CreateAppGroup({ appList, selectedAppGroup, closePopup, unAuthorizedApps }: CreateGroupType) {
24-
const { envId } = useParams<{ envId: string }>()
24+
export default function CreateAppGroup({
25+
appList,
26+
selectedAppGroup,
27+
closePopup,
28+
unAuthorizedApps,
29+
filterParentType,
30+
}: CreateGroupType) {
31+
const { appId, envId } = useParams<{ appId: string; envId: string }>()
2532
const CreateGroupRef = useRef<HTMLDivElement>(null)
2633
const [isLoading, setLoading] = useState(false)
2734
const [showErrorMsg, setShowErrorMsg] = useState(false)
2835
const [appGroupName, setAppGroupName] = useState<string>(selectedAppGroup?.label ?? '')
2936
const [appGroupDescription, setAppGroupDescription] = useState<string>(selectedAppGroup?.description ?? '')
30-
const [selectedTab, setSelectedTab] = useState<CreateGroupTabs>(CreateGroupTabs.SELECTED_APPS)
37+
const [selectedTab, setSelectedTab] = useState<CreateGroupTabs>(
38+
filterParentType === FilterParentType.app ? CreateGroupTabs.SELECTED_ENV : CreateGroupTabs.SELECTED_APPS,
39+
)
3140
const [allAppSearchText, setAllAppSearchText] = useState('')
3241
const [allAppSearchApplied, setAllAppSearchApplied] = useState(false)
3342
const [selectedAppSearchText, setSelectedAppSearchText] = useState('')
@@ -109,8 +118,8 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
109118
const appFilterAuthorizedList = () => {
110119
let _authorizedApp = []
111120
appList.forEach((app) => {
112-
if(!unAuthorizedApps.get(app.appName)) {
113-
_authorizedApp.push({id: app.id, appName: app.appName})
121+
if (!unAuthorizedApps.get(app.appName)) {
122+
_authorizedApp.push({ id: app.id, appName: app.appName })
114123
}
115124
})
116125
setAuthorizedAppList(_authorizedApp)
@@ -134,11 +143,11 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
134143
const appFilterList = () => {
135144
let _authorizedAppList = []
136145
let _unauthorizedAppList = []
137-
appList.forEach((app) =>{
138-
unAuthorizedApps.get(app.appName) ?
139-
_unauthorizedAppList.push({id: app.id, appName: app.appName})
140-
: _authorizedAppList.push({id: app.id, appName: app.appName})
141-
})
146+
appList.forEach((app) => {
147+
unAuthorizedApps.get(app.appName)
148+
? _unauthorizedAppList.push({ id: app.id, appName: app.appName })
149+
: _authorizedAppList.push({ id: app.id, appName: app.appName })
150+
})
142151
setUnauthorizedAppList(_unauthorizedAppList)
143152
setAuthorizedAppList(_authorizedAppList)
144153
}
@@ -232,7 +241,7 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
232241
arrow={false}
233242
placement="bottom-start"
234243
content="You don't have admin/manager pemission for this app."
235-
>
244+
>
236245
<div>{children}</div>
237246
</Tippy>
238247
)}
@@ -328,16 +337,29 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
328337
</div>
329338
<div>
330339
<ul role="tablist" className="tab-list dc__border-bottom mb-8">
331-
{renderTabItem(CreateGroupTabs.SELECTED_APPS, selectedAppsCount)}
332-
{renderTabItem(CreateGroupTabs.ALL_APPS, appList.length)}
340+
{renderTabItem(
341+
filterParentType === FilterParentType.app
342+
? CreateGroupTabs.SELECTED_ENV
343+
: CreateGroupTabs.SELECTED_APPS,
344+
selectedAppsCount,
345+
)}
346+
{renderTabItem(
347+
filterParentType === FilterParentType.app
348+
? CreateGroupTabs.ALL_ENV
349+
: CreateGroupTabs.ALL_APPS,
350+
appList.length,
351+
)}
333352
</ul>
334-
{selectedTab === CreateGroupTabs.SELECTED_APPS ? renderSelectedApps() : renderAllApps()}
353+
354+
{selectedTab === CreateGroupTabs.SELECTED_APPS || selectedTab === CreateGroupTabs.SELECTED_ENV
355+
? renderSelectedApps()
356+
: renderAllApps()}
335357
</div>
336358
</div>
337359
)
338360
}
339361

340-
const handleSave = async (e): Promise<void> => {
362+
const handleSave = async (e): Promise<void> => {
341363
e.preventDefault()
342364
if (!appGroupName || appGroupDescription?.length > 50) {
343365
return
@@ -351,7 +373,7 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
351373
for (const _appId in selectedAppsMap) {
352374
_selectedAppIds.push(+_appId)
353375
}
354-
376+
355377
let appListIds = []
356378
appList.forEach((element) => {
357379
if (!unAuthorizedApps.get(element.appName)) {
@@ -369,11 +391,13 @@ export default function CreateAppGroup({ appList, selectedAppGroup, closePopup,
369391
id: selectedAppGroup ? +selectedAppGroup.value : null,
370392
name: appGroupName,
371393
description: appGroupDescription,
372-
appIds: payloadAppIds,
394+
resourceIds: payloadAppIds,
395+
groupType: filterParentType,
373396
}
374397

375398
try {
376-
const { result } = await createEnvGroup(envId, payload, !!selectedAppGroup?.value)
399+
const id = filterParentType === FilterParentType.app ? appId : envId
400+
const { result } = await createEnvGroup(id, payload, !!selectedAppGroup?.value)
377401
toast.success('Successfully saved')
378402
closePopup(e, result.id)
379403
} catch (err) {

src/components/app/details/AppHeader.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useCallback, useRef, useEffect, useState, useMemo } from 'react'
22
import { NavLink } from 'react-router-dom'
3-
import { BreadCrumb, useBreadcrumb, noop } from '@devtron-labs/devtron-fe-common-lib'
3+
import { BreadCrumb, useBreadcrumb, noop, stopPropagation } from '@devtron-labs/devtron-fe-common-lib'
44
import { useParams, useRouteMatch, useHistory, generatePath, useLocation } from 'react-router'
55
import { URLS } from '../../../config'
66
import { AppSelector } from '../../AppSelector'
@@ -13,7 +13,8 @@ import AppGroupAppFilter from '../../ApplicationGroup/AppGroupAppFilter'
1313
import './appDetails/appDetails.scss'
1414
import './app.scss'
1515
import { AppGroupAppFilterContext } from '../../ApplicationGroup/AppGroupDetailsRoute'
16-
import { FilterParentType } from '../../ApplicationGroup/AppGroup.types'
16+
import { CreateGroupAppListType, FilterParentType, GroupOptionType } from '../../ApplicationGroup/AppGroup.types'
17+
import CreateAppGroup from '../../ApplicationGroup/CreateAppGroup'
1718

1819
const MandatoryTagWarning = importComponentFromFELibrary('MandatoryTagWarning')
1920

@@ -55,7 +56,7 @@ export function AppHeader({
5556
openCreateGroup,
5657
openDeleteGroup,
5758
isSuperAdmin,
58-
filterParentType: FilterParentType.app
59+
filterParentType: FilterParentType.app,
5960
}),
6061
[
6162
appListOptions,

src/components/app/details/app.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,23 @@
3030
padding: 0 0 8px 0;
3131
}
3232
}
33+
34+
.selected-app-row {
35+
.check-icon {
36+
display: block;
37+
}
38+
.delete-icon {
39+
display: none;
40+
use {
41+
fill: var(--R500);
42+
}
43+
}
44+
&:hover {
45+
.check-icon {
46+
display: none;
47+
}
48+
.delete-icon {
49+
display: block;
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)