mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Showing error modal when clicking hotspot toggle on Docker.
This commit is contained in:
parent
1230a3056d
commit
d28797326b
6 changed files with 178 additions and 56 deletions
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<meta
|
||||
name="description"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {Header, Segment, Statistic, StatisticGroup} from "./components/Theme";
|
|||
import {Link} from "react-router-dom";
|
||||
import {BandwidthProgressCombined, CPUUsageProgress} from "./components/admin/Status";
|
||||
import {ProgressPlaceholder} from "./components/Placeholder";
|
||||
import {Divider} from "semantic-ui-react";
|
||||
|
||||
export function Dashboard() {
|
||||
useTitle('Dashboard');
|
||||
|
|
@ -34,16 +35,16 @@ export function Dashboard() {
|
|||
}
|
||||
|
||||
return (<PageContainer>
|
||||
<SearchInput clearable
|
||||
searchStr={searchStr}
|
||||
onSubmit={setSearchStr}
|
||||
size='large'
|
||||
placeholder='Search Everywhere...'
|
||||
actionIcon='search'
|
||||
style={{marginBottom: '2em'}}
|
||||
/>
|
||||
{body}
|
||||
</PageContainer>)
|
||||
<SearchInput clearable
|
||||
searchStr={searchStr}
|
||||
onSubmit={setSearchStr}
|
||||
size='large'
|
||||
placeholder='Search Everywhere...'
|
||||
actionIcon='search'
|
||||
style={{marginBottom: '2em'}}
|
||||
/>
|
||||
{body}
|
||||
</PageContainer>)
|
||||
}
|
||||
|
||||
function DashboardStatus() {
|
||||
|
|
@ -64,24 +65,28 @@ function DashboardStatus() {
|
|||
pending_downloads = downloads['disabled'] ? 'x' : downloads['pending'];
|
||||
}
|
||||
|
||||
let bandwidths = <ProgressPlaceholder/>;
|
||||
if (status && status['bandwidth']) {
|
||||
bandwidths = status['bandwidth'].map(i => <BandwidthProgressCombined key={i['name']} bandwidth={i}/>);
|
||||
}
|
||||
|
||||
return <Segment>
|
||||
<Link to='/admin/status'>
|
||||
<Header as='h2'>Status</Header>
|
||||
<CPUUsageProgress value={percent} label='CPU Usage'/>
|
||||
|
||||
<Header as='h3'>Load</Header>
|
||||
<StatisticGroup size='mini'>
|
||||
<LoadStatistic label='1 Minute' value={load['minute_1']} cores={cores}/>
|
||||
<LoadStatistic label='5 Minute' value={load['minute_5']} cores={cores}/>
|
||||
<LoadStatistic label='15 Minute' value={load['minute_15']} cores={cores}/>
|
||||
<LoadStatistic label='1 Min. Load' value={load['minute_1']} cores={cores}/>
|
||||
<LoadStatistic label='5 Min. Load' value={load['minute_5']} cores={cores}/>
|
||||
<LoadStatistic label='15 Min. Load' value={load['minute_15']} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
|
||||
<Header as='h3'>Bandwidth</Header>
|
||||
{status && status['bandwidth'] ? status['bandwidth'].map(i => <BandwidthProgressCombined key={i['name']}
|
||||
bandwidth={i}/>) :
|
||||
<ProgressPlaceholder/>}
|
||||
{bandwidths}
|
||||
</Link>
|
||||
|
||||
<Divider/>
|
||||
|
||||
<Link to='/admin'>
|
||||
<StatisticGroup size='mini'>
|
||||
<Statistic label='Downloading' value={pending_downloads}/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import React, {useContext, useEffect, useState} from "react";
|
||||
import {Card, Container, IconGroup, Image, Input, Pagination, Responsive, TableCell, TableRow} from 'semantic-ui-react';
|
||||
import {
|
||||
Card,
|
||||
Container,
|
||||
IconGroup,
|
||||
Image,
|
||||
Input,
|
||||
Modal,
|
||||
Pagination,
|
||||
Responsive,
|
||||
TableCell,
|
||||
TableRow
|
||||
} from 'semantic-ui-react';
|
||||
import {Link, NavLink} from "react-router-dom";
|
||||
import Message from "semantic-ui-react/dist/commonjs/collections/Message";
|
||||
import {useDownloaders, useHotspot, useThrottle} from "../hooks/customHooks";
|
||||
|
|
@ -734,22 +745,61 @@ export function DarkModeToggle() {
|
|||
</>
|
||||
}
|
||||
|
||||
|
||||
export function UnsupportedModal(header, message, icon) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const onOpen = () => setOpen(true);
|
||||
const onClose = () => setOpen(false);
|
||||
|
||||
const modal = <Modal basic closeIcon
|
||||
onOpen={onOpen}
|
||||
onClose={onClose}
|
||||
open={open}
|
||||
>
|
||||
<Header>
|
||||
<Icon name={icon || 'exclamation triangle'}/>
|
||||
{header || 'Unsupported'}
|
||||
</Header>
|
||||
<Modal.Content>
|
||||
<Modal.Description>
|
||||
{message}
|
||||
</Modal.Description>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button basic inverted onClick={onClose}>Ok</Button>
|
||||
</Modal.Actions>
|
||||
</Modal>;
|
||||
|
||||
return {modal, doClose: onClose, doOpen: onOpen};
|
||||
}
|
||||
|
||||
export function HotspotStatusIcon() {
|
||||
const {on, setHotspot} = useHotspot();
|
||||
const {on, setHotspot, dockerized} = useHotspot();
|
||||
const {modal, doOpen} = UnsupportedModal(
|
||||
'Unsupported on Docker',
|
||||
'You cannot toggle the hotspot on Docker.'
|
||||
);
|
||||
|
||||
const toggleHotspot = (e) => {
|
||||
e.preventDefault();
|
||||
if (dockerized) {
|
||||
doOpen();
|
||||
}
|
||||
if (on != null) {
|
||||
setHotspot(!on);
|
||||
}
|
||||
}
|
||||
|
||||
return <a href='#' onClick={toggleHotspot}>
|
||||
<IconGroup size='large'>
|
||||
<Icon name='wifi' disabled={on !== true}/>
|
||||
{on === false && <Icon corner name='x'/>}
|
||||
{on === null && <Icon corner name='question'/>}
|
||||
</IconGroup>
|
||||
</a>
|
||||
return <>
|
||||
<a href='#' onClick={toggleHotspot}>
|
||||
<IconGroup size='large'>
|
||||
<Icon name='wifi' disabled={on !== true}/>
|
||||
{on === false && <Icon corner name='x'/>}
|
||||
{on === null && <Icon corner name='question'/>}
|
||||
</IconGroup>
|
||||
</a>
|
||||
{modal}
|
||||
</>
|
||||
}
|
||||
|
||||
export function useTitle(title) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useContext} from "react";
|
||||
import React, {useContext, useState} from "react";
|
||||
import {clearCompletedDownloads, clearFailedDownloads, killDownload, postDownload} from "../../api";
|
||||
import {Link} from "react-router-dom";
|
||||
import {
|
||||
|
|
@ -9,6 +9,7 @@ import {
|
|||
WROLModeMessage
|
||||
} from "../Common";
|
||||
import {
|
||||
Button as SemanticButton,
|
||||
Confirm,
|
||||
Modal,
|
||||
PlaceholderLine,
|
||||
|
|
@ -18,7 +19,7 @@ import {
|
|||
TableHeaderCell,
|
||||
TableRow
|
||||
} from "semantic-ui-react";
|
||||
import {Button, Header, Placeholder, Table} from "../Theme";
|
||||
import {Button, Header, Icon, Placeholder, Table} from "../Theme";
|
||||
import {ThemeContext} from "../../contexts/contexts";
|
||||
import {useDownloads} from "../../hooks/customHooks";
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ class DownloadRow extends React.Component {
|
|||
<pre style={{overflowX: 'scroll'}}>{error}</pre>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button onClick={() => this.setState({errorModalOpen: false})}>Close</Button>
|
||||
<SemanticButton onClick={() => this.setState({errorModalOpen: false})}>Close</SemanticButton>
|
||||
</Modal.Actions>
|
||||
</Modal>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {Header, Progress, Statistic, StatisticGroup} from "../Theme";
|
||||
import React, {useContext} from "react";
|
||||
import {humanBandwidth, humanFileSize, LoadStatistic} from "../Common";
|
||||
import {Divider} from "semantic-ui-react";
|
||||
import {Divider, Responsive} from "semantic-ui-react";
|
||||
import {ProgressPlaceholder} from "../Placeholder";
|
||||
import Grid from "semantic-ui-react/dist/commonjs/collections/Grid";
|
||||
import {StatusContext} from "../../contexts/contexts";
|
||||
|
|
@ -21,10 +21,51 @@ function DriveInfo({used, size, percent, mount}) {
|
|||
/>
|
||||
}
|
||||
|
||||
function DiskBandwidthProgress({bytes_ps, total, label}) {
|
||||
let percent = bytes_ps / total;
|
||||
percent = percent || 0;
|
||||
let color = null;
|
||||
if (percent >= 90) {
|
||||
color = 'red';
|
||||
} else if (percent >= 80) {
|
||||
color = 'orange';
|
||||
} else if (percent >= 50) {
|
||||
color = 'yellow';
|
||||
}
|
||||
label = `${label} ${humanBandwidth(bytes_ps)}`;
|
||||
return <Progress percent={percent} label={label} color={color} key={label}/>;
|
||||
}
|
||||
|
||||
function DiskBandwidth({name, bytes_read_ps, bytes_write_ps}) {
|
||||
const total = 10_000_000; // Arbitrary size. What is the real speed of the disk?
|
||||
|
||||
const read = <DiskBandwidthProgress
|
||||
bytes_ps={bytes_read_ps}
|
||||
total={total}
|
||||
label={`${name} read`}
|
||||
/>;
|
||||
const write = <DiskBandwidthProgress
|
||||
bytes_ps={bytes_write_ps}
|
||||
total={total}
|
||||
label={`${name} write`}
|
||||
/>;
|
||||
|
||||
return <Grid columns={2}>
|
||||
<Grid.Row>
|
||||
<Grid.Column>{read}</Grid.Column>
|
||||
<Grid.Column>{write}</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
}
|
||||
|
||||
function CPUTemperatureStatistic({value, high_temperature, critical_temperature}) {
|
||||
if (!value) {
|
||||
return <Statistic label='Temp C°' value='?'/>
|
||||
}
|
||||
if (critical_temperature && critical_temperature === high_temperature) {
|
||||
// Critical and high are equal, manually change it so high changes color before critical.
|
||||
high_temperature = critical_temperature - 25;
|
||||
}
|
||||
const props = {};
|
||||
if ((critical_temperature && value >= critical_temperature) || (!critical_temperature && value >= 75)) {
|
||||
props['color'] = 'red';
|
||||
|
|
@ -66,7 +107,7 @@ export function BandwidthProgressGroup({bandwidth, ...props}) {
|
|||
{...props}
|
||||
/>;
|
||||
|
||||
return <Grid columns={2} stackable>
|
||||
return <Grid columns={2}>
|
||||
<Grid.Row>
|
||||
<Grid.Column>
|
||||
{recv}
|
||||
|
|
@ -96,8 +137,6 @@ export function CPUUsageProgress({value, label}) {
|
|||
color = 'brown';
|
||||
} else if (value >= 50) {
|
||||
color = 'orange';
|
||||
} else if (value >= 30) {
|
||||
color = 'green';
|
||||
}
|
||||
return <Progress percent={value} progress color={color} label={label}/>
|
||||
}
|
||||
|
|
@ -115,6 +154,7 @@ export function Status() {
|
|||
let minute_15;
|
||||
let bandwidth;
|
||||
let drives = [];
|
||||
let disk_bandwidth = [];
|
||||
|
||||
if (status && status['cpu_info']) {
|
||||
const {cpu_info, load} = status;
|
||||
|
|
@ -130,36 +170,61 @@ export function Status() {
|
|||
|
||||
drives = status['drives'];
|
||||
bandwidth = status['bandwidth'];
|
||||
disk_bandwidth = status['disk_bandwidth'];
|
||||
}
|
||||
|
||||
return <>
|
||||
<CPUUsageProgress value={percent} label='CPU Usage'/>
|
||||
|
||||
<CPUTemperatureStatistic
|
||||
value={temperature}
|
||||
high_temperature={high_temperature}
|
||||
critical_temperature={critical_temperature}
|
||||
/>
|
||||
<Statistic label='Cores' value={cores || '?'}/>
|
||||
<Responsive minWidth={770}>
|
||||
<StatisticGroup>
|
||||
<CPUTemperatureStatistic
|
||||
value={temperature}
|
||||
high_temperature={high_temperature}
|
||||
critical_temperature={critical_temperature}
|
||||
/>
|
||||
<LoadStatistic label='1 Minute Load' value={minute_1} cores={cores}/>
|
||||
<LoadStatistic label='5 Minute Load' value={minute_5} cores={cores}/>
|
||||
<LoadStatistic label='15 Minute Load' value={minute_15} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
|
||||
<Divider/>
|
||||
<Divider/>
|
||||
|
||||
<StatisticGroup>
|
||||
<LoadStatistic label='1 Minute Load' value={minute_1} cores={cores}/>
|
||||
<LoadStatistic label='5 Minute Load' value={minute_5} cores={cores}/>
|
||||
<LoadStatistic label='15 Minute Load' value={minute_15} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
<Header as='h1'>Network Bandwidth</Header>
|
||||
{bandwidth ?
|
||||
bandwidth.map(i => <BandwidthProgressGroup key={i['name']} bandwidth={i}/>) :
|
||||
<ProgressPlaceholder/>}
|
||||
|
||||
<Divider/>
|
||||
<Divider/>
|
||||
|
||||
<Header as='h1'>Bandwidth</Header>
|
||||
{bandwidth ?
|
||||
bandwidth.map(i => <BandwidthProgressGroup key={i['name']} bandwidth={i}/>) :
|
||||
<ProgressPlaceholder/>}
|
||||
<Header as='h1'>Drive Usage</Header>
|
||||
{drives.map((drive) => <DriveInfo key={drive['mount']} {...drive}/>)}
|
||||
|
||||
<Divider/>
|
||||
<Header as='h1'>Drive Bandwidth</Header>
|
||||
{disk_bandwidth.map((disk) => <DiskBandwidth key={disk['name']} {...disk}/>)}
|
||||
</Responsive>
|
||||
<Responsive maxWidth={769}>
|
||||
<StatisticGroup size='mini'>
|
||||
<CPUTemperatureStatistic
|
||||
value={temperature}
|
||||
high_temperature={high_temperature}
|
||||
critical_temperature={critical_temperature}
|
||||
/>
|
||||
<LoadStatistic label='1 Min. Load' value={minute_1} cores={cores}/>
|
||||
<LoadStatistic label='5 Min. Load' value={minute_5} cores={cores}/>
|
||||
<LoadStatistic label='15 Min. Load' value={minute_15} cores={cores}/>
|
||||
</StatisticGroup>
|
||||
|
||||
<Header as='h1'>Drive Usage</Header>
|
||||
{drives.map((drive) => <DriveInfo key={drive['mount']} {...drive}/>)}
|
||||
<Header as='h2'>Network Bandwidth</Header>
|
||||
{bandwidth ?
|
||||
bandwidth.map(i => <BandwidthProgressGroup key={i['name']} bandwidth={i}/>) :
|
||||
<ProgressPlaceholder/>}
|
||||
|
||||
<Header as='h2'>Drive Usage</Header>
|
||||
{drives.map((drive) => <DriveInfo key={drive['mount']} {...drive}/>)}
|
||||
|
||||
<Header as='h2'>Drive Bandwidth</Header>
|
||||
{disk_bandwidth.map((disk) => <DiskBandwidth key={disk['name']} {...disk}/>)}
|
||||
</Responsive>
|
||||
</>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import {
|
|||
getDownloaders,
|
||||
getDownloads,
|
||||
getFiles,
|
||||
getHotspotStatus,
|
||||
getInventory,
|
||||
getSettings,
|
||||
getStatistics,
|
||||
|
|
@ -462,6 +461,8 @@ export const useBrowseFiles = () => {
|
|||
export const useHotspot = () => {
|
||||
const [on, setOn] = useState(null);
|
||||
const {status} = useContext(StatusContext);
|
||||
// Hotspot is unsupported on Docker.
|
||||
const {dockerized} = status;
|
||||
|
||||
useEffect(() => {
|
||||
if (status && status['hotspot_status']) {
|
||||
|
|
@ -481,7 +482,7 @@ export const useHotspot = () => {
|
|||
await setHotspot(on);
|
||||
}
|
||||
|
||||
return {on, setOn, setHotspot: localSetHotspot};
|
||||
return {on, setOn, setHotspot: localSetHotspot, dockerized};
|
||||
}
|
||||
|
||||
export const useDownloads = () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue