parent
c11483ecc1
commit
3c790549e0
@ -1,71 +0,0 @@
|
||||
import React, { FunctionComponent, useMemo } from "react";
|
||||
import { Redirect, Route, Switch, useHistory } from "react-router-dom";
|
||||
import { useDidMount } from "rooks";
|
||||
import { useIsRadarrEnabled, useIsSonarrEnabled } from "../@redux/hooks/site";
|
||||
import BlacklistRouter from "../Blacklist/Router";
|
||||
import DisplayItemRouter from "../DisplayItem/Router";
|
||||
import HistoryRouter from "../History/Router";
|
||||
import SettingRouter from "../Settings/Router";
|
||||
import EmptyPage, { RouterEmptyPath } from "../special-pages/404";
|
||||
import SystemRouter from "../System/Router";
|
||||
import { ScrollToTop } from "../utilities";
|
||||
import WantedRouter from "../Wanted/Router";
|
||||
|
||||
const Router: FunctionComponent<{ className?: string }> = ({ className }) => {
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
const radarr = useIsRadarrEnabled();
|
||||
const redirectPath = useMemo(() => {
|
||||
if (sonarr) {
|
||||
return "/series";
|
||||
} else if (radarr) {
|
||||
return "/movies";
|
||||
} else {
|
||||
return "/settings";
|
||||
}
|
||||
}, [sonarr, radarr]);
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
useDidMount(() => {
|
||||
history.listen(() => {
|
||||
// This is a hack to make sure ScrollToTop will be triggered in the next frame (When everything are loaded)
|
||||
setTimeout(ScrollToTop);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect exact to={redirectPath}></Redirect>
|
||||
</Route>
|
||||
<Route path={["/series", "/movies"]}>
|
||||
<DisplayItemRouter></DisplayItemRouter>
|
||||
</Route>
|
||||
<Route path="/wanted">
|
||||
<WantedRouter></WantedRouter>
|
||||
</Route>
|
||||
<Route path="/history">
|
||||
<HistoryRouter></HistoryRouter>
|
||||
</Route>
|
||||
<Route path="/blacklist">
|
||||
<BlacklistRouter></BlacklistRouter>
|
||||
</Route>
|
||||
<Route path="/settings">
|
||||
<SettingRouter></SettingRouter>
|
||||
</Route>
|
||||
<Route path="/system">
|
||||
<SystemRouter></SystemRouter>
|
||||
</Route>
|
||||
<Route exact path={RouterEmptyPath}>
|
||||
<EmptyPage></EmptyPage>
|
||||
</Route>
|
||||
<Route path="*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -1,36 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import {
|
||||
useIsRadarrEnabled,
|
||||
useIsSonarrEnabled,
|
||||
useSetSidebar,
|
||||
} from "../@redux/hooks/site";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import BlacklistMovies from "./Movies";
|
||||
import BlacklistSeries from "./Series";
|
||||
|
||||
const Router: FunctionComponent = () => {
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
const radarr = useIsRadarrEnabled();
|
||||
|
||||
useSetSidebar("Blacklist");
|
||||
return (
|
||||
<Switch>
|
||||
{sonarr && (
|
||||
<Route exact path="/blacklist/series">
|
||||
<BlacklistSeries></BlacklistSeries>
|
||||
</Route>
|
||||
)}
|
||||
{radarr && (
|
||||
<Route path="/blacklist/movies">
|
||||
<BlacklistMovies></BlacklistMovies>
|
||||
</Route>
|
||||
)}
|
||||
<Route path="/blacklist/*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -1,45 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import { useIsRadarrEnabled, useIsSonarrEnabled } from "../@redux/hooks";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import Episodes from "./Episodes";
|
||||
import MovieDetail from "./MovieDetail";
|
||||
import Movies from "./Movies";
|
||||
import Series from "./Series";
|
||||
|
||||
interface Props {}
|
||||
|
||||
const Router: FunctionComponent<Props> = () => {
|
||||
const radarr = useIsRadarrEnabled();
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
{radarr && (
|
||||
<Route exact path="/movies">
|
||||
<Movies></Movies>
|
||||
</Route>
|
||||
)}
|
||||
{radarr && (
|
||||
<Route path="/movies/:id">
|
||||
<MovieDetail></MovieDetail>
|
||||
</Route>
|
||||
)}
|
||||
{sonarr && (
|
||||
<Route exact path="/series">
|
||||
<Series></Series>
|
||||
</Route>
|
||||
)}
|
||||
{sonarr && (
|
||||
<Route path="/series/:id">
|
||||
<Episodes></Episodes>
|
||||
</Route>
|
||||
)}
|
||||
<Route path="*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -1,40 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import {
|
||||
useIsRadarrEnabled,
|
||||
useIsSonarrEnabled,
|
||||
useSetSidebar,
|
||||
} from "../@redux/hooks/site";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import MoviesHistory from "./Movies";
|
||||
import SeriesHistory from "./Series";
|
||||
import HistoryStats from "./Statistics";
|
||||
|
||||
const Router: FunctionComponent = () => {
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
const radarr = useIsRadarrEnabled();
|
||||
|
||||
useSetSidebar("History");
|
||||
return (
|
||||
<Switch>
|
||||
{sonarr && (
|
||||
<Route exact path="/history/series">
|
||||
<SeriesHistory></SeriesHistory>
|
||||
</Route>
|
||||
)}
|
||||
{radarr && (
|
||||
<Route exact path="/history/movies">
|
||||
<MoviesHistory></MoviesHistory>
|
||||
</Route>
|
||||
)}
|
||||
<Route exact path="/history/stats">
|
||||
<HistoryStats></HistoryStats>
|
||||
</Route>
|
||||
<Route path="/history/*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -0,0 +1,238 @@
|
||||
import {
|
||||
faClock,
|
||||
faCogs,
|
||||
faExclamationTriangle,
|
||||
faFileExcel,
|
||||
faFilm,
|
||||
faLaptop,
|
||||
faPlay,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { useMemo } from "react";
|
||||
import { useIsRadarrEnabled, useIsSonarrEnabled } from "../@redux/hooks";
|
||||
import { useReduxStore } from "../@redux/hooks/base";
|
||||
import BlacklistMoviesView from "../Blacklist/Movies";
|
||||
import BlacklistSeriesView from "../Blacklist/Series";
|
||||
import Episodes from "../DisplayItem/Episodes";
|
||||
import MovieDetail from "../DisplayItem/MovieDetail";
|
||||
import MovieView from "../DisplayItem/Movies";
|
||||
import SeriesView from "../DisplayItem/Series";
|
||||
import MoviesHistoryView from "../History/Movies";
|
||||
import SeriesHistoryView from "../History/Series";
|
||||
import HistoryStats from "../History/Statistics";
|
||||
import SettingsGeneralView from "../Settings/General";
|
||||
import SettingsLanguagesView from "../Settings/Languages";
|
||||
import SettingsNotificationsView from "../Settings/Notifications";
|
||||
import SettingsProvidersView from "../Settings/Providers";
|
||||
import SettingsRadarrView from "../Settings/Radarr";
|
||||
import SettingsSchedulerView from "../Settings/Scheduler";
|
||||
import SettingsSonarrView from "../Settings/Sonarr";
|
||||
import SettingsSubtitlesView from "../Settings/Subtitles";
|
||||
import SettingsUIView from "../Settings/UI";
|
||||
import EmptyPage, { RouterEmptyPath } from "../special-pages/404";
|
||||
import SystemLogsView from "../System/Logs";
|
||||
import SystemProvidersView from "../System/Providers";
|
||||
import SystemReleasesView from "../System/Releases";
|
||||
import SystemStatusView from "../System/Status";
|
||||
import SystemTasksView from "../System/Tasks";
|
||||
import WantedMoviesView from "../Wanted/Movies";
|
||||
import WantedSeriesView from "../Wanted/Series";
|
||||
import { Navigation } from "./nav";
|
||||
|
||||
export function useNavigationItems() {
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
const radarr = useIsRadarrEnabled();
|
||||
const { movies, episodes, providers } = useReduxStore((s) => s.site.badges);
|
||||
|
||||
const items = useMemo<Navigation.RouteItem[]>(
|
||||
() => [
|
||||
{
|
||||
name: "404",
|
||||
path: RouterEmptyPath,
|
||||
component: EmptyPage,
|
||||
routeOnly: true,
|
||||
},
|
||||
{
|
||||
icon: faPlay,
|
||||
name: "Series",
|
||||
path: "/series",
|
||||
component: SeriesView,
|
||||
enabled: sonarr,
|
||||
routes: [
|
||||
{
|
||||
name: "Episode",
|
||||
path: "/:id",
|
||||
component: Episodes,
|
||||
routeOnly: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faFilm,
|
||||
name: "Movies",
|
||||
path: "/movies",
|
||||
component: MovieView,
|
||||
enabled: radarr,
|
||||
routes: [
|
||||
{
|
||||
name: "Movie Details",
|
||||
path: "/:id",
|
||||
component: MovieDetail,
|
||||
routeOnly: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faClock,
|
||||
name: "History",
|
||||
path: "/history",
|
||||
routes: [
|
||||
{
|
||||
name: "Series",
|
||||
path: "/series",
|
||||
enabled: sonarr,
|
||||
component: SeriesHistoryView,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
path: "/movies",
|
||||
enabled: radarr,
|
||||
component: MoviesHistoryView,
|
||||
},
|
||||
{
|
||||
name: "Statistics",
|
||||
path: "/stats",
|
||||
component: HistoryStats,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faFileExcel,
|
||||
name: "Blacklist",
|
||||
path: "/blacklist",
|
||||
routes: [
|
||||
{
|
||||
name: "Series",
|
||||
path: "/series",
|
||||
enabled: sonarr,
|
||||
component: BlacklistSeriesView,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
path: "/movies",
|
||||
enabled: radarr,
|
||||
component: BlacklistMoviesView,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faExclamationTriangle,
|
||||
name: "Wanted",
|
||||
path: "/wanted",
|
||||
routes: [
|
||||
{
|
||||
name: "Series",
|
||||
path: "/series",
|
||||
badge: episodes,
|
||||
enabled: sonarr,
|
||||
component: WantedSeriesView,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
path: "/movies",
|
||||
badge: movies,
|
||||
enabled: radarr,
|
||||
component: WantedMoviesView,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faCogs,
|
||||
name: "Settings",
|
||||
path: "/settings",
|
||||
routes: [
|
||||
{
|
||||
name: "General",
|
||||
path: "/general",
|
||||
component: SettingsGeneralView,
|
||||
},
|
||||
{
|
||||
name: "Languages",
|
||||
path: "/languages",
|
||||
component: SettingsLanguagesView,
|
||||
},
|
||||
{
|
||||
name: "Providers",
|
||||
path: "/providers",
|
||||
badge: providers,
|
||||
component: SettingsProvidersView,
|
||||
},
|
||||
{
|
||||
name: "Subtitles",
|
||||
path: "/subtitles",
|
||||
component: SettingsSubtitlesView,
|
||||
},
|
||||
{
|
||||
name: "Sonarr",
|
||||
path: "/sonarr",
|
||||
component: SettingsSonarrView,
|
||||
},
|
||||
{
|
||||
name: "Radarr",
|
||||
path: "/radarr",
|
||||
component: SettingsRadarrView,
|
||||
},
|
||||
{
|
||||
name: "Notifications",
|
||||
path: "/notifications",
|
||||
component: SettingsNotificationsView,
|
||||
},
|
||||
{
|
||||
name: "Scheduler",
|
||||
path: "/scheduler",
|
||||
component: SettingsSchedulerView,
|
||||
},
|
||||
{
|
||||
name: "UI",
|
||||
path: "/ui",
|
||||
component: SettingsUIView,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faLaptop,
|
||||
name: "System",
|
||||
path: "/system",
|
||||
routes: [
|
||||
{
|
||||
name: "Tasks",
|
||||
path: "/tasks",
|
||||
component: SystemTasksView,
|
||||
},
|
||||
{
|
||||
name: "Logs",
|
||||
path: "/logs",
|
||||
component: SystemLogsView,
|
||||
},
|
||||
{
|
||||
name: "Providers",
|
||||
path: "/providers",
|
||||
component: SystemProvidersView,
|
||||
},
|
||||
{
|
||||
name: "Status",
|
||||
path: "/status",
|
||||
component: SystemStatusView,
|
||||
},
|
||||
{
|
||||
name: "Releases",
|
||||
path: "/releases",
|
||||
component: SystemReleasesView,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
[episodes, movies, providers, radarr, sonarr]
|
||||
);
|
||||
|
||||
return items;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FunctionComponent } from "react";
|
||||
|
||||
export declare namespace Navigation {
|
||||
type RouteWithoutChild = {
|
||||
icon?: IconDefinition;
|
||||
name: string;
|
||||
path: string;
|
||||
component: FunctionComponent;
|
||||
badge?: number;
|
||||
enabled?: boolean;
|
||||
routeOnly?: boolean;
|
||||
};
|
||||
|
||||
type RouteWithChild = {
|
||||
icon: IconDefinition;
|
||||
name: string;
|
||||
path: string;
|
||||
component?: FunctionComponent;
|
||||
badge?: number;
|
||||
enabled?: boolean;
|
||||
routes: RouteWithoutChild[];
|
||||
};
|
||||
|
||||
type RouteItem = RouteWithChild | RouteWithoutChild;
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
import { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch, useHistory } from "react-router";
|
||||
import { useDidMount } from "rooks";
|
||||
import { useNavigationItems } from "../Navigation";
|
||||
import { Navigation } from "../Navigation/nav";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import { BuildKey, ScrollToTop } from "../utilities";
|
||||
|
||||
const Router: FunctionComponent = () => {
|
||||
const navItems = useNavigationItems();
|
||||
|
||||
const history = useHistory();
|
||||
useDidMount(() => {
|
||||
history.listen(() => {
|
||||
// This is a hack to make sure ScrollToTop will be triggered in the next frame (When everything are loaded)
|
||||
setTimeout(ScrollToTop);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-row flex-grow-1 main-router">
|
||||
<Switch>
|
||||
{navItems.map((v, idx) => {
|
||||
if ("routes" in v) {
|
||||
return (
|
||||
<Route path={v.path} key={BuildKey(idx, v.name, "router")}>
|
||||
<ParentRouter {...v}></ParentRouter>
|
||||
</Route>
|
||||
);
|
||||
} else if (v.enabled !== false) {
|
||||
return (
|
||||
<Route
|
||||
key={BuildKey(idx, v.name, "root")}
|
||||
exact
|
||||
path={v.path}
|
||||
component={v.component}
|
||||
></Route>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
<Route path="*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
||||
|
||||
const ParentRouter: FunctionComponent<Navigation.RouteWithChild> = ({
|
||||
path,
|
||||
enabled,
|
||||
component,
|
||||
routes,
|
||||
}) => {
|
||||
if (enabled === false || (component === undefined && routes.length === 0)) {
|
||||
return null;
|
||||
}
|
||||
const ParentComponent =
|
||||
component ?? (() => <Redirect to={path + routes[0].path}></Redirect>);
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path={path} component={ParentComponent}></Route>
|
||||
{routes
|
||||
.filter((v) => v.enabled !== false)
|
||||
.map((v, idx) => (
|
||||
<Route
|
||||
key={BuildKey(idx, v.name, "route")}
|
||||
exact
|
||||
path={path + v.path}
|
||||
component={v.component}
|
||||
></Route>
|
||||
))}
|
||||
<Route path="*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
@ -1,58 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import { useSetSidebar } from "../@redux/hooks/site";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import General from "./General";
|
||||
import Languages from "./Languages";
|
||||
import Notifications from "./Notifications";
|
||||
import Providers from "./Providers";
|
||||
import Radarr from "./Radarr";
|
||||
import Scheduler from "./Scheduler";
|
||||
import Sonarr from "./Sonarr";
|
||||
import Subtitles from "./Subtitles";
|
||||
import UI from "./UI";
|
||||
|
||||
interface Props {}
|
||||
|
||||
const Router: FunctionComponent<Props> = () => {
|
||||
useSetSidebar("Settings");
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path="/settings">
|
||||
<Redirect exact to="/settings/general"></Redirect>
|
||||
</Route>
|
||||
<Route exact path="/settings/general">
|
||||
<General></General>
|
||||
</Route>
|
||||
<Route exact path="/settings/ui">
|
||||
<UI></UI>
|
||||
</Route>
|
||||
<Route exact path="/settings/sonarr">
|
||||
<Sonarr></Sonarr>
|
||||
</Route>
|
||||
<Route exact path="/settings/radarr">
|
||||
<Radarr></Radarr>
|
||||
</Route>
|
||||
<Route exact path="/settings/languages">
|
||||
<Languages></Languages>
|
||||
</Route>
|
||||
<Route exact path="/settings/subtitles">
|
||||
<Subtitles></Subtitles>
|
||||
</Route>
|
||||
<Route exact path="/settings/scheduler">
|
||||
<Scheduler></Scheduler>
|
||||
</Route>
|
||||
<Route exact path="/settings/providers">
|
||||
<Providers></Providers>
|
||||
</Route>
|
||||
<Route exact path="/settings/notifications">
|
||||
<Notifications></Notifications>
|
||||
</Route>
|
||||
<Route path="/settings/*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -1,179 +0,0 @@
|
||||
import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React, { FunctionComponent, useContext, useMemo } from "react";
|
||||
import { Badge, Collapse, ListGroupItem } from "react-bootstrap";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { siteChangeSidebar } from "../@redux/actions";
|
||||
import { useReduxAction, useReduxStore } from "../@redux/hooks/base";
|
||||
import { SidebarToggleContext } from "../App";
|
||||
import {
|
||||
BadgeProvider,
|
||||
ChildBadgeProvider,
|
||||
CollapseItemType,
|
||||
LinkItemType,
|
||||
} from "./types";
|
||||
|
||||
export const HiddenKeysContext = React.createContext<string[]>([]);
|
||||
|
||||
export const BadgesContext = React.createContext<BadgeProvider>({});
|
||||
|
||||
function useToggleSidebar() {
|
||||
return useReduxAction(siteChangeSidebar);
|
||||
}
|
||||
|
||||
function useSidebarKey() {
|
||||
return useReduxStore((s) => s.site.sidebar);
|
||||
}
|
||||
|
||||
export const LinkItem: FunctionComponent<LinkItemType> = ({
|
||||
link,
|
||||
name,
|
||||
icon,
|
||||
}) => {
|
||||
const badges = useContext(BadgesContext);
|
||||
const toggle = useContext(SidebarToggleContext);
|
||||
|
||||
const badgeValue = useMemo(() => {
|
||||
let badge: Nullable<number> = null;
|
||||
if (name in badges) {
|
||||
let item = badges[name];
|
||||
if (typeof item === "number") {
|
||||
badge = item;
|
||||
}
|
||||
}
|
||||
return badge;
|
||||
}, [badges, name]);
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
activeClassName="sb-active"
|
||||
className="list-group-item list-group-item-action sidebar-button"
|
||||
to={link}
|
||||
onClick={toggle}
|
||||
>
|
||||
<DisplayItem
|
||||
badge={badgeValue ?? undefined}
|
||||
name={name}
|
||||
icon={icon}
|
||||
></DisplayItem>
|
||||
</NavLink>
|
||||
);
|
||||
};
|
||||
|
||||
export const CollapseItem: FunctionComponent<CollapseItemType> = ({
|
||||
icon,
|
||||
name,
|
||||
children,
|
||||
}) => {
|
||||
const badges = useContext(BadgesContext);
|
||||
const hiddenKeys = useContext(HiddenKeysContext);
|
||||
const toggleSidebar = useContext(SidebarToggleContext);
|
||||
|
||||
const sidebarKey = useSidebarKey();
|
||||
const updateSidebar = useToggleSidebar();
|
||||
|
||||
const [badgeValue, childValue] = useMemo<
|
||||
[Nullable<number>, Nullable<ChildBadgeProvider>]
|
||||
>(() => {
|
||||
let badge: Nullable<number> = null;
|
||||
let child: Nullable<ChildBadgeProvider> = null;
|
||||
|
||||
if (name in badges) {
|
||||
const item = badges[name];
|
||||
if (typeof item === "number") {
|
||||
badge = item;
|
||||
} else if (typeof item === "object") {
|
||||
badge = 0;
|
||||
child = item;
|
||||
for (const it in item) {
|
||||
badge += item[it];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [badge, child];
|
||||
}, [badges, name]);
|
||||
|
||||
const active = useMemo(() => sidebarKey === name, [sidebarKey, name]);
|
||||
|
||||
const collapseBoxClass = useMemo(
|
||||
() => `sidebar-collapse-box ${active ? "active" : ""}`,
|
||||
[active]
|
||||
);
|
||||
|
||||
const childrenElems = useMemo(
|
||||
() =>
|
||||
children
|
||||
.filter((v) => !hiddenKeys.includes(v.hiddenKey ?? ""))
|
||||
.map((ch) => {
|
||||
let badge: Nullable<number> = null;
|
||||
if (childValue && ch.name in childValue) {
|
||||
badge = childValue[ch.name];
|
||||
}
|
||||
return (
|
||||
<NavLink
|
||||
key={ch.name}
|
||||
activeClassName="sb-active"
|
||||
className="list-group-item list-group-item-action sidebar-button sb-collapse"
|
||||
to={ch.link}
|
||||
onClick={toggleSidebar}
|
||||
>
|
||||
<DisplayItem
|
||||
badge={badge === 0 ? undefined : badge ?? undefined}
|
||||
name={ch.name}
|
||||
></DisplayItem>
|
||||
</NavLink>
|
||||
);
|
||||
}),
|
||||
[children, hiddenKeys, childValue, toggleSidebar]
|
||||
);
|
||||
|
||||
if (childrenElems.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={collapseBoxClass}>
|
||||
<ListGroupItem
|
||||
action
|
||||
className="sidebar-button"
|
||||
onClick={() => {
|
||||
if (active) {
|
||||
updateSidebar("");
|
||||
} else {
|
||||
updateSidebar(name);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DisplayItem
|
||||
badge={badgeValue === 0 ? undefined : badgeValue ?? undefined}
|
||||
icon={icon}
|
||||
name={name}
|
||||
></DisplayItem>
|
||||
</ListGroupItem>
|
||||
<Collapse in={active}>
|
||||
<div className="sidebar-collapse">{childrenElems}</div>
|
||||
</Collapse>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface DisplayProps {
|
||||
name: string;
|
||||
icon?: IconDefinition;
|
||||
badge?: number;
|
||||
}
|
||||
|
||||
const DisplayItem: FunctionComponent<DisplayProps> = ({
|
||||
name,
|
||||
icon,
|
||||
badge,
|
||||
}) => (
|
||||
<React.Fragment>
|
||||
{icon && (
|
||||
<FontAwesomeIcon size="1x" className="icon" icon={icon}></FontAwesomeIcon>
|
||||
)}
|
||||
<span className="d-flex flex-grow-1 justify-content-between">
|
||||
{name} <Badge variant="secondary">{badge}</Badge>
|
||||
</span>
|
||||
</React.Fragment>
|
||||
);
|
@ -1,148 +0,0 @@
|
||||
import {
|
||||
faClock,
|
||||
faCogs,
|
||||
faExclamationTriangle,
|
||||
faFileExcel,
|
||||
faFilm,
|
||||
faLaptop,
|
||||
faPlay,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { SidebarDefinition } from "./types";
|
||||
|
||||
export const SonarrDisabledKey = "sonarr-disabled";
|
||||
export const RadarrDisabledKey = "radarr-disabled";
|
||||
|
||||
export const SidebarList: SidebarDefinition[] = [
|
||||
{
|
||||
icon: faPlay,
|
||||
name: "Series",
|
||||
link: "/series",
|
||||
hiddenKey: SonarrDisabledKey,
|
||||
},
|
||||
{
|
||||
icon: faFilm,
|
||||
name: "Movies",
|
||||
link: "/movies",
|
||||
hiddenKey: RadarrDisabledKey,
|
||||
},
|
||||
{
|
||||
icon: faClock,
|
||||
name: "History",
|
||||
children: [
|
||||
{
|
||||
name: "Series",
|
||||
link: "/history/series",
|
||||
hiddenKey: SonarrDisabledKey,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
link: "/history/movies",
|
||||
hiddenKey: RadarrDisabledKey,
|
||||
},
|
||||
{
|
||||
name: "Statistics",
|
||||
link: "/history/stats",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faFileExcel,
|
||||
name: "Blacklist",
|
||||
children: [
|
||||
{
|
||||
name: "Series",
|
||||
link: "/blacklist/series",
|
||||
hiddenKey: SonarrDisabledKey,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
link: "/blacklist/movies",
|
||||
hiddenKey: RadarrDisabledKey,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faExclamationTriangle,
|
||||
name: "Wanted",
|
||||
children: [
|
||||
{
|
||||
name: "Series",
|
||||
link: "/wanted/series",
|
||||
hiddenKey: SonarrDisabledKey,
|
||||
},
|
||||
{
|
||||
name: "Movies",
|
||||
link: "/wanted/movies",
|
||||
hiddenKey: RadarrDisabledKey,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faCogs,
|
||||
name: "Settings",
|
||||
children: [
|
||||
{
|
||||
name: "General",
|
||||
link: "/settings/general",
|
||||
},
|
||||
{
|
||||
name: "Languages",
|
||||
link: "/settings/languages",
|
||||
},
|
||||
{
|
||||
name: "Providers",
|
||||
link: "/settings/providers",
|
||||
},
|
||||
{
|
||||
name: "Subtitles",
|
||||
link: "/settings/subtitles",
|
||||
},
|
||||
{
|
||||
name: "Sonarr",
|
||||
link: "/settings/sonarr",
|
||||
},
|
||||
{
|
||||
name: "Radarr",
|
||||
link: "/settings/radarr",
|
||||
},
|
||||
{
|
||||
name: "Notifications",
|
||||
link: "/settings/notifications",
|
||||
},
|
||||
{
|
||||
name: "Scheduler",
|
||||
link: "/settings/scheduler",
|
||||
},
|
||||
{
|
||||
name: "UI",
|
||||
link: "/settings/ui",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: faLaptop,
|
||||
name: "System",
|
||||
children: [
|
||||
{
|
||||
name: "Tasks",
|
||||
link: "/system/tasks",
|
||||
},
|
||||
{
|
||||
name: "Logs",
|
||||
link: "/system/logs",
|
||||
},
|
||||
{
|
||||
name: "Providers",
|
||||
link: "/system/providers",
|
||||
},
|
||||
{
|
||||
name: "Status",
|
||||
link: "/system/status",
|
||||
},
|
||||
{
|
||||
name: "Releases",
|
||||
link: "/system/releases",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
@ -1,29 +0,0 @@
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-common-types";
|
||||
|
||||
type SidebarDefinition = LinkItemType | CollapseItemType;
|
||||
|
||||
type BaseSidebar = {
|
||||
icon: IconDefinition;
|
||||
name: string;
|
||||
hiddenKey?: string;
|
||||
};
|
||||
|
||||
type LinkItemType = BaseSidebar & {
|
||||
link: string;
|
||||
};
|
||||
|
||||
type CollapseItemType = BaseSidebar & {
|
||||
children: {
|
||||
name: string;
|
||||
link: string;
|
||||
hiddenKey?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
type BadgeProvider = {
|
||||
[parent: string]: ChildBadgeProvider | number;
|
||||
};
|
||||
|
||||
type ChildBadgeProvider = {
|
||||
[child: string]: number;
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import { useSetSidebar } from "../@redux/hooks/site";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import Logs from "./Logs";
|
||||
import Providers from "./Providers";
|
||||
import Releases from "./Releases";
|
||||
import Status from "./Status";
|
||||
import Tasks from "./Tasks";
|
||||
|
||||
const Router: FunctionComponent = () => {
|
||||
useSetSidebar("System");
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path="/system/tasks">
|
||||
<Tasks></Tasks>
|
||||
</Route>
|
||||
<Route exact path="/system/status">
|
||||
<Status></Status>
|
||||
</Route>
|
||||
<Route exact path="/system/providers">
|
||||
<Providers></Providers>
|
||||
</Route>
|
||||
<Route exact path="/system/logs">
|
||||
<Logs></Logs>
|
||||
</Route>
|
||||
<Route exact path="/system/releases">
|
||||
<Releases></Releases>
|
||||
</Route>
|
||||
<Route path="/system/*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
@ -1,36 +0,0 @@
|
||||
import React, { FunctionComponent } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import {
|
||||
useIsRadarrEnabled,
|
||||
useIsSonarrEnabled,
|
||||
useSetSidebar,
|
||||
} from "../@redux/hooks/site";
|
||||
import { RouterEmptyPath } from "../special-pages/404";
|
||||
import Movies from "./Movies";
|
||||
import Series from "./Series";
|
||||
|
||||
const Router: FunctionComponent = () => {
|
||||
const sonarr = useIsSonarrEnabled();
|
||||
const radarr = useIsRadarrEnabled();
|
||||
|
||||
useSetSidebar("Wanted");
|
||||
return (
|
||||
<Switch>
|
||||
{sonarr && (
|
||||
<Route exact path="/wanted/series">
|
||||
<Series></Series>
|
||||
</Route>
|
||||
)}
|
||||
{radarr && (
|
||||
<Route exact path="/wanted/movies">
|
||||
<Movies></Movies>
|
||||
</Route>
|
||||
)}
|
||||
<Route path="/wanted/*">
|
||||
<Redirect to={RouterEmptyPath}></Redirect>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
export default Router;
|
Loading…
Reference in new issue