Copying some settings values to status to avoid calling both /settings and /status.

This commit is contained in:
Roland 2022-10-16 11:53:44 -06:00
parent 78218d3559
commit dbdcc7a57c
No known key found for this signature in database
GPG key ID: 9D6DBD3ACF11AB93
10 changed files with 105 additions and 68 deletions

View file

@ -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 (
<Container fluid>
<h1 className="display-4">Page Not Found!</h1>
<p>The page you requested cannot be found</p>
</Container>
)
return (<Container fluid>
<h1 className="display-4">Page Not Found!</h1>
<p>The page you requested cannot be found</p>
</Container>)
}
function Footer() {
const {t} = useContext(ThemeContext);
const {version} = useContext(SettingsContext);
const {status} = useContext(StatusContext);
const {version} = status;
return <Container textAlign='center' style={{marginTop: '1.5em', marginBottom: '1em'}}>
<span {...t}>WROLPi v{version} <a href='https://github.com/lrnselfreliance/wrolpi'>GitHub</a></span>
</Container>
}
export default function App() {
const {settings} = useSettingsInterval();
const status = useStatusInterval();
return (
<ThemeWrapper>
<SettingsContext.Provider value={settings}>
<header>
<NavBar/>
</header>
<>
<Routes>
<Route path='/videos/video/:videoId' exact element={<VideoWrapper/>}/>
<Route path='/videos/channel/:channelId/video/:videoId' exact element={<VideoWrapper/>}/>
<Route path="/" exact element={<Dashboard/>}/>
<Route path="/videos/*" element={<VideosRoute/>}/>
<Route path="/admin/*" element={<Admin/>}/>
<Route path="/apps/*" element={<AppsRoute/>}/>
<Route path="/inventory/*" element={<InventoryRoute/>}/>
<Route path='/archive/*' element={<ArchiveRoute/>}/>
<Route path='/map/*' element={<MapRoute/>}/>
<Route path='/files/*' element={<FilesRoute/>}/>
<Route element={<PageNotFound/>}/>
</Routes>
</>
<SemanticToastContainer position="top-right"/>
<Footer/>
</SettingsContext.Provider>
</ThemeWrapper>
);
return (<ThemeWrapper>
<StatusContext.Provider value={status}>
<header>
<NavBar/>
</header>
<>
<Routes>
<Route path='/videos/video/:videoId' exact element={<VideoWrapper/>}/>
<Route path='/videos/channel/:channelId/video/:videoId' exact element={<VideoWrapper/>}/>
<Route path="/" exact element={<Dashboard/>}/>
<Route path="/videos/*" element={<VideosRoute/>}/>
<Route path="/admin/*" element={<Admin/>}/>
<Route path="/apps/*" element={<AppsRoute/>}/>
<Route path="/inventory/*" element={<InventoryRoute/>}/>
<Route path='/archive/*' element={<ArchiveRoute/>}/>
<Route path='/map/*' element={<MapRoute/>}/>
<Route path='/files/*' element={<FilesRoute/>}/>
<Route element={<PageNotFound/>}/>
</Routes>
</>
<SemanticToastContainer position="top-right"/>
<Footer/>
</StatusContext.Provider>
</ThemeWrapper>);
}

View file

@ -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 = <DownloadMenu onOpen={onDownloadOpen}/>;
// Only show dashboard parts if not searching.
@ -32,8 +33,7 @@ export function Dashboard() {
</>;
}
return (
<PageContainer>
return (<PageContainer>
<SearchInput clearable
searchStr={searchStr}
onSubmit={setSearchStr}
@ -43,12 +43,12 @@ export function Dashboard() {
style={{marginBottom: '2em'}}
/>
{body}
</PageContainer>
)
</PageContainer>)
}
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 <Segment>
@ -78,8 +77,8 @@ function DashboardStatus() {
</StatisticGroup>
<Header as='h3'>Bandwidth</Header>
{status && status['bandwidth'] ?
status['bandwidth'].map(i => <BandwidthProgressCombined key={i['name']} bandwidth={i}/>) :
{status && status['bandwidth'] ? status['bandwidth'].map(i => <BandwidthProgressCombined key={i['name']}
bandwidth={i}/>) :
<ProgressPlaceholder/>}
</Link>

View file

@ -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 <Message icon='lock' header='WROL Mode Enabled' content={content}/>

View file

@ -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&nbsp; <Icon name='lock'/></> : 'WROLPi';
const {i} = useContext(ThemeContext);

View file

@ -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 <ThemeContext.Consumer>
{({i, t}) => <Container fluid>
{({t}) => <Container fluid>
<Header as="h1">WROL Mode</Header>
<Header as='h4'>

View file

@ -10,3 +10,5 @@ export const ThemeContext = React.createContext({
setTheme: () => {
},
});
export const StatusContext = React.createContext({});

View file

@ -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({});

View file

@ -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]:

View file

@ -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)

View file

@ -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):