Skip to content

Commit 437b243

Browse files
authoredNov 29, 2023
collection list - use HubListToolbar, add sort (#4507) (#4631)
* collection list, namespace detail - use HubListToolbar No-Issue * CollectionFilter - repurpose for HubListToolbar * HubListToolbar - add switcher, use in search * CollectionFilter cleanup * no more .hub-pagination-container, removing css * no more .hub-toolbar-left, remove css * fix Sort height when without Select * sort by name, namespace, pulp_created, version * remove unused exports * hub-list-toolbar: add data-cy (cherry picked from commit cc0a5af)

File tree

15 files changed

+166
-295
lines changed

15 files changed

+166
-295
lines changed
 

‎src/api/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export {
3131
} from './response-types/ansible-repository';
3232
export {
3333
CollectionDetailType,
34-
CollectionListType,
3534
CollectionUploadType,
3635
CollectionUsedByDependencies,
3736
CollectionVersion,

‎src/components/collection-list/collection-filter.scss

-4
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { t } from '@lingui/macro';
2+
import { AnsibleRepositoryAPI, TagAPI } from 'src/api';
3+
4+
const loadRepos = (inputText) =>
5+
AnsibleRepositoryAPI.list({
6+
name__icontains: inputText,
7+
pulp_label_select: '!hide_from_search',
8+
}).then(({ data: { results } }) =>
9+
results.map(({ name }) => ({
10+
id: name,
11+
title: name,
12+
})),
13+
);
14+
15+
const loadTags = (inputText) =>
16+
TagAPI.listCollections({ name__icontains: inputText, sort: '-count' }).then(
17+
({ data: { data } }) =>
18+
data.map(({ name, count }) => ({
19+
id: name,
20+
title: count === undefined ? name : t`${name} (${count})`,
21+
})),
22+
);
23+
24+
export const collectionFilter = ({
25+
featureFlags: { display_signatures, display_repositories },
26+
ignoredParams: i,
27+
}) => {
28+
const displayNamespaces = !i.includes('namespace');
29+
const displayRepos = display_repositories && !i.includes('repository_name');
30+
const displayTags = !i.includes('tags');
31+
32+
const filterConfig = [
33+
{
34+
id: 'keywords',
35+
title: t`Keywords`,
36+
},
37+
displayRepos && {
38+
id: 'repository_name',
39+
title: t`Repository`,
40+
inputType: 'typeahead' as const,
41+
},
42+
displayNamespaces && {
43+
id: 'namespace',
44+
title: t`Namespace`,
45+
},
46+
displayTags && {
47+
id: 'tags',
48+
title: t`Tag`,
49+
inputType: 'typeahead' as const,
50+
},
51+
display_signatures && {
52+
id: 'is_signed',
53+
title: t`Sign state`,
54+
inputType: 'select' as const,
55+
options: [
56+
{ id: 'true', title: t`Signed` },
57+
{ id: 'false', title: t`Unsigned` },
58+
],
59+
},
60+
].filter(Boolean);
61+
62+
const sortOptions = [
63+
{ title: t`Name`, id: 'name', type: 'alpha' as const },
64+
{ title: t`Namespace`, id: 'namespace', type: 'alpha' as const },
65+
{ title: t`Last Modified`, id: 'pulp_created', type: 'numeric' as const },
66+
{ title: t`Version`, id: 'version', type: 'numeric' as const },
67+
];
68+
69+
return {
70+
filterConfig,
71+
sortOptions,
72+
typeaheads: {
73+
repository_name: loadRepos,
74+
tags: loadTags,
75+
},
76+
};
77+
};

‎src/components/collection-list/collection-filter.tsx

-168
This file was deleted.

‎src/components/collection-list/collection-list.tsx

+21-23
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,36 @@ import { ParamHelper } from 'src/utilities';
1111
import './list.scss';
1212

1313
interface IProps {
14+
collectionControls: (collection) => {
15+
dropdownMenu?: React.ReactNode | null;
16+
uploadButton?: React.ReactNode | null;
17+
};
1418
collections: CollectionVersionSearch[];
1519
displaySignatures: boolean;
20+
ignoredParams: string[];
21+
itemCount: number;
1622
params: {
17-
sort?: string;
1823
page?: number;
1924
page_size?: number;
25+
sort?: string;
2026
};
2127
updateParams: (params) => void;
22-
itemCount: number;
23-
ignoredParams: string[];
24-
collectionControls: (collection) => {
25-
dropdownMenu?: React.ReactNode | null;
26-
uploadButton?: React.ReactNode | null;
27-
};
2828
}
2929

3030
// only used in namespace detail, collections uses individual items
31-
export const CollectionList = (props: IProps) => {
32-
const {
33-
collections,
34-
collectionControls,
35-
displaySignatures,
36-
params,
37-
updateParams,
38-
ignoredParams,
39-
itemCount,
40-
} = props;
41-
31+
export const CollectionList = ({
32+
collectionControls,
33+
collections,
34+
displaySignatures,
35+
ignoredParams,
36+
itemCount,
37+
params,
38+
updateParams,
39+
}: IProps) => {
4240
return (
43-
<React.Fragment>
41+
<>
4442
<DataList aria-label={t`List of Collections`}>
45-
{collections.length > 0 ? (
43+
{collections.length ? (
4644
collections.map((c, i) => (
4745
<CollectionListItem
4846
key={i}
@@ -65,10 +63,10 @@ export const CollectionList = (props: IProps) => {
6563
)}
6664
</DataList>
6765
<Pagination
68-
params={params}
69-
updateParams={(p) => updateParams(p)}
7066
count={itemCount}
67+
params={params}
68+
updateParams={updateParams}
7169
/>
72-
</React.Fragment>
70+
</>
7371
);
7472
};

‎src/components/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export { CollectionUsedbyDependenciesList } from './collection-dependencies-list
1212
export { CollectionContentList } from './collection-detail/collection-content-list';
1313
export { CollectionInfo } from './collection-detail/collection-info';
1414
export { TableOfContents } from './collection-detail/table-of-contents';
15-
export { CollectionFilter } from './collection-list/collection-filter';
15+
export { collectionFilter } from './collection-list/collection-filter';
1616
export { CollectionList } from './collection-list/collection-list';
1717
export { CollectionListItem } from './collection-list/collection-list-item';
1818
export { ConfirmModal } from './confirm-modal/confirm-modal';

‎src/components/shared/hub-list-toolbar.tsx

+26-10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import React, { ReactNode, useEffect, useState } from 'react';
88
import {
99
AppliedFilters,
10+
CardListSwitcher,
1011
CompoundFilter,
1112
FilterOption,
1213
Pagination,
@@ -22,6 +23,7 @@ interface IProps {
2223
ignoredParams: string[];
2324
params: ParamType;
2425
sortOptions?: SortFieldType[];
26+
switcher?: string;
2527
typeaheads?: Record<
2628
string,
2729
(inputText: string) => Promise<{ id: string; title: string }[]>
@@ -50,14 +52,14 @@ function useTypeaheads(typeaheads, { inputText, selectedFilter }) {
5052
return options;
5153
}
5254

53-
// FIXME: missing CardListSwitcher to be usable everywhere
5455
export function HubListToolbar({
5556
buttons,
5657
count,
5758
filterConfig,
5859
ignoredParams,
5960
params,
6061
sortOptions,
62+
switcher,
6163
typeaheads,
6264
updateParams,
6365
}: IProps) {
@@ -85,7 +87,7 @@ export function HubListToolbar({
8587
: null;
8688

8789
return (
88-
<Toolbar style={{ paddingLeft: '8px' }}>
90+
<Toolbar style={{ paddingLeft: '8px' }} data-cy='hub-list-toolbar'>
8991
<ToolbarContent>
9092
<ToolbarGroup
9193
style={{
@@ -128,17 +130,31 @@ export function HubListToolbar({
128130
) : (
129131
renderedButtons
130132
)}
131-
<ToolbarItem
133+
<ToolbarGroup
132134
alignment={{ default: 'alignRight' }}
133135
style={{ alignSelf: 'start' }}
134136
>
135-
<Pagination
136-
params={params}
137-
updateParams={updateParams}
138-
count={count}
139-
isTop
140-
/>
141-
</ToolbarItem>
137+
{switcher ? (
138+
<ToolbarItem>
139+
<CardListSwitcher
140+
size='sm'
141+
params={params}
142+
updateParams={(p) => {
143+
window.localStorage.setItem(switcher, p.view_type);
144+
updateParams(p);
145+
}}
146+
/>
147+
</ToolbarItem>
148+
) : null}
149+
<ToolbarItem>
150+
<Pagination
151+
params={params}
152+
updateParams={updateParams}
153+
count={count}
154+
isTop
155+
/>
156+
</ToolbarItem>
157+
</ToolbarGroup>
142158
</ToolbarContent>
143159
</Toolbar>
144160
);

‎src/components/shared/sort.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,14 @@ export class Sort extends React.Component<IProps, IState> {
156156
className='clickable'
157157
onClick={() => this.setDescending()}
158158
size='md'
159-
style={{ marginLeft: '5px' }}
159+
style={{ margin: '6px 0 6px 5px' }}
160160
/>
161161
) : (
162162
<IconAsc
163163
className='clickable'
164164
onClick={() => this.setDescending()}
165165
size='md'
166-
style={{ marginLeft: '5px' }}
166+
style={{ margin: '5px 0 7px 5px' }}
167167
/>
168168
)}
169169
</div>

‎src/containers/namespace-detail/namespace-detail.tsx

+14-24
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ import {
1919
AlertList,
2020
AlertType,
2121
ClipboardCopy,
22-
CollectionFilter,
2322
CollectionList,
2423
DeleteCollectionModal,
2524
DeleteModal,
2625
EmptyStateNoData,
2726
ExternalLink,
27+
HubListToolbar,
2828
ImportModal,
2929
LoadingPageWithHeader,
3030
Main,
31-
Pagination,
3231
PartnerHeader,
3332
SignAllCertificatesModal,
3433
StatefulDropdown,
3534
Tooltip,
3635
closeAlertMixin,
36+
collectionFilter,
3737
} from 'src/components';
3838
import { AppContext } from 'src/loaders/app-context';
3939
import { Paths, formatPath } from 'src/paths';
@@ -392,29 +392,19 @@ export class NamespaceDetail extends React.Component<RouteProps, IState> {
392392
params={tabParams}
393393
updateParams={(p) => this.updateParams(p)}
394394
pageControls={this.renderPageControls()}
395-
filters={
396-
tab === 'collections' ? (
397-
<div>
398-
<div className='hub-toolbar hub-toolbar-left'>
399-
<CollectionFilter
400-
ignoredParams={ignoredParams}
401-
params={params}
402-
updateParams={updateParams}
403-
/>
404-
405-
<div className='hub-pagination-container'>
406-
<Pagination
407-
params={params}
408-
updateParams={updateParams}
409-
count={filteredCount}
410-
isTop
411-
/>
412-
</div>
413-
</div>
414-
</div>
415-
) : null
416-
}
417395
/>
396+
{tab === 'collections' ? (
397+
<HubListToolbar
398+
count={filteredCount}
399+
ignoredParams={ignoredParams}
400+
params={params}
401+
updateParams={updateParams}
402+
{...collectionFilter({
403+
featureFlags: this.context.featureFlags,
404+
ignoredParams,
405+
})}
406+
/>
407+
) : null}
418408
<Main>
419409
{tab === 'collections' ? (
420410
noData ? (

‎src/containers/not-found/dispatch.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const SectionTitle = ({ children }: { children: ReactNode }) => (
2828
<h2 className='pf-c-title'>{children}</h2>
2929
);
3030

31-
export const Dispatch = ({ location, navigate }: RouteProps) => {
31+
const Dispatch = ({ location, navigate }: RouteProps) => {
3232
const { featureFlags } = useContext();
3333

3434
const { pathname } = ParamHelper.parseParamString(location.search) as {

‎src/containers/search/multi-search.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const Section = ({
6363

6464
const loading = [];
6565

66-
export const MultiSearch = (props: RouteProps) => {
66+
const MultiSearch = (props: RouteProps) => {
6767
const { featureFlags } = useContext();
6868
const [alerts, setAlerts] = useState<AlertType[]>([]);
6969
const [params, setParams] = useState({});

‎src/containers/search/search.scss

-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
display: flex;
44
flex-direction: column;
55

6-
.hub-pagination-container .card-list-switcher {
7-
margin-right: 24px;
8-
}
9-
106
.collection-container {
117
padding-top: 24px;
128
flex-grow: 1;

‎src/containers/search/search.tsx

+20-46
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ import {
1313
AlertList,
1414
AlertType,
1515
BaseHeader,
16-
CardListSwitcher,
1716
CollectionCard,
18-
CollectionFilter,
1917
CollectionListItem,
2018
CollectionNextPageCard,
2119
DeleteCollectionModal,
2220
EmptyStateFilter,
2321
EmptyStateNoData,
22+
HubListToolbar,
2423
ImportModal,
2524
LoadingPageSpinner,
2625
Pagination,
2726
StatefulDropdown,
2827
closeAlertMixin,
28+
collectionFilter,
2929
} from 'src/components';
3030
import { Constants } from 'src/constants';
3131
import { AppContext } from 'src/loaders/app-context';
@@ -157,6 +157,8 @@ class Search extends React.Component<RouteProps, IState> {
157157
? null
158158
: deleteCollection?.repository?.name;
159159

160+
const ignoredParams = ['page', 'page_size', 'sort', 'view_type'];
161+
160162
return (
161163
<div className='search-page'>
162164
<AlertList
@@ -205,48 +207,20 @@ class Search extends React.Component<RouteProps, IState> {
205207
namespace={updateCollection.collection_version.namespace}
206208
/>
207209
)}
208-
<BaseHeader className='hub-header-bordered' title={t`Collections`}>
209-
{!noData && (
210-
<div>
211-
<div className='hub-toolbar hub-toolbar-left'>
212-
<CollectionFilter
213-
ignoredParams={['page', 'page_size', 'sort', 'view_type']}
214-
params={params}
215-
updateParams={updateParams}
216-
/>
217-
218-
<div className='hub-pagination-container'>
219-
<div className='card-list-switcher'>
220-
<CardListSwitcher
221-
size='sm'
222-
params={params}
223-
updateParams={(p) =>
224-
this.updateParams(p, () =>
225-
// Note, we have to use this.state.params instead
226-
// of params in the callback because the callback
227-
// executes before the page can re-run render
228-
// which means params doesn't contain the most
229-
// up to date state
230-
localStorage.setItem(
231-
Constants.SEARCH_VIEW_TYPE_LOCAL_KEY,
232-
this.state.params.view_type,
233-
),
234-
)
235-
}
236-
/>
237-
</div>
238-
239-
<Pagination
240-
params={params}
241-
updateParams={updateParams}
242-
count={count}
243-
isTop
244-
/>
245-
</div>
246-
</div>
247-
</div>
248-
)}
249-
</BaseHeader>
210+
<BaseHeader className='hub-header-bordered' title={t`Collections`} />
211+
{!noData && (
212+
<HubListToolbar
213+
count={count}
214+
ignoredParams={ignoredParams}
215+
params={params}
216+
switcher={Constants.SEARCH_VIEW_TYPE_LOCAL_KEY}
217+
updateParams={updateParams}
218+
{...collectionFilter({
219+
featureFlags: this.context.featureFlags,
220+
ignoredParams,
221+
})}
222+
/>
223+
)}
250224
{loading ? (
251225
<LoadingPageSpinner />
252226
) : noData ? (
@@ -255,7 +229,7 @@ class Search extends React.Component<RouteProps, IState> {
255229
description={t`Collections will appear once uploaded`}
256230
/>
257231
) : (
258-
<React.Fragment>
232+
<>
259233
<section className='collection-container'>
260234
{this.renderCollections(collections, {
261235
count,
@@ -270,7 +244,7 @@ class Search extends React.Component<RouteProps, IState> {
270244
count={count}
271245
/>
272246
</section>
273-
</React.Fragment>
247+
</>
274248
)}
275249
</div>
276250
);

‎src/loaders/app.scss

-7
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ body,
5252
align-items: center;
5353
}
5454

55-
// collections and namespaces - align with cards/lists, instead of table columns
56-
.hub-toolbar-left {
57-
.pf-c-toolbar__content {
58-
padding-left: 0;
59-
}
60-
}
61-
6255
// inline alert inside pf-c-content has big title and extra margin
6356
.hub-content-alert-fix {
6457
.pf-c-alert__title {

‎test/cypress/e2e/collections/collections_list.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ describe('Collections list Tests', () => {
77
function deprecate(list) {
88
const container = list ? '.hub-list' : '.hub-cards';
99

10-
cy.get('.hub-toolbar')
10+
cy.get('[data-cy=hub-list-toolbar]')
1111
.get('[aria-label="keywords"]:first')
1212
.type('my_collection0{enter}');
1313
cy.get(container).contains('my_collection2').should('not.exist');
@@ -120,7 +120,7 @@ describe('Collections list Tests', () => {
120120

121121
it('Can delete collection in collection list', () => {
122122
cy.get('[data-cy="view_type_list"] svg').click();
123-
cy.get('.hub-toolbar')
123+
cy.get('[data-cy=hub-list-toolbar]')
124124
.get('[aria-label="keywords"]:first')
125125
.type('my_collection0{enter}');
126126
cy.get('.hub-list').contains('my_collection2').should('not.exist');
@@ -139,7 +139,7 @@ describe('Collections list Tests', () => {
139139

140140
it('Can delete collection in namespace collection list', () => {
141141
cy.visit(`${uiPrefix}namespaces/my_namespace`);
142-
cy.get('.hub-toolbar')
142+
cy.get('[data-cy=hub-list-toolbar]')
143143
.get('[aria-label="keywords"]:first')
144144
.type('my_collection1{enter}');
145145

0 commit comments

Comments
 (0)
Please sign in to comment.