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

Show status of auto updating lists #47

Merged
merged 3 commits into from
Oct 4, 2022
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
7 changes: 7 additions & 0 deletions src/components/CustomListEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import TextWithEditMode from "./TextWithEditMode";
import ShareIcon from "./icons/ShareIcon";

type CustomListEditorProps = {
autoUpdateStatus?: string;
collections?: AdminCollectionData[];
entries?: CustomListEditorEntriesData;
entryPoints?: string[];
Expand All @@ -32,6 +33,7 @@ type CustomListEditorProps = {
isFetchingMoreSearchResults: boolean;
isLoaded?: boolean;
isModified?: boolean;
isSearchModified?: boolean;
isOwner?: boolean;
isShared?: boolean;
isSharePending?: boolean;
Expand Down Expand Up @@ -72,6 +74,7 @@ type CustomListEditorProps = {
};

export default function CustomListEditor({
autoUpdateStatus,
collections,
entries,
entryPoints,
Expand All @@ -81,6 +84,7 @@ export default function CustomListEditor({
isFetchingMoreSearchResults,
isLoaded,
isModified,
isSearchModified,
isOwner,
isShared,
isSharePending,
Expand Down Expand Up @@ -254,6 +258,7 @@ export default function CustomListEditor({
<CustomListSearch
autoUpdate={properties.autoUpdate}
isOwner={isOwner}
listId={listId}
searchParams={searchParams}
updateAutoUpdate={(value) => updateProperty?.("autoUpdate", value)}
updateSearchParam={updateSearchParam}
Expand All @@ -272,8 +277,10 @@ export default function CustomListEditor({
</section>

<CustomListEntriesEditor
autoUpdateStatus={autoUpdateStatus}
autoUpdate={properties.autoUpdate}
isOwner={isOwner}
isSearchModified={isSearchModified}
searchResults={searchResults}
entries={entries.current}
loadMoreSearchResults={loadMoreSearchResults}
Expand Down
264 changes: 153 additions & 111 deletions src/components/CustomListEntriesEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import LoadButton from "./LoadButton";

export interface CustomListEntriesEditorProps {
autoUpdate?: boolean;
autoUpdateStatus?: string;
entries?: Entry[];
entryCount?: number;
isFetchingMoreCustomListEntries: boolean;
isFetchingSearchResults: boolean;
isFetchingMoreSearchResults: boolean;
isOwner?: boolean;
isSearchModified?: boolean;
listId?: string | number;
opdsFeedUrl?: string;
searchResults?: CollectionData;
Expand Down Expand Up @@ -55,12 +57,14 @@ const renderCatalogLink = (book, opdsFeedUrl) => {

const CustomListEntriesEditor = ({
autoUpdate,
entries,
entryCount,
autoUpdateStatus,
entries = [],
entryCount = 0,
isFetchingMoreCustomListEntries,
isFetchingSearchResults,
isFetchingMoreSearchResults,
isOwner,
isSearchModified,
listId,
opdsFeedUrl,
searchResults,
Expand Down Expand Up @@ -134,7 +138,7 @@ const CustomListEntriesEditor = ({

const readOnly = !isOwner || autoUpdate;

let searchResultList = null;
let searchResultList: JSX.Element | null = null;

if (isOwner) {
searchResultList = (
Expand Down Expand Up @@ -210,7 +214,7 @@ const CustomListEntriesEditor = ({
<div className="title">{book.title}</div>

<div className="authors">
{book.authors.join(", ")}
{book.authors?.join(", ")}
</div>
</div>

Expand Down Expand Up @@ -256,125 +260,163 @@ const CustomListEntriesEditor = ({
);
}

let entryList = null;

if (!autoUpdate) {
const visibleEntryCount = entries.length;
const startNum = visibleEntryCount > 0 ? 1 : 0;
const endNum = visibleEntryCount;
const booksText = entryCount === 1 ? "book" : "books";

const entryListDisplay =
entryCount > 0
? `Displaying ${startNum} - ${endNum} of ${entryCount} ${booksText}`
: "No books in this list";

entryList = (
<div className="custom-list-entries">
<div className="droppable-header">
<h4>List Entries: {entryListDisplay}</h4>
const visibleEntryCount = entries.length;
const startNum = visibleEntryCount > 0 ? 1 : 0;
const endNum = visibleEntryCount;
const booksText = entryCount === 1 ? "book" : "books";

const entryListDisplay =
entryCount > 0
? `Displaying ${startNum} - ${endNum} of ${entryCount} ${booksText}`
: "No books in this list";

let autoUpdateStatusName = null;
let autoUpdateStatusDescription = null;

if (!listId) {
autoUpdateStatusName = "New";
autoUpdateStatusDescription =
"This is a new list. Once the initial search criteria have been saved, the system will begin to populate its entries; however, the list might not be fully populated until the next scheduled update.";
} else if (isSearchModified) {
autoUpdateStatusName = "Search criteria modified";
autoUpdateStatusDescription =
"There are unsaved changes to the search criteria for this list. Once the changes have been saved, the new search criteria will be used to repopulate the list during the next scheduled update.";
} else {
if (autoUpdateStatus === "init") {
autoUpdateStatusName = "Initializing";
autoUpdateStatusDescription =
"This list was created recently. The system has partially populated the list using the configured search criteria and will fully populate the list during the next scheduled update.";
} else if (autoUpdateStatus === "repopulate") {
autoUpdateStatusName = "Repopulating";
autoUpdateStatusDescription =
"The search criteria for this list were changed recently, but the entries have not yet been updated. The new search criteria will be used to repopulate the list during the next scheduled update.";
} else if (autoUpdateStatus === "updated") {
autoUpdateStatusName = "Updated";
autoUpdateStatusDescription =
"This list was fully populated during the last scheduled update, using the configured search criteria and the titles that were available at the time. New titles matching the criteria will be added to the list during the next scheduled update.";
} else if (!autoUpdateStatus) {
autoUpdateStatusName = "Changing to automatic";
autoUpdateStatusDescription =
"This list was populated manually, but is being changed to be updated automatically. The configured search criteria will be used to repopulate the list during the next scheduled update.";
} else {
autoUpdateStatusName = autoUpdateStatus;
}
}

{!readOnly && entries?.length > 0 && (
<div>
<span>Remove all currently visible items from list:</span>
const entryList = (
<div className="custom-list-entries">
<div className="droppable-header">
<h4>List Entries: {entryListDisplay}</h4>

<Button
className="danger delete-all-button top-align"
callback={deleteAllEntries}
content={
<span>
Delete
<TrashIcon />
</span>
}
/>
{autoUpdate && (
<>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I didn't know this Fragment shorthand. Had me confused for a minute.

<div className="auto-update-status-name">
Status: {autoUpdateStatusName}
</div>
)}
</div>
<aside className="auto-update-status-desc">
{autoUpdateStatusDescription}
</aside>
</>
)}

{!readOnly && <p>Drag search results here to add them to the list.</p>}

<Droppable
droppableId="custom-list-entries"
isDropDisabled={readOnly || draggingFrom !== "search-results"}
>
{(provided, snapshot) => (
<ul
ref={provided.innerRef}
id="custom-list-entries-droppable"
className={
snapshot.isDraggingOver
? " droppable dragging-over"
: "droppable"
{!readOnly && entries?.length > 0 && (
<div>
<span>Remove all currently visible items from list:</span>

<Button
className="danger delete-all-button top-align"
callback={deleteAllEntries}
content={
<span>
Delete
<TrashIcon />
</span>
}
>
{entries?.map((book) => (
<Draggable
key={book.id}
draggableId={book.id}
isDragDisabled={readOnly}
>
{(provided, snapshot) => (
<li>
<div
className={
"custom-list-entry" +
(snapshot.isDragging ? " dragging" : "")
}
ref={provided.innerRef}
style={provided.draggableStyle}
{...provided.dragHandleProps}
>
{!readOnly && <GrabIcon />}

<div>
<div className="title">{book.title}</div>

<div className="authors">
{book.authors.join(", ")}
</div>
</div>
/>
</div>
)}
</div>

{!readOnly && <p>Drag search results here to add them to the list.</p>}

<Droppable
droppableId="custom-list-entries"
isDropDisabled={readOnly || draggingFrom !== "search-results"}
>
{(provided, snapshot) => (
<ul
ref={provided.innerRef}
id="custom-list-entries-droppable"
className={
snapshot.isDraggingOver ? " droppable dragging-over" : "droppable"
}
>
{entries?.map((book) => (
<Draggable
key={book.id}
draggableId={book.id}
isDragDisabled={readOnly}
>
{(provided, snapshot) => (
<li>
<div
className={
"custom-list-entry" +
(snapshot.isDragging ? " dragging" : "")
}
ref={provided.innerRef}
style={provided.draggableStyle}
{...provided.dragHandleProps}
>
{!readOnly && <GrabIcon />}

{getMediumSVG(getMedium(book))}

<div className="links">
{renderCatalogLink(book, opdsFeedUrl)}

{!readOnly && (
<Button
className="small right-align"
callback={() => deleteEntry?.(book.id)}
content={
<span>
Remove from list
<TrashIcon />
</span>
}
/>
)}
<div>
<div className="title">{book.title}</div>

<div className="authors">
{book.authors?.join(", ")}
</div>
</div>

{provided.placeholder}
</li>
)}
</Draggable>
))}
{getMediumSVG(getMedium(book))}

{provided.placeholder}
</ul>
)}
</Droppable>
<div className="links">
{renderCatalogLink(book, opdsFeedUrl)}

{loadMoreEntries && (
<LoadButton
isFetching={isFetchingMoreCustomListEntries}
loadMore={loadMoreEntries}
/>
{!readOnly && (
<Button
className="small right-align"
callback={() => deleteEntry?.(book.id)}
content={
<span>
Remove from list
<TrashIcon />
</span>
}
/>
)}
</div>
</div>

{provided.placeholder}
</li>
)}
</Draggable>
))}

{provided.placeholder}
</ul>
)}
</div>
);
}
</Droppable>

{loadMoreEntries && (
<LoadButton
isFetching={isFetchingMoreCustomListEntries}
loadMore={loadMoreEntries}
/>
)}
</div>
);

return (
<DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
Expand Down
Loading