🔧 Library page table pagination

This commit is contained in:
2022-10-27 23:06:40 -07:00
parent 63e96bf96e
commit ff5ce10e17
8 changed files with 309 additions and 180 deletions

View File

@@ -411,10 +411,18 @@ pre {
}
// Library
.sticky {
position: sticky;
top: 57px;
z-index: 2;
background: #fffffc;
position: sticky;
top: 107px;
z-index: 5;
.title {
background: #fffffc;
position: relative;
top: -56px;
z-index: 99999;
padding-top: 20px;
}
}
.library {
@@ -423,7 +431,7 @@ pre {
width: 100%;
thead {
position: sticky;
top: 146px;
top: 176px;
z-index: 1;
background: #fffffc;
min-height: 130px;

View File

@@ -20,7 +20,7 @@ export const PullList = ({ issues }: PullListProps): ReactElement => {
useEffect(() => {
dispatch(
getWeeklyPullList({
startDate: "2022-9-9",
startDate: "2022-10-9",
pageSize: "15",
currentPage: "1",
}),

View File

@@ -1,22 +1,169 @@
import React, { useMemo, ReactElement, useCallback } from "react";
import React, { useMemo, ReactElement, useCallback, useEffect } from "react";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
import T2Table from "../shared/T2Table";
import { isEmpty, isNil, isUndefined } from "lodash";
import MetadataPanel from "../shared/MetadataPanel";
import SearchBar from "./SearchBar";
import { useDispatch } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import { searchIssue } from "../../actions/fileops.actions";
import ellipsize from "ellipsize";
interface IComicBookLibraryProps {
data: {
searchResults: any;
};
}
export const Library = (data: IComicBookLibraryProps): ReactElement => {
const { searchResults } = data.data;
import {
ColumnDef,
flexRender,
getCoreRowModel,
getFilteredRowModel,
useReactTable,
PaginationState,
} from "@tanstack/react-table";
export const Library = (): ReactElement => {
const searchResults = useSelector(
(state: RootState) => state.fileOps.libraryComics,
);
const searchError = useSelector(
(state: RootState) => state.fileOps.librarySearchError,
);
const dispatch = useDispatch();
useEffect(() => {
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: 25,
from: 0,
},
type: "all",
trigger: "libraryPage"
},
),
);
}, []);
const T2Table = (tableOptions): ReactElement => {
const { columns, totalPages, rowClickHandler } =
tableOptions;
// pagination methods
const goToNextPage = useCallback((pageIndex, pageSize) => {
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: pageSize,
from: pageSize * pageIndex + 1,
},
type: "all",
trigger: "libraryPage",
},
),
);
}, []);
const goToPreviousPage = useCallback((pageIndex, pageSize) => {
let from = 0;
if (pageIndex === 2) {
from = (pageIndex - 1) * pageSize + 2 - 27;
} else {
from = (pageIndex - 1) * pageSize + 2 - 26;
}
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: pageSize,
from,
},
type: "all",
trigger: "libraryPage"
},
),
);
}, []);
const table = useReactTable({
data: searchResults.hits.hits,
columns,
manualPagination: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
pageCount: totalPages,
// getPaginationRowModel: getPaginationRowModel(),
debugTable: true,
});
return (
<>
<table className="table is-hoverable">
<thead>
{table.getHeaderGroups().map((headerGroup, idx) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header, idx) => (
<th
key={header.id}
colSpan={header.colSpan}
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row, idx) => {
return (
<tr
key={row.id}
onClick={() => rowClickHandler(row)}
>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
);
})}
</tbody>
</table>
{/* pagination control */}
<nav className="pagination">
{table.getState().pagination.pageIndex + 1}
<div className="field has-addons">
<p className="control">
<div className="button" onClick={() => goToNextPage(table.getState().pagination.pageIndex + 1, 25)}> Next Page </div>
</p>
<p className="control">
<div className="button" > Previous Page</div>
</p>
</div>
</nav>
</>
);
};
// programatically navigate to comic detail
const navigate = useNavigate();
@@ -65,124 +212,81 @@ export const Library = (data: IComicBookLibraryProps): ReactElement => {
const WantedStatus = ({ value }) => {
return !value ? <span className="tag is-info is-light">Wanted</span> : null;
};
const columns = [
{
header: "Comic Metadata",
footer: 1,
columns: [
{
header: "File Details",
id: "fileDetails",
minWidth: 400,
accessorKey: "_source",
cell: info => {
return <MetadataPanel data={info.getValue()} />;
},
const columns = [
{
header: "Comic Metadata",
footer: 1,
columns: [
{
header: "File Details",
id: "fileDetails",
minWidth: 400,
accessorKey: "_source",
cell: info => {
return <MetadataPanel data={info.getValue()} />;
},
{
header: "ComicInfo.xml",
accessorKey: "_source.sourcedMetadata.comicInfo",
align: "center",
minWidth: 250,
cell: info =>
!isEmpty(info.getValue()) ? (
<ComicInfoXML data={info.getValue()} />
) : (
<span className="tag">No ComicInfo.xml</span>
),
},
{
header: "ComicInfo.xml",
accessorKey: "_source.sourcedMetadata.comicInfo",
align: "center",
minWidth: 250,
cell: info =>
!isEmpty(info.getValue()) ? (
<ComicInfoXML data={info.getValue()} />
) : (
<span className="tag">No ComicInfo.xml</span>
),
},
],
},
{
header: "Additional Metadata",
columns: [
{
header: "Publisher",
accessorKey:
"_source.sourcedMetadata.comicvine.volumeInformation",
cell: info => {
return (
!isNil(info.getValue()) && (
<h6 className="is-size-7 has-text-weight-bold">
{info.getValue().publisher.name}
</h6>
)
);
},
],
},
{
header: "Additional Metadata",
columns: [
{
header: "Publisher",
accessorKey:
"_source.sourcedMetadata.comicvine.volumeInformation",
cell: info => {
return (
!isNil(info.getValue()) && (
<h6 className="is-size-7 has-text-weight-bold">
{ info.getValue().publisher.name }
</h6>
)
);
},
},
{
header: "Something",
accessorKey: "_source.acquisition.source.wanted",
cell: info => {
!isUndefined(info.getValue()) ?
},
{
header: "Something",
accessorKey: "_source.acquisition.source.wanted",
cell: info => {
!isUndefined(info.getValue()) ?
<WantedStatus value={info.getValue().toString()} /> : "Nothing";
},
},
],
}
]
},
],
}
]
// ImportStatus.propTypes = {
// value: PropTypes.bool.isRequired,
// };
const dispatch = useDispatch();
const goToNextPage = useCallback((pageIndex, pageSize) => {
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: pageSize,
from: pageSize * pageIndex + 1,
},
type: "all",
},
),
);
}, []);
const goToPreviousPage = useCallback((pageIndex, pageSize) => {
let from = 0;
if (pageIndex === 2) {
from = (pageIndex - 1) * pageSize + 2 - 27;
} else {
from = (pageIndex - 1) * pageSize + 2 - 26;
}
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: pageSize,
from,
},
type: "all",
},
),
);
}, []);
return (
<section className="container">
<div className="section">
<h1 className="title">Library</h1>
<div className="sticky"><h1 className="title">Library</h1></div>
{/* Search bar */}
<SearchBar />
{!isUndefined(searchResults) && (
{!isUndefined(searchResults.hits) && (
<div>
<div className="library">
<T2Table
rowData={searchResults.hits.hits}
totalPages={searchResults.hits.total.value}
columns={columns}
paginationHandlers={{
nextPage: goToNextPage,
previousPage: goToPreviousPage,
}}
rowClickHandler={navigateToComicDetail}
/>
{/* pagination controls */}

View File

@@ -5,59 +5,58 @@ import { searchIssue } from "../../actions/fileops.actions";
import { Library } from "./Library";
const LibraryContainer = (): ReactElement => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(
searchIssue(
{
query: {},
},
{
pagination: {
size: 25,
from: 0,
},
type: "all",
trigger: "libraryPage"
},
),
);
}, []);
// const dispatch = useDispatch();
// useEffect(() => {
// dispatch(
// searchIssue(
// {
// query: {},
// },
// {
// pagination: {
// size: 25,
// from: 0,
// },
// type: "all",
// trigger: "libraryPage"
// },
// ),
// );
// }, []);
const searchResults = useSelector(
(state: RootState) => state.fileOps.libraryComics,
);
const searchError = useSelector(
(state: RootState) => state.fileOps.librarySearchError,
);
// const searchResults = useSelector(
// (state: RootState) => state.fileOps.libraryComics,
// );
// const searchError = useSelector(
// (state: RootState) => state.fileOps.librarySearchError,
// );
return !isEmpty(searchResults) ? (
<Library data={{ searchResults }} />
) : (
<div className="container">
<section className="section is-small">
<div className="columns">
<div className="column is-two-thirds">
<article className="message is-link">
<div className="message-body">
No comics were found in the library, Elasticsearch reports no
indices. Try importing a few comics into the library and come
back.
</div>
</article>
<pre>
{!isUndefined(searchError.data) &&
JSON.stringify(
searchError.data.meta.body.error.root_cause,
null,
4,
)}
</pre>
</div>
</div>
</section>
</div>
);
return (
<Library />)
// : (
// <div className="container">
// <section className="section is-small">
// <div className="columns">
// <div className="column is-two-thirds">
// <article className="message is-link">
// <div className="message-body">
// No comics were found in the library, and Elasticsearch doesn't have any
// indices. Try resetting the library from <code>Settings > Flush DB & Temporary Folders</code> and then import your library again.
// </div>
// </article>
// <pre>
// {!isUndefined(searchError.data) &&
// JSON.stringify(
// searchError.data.meta.body.error.root_cause,
// null,
// 4,
// )}
// </pre>
// </div>
// </div>
// </section>
// </div>
// );
};
export default LibraryContainer;

View File

@@ -26,14 +26,14 @@ export const SearchBar = (): ReactElement => {
);
}, []);
return (
<div className="box sticky">
<div className="sticky">
<Form
onSubmit={handleSubmit}
initialValues={{}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<div className="field is-grouped">
<div className="control is-expanded search">
<div className="control search">
<Field name="search">
{({ input, meta }) => {
return (

View File

@@ -77,14 +77,9 @@ export const MetadataPanel = (props: IMetadatPanelProps): ReactElement => {
</div>
)}
</div>
</div>
<div className="control">
<div className="tags has-addons">
<span className="tag is-light is-success">Path</span>
<span className="tag is-warning is-light">{rawFileDetails.containedIn}</span>
</div>
</div>
</dd>
</dl>
),
@@ -218,7 +213,7 @@ export const MetadataPanel = (props: IMetadatPanelProps): ReactElement => {
orientation={"vertical"}
hasDetails={false}
imageStyle={props.imageStyle}
// cardContainerStyle={{ maxWidth: 200 }}
// cardContainerStyle={{ maxWidth: 200 }}
/>
</div>
<div className="column">{metadataPanel.content()}</div>

View File

@@ -4,22 +4,39 @@ import {
ColumnDef,
flexRender,
getCoreRowModel,
getFilteredRowModel,
useReactTable,
PaginationState,
} from "@tanstack/react-table";
export const T2Table = (tableOptions): ReactElement => {
const { rowData, columns, paginationHandlers, totalPages, rowClickHandler } =
const { rowData, columns, paginationHandlers: { nextPage, previousPage }, totalPages, rowClickHandler } =
tableOptions;
const [isPageSizeDropdownCollapsed, collapsePageSizeDropdown] =
useState(false);
const togglePageSizeDropdown = () =>
collapsePageSizeDropdown(!isPageSizeDropdownCollapsed);
const table = useReactTable({
data: rowData,
columns,
manualPagination: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
pageCount: totalPages,
// getPaginationRowModel: getPaginationRowModel(),
});
const [{ pageIndex, pageSize }, setPagination] =
React.useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
})
const pagination = React.useMemo(
() => ({
pageIndex,
pageSize,
}),
[pageIndex, pageSize]
)
return (
<>
<table className="table is-hoverable">
@@ -62,6 +79,12 @@ export const T2Table = (tableOptions): ReactElement => {
</table>
{/* pagination control */}
<nav className="pagination">
{table.getState().pagination.pageIndex + 1}
<div className="button" onClick={() => table.nextPage()}> Next Page </div>
<div className="button" onClick={previousPage}> Previous Page</div>
</nav>
</>
);

View File

@@ -188,6 +188,7 @@ function fileOpsReducer(state = initialState, action) {
}
case SS_SEARCH_RESULTS_FETCHED: {
console.log(action.data);
return {
...state,
libraryComics: action.data,
@@ -196,7 +197,6 @@ function fileOpsReducer(state = initialState, action) {
}
case SS_SEARCH_RESULTS_FETCHED_SPECIAL: {
const foo = [];
console.log(action.data.hits)
if (!isUndefined(action.data.hits)) {
map(action.data.hits.hits, ({ _source }) => {
foo.push(_source);