Skip to content

Commit 1cc12d4

Browse files
committed
Repository list - filter by Remote (or None)
add typeahead filter by Remote, with an extra None (remote=null) option Issue: AAH-2271
1 parent 8d86d93 commit 1cc12d4

File tree

4 files changed

+76
-26
lines changed

4 files changed

+76
-26
lines changed

src/components/page/list-page.tsx

+30-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
EmptyStateFilter,
1717
EmptyStateNoData,
1818
EmptyStateUnauthorized,
19+
FilterOption,
1920
LoadingPageSpinner,
2021
Main,
2122
Pagination,
@@ -43,6 +44,7 @@ interface IState<T> {
4344
alerts: AlertType[];
4445
unauthorised: boolean;
4546
inputText: string;
47+
selectedFilter: string;
4648
}
4749

4850
// states:
@@ -82,8 +84,7 @@ interface ListPageParams<T> {
8284
defaultSort?: string;
8385
displayName: string;
8486
errorTitle: MessageDescriptor;
85-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
86-
filterConfig: any[]; // FilterOption[] but { title: MessageDescriptor }
87+
filterConfig: ({ state }) => FilterOption[];
8788
headerActions?: ActionType[];
8889
listItemActions?: ActionType[];
8990
noDataButton?: (item, actionContext) => React.ReactNode;
@@ -94,6 +95,7 @@ interface ListPageParams<T> {
9495
renderTableRow: RenderTableRow<T>;
9596
sortHeaders: SortHeaders;
9697
title: MessageDescriptor;
98+
typeaheadQuery?: ({ inputText, selectedFilter, setState }) => void;
9799
}
98100

99101
export const ListPage = function <T>({
@@ -127,6 +129,8 @@ export const ListPage = function <T>({
127129
sortHeaders,
128130
// container title
129131
title,
132+
// for typeahed filters
133+
typeaheadQuery,
130134
}: ListPageParams<T>) {
131135
renderModals ||= function (actionContext) {
132136
return (
@@ -174,6 +178,7 @@ export const ListPage = function <T>({
174178
items: [],
175179
loading: true,
176180
params,
181+
selectedFilter: null,
177182
unauthorised: false,
178183
};
179184
}
@@ -193,13 +198,7 @@ export const ListPage = function <T>({
193198
const { alerts, itemCount, items, loading, params, unauthorised } =
194199
this.state;
195200

196-
const localizedFilterConfig = (filterConfig || [])
197-
.map(translateTitle)
198-
.map(({ options, ...rest }) => ({
199-
...rest,
200-
options: options?.map(translateTitle),
201-
}));
202-
201+
const localizedFilterConfig = filterConfig({ state: this.state }) || [];
203202
const knownFilters = localizedFilterConfig.map(({ id }) => id);
204203
const noData = items.length === 0 && !filterIsSet(params, knownFilters);
205204

@@ -257,15 +256,34 @@ export const ListPage = function <T>({
257256
<ToolbarItem>
258257
<CompoundFilter
259258
inputText={this.state.inputText}
260-
onChange={(inputText) =>
261-
this.setState({ inputText })
262-
}
259+
onChange={(inputText) => {
260+
this.setState({ inputText });
261+
262+
if (typeaheadQuery) {
263+
typeaheadQuery({
264+
inputText,
265+
selectedFilter: this.state.selectedFilter,
266+
setState: (s) => this.setState(s),
267+
});
268+
}
269+
}}
263270
updateParams={(p) => {
264271
this.setState({ inputText: '' });
265272
updateParams(p);
266273
}}
267274
params={params}
268275
filterConfig={localizedFilterConfig}
276+
selectFilter={(selectedFilter) => {
277+
this.setState({ selectedFilter });
278+
279+
if (typeaheadQuery) {
280+
typeaheadQuery({
281+
inputText: '',
282+
selectedFilter,
283+
setState: (s) => this.setState(s),
284+
});
285+
}
286+
}}
269287
/>
270288
</ToolbarItem>
271289
{headerActions?.length &&

src/components/patternfly-wrappers/compound-filter.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,10 @@ export class CompoundFilter extends React.Component<IProps, IState> {
166166
/>
167167
);
168168
case 'typeahead': {
169-
const typeAheadResults = this.props.filterConfig
169+
const typeaheadResults = this.props.filterConfig
170170
.find(({ id }) => id === selectedFilter.id)
171171
.options.map(({ id, title }) => ({ id, name: title }));
172+
172173
return (
173174
<APISearchTypeAhead
174175
multiple={false}
@@ -179,13 +180,14 @@ export class CompoundFilter extends React.Component<IProps, IState> {
179180
this.props.onChange('');
180181
}}
181182
onSelect={(event, value) => {
182-
this.submitFilter(value);
183+
const item = typeaheadResults.find(({ name }) => name === value);
184+
this.submitFilter(item?.id || value);
183185
}}
184186
placeholderText={
185187
selectedFilter?.placeholder ||
186188
t`Filter by ${selectedFilter.title.toLowerCase()}`
187189
}
188-
results={typeAheadResults}
190+
results={typeaheadResults}
189191
/>
190192
);
191193
}

src/containers/ansible-remote/list.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { msg } from '@lingui/macro';
1+
import { msg, t } from '@lingui/macro';
22
import React from 'react';
33
import { Link } from 'react-router-dom';
44
import {
@@ -34,10 +34,10 @@ const AnsibleRemoteList = ListPage<AnsibleRemoteType>({
3434
defaultSort: '-pulp_created',
3535
displayName: 'AnsibleRemoteList',
3636
errorTitle: msg`Remotes could not be displayed.`,
37-
filterConfig: [
37+
filterConfig: () => [
3838
{
3939
id: 'name__icontains',
40-
title: msg`Remote name`,
40+
title: t`Remote name`,
4141
},
4242
],
4343
headerActions: [ansibleRemoteCreateAction], // Add remote

src/containers/ansible-repository/list.tsx

+38-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { msg } from '@lingui/macro';
1+
import { msg, t } from '@lingui/macro';
22
import React from 'react';
33
import { Link } from 'react-router-dom';
44
import {
@@ -8,7 +8,11 @@ import {
88
ansibleRepositoryEditAction,
99
ansibleRepositorySyncAction,
1010
} from 'src/actions';
11-
import { AnsibleRepositoryAPI, AnsibleRepositoryType } from 'src/api';
11+
import {
12+
AnsibleRemoteAPI,
13+
AnsibleRepositoryAPI,
14+
AnsibleRepositoryType,
15+
} from 'src/api';
1216
import {
1317
DateComponent,
1418
ListItemActions,
@@ -31,34 +35,59 @@ const listItemActions = [
3135
ansibleRepositoryDeleteAction,
3236
];
3337

38+
const typeaheadQuery = ({ inputText, selectedFilter, setState }) => {
39+
console.log('typeaheadQuery', { inputText, selectedFilter });
40+
if (selectedFilter !== 'remote') {
41+
return;
42+
}
43+
44+
return AnsibleRemoteAPI.list({ name__icontains: inputText })
45+
.then(({ data: { results } }) =>
46+
results.map(({ name, pulp_href }) => ({ id: pulp_href, title: name })),
47+
)
48+
.then((remotes) => setState({ remotes }));
49+
};
50+
3451
const AnsibleRepositoryList = ListPage<AnsibleRepositoryType>({
3552
condition: canViewAnsibleRepositories,
3653
defaultPageSize: 10,
3754
defaultSort: '-pulp_created',
3855
displayName: 'AnsibleRepositoryList',
3956
errorTitle: msg`Repositories could not be displayed.`,
40-
filterConfig: [
57+
filterConfig: ({ state: { remotes } }) => [
4158
{
4259
id: 'name__icontains',
43-
title: msg`Repository name`,
60+
title: t`Repository name`,
4461
},
4562
{
4663
id: 'pulp_label_select',
47-
title: msg`Pipeline`,
64+
title: t`Pipeline`,
4865
inputType: 'select',
4966
options: [
5067
{
5168
id: `pipeline=${Constants.NOTCERTIFIED}`,
52-
title: msg`Rejected`,
69+
title: t`Rejected`,
5370
},
5471
{
5572
id: `pipeline=${Constants.NEEDSREVIEW}`,
56-
title: msg`Needs Review`,
73+
title: t`Needs Review`,
5774
},
5875
{
5976
id: `pipeline=${Constants.APPROVED}`,
60-
title: msg`Approved`,
77+
title: t`Approved`,
78+
},
79+
],
80+
},
81+
{
82+
id: 'remote',
83+
title: t`Remote`,
84+
inputType: 'typeahead',
85+
options: [
86+
{
87+
id: 'null',
88+
title: t`None`,
6189
},
90+
...(remotes || []),
6291
],
6392
},
6493
],
@@ -68,6 +97,7 @@ const AnsibleRepositoryList = ListPage<AnsibleRepositoryType>({
6897
noDataDescription: msg`Repositories will appear once created.`,
6998
noDataTitle: msg`No repositories yet`,
7099
query: ({ params }) => AnsibleRepositoryAPI.list(params),
100+
typeaheadQuery,
71101
renderTableRow(item: AnsibleRepositoryType, index: number, actionContext) {
72102
const {
73103
last_sync_task,

0 commit comments

Comments
 (0)