mirror of https://github.com/boxyhq/jackson.git
129 lines
4.8 KiB
TypeScript
129 lines
4.8 KiB
TypeScript
import type { NextPage } from 'next';
|
|
import { DocumentMagnifyingGlassIcon, PlusIcon, WrenchScrewdriverIcon } from '@heroicons/react/24/outline';
|
|
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
|
import EmptyState from '@components/EmptyState';
|
|
import { useProjects } from '@lib/ui/retraced';
|
|
import Loading from '@components/Loading';
|
|
import { IconButton } from '@components/IconButton';
|
|
import { useTranslation } from 'next-i18next';
|
|
import router from 'next/router';
|
|
import { Pagination, pageLimit, NoMoreResults } from '@components/Pagination';
|
|
import usePaginate from '@lib/ui/hooks/usePaginate';
|
|
import { LinkPrimary } from '@components/LinkPrimary';
|
|
import { errorToast } from '@components/Toaster';
|
|
|
|
const ProjectList: NextPage = () => {
|
|
const { t } = useTranslation('common');
|
|
const { paginate, setPaginate } = usePaginate();
|
|
const { projects, isError, isLoading } = useProjects(paginate.offset, pageLimit);
|
|
|
|
if (isLoading) {
|
|
return <Loading />;
|
|
}
|
|
|
|
if (isError) {
|
|
errorToast(isError?.message || t('unable_to_fetch_projects'));
|
|
return null;
|
|
}
|
|
|
|
const noProjects = projects.length === 0 && paginate.offset === 0;
|
|
const noMoreResults = projects.length === 0 && paginate.offset > 0;
|
|
|
|
return (
|
|
<div>
|
|
<div className='mb-5 flex items-center justify-between'>
|
|
<h2 className='font-bold text-gray-700 dark:text-white md:text-xl'>{t('projects')}</h2>
|
|
<LinkPrimary Icon={PlusIcon} href={'/admin/retraced/projects/new'}>
|
|
{t('new_project')}
|
|
</LinkPrimary>
|
|
</div>
|
|
{noProjects ? (
|
|
<EmptyState title={t('no_projects_found')} href='/admin/retraced/projects/new' />
|
|
) : (
|
|
<>
|
|
<div className='rounder border'>
|
|
<table className='w-full text-left text-sm text-gray-500 dark:text-gray-400'>
|
|
<thead className='bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400'>
|
|
<tr>
|
|
<th scope='col' className='px-6 py-3'>
|
|
{t('name')}
|
|
</th>
|
|
<th scope='col' className='px-6 py-3'>
|
|
{t('id')}
|
|
</th>
|
|
<th scope='col' className='px-6 py-3'>
|
|
{t('created_at')}
|
|
</th>
|
|
<th scope='col' className='px-6 py-3'>
|
|
{t('actions')}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{projects?.map((project) => (
|
|
<tr key={project.id} className='border-b bg-white dark:border-gray-700 dark:bg-gray-800'>
|
|
<td className='whitespace-nowrap px-6 py-3 text-sm text-gray-500 dark:text-gray-400'>
|
|
{project.name}
|
|
</td>
|
|
<td className='whitespace-nowrap px-6 py-3 text-sm text-gray-500 dark:text-gray-400'>
|
|
{project.id}
|
|
</td>
|
|
<td className='whitespace-nowrap px-6 py-3 text-sm text-gray-500 dark:text-gray-400'>
|
|
{project.created}
|
|
</td>
|
|
<td className='px-6 py-3'>
|
|
<span className='inline-flex items-baseline'>
|
|
<IconButton
|
|
tooltip={t('configuration')}
|
|
Icon={WrenchScrewdriverIcon}
|
|
className='mr-3 hover:text-green-400'
|
|
onClick={() => {
|
|
router.push(`/admin/retraced/projects/${project.id}`);
|
|
}}
|
|
/>
|
|
<IconButton
|
|
tooltip={t('view_events')}
|
|
Icon={DocumentMagnifyingGlassIcon}
|
|
className='mr-3 hover:text-green-400'
|
|
onClick={() => {
|
|
router.push(`/admin/retraced/projects/${project.id}/events`);
|
|
}}
|
|
/>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
{noMoreResults && <NoMoreResults colSpan={4} />}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<Pagination
|
|
itemsCount={projects.length}
|
|
offset={paginate.offset}
|
|
onPrevClick={() => {
|
|
setPaginate({
|
|
offset: paginate.offset - pageLimit,
|
|
});
|
|
}}
|
|
onNextClick={() => {
|
|
setPaginate({
|
|
offset: paginate.offset + pageLimit,
|
|
});
|
|
}}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export async function getServerSideProps({ locale }) {
|
|
return {
|
|
props: {
|
|
...(await serverSideTranslations(locale, ['common'])),
|
|
},
|
|
};
|
|
}
|
|
|
|
export default ProjectList;
|