Skip to content

Commit 574588a

Browse files
Merge pull request #1339 from devtron-labs/app_env_filter
feat: App env filter
2 parents ce4b488 + 841b7d4 commit 574588a

35 files changed

+1190
-522
lines changed

src/components/ApplicationGroup/AppGroup.service.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {
2222
EnvAppType,
2323
EnvDeploymentStatusType,
2424
EnvGroupListResponse,
25-
EnvGroupListType,
2625
EnvGroupResponse,
2726
WorkflowsResponseType,
2827
} from './AppGroup.types'
@@ -194,15 +193,19 @@ export const getAppGroupList = (envId: number): Promise<AppGroupList> => {
194193
return get(`${Routes.APP_LIST_GROUP}/${envId}`)
195194
}
196195

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

201204
export const getEnvGroup = (envId: number, groupId: number): Promise<EnvGroupResponse> => {
202205
return get(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${groupId}`)
203206
}
204207

205-
export const createEnvGroup = (envId: string, data: EnvGroupListType, isEdit: boolean): Promise<EnvGroupResponse> => {
208+
export const createEnvGroup = (envId: string, data, isEdit: boolean): Promise<EnvGroupResponse> => {
206209
if (isEdit) {
207210
return put(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}`, data)
208211
}
@@ -213,6 +216,10 @@ export const appGroupPermission = (envId: string, data: CheckPermissionType): Pr
213216
return post(`${Routes.ENVIRONMENT}/${envId}/${Routes.GROUP}/${Routes.PERMISSION}`, data)
214217
}
215218

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

src/components/ApplicationGroup/AppGroup.types.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ export interface BulkCIDetailType extends BulkTriggerAppDetailType {
3131
filteredCIPipelines: any
3232
}
3333

34-
export interface BulkCDDetailTypeResponse{
35-
bulkCDDetailType: BulkCDDetailType[],
36-
uniqueReleaseTags: string[],
34+
export interface BulkCDDetailTypeResponse {
35+
bulkCDDetailType: BulkCDDetailType[]
36+
uniqueReleaseTags: string[]
3737
}
3838

3939
export interface BulkCDDetailType extends BulkTriggerAppDetailType {
@@ -233,11 +233,7 @@ export interface AppOverridesType {
233233
setEnvironments: any
234234
}
235235

236-
export interface EnvHeaderType {
237-
envName: string
238-
setEnvName: (label: string) => void
239-
setShowEmpty: (empty: boolean) => void
240-
showEmpty: boolean
236+
export interface GroupFilterType {
241237
appListOptions: OptionType[]
242238
selectedAppList: MultiValue<OptionType>
243239
setSelectedAppList: React.Dispatch<React.SetStateAction<MultiValue<OptionType>>>
@@ -251,6 +247,13 @@ export interface EnvHeaderType {
251247
isSuperAdmin: boolean
252248
}
253249

250+
export interface EnvHeaderType extends GroupFilterType {
251+
envName: string
252+
setEnvName: (label: string) => void
253+
setShowEmpty: (empty: boolean) => void
254+
showEmpty: boolean
255+
}
256+
254257
export interface AppGroupAdminType {
255258
isSuperAdmin: boolean
256259
}
@@ -289,6 +292,7 @@ export interface AppGroupAppFilterContextType {
289292
openCreateGroup: (e, groupId?: string, _edit?: boolean) => void
290293
openDeleteGroup: (e, groupId: string, _delete?: boolean) => void
291294
isSuperAdmin: boolean
295+
filterParentType: FilterParentType
292296
}
293297

294298
export interface CreateGroupAppListType {
@@ -297,7 +301,7 @@ export interface CreateGroupAppListType {
297301
isSelected: boolean
298302
}
299303

300-
export interface CreateTypeOfAppListType{
304+
export interface CreateTypeOfAppListType {
301305
id: number
302306
appName: string
303307
}
@@ -307,6 +311,7 @@ export interface CreateGroupType {
307311
selectedAppGroup: GroupOptionType
308312
unAuthorizedApps?: Map<string, boolean>
309313
closePopup: (e, groupId?: number) => void
314+
filterParentType: FilterParentType
310315
}
311316

312317
export interface ApplistEnvType {
@@ -345,7 +350,7 @@ export interface EnvGroupListType {
345350
description: string
346351
}
347352

348-
export interface CheckPermissionType{
353+
export interface CheckPermissionType {
349354
id?: number
350355
appIds: number[]
351356
name?: string
@@ -378,3 +383,8 @@ export interface SearchBarType {
378383
searchApplied: boolean
379384
setSearchApplied: React.Dispatch<React.SetStateAction<boolean>>
380385
}
386+
387+
export enum FilterParentType {
388+
app = 'env-group',
389+
env = 'app-group',
390+
}

src/components/ApplicationGroup/AppGroupAppFilter.components.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,27 @@ import { ReactComponent as InfoIcon } from '../../assets/icons/ic-info-outlined.
1010
import { ReactComponent as Edit } from '../../assets/icons/ic-pencil.svg'
1111
import { ReactComponent as Trash } from '../../assets/icons/ic-delete-interactive.svg'
1212
import { ReactComponent as CheckIcon } from '../../assets/icons/ic-check.svg'
13-
import { AppGroupAppFilterContextType } from './AppGroup.types'
13+
import { AppGroupAppFilterContextType, FilterParentType } from './AppGroup.types'
1414
import { AppFilterTabs } from './Constants'
1515
import { ConditionalWrap } from '@devtron-labs/devtron-fe-common-lib'
1616
import Tippy from '@tippyjs/react'
1717

1818
export const ValueContainer = (props): JSX.Element => {
19-
const { appListOptions, selectedAppList, selectedFilterTab, selectedGroupFilter }: AppGroupAppFilterContextType =
20-
useAppGroupAppFilterContext()
19+
const {
20+
appListOptions,
21+
selectedAppList,
22+
selectedFilterTab,
23+
selectedGroupFilter,
24+
filterParentType,
25+
}: AppGroupAppFilterContextType = useAppGroupAppFilterContext()
2126
let selectorText,
2227
selectedAppsLength = props.getValue().length
2328
if (selectedFilterTab === AppFilterTabs.GROUP_FILTER && selectedGroupFilter[0]) {
2429
selectorText = selectedGroupFilter[0]?.label
2530
} else {
2631
selectorText = `${selectedAppList.length > 0 ? selectedAppList.length : appListOptions.length}/${
2732
appListOptions.length
28-
} Applications`
33+
} ${filterParentType === FilterParentType.env ? 'Applications' : 'Environments'}`
2934
}
3035
return (
3136
<components.ValueContainer {...props}>
@@ -144,6 +149,7 @@ export const MenuList = (props: any): JSX.Element => {
144149
openCreateGroup,
145150
selectedGroupFilter,
146151
setSelectedGroupFilter,
152+
filterParentType,
147153
}: AppGroupAppFilterContextType = useAppGroupAppFilterContext()
148154
const clearSelection = (): void => {
149155
setSelectedAppList([])
@@ -152,6 +158,7 @@ export const MenuList = (props: any): JSX.Element => {
152158
const onTabChange = (e): void => {
153159
setSelectedFilterTab(e.currentTarget.dataset.selectedTab)
154160
}
161+
const selectedType = filterParentType === FilterParentType.env ? 'applications' : 'environments'
155162
return (
156163
<components.MenuList {...props}>
157164
<div className="dc__position-sticky dc__top-0 bcn-0">
@@ -183,7 +190,7 @@ export const MenuList = (props: any): JSX.Element => {
183190
selectedFilterTab === AppFilterTabs.APP_FILTER ? 'fw-6 active' : 'fw-4'
184191
}`}
185192
>
186-
<span>All applications </span>
193+
<span>All {selectedType} </span>
187194
</div>
188195
{selectedFilterTab === AppFilterTabs.APP_FILTER && <div className="apps-tab__active-tab" />}
189196
</li>
@@ -192,9 +199,9 @@ export const MenuList = (props: any): JSX.Element => {
192199
<div className="flex flex-justify dc__window-bg w-100 pt-6 pr-8 pb-6 pl-8">
193200
<span className="fs-12 fw-6 cn-9">
194201
Working with {selectedAppList?.length > 0 ? selectedAppList.length : appListOptions.length}/
195-
{appListOptions?.length} Applications
202+
{appListOptions?.length} {selectedType}
196203
</span>
197-
{selectedAppList?.length > 0 && selectedAppList.length !== appListOptions?.length && (
204+
{selectedAppList?.length > 0 && (
198205
<Clear className="icon-dim-16 mr-4 mw-18 cursor icon-n4" onClick={clearSelection} />
199206
)}
200207
</div>
@@ -206,8 +213,8 @@ export const MenuList = (props: any): JSX.Element => {
206213
<InfoIcon className="icon-dim-20 mr-4 mw-18 cursor fcn-6 mb-4" />
207214
<div className="fs-13 fw-6 cn-9 mb-4">No saved filters</div>
208215
<div className="fs-12 fw-4 cn-7 dc__align-center ">
209-
To save a filter, select some applications from All applications and click on ‘Save selection as
210-
filter’
216+
To save a filter, select some {selectedType} from All {selectedType} and click on ‘Save
217+
selection as filter’
211218
</div>
212219
</div>
213220
)}

src/components/ApplicationGroup/AppGroupAppFilter.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { useState } from 'react'
22
import ReactSelect from 'react-select'
33
import { useAppGroupAppFilterContext } from './AppGroupDetailsRoute'
44
import { appGroupAppSelectorStyle } from './AppGroup.utils'
5-
import { AppGroupAppFilterContextType } from './AppGroup.types'
5+
import { AppGroupAppFilterContextType, FilterParentType } from './AppGroup.types'
66
import { AppFilterTabs } from './Constants'
77
import { MenuList, Option, ValueContainer } from './AppGroupAppFilter.components'
88

@@ -18,6 +18,7 @@ export default function AppGroupAppFilter() {
1818
groupFilterOptions,
1919
selectedGroupFilter,
2020
setSelectedGroupFilter,
21+
filterParentType
2122
}: AppGroupAppFilterContextType = useAppGroupAppFilterContext()
2223
const [appFilterAppInput, setAppFilterAppInput] = useState('')
2324
const [appFilterGroupInput, setAppFilterGroupInput] = useState('')
@@ -76,6 +77,13 @@ export default function AppGroupAppFilter() {
7677
}
7778
}
7879

80+
const getPlaceHolder = (): string => {
81+
if (selectedFilterTab === AppFilterTabs.APP_FILTER) {
82+
return `Search ${filterParentType === FilterParentType.env ? 'applications' : 'environments'}`
83+
}
84+
return 'Search filters'
85+
}
86+
7987
return (
8088
<ReactSelect
8189
menuIsOpen={isMenuOpen}
@@ -98,7 +106,7 @@ export default function AppGroupAppFilter() {
98106
ValueContainer: ValueContainer,
99107
MenuList: MenuList,
100108
}}
101-
placeholder={selectedFilterTab === AppFilterTabs.APP_FILTER ? 'Search applications' : 'Search filters'}
109+
placeholder={getPlaceHolder()}
102110
styles={appGroupAppSelectorStyle}
103111
onKeyDown={escHandler}
104112
/>

src/components/ApplicationGroup/AppGroupDetailsRoute.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
CheckPermissionType,
3232
CreateGroupAppListType,
3333
EnvHeaderType,
34+
FilterParentType,
3435
GroupOptionType,
3536
} from './AppGroup.types'
3637
import { MultiValue } from 'react-select'
@@ -43,7 +44,7 @@ import { CONTEXT_NOT_AVAILABLE_ERROR } from '../../config/constantMessaging'
4344
import { toast } from 'react-toastify'
4445
import CreateAppGroup from './CreateAppGroup'
4546

46-
const AppGroupAppFilterContext = React.createContext<AppGroupAppFilterContextType>(null)
47+
export const AppGroupAppFilterContext = React.createContext<AppGroupAppFilterContextType>(null)
4748

4849
export function useAppGroupAppFilterContext() {
4950
const context = React.useContext(AppGroupAppFilterContext)
@@ -392,6 +393,7 @@ export default function AppGroupDetailsRoute({ isSuperAdmin }: AppGroupAdminType
392393
appList={allAppsList}
393394
selectedAppGroup={clickedGroup}
394395
closePopup={closeCreateGroup}
396+
filterParentType={FilterParentType.env}
395397
/>
396398
)}
397399
{showDeleteGroup && isPopupBox && (
@@ -445,6 +447,7 @@ export function EnvHeader({
445447
openCreateGroup,
446448
openDeleteGroup,
447449
isSuperAdmin,
450+
filterParentType: FilterParentType.env,
448451
}),
449452
[
450453
appListOptions,
@@ -519,7 +522,6 @@ export function EnvHeader({
519522
onClickTabPreventDefault(event, 'active')
520523
}
521524

522-
523525
const renderEnvDetailsTabs = () => {
524526
return (
525527
<ul role="tablist" className="tab-list">
@@ -528,7 +530,9 @@ export function EnvHeader({
528530
activeClassName="active"
529531
to={`${match.url}/${URLS.APP_OVERVIEW}`}
530532
className="tab-list__tab-link"
531-
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+
}
532536
>
533537
Overview
534538
</NavLink>
@@ -539,7 +543,9 @@ export function EnvHeader({
539543
to={`${match.url}/${URLS.APP_TRIGGER}`}
540544
className="tab-list__tab-link"
541545
data-testid="group-build-deploy"
542-
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+
}
543549
>
544550
Build & Deploy
545551
</NavLink>
@@ -571,7 +577,9 @@ export function EnvHeader({
571577
to={`${match.url}/${URLS.APP_CONFIG}`}
572578
className="tab-list__tab-link flex"
573579
data-testid="group-configuration"
574-
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+
}
575583
>
576584
<Settings className="tab-list__icon icon-dim-16 fcn-9 mr-4" />
577585
Configurations

src/components/ApplicationGroup/Constants.ts

Lines changed: 7 additions & 1 deletion
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 => {
@@ -179,4 +183,6 @@ export const GetBranchChangeStatus = (statusText: string): BulkResponseStatus =>
179183
default:
180184
return
181185
}
182-
}
186+
}
187+
188+
export const FILTER_NAME_REGEX = /^[a-z][a-z0-9-]{1,}[a-z0-9]$/

0 commit comments

Comments
 (0)