Skip to content

Commit 21697fe

Browse files
kyle-ssgZaimwa9
andauthored
chore: componentise feature filters (#6119)
Co-authored-by: Zaimwa9 <[email protected]>
1 parent acd5420 commit 21697fe

File tree

10 files changed

+316
-548
lines changed

10 files changed

+316
-548
lines changed

frontend/common/useDebouncedSearch.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export default function useDebouncedSearch(initialValue = '') {
1515
}, debounceTime)
1616

1717
const handleSearchInput = (value: string) => {
18-
console.log(debounceTime)
1918
setSearchInput(value)
2019
debouncedSearch(value)
2120
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import React from 'react'
2+
import ClearFilters from 'components/ClearFilters'
3+
import TableSearchFilter from 'components/tables/TableSearchFilter'
4+
import TableTagFilter from 'components/tables/TableTagFilter'
5+
import TableValueFilter from 'components/tables/TableValueFilter'
6+
import TableOwnerFilter from 'components/tables/TableOwnerFilter'
7+
import TableGroupsFilter from 'components/tables/TableGroupsFilter'
8+
import TableFilterOptions from 'components/tables/TableFilterOptions'
9+
import TableSortFilter, { SortValue } from 'components/tables/TableSortFilter'
10+
import { getViewMode, setViewMode, ViewMode } from 'common/useViewMode'
11+
import { isEqual } from 'lodash'
12+
import Utils from 'common/utils/utils'
13+
import { TagStrategy } from 'common/types/responses'
14+
import Format from 'common/utils/format'
15+
16+
export type FiltersValue = {
17+
search: string | null
18+
page: number
19+
tag_strategy: TagStrategy
20+
tags: (number | string)[]
21+
is_archived: boolean
22+
value_search: string | null
23+
is_enabled: boolean | null
24+
owners: number[]
25+
group_owners: number[]
26+
sort: SortValue
27+
}
28+
29+
type Props = {
30+
value: FiltersValue
31+
onChange: (next: FiltersValue) => void
32+
projectId: string | number
33+
orgId?: number
34+
isLoading?: boolean
35+
}
36+
37+
const DEFAULTS: FiltersValue = {
38+
group_owners: [],
39+
is_archived: false,
40+
is_enabled: null,
41+
owners: [],
42+
page: 1,
43+
search: '',
44+
sort: { label: 'Name', sortBy: 'name', sortOrder: 'asc' },
45+
tag_strategy: 'INTERSECTION',
46+
tags: [],
47+
value_search: '',
48+
}
49+
50+
// Converts filters to url params, excluding ones that are already default
51+
export function getURLParamsFromFilters(f: FiltersValue) {
52+
const existing = Utils.fromParam() as Record<string, string | undefined>
53+
54+
return {
55+
...existing,
56+
group_owners: f.group_owners?.length ? f.group_owners.join(',') : undefined,
57+
is_archived: f.is_archived ? 'true' : undefined,
58+
is_enabled:
59+
f.is_enabled === null ? undefined : f.is_enabled ? 'true' : 'false',
60+
owners: f.owners?.length ? f.owners.join(',') : undefined,
61+
page: f.page !== DEFAULTS.page ? String(f.page) : undefined,
62+
search: f.search || undefined,
63+
sortBy: f.sort.sortBy,
64+
sortOrder: f.sort.sortOrder,
65+
tag_strategy:
66+
f.tag_strategy !== DEFAULTS.tag_strategy
67+
? String(f.tag_strategy)
68+
: undefined,
69+
tags: f.tags?.length ? f.tags.join(',') : undefined,
70+
value_search: f.value_search || undefined,
71+
}
72+
}
73+
// Gets expected filters from URL parameters
74+
export const parseFiltersFromUrlParams = (
75+
params: Record<string, string | undefined>,
76+
) => {
77+
return {
78+
group_owners:
79+
typeof params.group_owners === 'string'
80+
? params.group_owners.split(',').map((v) => parseInt(v))
81+
: [],
82+
is_archived: params.is_archived === 'true',
83+
is_enabled:
84+
params.is_enabled === 'true'
85+
? true
86+
: params.is_enabled === 'false'
87+
? false
88+
: null,
89+
owners:
90+
typeof params.owners === 'string'
91+
? params.owners.split(',').map((v) => parseInt(v))
92+
: [],
93+
page: params.page ? parseInt(params.page) - 1 : 1,
94+
search: params.search || '',
95+
sort: {
96+
label: Format.camelCase(params.sortBy || 'Name'),
97+
sortBy: params.sortBy || 'name',
98+
sortOrder: params.sortOrder || 'asc',
99+
},
100+
tag_strategy: params.tag_strategy || 'INTERSECTION',
101+
tags:
102+
typeof params.tags === 'string'
103+
? params.tags.split(',').map((v) => (v ? parseInt(v) : v))
104+
: [],
105+
value_search:
106+
typeof params.value_search === 'string' ? params.value_search : '',
107+
} as FiltersValue
108+
}
109+
110+
//Converts filter to api expected properties
111+
export const getServerFilter = (f: FiltersValue) => ({
112+
...f,
113+
group_owners: f.group_owners?.length ? f.group_owners : undefined,
114+
owners: f.owners.length ? f.owners : undefined,
115+
search: (f.search || '').trim(),
116+
sort: f.sort,
117+
tags: f.tags.length ? f.tags.join(',') : undefined,
118+
})
119+
120+
//Detect if the filter is default
121+
const isDefault = (v: FiltersValue) => isEqual(v, DEFAULTS)
122+
123+
const FeatureFilters: React.FC<Props> = ({
124+
isLoading,
125+
onChange,
126+
orgId,
127+
projectId,
128+
value,
129+
}) => {
130+
const set = (partial: Partial<FiltersValue>) =>
131+
onChange({ ...value, ...partial })
132+
const clearAll = () => onChange({ ...DEFAULTS })
133+
return (
134+
<div className='table-header d-flex align-items-center'>
135+
<div className='table-column flex-row flex-fill'>
136+
<TableSearchFilter
137+
onChange={(e) => set({ search: Utils.safeParseEventValue(e) })}
138+
value={value.search}
139+
/>
140+
<div className='d-flex align-items-center py-2 py-lg-0 px-1 px-lg-0 flex-fill justify-content-lg-end'>
141+
{!isDefault(value) && <ClearFilters onClick={clearAll} />}
142+
<TableTagFilter
143+
isLoading={!!isLoading}
144+
projectId={projectId}
145+
className='me-4'
146+
tagStrategy={value.tag_strategy}
147+
onChangeStrategy={(tag_strategy) => set({ tag_strategy })}
148+
value={value.tags}
149+
onToggleArchived={(next) => set({ is_archived: next })}
150+
showArchived={value.is_archived}
151+
onChange={(tags) => {
152+
if (tags.includes('') && tags.length > 1) {
153+
if (!(value.tags || []).includes('')) set({ tags: [''] })
154+
else set({ tags: tags.filter((v) => !!v) })
155+
} else set({ tags })
156+
}}
157+
/>
158+
<TableValueFilter
159+
className={'me-4'}
160+
value={{
161+
enabled: value.is_enabled,
162+
valueSearch: value.value_search,
163+
}}
164+
onChange={({ enabled, valueSearch }) =>
165+
set({ is_enabled: enabled, value_search: valueSearch })
166+
}
167+
/>
168+
<TableOwnerFilter
169+
className={'me-4'}
170+
value={value.owners}
171+
onChange={(owners) => set({ owners })}
172+
/>
173+
<TableGroupsFilter
174+
className={'me-4'}
175+
orgId={orgId}
176+
value={value.group_owners}
177+
onChange={(group_owners) => set({ group_owners })}
178+
/>
179+
<TableFilterOptions
180+
title={'View'}
181+
className={'me-4'}
182+
value={getViewMode()}
183+
onChange={setViewMode as any}
184+
options={[
185+
{ label: 'Default', value: 'default' as ViewMode },
186+
{ label: 'Compact', value: 'compact' as ViewMode },
187+
]}
188+
/>
189+
<TableSortFilter
190+
isLoading={!!isLoading}
191+
value={value.sort}
192+
options={[
193+
{ label: 'Name', value: 'name' },
194+
{ label: 'Created Date', value: 'created_date' },
195+
]}
196+
onChange={(sort) => set({ sort })}
197+
/>
198+
</div>
199+
</div>
200+
</div>
201+
)
202+
}
203+
204+
export default FeatureFilters

frontend/web/components/feature-summary/FeatureTags.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ const FeatureTags: FC<FeatureTagsType> = ({ editFeature, projectFlag }) => {
4242
'git_code_references',
4343
)
4444
const hasScannedCodeReferences =
45-
projectFlag?.code_references_counts.length > 0
45+
projectFlag?.code_references_counts?.length > 0
4646
const codeReferencesCounts =
47-
projectFlag?.code_references_counts.reduce(
47+
projectFlag?.code_references_counts?.reduce(
4848
(acc, curr) => acc + curr.count,
4949
0,
5050
) || 0

frontend/web/components/modals/CreateFlag.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,9 +1757,10 @@ const CreateFlag = class extends Component {
17571757
e.stopPropagation()
17581758
removeUserOverride(
17591759
{
1760-
cb: () =>
1760+
cb: () =>
17611761
this.userOverridesPage(
1762-
1, true
1762+
1,
1763+
true,
17631764
),
17641765
environmentId:
17651766
this.props

0 commit comments

Comments
 (0)