mirror of
https://github.com/idanoo/autobrr
synced 2025-07-26 02:09:13 +00:00
enhancement(web): add react suspense and improve DX (#1089)
* add react suspense, fix broken stuff, clean up code, improve DX enhancement: added react suspense + spinner to show loading (still can be added in certain places) chore: cleaned up Header/NavBar code chore: cleaned up DeleteModal code chore: cleaned up other relevant code enhancement: changed remove button style to be much more pleasant (see e.g. filter tabs) fix: made active tab on filters page to be blue (as it should've been) when active fix: fixed ghost delimiter which was only visible when DeleteModal was active in FormButtonGroup chore: removed most of linter warnings/errors fix: fixed incorrect/double modal transition in FilterExternalItem fix: fixed incorrect z-height on Options popover in Settings/IRC (would've been visible when Add new was clicked) enhancement: improved robustness of all Context classes to support seamless new-feature expansion (#866) enhancement: improved expand logic (see #994 comments) * reverted irc expand view to previous design * forgot to propagate previous z-height fix * jinxed it * add license header to new files --------- Co-authored-by: martylukyy <35452459+martylukyy@users.noreply.github.com> Co-authored-by: Kyle Sanderson <kyle.leet@gmail.com>
This commit is contained in:
parent
cbf668e87c
commit
2fed48e0dd
23 changed files with 845 additions and 737 deletions
|
@ -23,7 +23,7 @@ import { DeleteModal } from "@components/modals";
|
|||
import { FeedUpdateForm } from "@forms/settings/FeedForms";
|
||||
import { EmptySimple } from "@components/emptystates";
|
||||
import { ImplementationBadges } from "./Indexer";
|
||||
import {ArrowPathIcon} from "@heroicons/react/24/solid";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
export const feedKeys = {
|
||||
all: ["feeds"] as const,
|
||||
|
@ -64,7 +64,8 @@ function useSort(items: ListItemProps["feed"][], config?: SortConfig) {
|
|||
return sortableItems;
|
||||
}, [items, sortConfig]);
|
||||
|
||||
const requestSort = (key: keyof ListItemProps["feed"] | "enabled") => { let direction: "ascending" | "descending" = "ascending";
|
||||
const requestSort = (key: keyof ListItemProps["feed"] | "enabled") => {
|
||||
let direction: "ascending" | "descending" = "ascending";
|
||||
if (
|
||||
sortConfig &&
|
||||
sortConfig.key === key &&
|
||||
|
@ -133,13 +134,13 @@ function FeedSettings() {
|
|||
Last run <span className="sort-indicator">{sortedFeeds.getSortIndicator("last_run")}</span>
|
||||
</div>
|
||||
<div
|
||||
className="hidden md:flex col-span-2 px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider cursor-pointer"
|
||||
onClick={() => sortedFeeds.requestSort("next_run")}>
|
||||
className="hidden md:flex col-span-2 px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider cursor-pointer"
|
||||
onClick={() => sortedFeeds.requestSort("next_run")}>
|
||||
Next run <span className="sort-indicator">{sortedFeeds.getSortIndicator("next_run")}</span>
|
||||
</div>
|
||||
</li>
|
||||
{sortedFeeds.items.map((feed) => (
|
||||
<ListItem key={feed.id} feed={feed}/>
|
||||
<ListItem key={feed.id} feed={feed} />
|
||||
))}
|
||||
</ol>
|
||||
</section>
|
||||
|
@ -150,7 +151,7 @@ function FeedSettings() {
|
|||
}
|
||||
|
||||
interface ListItemProps {
|
||||
feed: Feed;
|
||||
feed: Feed;
|
||||
}
|
||||
|
||||
function ListItem({ feed }: ListItemProps) {
|
||||
|
@ -165,7 +166,7 @@ function ListItem({ feed }: ListItemProps) {
|
|||
queryClient.invalidateQueries({ queryKey: feedKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: feedKeys.detail(feed.id) });
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`${feed.name} was ${!enabled ? "disabled" : "enabled"} successfully.`} t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body={`${feed.name} was ${!enabled ? "disabled" : "enabled"} successfully.`} t={t} />);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -176,7 +177,7 @@ function ListItem({ feed }: ListItemProps) {
|
|||
|
||||
return (
|
||||
<li key={feed.id} className="text-gray-500 dark:text-gray-400">
|
||||
<FeedUpdateForm isOpen={updateFormIsOpen} toggle={toggleUpdateForm} feed={feed}/>
|
||||
<FeedUpdateForm isOpen={updateFormIsOpen} toggle={toggleUpdateForm} feed={feed} />
|
||||
|
||||
<div className="grid grid-cols-12 items-center">
|
||||
<div className="col-span-2 sm:col-span-1 px-6 flex items-center">
|
||||
|
@ -230,9 +231,9 @@ function ListItem({ feed }: ListItemProps) {
|
|||
}
|
||||
|
||||
interface FeedItemDropdownProps {
|
||||
feed: Feed;
|
||||
onToggle: (newState: boolean) => void;
|
||||
toggleUpdate: () => void;
|
||||
feed: Feed;
|
||||
onToggle: (newState: boolean) => void;
|
||||
toggleUpdate: () => void;
|
||||
}
|
||||
|
||||
const FeedItemDropdown = ({
|
||||
|
@ -254,14 +255,14 @@ const FeedItemDropdown = ({
|
|||
queryClient.invalidateQueries({ queryKey: feedKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: feedKeys.detail(feed.id) });
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`Feed ${feed?.name} was deleted`} t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body={`Feed ${feed?.name} was deleted`} t={t} />);
|
||||
}
|
||||
});
|
||||
|
||||
const deleteCacheMutation = useMutation({
|
||||
mutationFn: (id: number) => APIClient.feeds.deleteCache(id),
|
||||
onSuccess: () => {
|
||||
toast.custom((t) => <Toast type="success" body={`Feed ${feed?.name} cache was cleared!`} t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body={`Feed ${feed?.name} cache was cleared!`} t={t} />);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -269,6 +270,7 @@ const FeedItemDropdown = ({
|
|||
<Menu as="div">
|
||||
<DeleteModal
|
||||
isOpen={deleteModalIsOpen}
|
||||
isLoading={deleteMutation.isLoading}
|
||||
toggle={toggleDeleteModal}
|
||||
buttonRef={cancelModalButtonRef}
|
||||
deleteAction={() => {
|
||||
|
@ -279,14 +281,15 @@ const FeedItemDropdown = ({
|
|||
text="Are you sure you want to remove this feed? This action cannot be undone."
|
||||
/>
|
||||
<DeleteModal
|
||||
isOpen={deleteCacheModalIsOpen}
|
||||
toggle={toggleDeleteCacheModal}
|
||||
buttonRef={cancelCacheModalButtonRef}
|
||||
deleteAction={() => {
|
||||
deleteCacheMutation.mutate(feed.id);
|
||||
}}
|
||||
title={`Remove feed cache: ${feed.name}`}
|
||||
text="Are you sure you want to remove the feed cache? This action cannot be undone."
|
||||
isOpen={deleteCacheModalIsOpen}
|
||||
isLoading={deleteMutation.isLoading}
|
||||
toggle={toggleDeleteCacheModal}
|
||||
buttonRef={cancelCacheModalButtonRef}
|
||||
deleteAction={() => {
|
||||
deleteCacheMutation.mutate(feed.id);
|
||||
}}
|
||||
title={`Remove feed cache: ${feed.name}`}
|
||||
text="Are you sure you want to remove the feed cache? This action cannot be undone."
|
||||
/>
|
||||
<Menu.Button className="px-4 py-2">
|
||||
<EllipsisHorizontalIcon
|
||||
|
@ -349,49 +352,49 @@ const FeedItemDropdown = ({
|
|||
</Menu.Item>
|
||||
</div>
|
||||
<div>
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<a
|
||||
href={`${baseUrl()}api/feeds/${feed.id}/latest`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={classNames(
|
||||
active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
>
|
||||
<DocumentTextIcon
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<a
|
||||
href={`${baseUrl()}api/feeds/${feed.id}/latest`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
View latest run
|
||||
</a>
|
||||
)}
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
>
|
||||
<DocumentTextIcon
|
||||
className={classNames(
|
||||
active ? "bg-red-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
active ? "text-white" : "text-blue-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}
|
||||
onClick={() => toggleDeleteCacheModal()}
|
||||
title="Manually clear all feed cache"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
View latest run
|
||||
</a>
|
||||
)}
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={classNames(
|
||||
active ? "bg-red-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
)}
|
||||
onClick={() => toggleDeleteCacheModal()}
|
||||
title="Manually clear all feed cache"
|
||||
>
|
||||
<ArrowPathIcon
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-red-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
active ? "text-white" : "text-red-500",
|
||||
"w-5 h-5 mr-2"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Clear feed cache
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
)}
|
||||
</Menu.Item>
|
||||
</div>
|
||||
<div className="px-1 py-1">
|
||||
<Menu.Item>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue