Skip to content

Commit

Permalink
Support loading more search results (loic-sharma#437)
Browse files Browse the repository at this point in the history
Addresses loic-sharma#412
  • Loading branch information
loic-sharma authored Jul 4, 2020
1 parent 673eb0f commit 5aeef27
Showing 1 changed file with 129 additions and 40 deletions.
169 changes: 129 additions & 40 deletions src/BaGet.UI/src/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Link } from 'react-router-dom';
import './SearchResults.css';
import DefaultPackageIcon from "./default-package-icon-256x256.png";

const defaultSearchTake = 20;

interface ISearchResultsProps {
input: string;
}
Expand All @@ -24,6 +26,7 @@ interface ISearchResultsState {
includePrerelease: boolean;
packageType: string;
targetFramework: string;
page: number;
items: IPackage[];
loading: boolean;
}
Expand All @@ -41,15 +44,16 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS

this.state = {
includePrerelease: true,
items: [],
packageType: 'any',
targetFramework: 'any',
page: 1,
items: [],
loading: false
};
}

public componentDidMount() {
this._loadItems(
this.loadItems(
this.props.input,
this.state.includePrerelease,
this.state.packageType,
Expand All @@ -67,14 +71,18 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS
return;
}

this._loadItems(
this.loadItems(
this.props.input,
this.state.includePrerelease,
this.state.packageType,
this.state.targetFramework);
}

public render() {
let noResultsFound = !this.state.loading && this.state.items.length === 0;
let showLoadMore = !this.state.loading &&
this.state.items.length === this.state.page * defaultSearchTake;

return (
<div>
<form className="search-options form-inline">
Expand Down Expand Up @@ -161,9 +169,21 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS
/>
</div>
</form>

{(() => {
if (this.state.loading || this.state.items.length > 0) {
if (noResultsFound) {
return (
<div>
<h2>Oops, nothing here...</h2>
<p>
It looks like there's no package here to see. Take a look below for useful links.
</p>
<p><Link to="/upload">Upload a package</Link></p>
<p><a href="https://loic-sharma.github.io/BaGet/" target="_blank" rel="noopener noreferrer">BaGet documentation</a></p>
<p><a href="https://github.com/loic-sharma/BaGet/issues" target="_blank" rel="noopener noreferrer">BaGet issues</a></p>
</div>
);
} else {
return this.state.items.map(value => (
<div key={value.id} className="row search-result">
<div className="col-sm-1 hidden-xs hidden-sm">
Expand Down Expand Up @@ -207,42 +227,103 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS
</div>
));
}
else
{
return (
<div>
<h2>Oops, nothing here...</h2>
<p>
It looks like there's no package here to see. Take a look below for useful links.
</p>
<p><Link to="/upload">Upload a package</Link></p>
<p><a href="https://loic-sharma.github.io/BaGet/" target="_blank" rel="noopener noreferrer">BaGet documentation</a></p>
<p><a href="https://github.com/loic-sharma/BaGet/issues" target="_blank" rel="noopener noreferrer">BaGet issues</a></p>
</div>
);
}
})()}

{showLoadMore &&
<div className="row text-center">
<div className="col-sm-12">
<h3>
<button type="button" onClick={this.loadMore} className="link-button">
<span>Load more...</span>
</button>
</h3>
</div>
</div>
}

</div>
);
}

private _loadItems(query: string, includePrerelease: boolean, packageType: string, targetFramework: string): void {
private loadItems(
query: string,
includePrerelease: boolean,
packageType: string,
targetFramework: string
): void {
const url = this.buildUrl(
query,
0,
includePrerelease,
packageType,
targetFramework
);

let resetItems = () =>
this.setState({
page: 1,
items: [],
includePrerelease: includePrerelease,
packageType: packageType,
targetFramework: targetFramework,
loading: true,
});

let setItems = (results: ISearchResponse) =>
this.setState({
page: 1,
items: results.data,
includePrerelease: includePrerelease,
packageType: packageType,
targetFramework: targetFramework,
loading: false,
});

this.fetchSearchResults(url, resetItems, setItems);
}

private loadMoreItems(): void {
const url = this.buildUrl(
this.props.input,
this.state.page * defaultSearchTake,
this.state.includePrerelease,
this.state.packageType,
this.state.targetFramework);

let showLoading = () =>
this.setState({
...this.state,
loading: true
});

let addPage = (results: ISearchResponse) =>
this.setState({
page: this.state.page + 1,
items: this.state.items.concat(results.data),
includePrerelease: this.state.includePrerelease,
packageType: this.state.packageType,
targetFramework: this.state.targetFramework,
loading: false
});

this.fetchSearchResults(
url,
showLoading,
addPage);
}

private fetchSearchResults(
url: string,
onStart: () => void,
onComplete: (results: ISearchResponse) => void
): void {
if (this.resultsController) {
this.resultsController.abort();
}

this.resultsController = new AbortController();

this.setState({
includePrerelease,
items: [],
packageType,
targetFramework,
loading: true
});

const url = this.buildUrl(query, includePrerelease, packageType, targetFramework);
onStart();

fetch(url, {signal: this.resultsController.signal}).then(response => {
return response.ok
Expand All @@ -255,12 +336,7 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS

const results = resultsJson as ISearchResponse;

this.setState({
includePrerelease,
items: results.data,
targetFramework,
loading: false
});
onComplete(results);
})
.catch((e) => {
var ex = e as DOMException;
Expand All @@ -270,15 +346,26 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS
});
}

private buildUrl(query: string, includePrerelease: boolean, packageType?: string, targetFramework?: string) {
private buildUrl(
query: string,
skip: number,
includePrerelease: boolean,
packageType?: string,
targetFramework?: string
): string {
const parameters: { [parameter: string]: string } = {
semVerLevel: "2.0.0"
semVerLevel: "2.0.0",
take: defaultSearchTake.toString()
};

if (query && query.length !== 0) {
parameters.q = query;
}

if (skip !== 0) {
parameters.skip = skip.toString();
}

if (includePrerelease) {
parameters.prerelease = 'true';
}
Expand All @@ -303,28 +390,30 @@ class SearchResults extends React.Component<ISearchResultsProps, ISearchResultsS
}

private onChangePackageType = (e: React.FormEvent<HTMLDivElement>, option?: IDropdownOption) : void => {
this._loadItems(
this.loadItems(
this.props.input,
this.state.includePrerelease,
(option) ? option.key.toString() : 'any',
this.state.targetFramework);
}

private onChangeFramework = (e: React.FormEvent<HTMLDivElement>, option?: IDropdownOption) : void => {
this._loadItems(
this.loadItems(
this.props.input,
this.state.includePrerelease,
this.state.packageType,
option!.key.toString());
}

private onChangePrerelease = () : void => {
this._loadItems(
this.loadItems(
this.props.input,
!this.state.includePrerelease,
this.state.packageType,
this.state.targetFramework);
}

private loadMore = () : void => this.loadMoreItems();
}

export default SearchResults;

0 comments on commit 5aeef27

Please sign in to comment.