Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gitlab): add filtering and pagination (#403) #403

Merged
merged 2 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions reana-ui/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export const USER_REQUEST_TOKEN_URL = `${api}/api/token`;
export const USER_CONFIRM_EMAIL_URL = `${api}/api/confirm-email`;
export const CLUSTER_STATUS_URL = `${api}/api/status`;
export const GITLAB_AUTH_URL = `${api}/api/gitlab/connect`;
export const GITLAB_PROJECTS_URL = `${api}/api/gitlab/projects`;
export const GITLAB_PROJECTS_URL = (params) =>
`${api}/api/gitlab/projects?${stringifyQueryParams(params)}`;
export const GITLAB_WEBHOOK_URL = `${api}/api/gitlab/webhook`;
export const WORKFLOWS_URL = (params) =>
`${api}/api/workflows?verbose=true&${stringifyQueryParams(params)}`;
Expand Down Expand Up @@ -174,8 +175,10 @@ class Client {
});
}

getGitlabProjects() {
return this._request(GITLAB_PROJECTS_URL);
getGitlabProjects({ search, pagination } = {}) {
return this._request(
GITLAB_PROJECTS_URL({ ...(pagination ?? {}), search }),
);
}

toggleGitlabProject(method, data) {
Expand Down
4 changes: 3 additions & 1 deletion reana-ui/src/components/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import styles from "./Search.module.scss";

const TYPING_DELAY = 1000;

export default function Search({ search }) {
export default function Search({ search, loading = false }) {
const handleChange = debounce(search, TYPING_DELAY);
return (
<Input
Expand All @@ -25,12 +25,14 @@ export default function Search({ search }) {
placeholder="Search..."
className={styles.input}
onChange={(_, data) => handleChange(data.value)}
loading={loading}
/>
);
}

Search.propTypes = {
search: PropTypes.func.isRequired,
loading: PropTypes.bool,
};

export const applyFilter = (filter, pagination, setPagination) => (value) => {
Expand Down
98 changes: 71 additions & 27 deletions reana-ui/src/pages/profile/components/GitLabProjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,66 @@
*/

import isEmpty from "lodash/isEmpty";
import { useEffect, useState } from "react";
import { useEffect, useState, useRef } from "react";
import { Button, List, Loader, Radio, Message, Icon } from "semantic-ui-react";

import client, { GITLAB_AUTH_URL } from "~/client";
import { Search, Pagination } from "~/components";

import styles from "./GitLabProjects.module.scss";

export default function GitLabProjects() {
const DEFAULT_PAGINATION = { page: 1, size: 10 };

const [projects, setProjects] = useState(null);
const [fetchingProjects, setFetchingProjects] = useState(false);
const [searchFilter, setSearchFilter] = useState(null);
const [pagination, setPagination] = useState(DEFAULT_PAGINATION);
const [totalPages, setTotalPages] = useState(0);

// keep track of last fetch request in order to avoid
// updating the state with out-of-order responses
const lastFetchRequest = useRef(null);

useEffect(() => {
/**
* Gets data from the specified API
*/
const getProjects = () => {
setFetchingProjects(true);
client
.getGitlabProjects()
.then((res) => {
let newProjects = {};
for (const [id, details] of Object.entries(res.data)) {
newProjects[id] = { ...details, toggling: false };
}
setProjects(newProjects);
setFetchingProjects(false);
})
.catch((e) => {
setProjects(null);
setFetchingProjects(false);
});
};

getProjects();
}, []);
// Fetch project list
setFetchingProjects(true);
let request = client.getGitlabProjects({
pagination,
search: searchFilter,
});
lastFetchRequest.current = request;

request
.then((res) => {
if (request !== lastFetchRequest.current) {
// this is not the last request, so ignore it
return;
}
let newProjects = {};
for (const project of res.data.items) {
newProjects[project.id] = { ...project, toggling: false };
}
setProjects(newProjects);
const newTotalPages =
res.data.total != null
? Math.ceil(res.data.total / pagination.size)
: res.data.has_next
? pagination.page + 1
: pagination.page;
setTotalPages(newTotalPages);
setFetchingProjects(false);
})
.catch((e) => {
if (lastFetchRequest.current !== request) {
// this is not the last request, so ignore it
return;
}
setProjects(null);
setTotalPages(0);
setFetchingProjects(false);
});
}, [searchFilter, pagination]);

const setToggling = (projectId, toggling) => {
setProjects((currentProjects) => ({
Expand Down Expand Up @@ -91,7 +116,14 @@ export default function GitLabProjects() {
});
};

if (fetchingProjects) {
const onSearchFilterChange = (value) => {
// reset pagination if search filter changes
setPagination(DEFAULT_PAGINATION);
setSearchFilter(value);
};

if (fetchingProjects && projects === null) {
// projects were never fetched before, show spinner
return (
<Loader active inline="centered">
Fetching projects...
Expand Down Expand Up @@ -125,6 +157,7 @@ export default function GitLabProjects() {
} else {
return (
<>
<Search search={onSearchFilterChange} loading={fetchingProjects} />
{!isEmpty(projects) ? (
<>
<List>
Expand Down Expand Up @@ -155,20 +188,31 @@ export default function GitLabProjects() {
},
)}
</List>
<div className={styles.pagination}>
<Pagination
activePage={pagination.page}
totalPages={totalPages}
onPageChange={(_, { activePage }) => {
setPagination({ ...pagination, page: activePage });
}}
disabled={fetchingProjects}
/>
</div>
</>
) : (
<Message info icon>
<Icon name="info circle" />
<Message.Content>
<Message.Header>No GitLab projects found</Message.Header>
<p>
If you would like to use REANA with GitLab, please{" "}
If you would like to use REANA with GitLab, please adjust your
search query or{" "}
<a
href="https://gitlab.cern.ch/projects/new"
rel="noopener noreferrer"
target="_blank"
>
create a project
create a new project
</a>{" "}
and come back.
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@
display: flex;
align-items: center;
}

.pagination {
width: fit-content;
margin: auto;
}