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

Paginate the commit history page with query params #1028

Merged
merged 3 commits into from
Aug 28, 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
14 changes: 12 additions & 2 deletions webapp/src/dogma/common/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ import NextLink from 'next/link';
interface BreadcrumbsProps {
path: string;
omitIndexList?: number[];
omitQueryList?: number[];
unlinkedList?: number[];
replaces?: { [key: number]: string };
suffixes?: { [key: number]: string };
query?: string;
}

export const Breadcrumbs = ({
path,
omitIndexList = [],
omitQueryList = [],
unlinkedList = [],
replaces = {},
// /project/projectName/repos/repoName -> /project/projectName/repos/repoName/tree/head
suffixes = {},
query = '',
}: BreadcrumbsProps) => {
const asPathNestedRoutes = path
// If the path belongs to a file, the top level should be a directory
Expand All @@ -30,18 +34,24 @@ export const Breadcrumbs = ({
return (
<Breadcrumb spacing="8px" separator={<FcNext />} mb={8} fontWeight="medium" fontSize="2xl">
{asPathNestedRoutes.map((page, i) => {
prefixes.push(page);
const item = replaces[i] || page;
prefixes.push(item);
if (omitIndexList.includes(i)) {
return null;
}
let query0;
if (omitQueryList.includes(i) || omitQueryList.includes(i - asPathNestedRoutes.length)) {
query0 = '';
} else {
query0 = query ? `?${query}` : '';
}

return (
<BreadcrumbItem key={i}>
{!unlinkedList.includes(i) && i < asPathNestedRoutes.length - 1 ? (
<BreadcrumbLink
as={NextLink}
href={`/${prefixes.join('/')}${suffixes[i] || ''}`}
href={`/${prefixes.join('/')}${suffixes[i] || ''}${query0}`}
paddingBottom={1}
>
{decodeURI(item)}
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/dogma/common/components/CompareButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ const CompareButton = ({ projectName, repoName, headRevision }: CompareButtonPro
Compare
</Button>
</PopoverTrigger>
<PopoverContent width={'220px'}>
<PopoverContent width={'240px'}>
<PopoverArrow />
<PopoverBody>
<form onSubmit={handleSubmit(onSubmit)}>
<Stack direction={'row'}>
<FormControl isRequired>
<Input
type="number"
placeholder={`Revision 1..${headRevision - 1}`}
placeholder={`Rev 1..${headRevision - 1}`}
autoFocus
{...register('baseRevision', { required: true, min: 1, max: headRevision - 1 })}
/>
Expand Down
1 change: 1 addition & 0 deletions webapp/src/dogma/common/components/Deferred.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Loading } from './Loading';

interface LoadingProps {
isLoading: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
error: any;
children: () => ReactNode;
}
Expand Down
12 changes: 6 additions & 6 deletions webapp/src/dogma/common/components/editor/FileEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { newNotification } from 'dogma/features/notification/notificationSlice';
import ErrorMessageParser from 'dogma/features/services/ErrorMessageParser';
import Router from 'next/router';
import Link from 'next/link';
import { FaCodeCommit } from 'react-icons/fa6';
import { FaHistory } from 'react-icons/fa';

export type FileEditorProps = {
projectName: string;
Expand All @@ -37,7 +37,7 @@ export type FileEditorProps = {
originalContent: string;
path: string;
name: string;
commitRevision: number;
revision: string | number;
};

// Map file extension to language identifier
Expand Down Expand Up @@ -66,7 +66,7 @@ const FileEditor = ({
originalContent,
path,
name,
commitRevision,
revision,
}: FileEditorProps) => {
const dispatch = useAppDispatch();
const language = extensionToLanguageMap[extension] || extension;
Expand Down Expand Up @@ -117,12 +117,12 @@ const FileEditor = ({
<Button
size={'sm'}
as={Link}
href={`/app/projects/${projectName}/repos/${repoName}/commit/${commitRevision}/${path}`}
leftIcon={<FaCodeCommit />}
href={`/app/projects/${projectName}/repos/${repoName}/commits/${path}${revision !== 'head' ? `?from=${revision}` : ''}`}
leftIcon={<FaHistory />}
variant="outline"
colorScheme="gray"
>
Commit
History
</Button>
<Button
onClick={switchMode}
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/dogma/common/components/table/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const DataTable = <Data extends object>({ table }: { table: ReactTable<Da
<Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
// see https://tanstack.com/table/v8/docs/api/core/column-def#meta to type this correctly
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const meta: any = header.column.columnDef.meta;
return (
<Th
Expand Down Expand Up @@ -41,6 +42,7 @@ export const DataTable = <Data extends object>({ table }: { table: ReactTable<Da
<Tr key={row.id} data-testid="table-row">
{row.getVisibleCells().map((cell) => {
// see https://tanstack.com/table/v8/docs/api/core/column-def#meta to type this correctly
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const meta: any = cell.column.columnDef.meta;
return (
<Td key={cell.id} isNumeric={meta?.isNumeric}>
Expand Down
28 changes: 19 additions & 9 deletions webapp/src/dogma/common/components/table/DynamicDataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import {
import { DataTable } from 'dogma/common/components/table/DataTable';
import { Filter } from 'dogma/common/components/table/Filter';
import { PaginationBar } from 'dogma/common/components/table/PaginationBar';
import { Dispatch, SetStateAction, useState } from 'react';
import React, { ReactElement, useState } from 'react';

export type DynamicDataTableProps<Data extends object> = {
data: Data[];
columns: ColumnDef<Data>[];
pagination?: { pageIndex: number; pageSize: number };
setPagination?: Dispatch<SetStateAction<PaginationState>>;
setPagination?: (updater: (old: PaginationState) => PaginationState) => void;
pageCount?: number;
disableGotoButton?: boolean;
onEmptyData?: ReactElement;
};

export const DynamicDataTable = <Data extends object>({
Expand All @@ -29,6 +31,8 @@ export const DynamicDataTable = <Data extends object>({
pagination,
setPagination,
pageCount,
disableGotoButton,
onEmptyData,
}: DynamicDataTableProps<Data>) => {
const [sorting, setSorting] = useState<SortingState>([]);
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
Expand All @@ -53,13 +57,19 @@ export const DynamicDataTable = <Data extends object>({

return (
<>
<Text mb="8px">Filter by {table.getHeaderGroups()[0].headers[0].id} </Text>
<Filter
table={table}
column={table.getHeaderGroups()[0].headers[0].column /* Filter by the 1st column */}
/>
<DataTable table={table} />
{pagination && <PaginationBar table={table} />}
{table.getRowModel().rows.length == 0 && onEmptyData ? (
onEmptyData
) : (
<>
<Text mb="8px">Filter by {table.getHeaderGroups()[0].headers[0].id} </Text>
<Filter
table={table}
column={table.getHeaderGroups()[0].headers[0].column /* Filter by the 1st column */}
/>
<DataTable table={table} />
</>
)}
{pagination && <PaginationBar table={table} disableGotoButton={disableGotoButton} />}
</>
);
};
60 changes: 35 additions & 25 deletions webapp/src/dogma/common/components/table/PaginationBar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { Flex, Input, Text, Select, Spacer, IconButton } from '@chakra-ui/react';
import { Flex, IconButton, Input, Select, Spacer, Text } from '@chakra-ui/react';
import { Table as ReactTable } from '@tanstack/react-table';
import { MdNavigateBefore, MdNavigateNext, MdSkipNext, MdSkipPrevious } from 'react-icons/md';

export const PaginationBar = <Data extends object>({ table }: { table: ReactTable<Data> }) => {
type PaginationBarProps<Data extends object> = {
table: ReactTable<Data>;
disableGotoButton?: boolean;
};

export const PaginationBar = <Data extends object>({ table, disableGotoButton }: PaginationBarProps<Data>) => {
return (
<Flex gap={2} mt={2} alignItems="center">
{disableGotoButton && <Spacer />}
<IconButton
aria-label="First page"
icon={<MdSkipPrevious />}
Expand Down Expand Up @@ -34,29 +40,33 @@ export const PaginationBar = <Data extends object>({ table }: { table: ReactTabl
{table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
</Text>
<Spacer />
<Text>Go to page:</Text>
<Input
type="number"
defaultValue={table.getState().pagination.pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
table.setPageIndex(page);
}}
width={20}
/>
<Select
value={table.getState().pagination.pageSize}
onChange={(e) => {
table.setPageSize(Number(e.target.value));
}}
width="auto"
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</Select>
{!disableGotoButton && (
<>
<Text>Go to page:</Text>
<Input
type="number"
defaultValue={table.getState().pagination.pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
table.setPageIndex(page);
}}
width={20}
/>
<Select
value={table.getState().pagination.pageSize}
onChange={(e) => {
table.setPageSize(Number(e.target.value));
}}
width="auto"
>
{[10, 20, 30, 40, 50, 100, 200, 400].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</Select>
</>
)}
</Flex>
);
};
6 changes: 5 additions & 1 deletion webapp/src/dogma/features/api/apiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export type GetFileContent = {
projectName: string;
repoName: string;
filePath: string;
revision: string;
revision: string | number;
};

export type TitleDto = {
Expand Down Expand Up @@ -328,6 +328,7 @@ export const apiSlice = createApi({
query: ({ projectName, id }) => `/api/v1/projects/${projectName}/mirrors/${id}`,
providesTags: ['Metadata'],
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
addNewMirror: builder.mutation<any, MirrorDto>({
query: (mirror) => ({
url: `/api/v1/projects/${mirror.projectName}/mirrors`,
Expand All @@ -336,6 +337,7 @@ export const apiSlice = createApi({
}),
invalidatesTags: ['Metadata'],
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
updateMirror: builder.mutation<any, { projectName: string; id: string; mirror: MirrorDto }>({
query: ({ projectName, id, mirror }) => ({
url: `/api/v1/projects/${projectName}/mirrors/${id}`,
Expand All @@ -352,6 +354,7 @@ export const apiSlice = createApi({
query: ({ projectName, id }) => `/api/v1/projects/${projectName}/credentials/${id}`,
providesTags: ['Metadata'],
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
addNewCredential: builder.mutation<any, { projectName: string; credential: CredentialDto }>({
query: ({ projectName, credential }) => ({
url: `/api/v1/projects/${projectName}/credentials`,
Expand All @@ -360,6 +363,7 @@ export const apiSlice = createApi({
}),
invalidatesTags: ['Metadata'],
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
updateCredential: builder.mutation<any, { projectName: string; id: string; credential: CredentialDto }>({
query: ({ projectName, id, credential }) => ({
url: `/api/v1/projects/${projectName}/credentials/${id}`,
Expand Down
1 change: 1 addition & 0 deletions webapp/src/dogma/features/file/FileDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export interface FileDto {
revision: number;
type: FileType;
url: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
content?: string | any;
}
Loading
Loading