diff --git a/app/src/App.js b/app/src/App.js index 397bb565..32bf9fea 100644 --- a/app/src/App.js +++ b/app/src/App.js @@ -12,57 +12,53 @@ import {AppsRoute} from "./components/Apps"; import {InventoryRoute} from "./components/Inventory"; import {ArchiveRoute} from "./components/Archive"; import {FilesRoute} from "./components/Files"; -import {useSettingsInterval} from "./hooks/customHooks"; +import {useStatusInterval} from "./hooks/customHooks"; import {MapRoute} from "./components/Map"; -import {SettingsContext, ThemeContext} from "./contexts/contexts"; +import {StatusContext, ThemeContext} from "./contexts/contexts"; import {ThemeWrapper} from "./components/Theme"; import {Dashboard} from "./Dashboard"; function PageNotFound() { - return ( - - Page Not Found! - The page you requested cannot be found - - ) + return ( + Page Not Found! + The page you requested cannot be found + ) } function Footer() { const {t} = useContext(ThemeContext); - - const {version} = useContext(SettingsContext); + const {status} = useContext(StatusContext); + const {version} = status; return WROLPi v{version} GitHub } export default function App() { - const {settings} = useSettingsInterval(); + const status = useStatusInterval(); - return ( - - - - - - <> - - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - - > - - - - - ); + return ( + + + + + <> + + }/> + }/> + }/> + }/> + }/> + }/> + }/> + }/> + }/> + }/> + }/> + + > + + + + ); } diff --git a/app/src/Dashboard.js b/app/src/Dashboard.js index 865ebf46..ab47db63 100644 --- a/app/src/Dashboard.js +++ b/app/src/Dashboard.js @@ -1,7 +1,7 @@ import {LoadStatistic, PageContainer, SearchInput, useTitle} from "./components/Common"; -import {useSearchFiles, useStatus} from "./hooks/customHooks"; +import {useSearchFiles} from "./hooks/customHooks"; import React, {useContext, useState} from "react"; -import {SettingsContext} from "./contexts/contexts"; +import {StatusContext} from "./contexts/contexts"; import {DownloadMenu} from "./components/Upload"; import {FilesSearchView} from "./components/Files"; import {Header, Segment, Statistic, StatisticGroup} from "./components/Theme"; @@ -14,10 +14,11 @@ export function Dashboard() { const {searchStr, setSearchStr} = useSearchFiles(); + const {status} = useContext(StatusContext); + const wrol_mode = status ? status['wrol_mode'] : null; + const [downloadOpen, setDownloadOpen] = useState(false); const onDownloadOpen = (name) => setDownloadOpen(!!name); - const {wrol_mode} = useContext(SettingsContext); - const downloads = ; // Only show dashboard parts if not searching. @@ -32,8 +33,7 @@ export function Dashboard() { >; } - return ( - + return ( {body} - - ) + ) } function DashboardStatus() { - const {status} = useStatus(); + const {status} = useContext(StatusContext); + let percent = 0; let load = {}; let cores = 0; @@ -57,12 +57,11 @@ function DashboardStatus() { percent = status['cpu_info']['percent']; load = status['load']; cores = status['cpu_info']['cores']; - pending_downloads = status['downloads']['pending_downloads']; } - const {download_manager_disabled, download_manager_stopped} = useContext(SettingsContext); - if (pending_downloads === 0 && (download_manager_disabled || download_manager_stopped)) { - pending_downloads = 'x'; + const {downloads} = status; + if (downloads) { + pending_downloads = downloads['disabled'] ? 'x' : downloads['pending']; } return @@ -78,8 +77,8 @@ function DashboardStatus() { Bandwidth - {status && status['bandwidth'] ? - status['bandwidth'].map(i => ) : + {status && status['bandwidth'] ? status['bandwidth'].map(i => ) : } diff --git a/app/src/components/Common.js b/app/src/components/Common.js index 69d060d1..7a7c0f4d 100644 --- a/app/src/components/Common.js +++ b/app/src/components/Common.js @@ -3,7 +3,7 @@ import {Card, Container, Image, Input, Pagination, Responsive, TableCell, TableR import {Link, NavLink} from "react-router-dom"; import Message from "semantic-ui-react/dist/commonjs/collections/Message"; import {useDownloaders, useHotspot, useThrottle} from "../hooks/customHooks"; -import {darkTheme, SettingsContext, ThemeContext} from "../contexts/contexts"; +import {darkTheme, StatusContext, ThemeContext} from "../contexts/contexts"; import {Button, CardIcon, Form, Header, Icon, Menu, Popup, Statistic} from "./Theme"; export const API_URI = `http://${window.location.host}/api`; @@ -471,8 +471,8 @@ export function SearchInput({ } export function WROLModeMessage({content}) { - const settings = useContext(SettingsContext); - const wrol_mode = settings ? settings.wrol_mode : null; + const {status} = useContext(StatusContext); + const wrol_mode = status ? status.wrol_mode : null; if (wrol_mode) { return diff --git a/app/src/components/Nav.js b/app/src/components/Nav.js index ac6f498a..dc05c5ed 100644 --- a/app/src/components/Nav.js +++ b/app/src/components/Nav.js @@ -1,7 +1,7 @@ import React, {useContext} from "react"; import {NavLink} from "react-router-dom"; import {Dropdown, Menu, Responsive} from "semantic-ui-react"; -import {SettingsContext, ThemeContext} from "../contexts/contexts"; +import {StatusContext, ThemeContext} from "../contexts/contexts"; import Icon from "semantic-ui-react/dist/commonjs/elements/Icon"; import {DarkModeToggle} from "./Common"; @@ -64,8 +64,8 @@ function MenuLink(props) { } export function NavBar() { - const settings = useContext(SettingsContext); - const wrol_mode = settings ? settings.wrol_mode : null; + const {status} = useContext(StatusContext); + const wrol_mode = status ? status['wrol_mode'] : null; const topNavText = wrol_mode ? <>WROLPi > : 'WROLPi'; const {i} = useContext(ThemeContext); diff --git a/app/src/components/admin/Admin.js b/app/src/components/admin/Admin.js index fad8cfc2..c7655e69 100644 --- a/app/src/components/admin/Admin.js +++ b/app/src/components/admin/Admin.js @@ -1,6 +1,6 @@ import React from 'react'; import {Container} from "semantic-ui-react"; -import {getSettings, saveSettings} from "../../api"; +import {getStatus, saveSettings} from "../../api"; import {PageContainer, TabLinks, Toggle} from "../Common"; import {Route, Routes} from "react-router-dom"; import {ThemeContext} from "../../contexts/contexts"; @@ -20,8 +20,8 @@ class WROLMode extends React.Component { async componentDidMount() { try { - let settings = await getSettings(); - this.setState({ready: true, WROLMode: settings.wrol_mode}); + const {wrol_mode} = await getStatus(); + this.setState({ready: true, WROLMode: wrol_mode}); } catch (e) { console.error(e); } @@ -42,7 +42,7 @@ class WROLMode extends React.Component { } return - {({i, t}) => + {({t}) => WROL Mode diff --git a/app/src/contexts/contexts.js b/app/src/contexts/contexts.js index 85aa26fe..64f455f2 100644 --- a/app/src/contexts/contexts.js +++ b/app/src/contexts/contexts.js @@ -10,3 +10,5 @@ export const ThemeContext = React.createContext({ setTheme: () => { }, }); + +export const StatusContext = React.createContext({}); diff --git a/app/src/hooks/customHooks.js b/app/src/hooks/customHooks.js index badee288..437d6e46 100644 --- a/app/src/hooks/customHooks.js +++ b/app/src/hooks/customHooks.js @@ -656,6 +656,19 @@ export const useStatus = () => { return {status, fetchStatus} } +export const useStatusInterval = () => { + const {status, fetchStatus} = useStatus(); + + useEffect(() => { + const interval = setInterval(() => { + fetchStatus(); + }, 1000 * 3); + return () => clearInterval(interval); + }, []); + + return {status, fetchStatus}; +} + export const useVideoStatistics = () => { const [statistics, setStatistics] = useState({}); diff --git a/wrolpi/downloader.py b/wrolpi/downloader.py index 2d491a43..7acd3757 100644 --- a/wrolpi/downloader.py +++ b/wrolpi/downloader.py @@ -877,13 +877,26 @@ class DownloadManager: ) return data - @staticmethod - def get_summary(): + def get_summary(self) -> dict: + """ + Get a summary of what Downloads are happening as well as the status of the DownloadManager. + """ with get_db_curs() as curs: - stmt = """SELECT COUNT(*) AS pending_downloads FROM download WHERE status='pending'""" + stmt = """ + SELECT + COUNT(*) FILTER (WHERE status = 'pending') AS pending_downloads, + COUNT(*) FILTER (WHERE frequency IS NOT NULL) AS recurring_downloads + FROM download + """ curs.execute(stmt) - result = [dict(i) for i in curs.fetchall()][0] - return result + counts = list(map(dict, curs.fetchall()))[0] + summary = dict( + pending=counts['pending_downloads'], + recurring=counts['recurring_downloads'], + disabled=self.disabled.is_set(), + stopped=self.stopped.is_set(), + ) + return summary @optional_session def get_pending_downloads(self, session: Session) -> List[Download]: diff --git a/wrolpi/root_api.py b/wrolpi/root_api.py index 07fa3d20..d4343ba7 100644 --- a/wrolpi/root_api.py +++ b/wrolpi/root_api.py @@ -314,7 +314,17 @@ async def throttle_off(_: Request): async def get_status(_: Request): s = await status.get_status() downloads = download_manager.get_summary() - ret = dict(downloads=downloads, **s.__dict__) + ret = dict( + bandwidth=s.bandwidth, + cpu_info=s.cpu_info, + downloads=downloads, + drives=s.drives, + hotspot_status=admin.hotspot_status().name, + load=s.load, + throttle_status=admin.throttle_status().name, + version=__version__, + wrol_mode=wrol_mode_enabled(), + ) return json_response(ret) diff --git a/wrolpi/test/test_root_api.py b/wrolpi/test/test_root_api.py index 227bd3e2..14decddb 100644 --- a/wrolpi/test/test_root_api.py +++ b/wrolpi/test/test_root_api.py @@ -310,6 +310,10 @@ def test_get_status(test_client, test_session): assert 'cpu_info' in response.json and isinstance(response.json['cpu_info'], dict) assert 'load' in response.json and isinstance(response.json['load'], dict) assert 'drives' in response.json and isinstance(response.json['drives'], list) + assert 'downloads' in response.json and isinstance(response.json['downloads'], dict) + assert 'hotspot_status' in response.json and isinstance(response.json['hotspot_status'], str) + assert 'throttle_status' in response.json and isinstance(response.json['throttle_status'], str) + assert 'version' in response.json and isinstance(response.json['version'], str) def test_post_download(test_session, test_client, test_download_manager_config):
The page you requested cannot be found