feat: Implemented sorting on search page
Signed-off-by: Raul Kele <raulkeleblk@gmail.com>
This commit is contained in:
parent
f33aa8d647
commit
49093f9493
@ -1,4 +1,5 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { api } from 'api';
|
||||
import Explore from 'components/Explore';
|
||||
import React from 'react';
|
||||
@ -177,4 +178,16 @@ describe('Explore component', () => {
|
||||
render(<StateExploreWrapper />);
|
||||
await waitFor(() => expect(error).toBeCalledTimes(1));
|
||||
});
|
||||
|
||||
it("should render the sort filter and be able to change it's value", async () => {
|
||||
// @ts-ignore
|
||||
jest.spyOn(api, 'get').mockResolvedValue({ status: 200, data: { data: mockImageList } });
|
||||
render(<StateExploreWrapper />);
|
||||
const selectFilter = await screen.findByText('Relevance');
|
||||
expect(selectFilter).toBeInTheDocument();
|
||||
userEvent.click(selectFilter);
|
||||
const newOption = await screen.findByText('Alphabetical');
|
||||
userEvent.click(newOption);
|
||||
expect(await screen.findByText('Alphabetical')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
13
src/api.js
13
src/api.js
@ -1,6 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import axios from 'axios';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { sortByCriteria } from 'utilities/sortCriteria';
|
||||
|
||||
const api = {
|
||||
// This method returns the generic request configuration for axios
|
||||
@ -78,9 +79,17 @@ const endpoints = {
|
||||
`/v2/_zot/ext/search?query={BaseImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned Vulnerabilities {MaxSeverity Count}}}`,
|
||||
isDependentOnForImage: (name) =>
|
||||
`/v2/_zot/ext/search?query={DerivedImageList(image: "${name}"){RepoName Tag Description Digest Vendor DownloadCount LastUpdated Size Platform {Os Arch} IsSigned Vulnerabilities {MaxSeverity Count}}}`,
|
||||
globalSearch: ({ searchQuery = '""', pageNumber = 1, pageSize = 15, filter = {} }) => {
|
||||
globalSearch: ({
|
||||
searchQuery = '""',
|
||||
pageNumber = 1,
|
||||
pageSize = 15,
|
||||
sortBy = sortByCriteria.relevance.value,
|
||||
filter = {}
|
||||
}) => {
|
||||
const searchParam = searchQuery !== '' ? `query:"${searchQuery}"` : `query:""`;
|
||||
const paginationParam = `requestedPage: {limit:${pageSize} offset:${(pageNumber - 1) * pageSize}}`;
|
||||
const paginationParam = `requestedPage: {limit:${pageSize} offset:${
|
||||
(pageNumber - 1) * pageSize
|
||||
} sortBy: ${sortBy}}`;
|
||||
let filterParam = `,filter: {`;
|
||||
if (filter.Os) filterParam += ` Os:${!isEmpty(filter.Os) ? `${JSON.stringify(filter.Os)}` : '""'}`;
|
||||
if (filter.Arch) filterParam += ` Arch:${!isEmpty(filter.Arch) ? `${JSON.stringify(filter.Arch)}` : '""'}`;
|
||||
|
@ -6,7 +6,7 @@ import RepoCard from './RepoCard.jsx';
|
||||
import Loading from './Loading';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import { Container, Grid, Stack } from '@mui/material';
|
||||
import { Container, FormControl, Grid, InputLabel, MenuItem, Select, Stack } from '@mui/material';
|
||||
|
||||
import makeStyles from '@mui/styles/makeStyles';
|
||||
|
||||
@ -18,6 +18,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import FilterCard from './FilterCard.jsx';
|
||||
import { isEmpty } from 'lodash';
|
||||
import filterConstants from 'utilities/filterConstants.js';
|
||||
import { sortByCriteria } from 'utilities/sortCriteria.js';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
gridWrapper: {
|
||||
@ -46,14 +47,16 @@ const useStyles = makeStyles(() => ({
|
||||
sortForm: {
|
||||
backgroundColor: '#ffffff',
|
||||
borderColor: '#E0E0E0',
|
||||
borderRadius: '0.375em'
|
||||
borderRadius: '0.375em',
|
||||
width: '25%',
|
||||
textAlign: 'left'
|
||||
}
|
||||
}));
|
||||
|
||||
function Explore() {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [exploreData, setExploreData] = useState([]);
|
||||
// const [sortFilter, setSortFilter] = useState('');
|
||||
const [sortFilter, setSortFilter] = useState(sortByCriteria.relevance.value);
|
||||
const [queryParams] = useSearchParams();
|
||||
const search = queryParams.get('search');
|
||||
// filtercard filters
|
||||
@ -78,7 +81,7 @@ function Explore() {
|
||||
setIsLoading(true);
|
||||
api
|
||||
.get(
|
||||
`${host()}${endpoints.globalSearch({ searchQuery: search, filter: buildFilterQuery() })}`,
|
||||
`${host()}${endpoints.globalSearch({ searchQuery: search, sortBy: sortFilter, filter: buildFilterQuery() })}`,
|
||||
abortController.signal
|
||||
)
|
||||
.then((response) => {
|
||||
@ -93,11 +96,12 @@ function Explore() {
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
setIsLoading(false);
|
||||
});
|
||||
return () => {
|
||||
abortController.abort();
|
||||
};
|
||||
}, [search, queryParams, imageFilters, osFilters, archFilters]);
|
||||
}, [search, queryParams, imageFilters, osFilters, archFilters, sortFilter]);
|
||||
|
||||
const renderRepoCards = () => {
|
||||
return (
|
||||
@ -150,26 +154,35 @@ function Explore() {
|
||||
);
|
||||
};
|
||||
|
||||
// const handleSortChange = (event) => {
|
||||
// setSortFilter(event.target.value);
|
||||
// };
|
||||
const handleSortChange = (event) => {
|
||||
setSortFilter(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg">
|
||||
<Grid container className={classes.gridWrapper}>
|
||||
<Grid container item xs={12}>
|
||||
<Grid item xs={0}></Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid item xs={3}></Grid>
|
||||
<Grid item xs={9}>
|
||||
<Stack direction="row" className={classes.resultsRow}>
|
||||
<Typography variant="body2" className={classes.results}>
|
||||
Results {exploreData.length}
|
||||
</Typography>
|
||||
{/* <FormControl sx={{m:'1', minWidth:"4.6875rem"}} className={classes.sortForm} size="small">
|
||||
<InputLabel>Sort</InputLabel>
|
||||
<Select label="Sort" value={sortFilter} onChange={handleSortChange} MenuProps={{disableScrollLock: true}}>
|
||||
<MenuItem value='relevance'>Relevance</MenuItem>
|
||||
</Select>
|
||||
</FormControl> */}
|
||||
<FormControl sx={{ m: '1', minWidth: '4.6875rem' }} className={classes.sortForm} size="small">
|
||||
<InputLabel>Sort</InputLabel>
|
||||
<Select
|
||||
label="Sort"
|
||||
value={sortFilter}
|
||||
onChange={handleSortChange}
|
||||
MenuProps={{ disableScrollLock: true }}
|
||||
>
|
||||
{Object.values(sortByCriteria).map((el) => (
|
||||
<MenuItem key={el.value} value={el.value}>
|
||||
{el.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
26
src/utilities/sortCriteria.js
Normal file
26
src/utilities/sortCriteria.js
Normal file
@ -0,0 +1,26 @@
|
||||
export const sortByCriteria = {
|
||||
relevance: {
|
||||
value: 'RELEVANCE',
|
||||
label: 'Relevance'
|
||||
},
|
||||
updateTime: {
|
||||
value: 'UPDATE_TIME',
|
||||
label: 'Recent'
|
||||
},
|
||||
alphabetic: {
|
||||
value: 'ALPHABETIC_ASC',
|
||||
label: 'Alphabetical'
|
||||
},
|
||||
alphabeticDesc: {
|
||||
value: 'ALPHABETIC_DSC',
|
||||
label: 'Alphabetical desc'
|
||||
},
|
||||
stars: {
|
||||
value: 'STARS',
|
||||
label: 'Most starred'
|
||||
},
|
||||
downloads: {
|
||||
value: 'DOWNLOADS',
|
||||
label: 'Most downloaded'
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user