🏗️ Refactored AirDC++ session status indicator
This commit is contained in:
@@ -10,6 +10,7 @@ import VolumeDetail from "./VolumeDetail/VolumeDetail";
|
|||||||
import Downloads from "./Downloads/Downloads";
|
import Downloads from "./Downloads/Downloads";
|
||||||
|
|
||||||
import { Routes, Route } from "react-router-dom";
|
import { Routes, Route } from "react-router-dom";
|
||||||
|
import { Outlet } from "react-router-dom";
|
||||||
import Navbar from "./shared/Navbar";
|
import Navbar from "./shared/Navbar";
|
||||||
import "../assets/scss/App.scss";
|
import "../assets/scss/App.scss";
|
||||||
|
|
||||||
@@ -46,7 +47,12 @@ export const App = (): ReactElement => {
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// }, []);
|
// }, []);
|
||||||
return <>{/* <Navbar /> */}</>;
|
return (
|
||||||
|
<>
|
||||||
|
<Navbar />
|
||||||
|
<Outlet />
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
const {
|
const {
|
||||||
airDCPPSocketConnected,
|
airDCPPSocketConnected,
|
||||||
airDCPPDisconnectionInfo,
|
airDCPPDisconnectionInfo,
|
||||||
airDCPPSocketConnectionInformation,
|
airDCPPSessionInformation,
|
||||||
airDCPPClientConfiguration,
|
airDCPPClientConfiguration,
|
||||||
airDCPPSocketInstance,
|
airDCPPSocketInstance,
|
||||||
} = useStore(
|
} = useStore(
|
||||||
@@ -20,8 +20,7 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
||||||
airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo,
|
airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo,
|
||||||
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
||||||
airDCPPSocketConnectionInformation:
|
airDCPPSessionInformation: state.airDCPPSessionInformation,
|
||||||
state.airDCPPSocketConnectionInformation,
|
|
||||||
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
@@ -48,10 +47,8 @@ export const AirDCPPSettingsForm = (): ReactElement => {
|
|||||||
formHeading={"Configure AirDC++"}
|
formHeading={"Configure AirDC++"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!isEmpty(airDCPPSocketConnectionInformation) ? (
|
{!isEmpty(airDCPPSessionInformation) ? (
|
||||||
<AirDCPPSettingsConfirmation
|
<AirDCPPSettingsConfirmation settings={airDCPPSessionInformation} />
|
||||||
settings={airDCPPSocketConnectionInformation}
|
|
||||||
/>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!isEmpty(airDCPPClientConfiguration) ? (
|
{!isEmpty(airDCPPClientConfiguration) ? (
|
||||||
|
|||||||
5
src/client/components/shared/ErrorPage.tsx
Normal file
5
src/client/components/shared/ErrorPage.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const ErrorPage = () => {
|
||||||
|
return <>Error has been encountered.</>;
|
||||||
|
};
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import React, { useContext } from "react";
|
import React from "react";
|
||||||
import { SearchBar } from "../GlobalSearchBar/SearchBar";
|
import { SearchBar } from "../GlobalSearchBar/SearchBar";
|
||||||
import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick";
|
import { DownloadProgressTick } from "../ComicDetail/DownloadProgressTick";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useSelector } from "react-redux";
|
import { isEmpty, isUndefined } from "lodash";
|
||||||
import { isUndefined } from "lodash";
|
|
||||||
import { format, fromUnixTime } from "date-fns";
|
import { format, fromUnixTime } from "date-fns";
|
||||||
import { useStore } from "../../store/index";
|
import { useStore } from "../../store/index";
|
||||||
import { useShallow } from "zustand/react/shallow";
|
import { useShallow } from "zustand/react/shallow";
|
||||||
@@ -12,7 +11,8 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
const {
|
const {
|
||||||
airDCPPSocketConnected,
|
airDCPPSocketConnected,
|
||||||
airDCPPDisconnectionInfo,
|
airDCPPDisconnectionInfo,
|
||||||
airDCPPSocketConnectionInformation,
|
airDCPPSessionInformation,
|
||||||
|
airDCPPDownloadTick,
|
||||||
airDCPPClientConfiguration,
|
airDCPPClientConfiguration,
|
||||||
airDCPPSocketInstance,
|
airDCPPSocketInstance,
|
||||||
} = useStore(
|
} = useStore(
|
||||||
@@ -20,43 +20,43 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
airDCPPSocketConnected: state.airDCPPSocketConnected,
|
||||||
airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo,
|
airDCPPDisconnectionInfo: state.airDCPPDisconnectionInfo,
|
||||||
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
airDCPPClientConfiguration: state.airDCPPClientConfiguration,
|
||||||
airDCPPSocketConnectionInformation:
|
airDCPPSessionInformation: state.airDCPPSessionInformation,
|
||||||
state.airDCPPSocketConnectionInformation,
|
|
||||||
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
airDCPPSocketInstance: state.airDCPPSocketInstance,
|
||||||
|
airDCPPDownloadTick: state.airDCPPDownloadTick,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
const downloadProgressTick = useSelector(
|
// const downloadProgressTick = useSelector(
|
||||||
(state: RootState) => state.airdcpp.downloadProgressData,
|
// (state: RootState) => state.airdcpp.downloadProgressData,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
const airDCPPSocketConnectionStatus = useSelector(
|
// const airDCPPSocketConnectionStatus = useSelector(
|
||||||
(state: RootState) => state.airdcpp.isAirDCPPSocketConnected,
|
// (state: RootState) => state.airdcpp.isAirDCPPSocketConnected,
|
||||||
);
|
// );
|
||||||
const airDCPPSessionInfo = useSelector(
|
// const airDCPPSessionInfo = useSelector(
|
||||||
(state: RootState) => state.airdcpp.airDCPPSessionInfo,
|
// (state: RootState) => state.airdcpp.airDCPPSessionInfo,
|
||||||
);
|
// );
|
||||||
const socketDisconnectionReason = useSelector(
|
// const socketDisconnectionReason = useSelector(
|
||||||
(state: RootState) => state.airdcpp.socketDisconnectionReason,
|
// (state: RootState) => state.airdcpp.socketDisconnectionReason,
|
||||||
);
|
// );
|
||||||
|
|
||||||
// Import-related selector hooks
|
// Import-related selector hooks
|
||||||
const successfulImportJobCount = useSelector(
|
// const successfulImportJobCount = useSelector(
|
||||||
(state: RootState) => state.fileOps.successfulJobCount,
|
// (state: RootState) => state.fileOps.successfulJobCount,
|
||||||
);
|
// );
|
||||||
const failedImportJobCount = useSelector(
|
// const failedImportJobCount = useSelector(
|
||||||
(state: RootState) => state.fileOps.failedJobCount,
|
// (state: RootState) => state.fileOps.failedJobCount,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
const lastQueueJob = useSelector(
|
// const lastQueueJob = useSelector(
|
||||||
(state: RootState) => state.fileOps.lastQueueJob,
|
// (state: RootState) => state.fileOps.lastQueueJob,
|
||||||
);
|
// );
|
||||||
const libraryQueueImportStatus = useSelector(
|
// const libraryQueueImportStatus = useSelector(
|
||||||
(state: RootState) => state.fileOps.LSQueueImportStatus,
|
// (state: RootState) => state.fileOps.LSQueueImportStatus,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
const allImportJobResults = useSelector(
|
// const allImportJobResults = useSelector(
|
||||||
(state: RootState) => state.fileOps.importJobStatistics,
|
// (state: RootState) => state.fileOps.importJobStatistics,
|
||||||
);
|
// );
|
||||||
return (
|
return (
|
||||||
<nav className="navbar is-fixed-top">
|
<nav className="navbar is-fixed-top">
|
||||||
<div className="navbar-brand">
|
<div className="navbar-brand">
|
||||||
@@ -106,7 +106,7 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
Downloads
|
Downloads
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<SearchBar />
|
{/* <SearchBar /> */}
|
||||||
|
|
||||||
<Link to="/search" className="navbar-item">
|
<Link to="/search" className="navbar-item">
|
||||||
Search ComicVine
|
Search ComicVine
|
||||||
@@ -119,52 +119,22 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
<div className="navbar-item has-dropdown is-hoverable">
|
<div className="navbar-item has-dropdown is-hoverable">
|
||||||
<a className="navbar-link is-arrowless">
|
<a className="navbar-link is-arrowless">
|
||||||
<i className="fa-solid fa-download"></i>
|
<i className="fa-solid fa-download"></i>
|
||||||
{downloadProgressTick && <div className="pulsating-circle"></div>}
|
{!isEmpty(airDCPPDownloadTick) && (
|
||||||
|
<div className="pulsating-circle"></div>
|
||||||
|
)}
|
||||||
</a>
|
</a>
|
||||||
{!isUndefined(downloadProgressTick) ? (
|
{!isEmpty(airDCPPDownloadTick) ? (
|
||||||
<div className="navbar-dropdown is-right is-boxed">
|
<div className="navbar-dropdown is-right is-boxed">
|
||||||
<a className="navbar-item">
|
<a className="navbar-item">
|
||||||
<DownloadProgressTick data={downloadProgressTick} />
|
<DownloadProgressTick data={airDCPPDownloadTick} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isUndefined(libraryQueueImportStatus) &&
|
|
||||||
location.hash !== "#/import" ? (
|
|
||||||
<div className="navbar-item has-dropdown is-hoverable">
|
|
||||||
<a className="navbar-link is-arrowless">
|
|
||||||
<i className="fa-solid fa-file-import has-text-warning-dark"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div className="navbar-dropdown is-right is-boxed">
|
|
||||||
<a className="navbar-item">
|
|
||||||
<ul>
|
|
||||||
{successfulImportJobCount > 0 ? (
|
|
||||||
<li className="mb-2">
|
|
||||||
<span className="tag is-success mr-2">
|
|
||||||
{successfulImportJobCount}
|
|
||||||
</span>
|
|
||||||
imported.
|
|
||||||
</li>
|
|
||||||
) : null}
|
|
||||||
{failedImportJobCount > 0 ? (
|
|
||||||
<li>
|
|
||||||
<span className="tag is-danger mr-2">
|
|
||||||
{failedImportJobCount}
|
|
||||||
</span>
|
|
||||||
failed to import.
|
|
||||||
</li>
|
|
||||||
) : null}
|
|
||||||
</ul>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{/* AirDC++ socket connection status */}
|
{/* AirDC++ socket connection status */}
|
||||||
<div className="navbar-item has-dropdown is-hoverable">
|
<div className="navbar-item has-dropdown is-hoverable">
|
||||||
{airDCPPSocketConnectionStatus ? (
|
{airDCPPSocketConnected ? (
|
||||||
<>
|
<>
|
||||||
<a className="navbar-link is-arrowless has-text-success">
|
<a className="navbar-link is-arrowless has-text-success">
|
||||||
<i className="fa-solid fa-bolt"></i>
|
<i className="fa-solid fa-bolt"></i>
|
||||||
@@ -176,7 +146,7 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
Last login was{" "}
|
Last login was{" "}
|
||||||
<span className="tag">
|
<span className="tag">
|
||||||
{format(
|
{format(
|
||||||
fromUnixTime(airDCPPSessionInfo.user.last_login),
|
fromUnixTime(airDCPPSessionInformation.user.last_login),
|
||||||
"dd MMMM, yyyy",
|
"dd MMMM, yyyy",
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
@@ -184,15 +154,15 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
<hr className="navbar-divider" />
|
<hr className="navbar-divider" />
|
||||||
<p>
|
<p>
|
||||||
<span className="tag has-text-success">
|
<span className="tag has-text-success">
|
||||||
{airDCPPSessionInfo.user.username}
|
{airDCPPSessionInformation.user.username}
|
||||||
</span>
|
</span>
|
||||||
connected to{" "}
|
connected to{" "}
|
||||||
<span className="tag has-text-success">
|
<span className="tag has-text-success">
|
||||||
{airDCPPSessionInfo.system_info.client_version}
|
{airDCPPSessionInformation.system_info.client_version}
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
with session ID{" "}
|
with session ID{" "}
|
||||||
<span className="tag has-text-success">
|
<span className="tag has-text-success">
|
||||||
{airDCPPSessionInfo.session_id}
|
{airDCPPSessionInformation.session_id}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -205,9 +175,7 @@ const Navbar: React.FunctionComponent = (props) => {
|
|||||||
<i className="fa-solid fa-bolt"></i>
|
<i className="fa-solid fa-bolt"></i>
|
||||||
</a>
|
</a>
|
||||||
<div className="navbar-dropdown pr-2 pl-2 is-right is-boxed">
|
<div className="navbar-dropdown pr-2 pl-2 is-right is-boxed">
|
||||||
<pre>
|
<pre>{JSON.stringify(airDCPPDisconnectionInfo, null, 2)}</pre>
|
||||||
{JSON.stringify(socketDisconnectionReason, null, 2)}
|
|
||||||
</pre>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { createRoot } from "react-dom/client";
|
|||||||
import App from "./components/App";
|
import App from "./components/App";
|
||||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||||
import Settings from "./components/Settings/Settings";
|
import Settings from "./components/Settings/Settings";
|
||||||
|
import { ErrorPage } from "./components/shared/ErrorPage";
|
||||||
const rootEl = document.getElementById("root");
|
const rootEl = document.getElementById("root");
|
||||||
const root = createRoot(rootEl);
|
const root = createRoot(rootEl);
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
@@ -15,10 +16,8 @@ const router = createBrowserRouter([
|
|||||||
{
|
{
|
||||||
path: "/",
|
path: "/",
|
||||||
element: <App />,
|
element: <App />,
|
||||||
},
|
errorElement: <ErrorPage />,
|
||||||
{
|
children: [{ path: "settings", element: <Settings /> }],
|
||||||
path: "/settings",
|
|
||||||
element: <Settings />,
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const useStore = create((set, get) => ({
|
|||||||
airDCPPSocketConnected: false,
|
airDCPPSocketConnected: false,
|
||||||
airDCPPDisconnectionInfo: {},
|
airDCPPDisconnectionInfo: {},
|
||||||
airDCPPClientConfiguration: {},
|
airDCPPClientConfiguration: {},
|
||||||
airDCPPSocketConnectionInformation: {},
|
airDCPPSessionInformation: {},
|
||||||
setAirDCPPSocketConnectionStatus: () =>
|
setAirDCPPSocketConnectionStatus: () =>
|
||||||
set((value) => ({
|
set((value) => ({
|
||||||
airDCPPSocketConnected: value,
|
airDCPPSocketConnected: value,
|
||||||
@@ -54,10 +54,9 @@ const initializeAirDCPPSocket = async (configuration): Promise<any> => {
|
|||||||
};
|
};
|
||||||
// AirDC++ Socket-related connection and post-connection
|
// AirDC++ Socket-related connection and post-connection
|
||||||
// Attempt connection
|
// Attempt connection
|
||||||
const airDCPPSocketConnectionInformation =
|
const airDCPPSessionInformation = await initializedAirDCPPSocket.connect();
|
||||||
await initializedAirDCPPSocket.connect();
|
|
||||||
setState({
|
setState({
|
||||||
airDCPPSocketConnectionInformation,
|
airDCPPSessionInformation,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up event listeners
|
// Set up event listeners
|
||||||
|
|||||||
Reference in New Issue
Block a user