2022-02-28 17:00:12 +01:00
|
|
|
import { useContext, useMemo, useState } from 'react';
|
2022-05-05 13:42:18 +02:00
|
|
|
import { Link, useNavigate } from 'react-router-dom';
|
2021-07-07 11:04:36 +02:00
|
|
|
import { mutate } from 'swr';
|
2022-02-28 17:00:12 +01:00
|
|
|
import { getProjectFetcher } from 'hooks/api/getters/useProject/getProjectFetcher';
|
|
|
|
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
2022-05-02 12:52:33 +02:00
|
|
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
2022-03-01 22:23:23 +01:00
|
|
|
import { ProjectCard } from '../ProjectCard/ProjectCard';
|
2021-07-16 15:41:54 +02:00
|
|
|
import { useStyles } from './ProjectList.styles';
|
2022-02-28 17:00:12 +01:00
|
|
|
import { IProjectCard } from 'interfaces/project';
|
2021-07-07 11:04:36 +02:00
|
|
|
import loadingData from './loadingData';
|
2022-02-28 17:00:12 +01:00
|
|
|
import useLoading from 'hooks/useLoading';
|
|
|
|
import PageContent from 'component/common/PageContent';
|
|
|
|
import AccessContext from 'contexts/AccessContext';
|
2022-05-02 12:52:33 +02:00
|
|
|
import { HeaderTitle } from 'component/common/HeaderTitle/HeaderTitle';
|
2022-02-28 17:00:12 +01:00
|
|
|
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
|
|
|
|
import { CREATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
2022-05-02 15:52:41 +02:00
|
|
|
import { Add } from '@mui/icons-material';
|
2022-02-28 17:00:12 +01:00
|
|
|
import ApiError from 'component/common/ApiError/ApiError';
|
|
|
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|
|
|
import { SearchField } from 'component/common/SearchField/SearchField';
|
|
|
|
import classnames from 'classnames';
|
2021-07-07 11:04:36 +02:00
|
|
|
|
|
|
|
type projectMap = {
|
|
|
|
[index: string]: boolean;
|
|
|
|
};
|
|
|
|
|
2021-10-01 12:15:02 +02:00
|
|
|
function resolveCreateButtonData(isOss: boolean, hasAccess: boolean) {
|
2021-10-19 13:08:25 +02:00
|
|
|
if (isOss) {
|
2021-10-01 12:15:02 +02:00
|
|
|
return {
|
|
|
|
title: 'You must be on a paid subscription to create new projects',
|
2021-10-19 13:08:25 +02:00
|
|
|
disabled: true,
|
|
|
|
};
|
2021-10-01 12:15:02 +02:00
|
|
|
} else if (!hasAccess) {
|
|
|
|
return {
|
2021-10-19 13:08:25 +02:00
|
|
|
title: 'You do not have permission to create new projects',
|
|
|
|
disabled: true,
|
|
|
|
};
|
2021-10-01 12:15:02 +02:00
|
|
|
} else {
|
|
|
|
return {
|
|
|
|
title: 'Click to create a new project',
|
2021-10-19 13:08:25 +02:00
|
|
|
disabled: false,
|
|
|
|
};
|
2021-10-01 12:15:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-28 17:00:12 +01:00
|
|
|
export const ProjectListNew = () => {
|
2021-07-07 11:04:36 +02:00
|
|
|
const { hasAccess } = useContext(AccessContext);
|
2022-05-05 13:42:18 +02:00
|
|
|
const navigate = useNavigate();
|
2022-05-02 15:52:41 +02:00
|
|
|
const { classes: styles } = useStyles();
|
2021-07-07 11:04:36 +02:00
|
|
|
const { projects, loading, error, refetch } = useProjects();
|
|
|
|
const [fetchedProjects, setFetchedProjects] = useState<projectMap>({});
|
|
|
|
const ref = useLoading(loading);
|
2021-10-01 12:15:02 +02:00
|
|
|
const { isOss } = useUiConfig();
|
2022-02-28 17:00:12 +01:00
|
|
|
const [filter, setFilter] = useState('');
|
|
|
|
|
|
|
|
const filteredProjects = useMemo(() => {
|
|
|
|
const regExp = new RegExp(filter, 'i');
|
|
|
|
return filter
|
2022-03-01 09:50:29 +01:00
|
|
|
? projects.filter(project => regExp.test(project.name))
|
2022-02-28 17:00:12 +01:00
|
|
|
: projects;
|
|
|
|
}, [projects, filter]);
|
2021-07-07 11:04:36 +02:00
|
|
|
|
|
|
|
const handleHover = (projectId: string) => {
|
|
|
|
if (fetchedProjects[projectId]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { KEY, fetcher } = getProjectFetcher(projectId);
|
|
|
|
mutate(KEY, fetcher);
|
|
|
|
setFetchedProjects(prev => ({ ...prev, [projectId]: true }));
|
|
|
|
};
|
|
|
|
|
2021-10-19 13:08:25 +02:00
|
|
|
const createButtonData = resolveCreateButtonData(
|
|
|
|
isOss(),
|
|
|
|
hasAccess(CREATE_PROJECT)
|
|
|
|
);
|
2021-10-01 12:15:02 +02:00
|
|
|
|
2021-07-07 11:04:36 +02:00
|
|
|
const renderError = () => {
|
|
|
|
return (
|
|
|
|
<ApiError
|
|
|
|
onClick={refetch}
|
|
|
|
className={styles.apiError}
|
|
|
|
text="Error fetching projects"
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderProjects = () => {
|
|
|
|
if (loading) {
|
|
|
|
return renderLoading();
|
|
|
|
}
|
|
|
|
|
2022-03-01 09:50:29 +01:00
|
|
|
return filteredProjects.map((project: IProjectCard) => {
|
2021-07-07 11:04:36 +02:00
|
|
|
return (
|
|
|
|
<Link
|
|
|
|
key={project.id}
|
2022-05-05 13:42:18 +02:00
|
|
|
to={`/projects/${project.id}`}
|
2021-07-07 11:04:36 +02:00
|
|
|
className={styles.cardLink}
|
|
|
|
>
|
|
|
|
<ProjectCard
|
|
|
|
onHover={() => handleHover(project?.id)}
|
|
|
|
name={project?.name}
|
2022-05-04 15:39:50 +02:00
|
|
|
memberCount={project?.memberCount ?? 0}
|
2021-07-07 11:04:36 +02:00
|
|
|
health={project?.health}
|
2021-07-16 15:41:54 +02:00
|
|
|
id={project?.id}
|
2021-07-07 11:04:36 +02:00
|
|
|
featureCount={project?.featureCount}
|
|
|
|
/>
|
|
|
|
</Link>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderLoading = () => {
|
|
|
|
return loadingData.map((project: IProjectCard) => {
|
|
|
|
return (
|
|
|
|
<ProjectCard
|
|
|
|
data-loading
|
|
|
|
onHover={() => {}}
|
|
|
|
key={project.id}
|
2021-07-16 15:41:54 +02:00
|
|
|
name={project.name}
|
|
|
|
id={project.id}
|
|
|
|
memberCount={2}
|
2021-07-07 11:04:36 +02:00
|
|
|
health={95}
|
2021-07-16 15:41:54 +02:00
|
|
|
featureCount={4}
|
2021-07-07 11:04:36 +02:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div ref={ref}>
|
2022-02-28 17:00:12 +01:00
|
|
|
<div className={styles.searchBarContainer}>
|
|
|
|
<SearchField
|
|
|
|
initialValue={filter}
|
|
|
|
updateValue={setFilter}
|
|
|
|
showValueChip
|
|
|
|
className={classnames(styles.searchBar, {
|
|
|
|
skeleton: loading,
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
</div>
|
2021-07-07 11:04:36 +02:00
|
|
|
<PageContent
|
|
|
|
headerContent={
|
|
|
|
<HeaderTitle
|
|
|
|
title="Projects"
|
|
|
|
actions={
|
2021-10-20 12:05:44 +02:00
|
|
|
<ResponsiveButton
|
|
|
|
Icon={Add}
|
2022-05-05 13:42:18 +02:00
|
|
|
onClick={() => navigate('/projects/create')}
|
2021-10-20 12:05:44 +02:00
|
|
|
maxWidth="700px"
|
|
|
|
permission={CREATE_PROJECT}
|
|
|
|
disabled={createButtonData.disabled}
|
|
|
|
>
|
2022-02-23 00:10:48 +01:00
|
|
|
New project
|
2021-10-20 12:05:44 +02:00
|
|
|
</ResponsiveButton>
|
2021-07-07 11:04:36 +02:00
|
|
|
}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<ConditionallyRender condition={error} show={renderError()} />
|
|
|
|
<div className={styles.container}>
|
|
|
|
<ConditionallyRender
|
2022-03-01 09:50:29 +01:00
|
|
|
condition={filteredProjects.length < 1 && !loading}
|
2021-07-07 11:04:36 +02:00
|
|
|
show={<div>No projects available.</div>}
|
|
|
|
elseShow={renderProjects()}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</PageContent>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|