Skip to content

Commit

Permalink
Added a view for devices on lan
Browse files Browse the repository at this point in the history
This requests and parses the response from the backend endpoint
/lan_devices. This endpoint gathers data for all devices within
the lan.
  • Loading branch information
kennethAltheaSystems authored and jkilpatr committed Nov 29, 2022
1 parent d61538c commit f0ea558
Show file tree
Hide file tree
Showing 13 changed files with 2,423 additions and 2,198 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.8.1",
"react-i18next": "^10.0.0",
"react-icons": "^4.6.0",
"react-phone-number-input": "^3.2.2",
"react-scripts": "^5.0.1",
"react-sigma": "^1.2.30",
Expand Down
2 changes: 0 additions & 2 deletions src/AdvancedSettings/AdvancedDebugging.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ const AdvancedDebugging = () => {

let isTunnelWorking = exit.length > 0 ? exit[0].is_tunnel_working : false;

console.assert(exit.length, 1);

if (selectedExit) {
({ haveRoute, isReachable, isTunnelWorking } = selectedExit);
}
Expand Down
74 changes: 74 additions & 0 deletions src/DevicesOnLan/Device.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Card } from "reactstrap";

const Device = (props) => {
let [t] = useTranslation();

return (
<div>
<Card>
<p>
<b>{t("device")}</b>: {props.newDevice.name}
<br></br>
<b>{t("signalStrength")}</b>:
{format_signal_strength(props.newDevice.signalStrength)}
<br></br>
<b>{t("uploadedBytes")}</b>:
{prettyBytes(props.newDevice.uploadBytesUsed)}
<br></br>
<b>{t("downloadedBytes")}</b>:
{prettyBytes(props.newDevice.downloadBytesUsed)}
<br></br>
<b>{t("ipAddr")}</b>: {format_ips(props.newDevice.ipAddr)}
<br></br>
<b>{t("macAddr")}</b>: {props.newDevice.macAddr}
<br></br>
<b>{t("wired")}</b>: {t(props.newDevice.wired.toString())}
</p>
</Card>
</div>
);
};

function prettyBytes(bytes) {
if (bytes === null) return " N/A";
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
const i = Math.min(
parseInt(Math.floor(Math.log(bytes) / Math.log(1024)).toString(), 10),
sizes.length - 1
);
return ` ${(bytes / 1024 ** i).toFixed(i ? 1 : 0)}${sizes[i]}`;
}

function format_ips(ips) {
let ip4index = 0;
let ip6index = 0;
let ipv4 = [];
let ipv6 = [];

const regexIp6 =
/^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/m;
const regexIp4 =
/^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/m;
for (let i = 0; i < ips.length; i++) {
let ipAddr = ips[i];
if (regexIp4.test(ipAddr)) {
ipv4[ip4index] = ipAddr;
ip4index += 1;
} else if (regexIp6.test(ipAddr)) {
ipv6[ip6index] = ipAddr;
ip6index += 1;
}
}
let all_ips = ipv4.concat(ipv6);
return all_ips.join(", ");
}

function format_signal_strength(signalStrength) {
if (signalStrength !== null) {
return " " + signalStrength.replace(/ *\[[^\]]*]/, "");
} else return " N/A";
}

export default Device;
59 changes: 59 additions & 0 deletions src/DevicesOnLan/Devices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useEffect, useState } from "react";
import { Card, CardBody } from "reactstrap";
import { get } from "store";
import Device from "./Device";
import { useTranslation } from "react-i18next";
import ClipLoader from "react-spinners/ClipLoader";

const Devices = () => {
const [loading, setLoading] = useState(null);
const [devices, setDevices] = useState(null);
let [t] = useTranslation();

useEffect(() => {
const controller = new AbortController();

(async () => {
if (loading == null) {
setLoading(true);
let lanDevices = await get("/lan_devices");
if (!(lanDevices instanceof Error))
setDevices(lanDevices.allLanDevices);
setLoading(false);
}
})();

return () => controller.abort();
});

if (loading) {
return (
<ClipLoader
color="#89CFF0"
loading={loading != null && loading}
size={50}
aria-label="Loading Spinner"
data-testid="loader"
/>
);
} else if (
typeof devices === "undefined" ||
devices === null ||
devices.length === 0
)
return <div>{t("noDevices")}</div>;

return (
<Card>
<CardBody>
<div>
{devices.map((device, index) => (
<Device key={"Device" + index} newDevice={device} index={index} />
))}
</div>
</CardBody>
</Card>
);
};

export default Devices;
20 changes: 20 additions & 0 deletions src/DevicesOnLan/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable import/no-anonymous-default-export */
import { React } from "react";
import { useTranslation } from "react-i18next";
import { InputGroup } from "reactstrap";
import Devices from "./Devices";

const LanDevices = () => {
let [t] = useTranslation();

return (
<div>
<InputGroup>
<h2 id="devicesPage">{t("devicesLan")}</h2>
</InputGroup>
<Devices />
</div>
);
};

export default LanDevices;
1 change: 1 addition & 0 deletions src/Endpoints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const endpoints = [
"/usage/client",
"/usage/relay",
"/usage/payments",
"/lan_devices",
];

const APIDump = () => {
Expand Down
1 change: 1 addition & 0 deletions src/Layout/Nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const AltheaNav = ({ page, setOpen }) => {
"selling-bandwidth": t("sellingBandwidth"),
settings: t("settings"),
advanced: t("advanced"),
devices: t("devices"),
};

let navItems = Object.keys(pages).map((path, i) => {
Expand Down
2 changes: 2 additions & 0 deletions src/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Settings,
AdvancedSettings,
Endpoints,
DevicesOnLan,
} from "./pages";

let routes = {
Expand All @@ -21,6 +22,7 @@ let routes = {
advanced: <AdvancedSettings />,
settings: <Settings />,
endpoints: <Endpoints />,
devices: <DevicesOnLan />,
};

const Router = ({ page, setPage, setOpen }) => {
Expand Down
15 changes: 14 additions & 1 deletion src/locales/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,5 +405,18 @@
"enableSelfLimit": "Enable bandwidth limiter",
"bandwidthLimitSaved": "Changes Saved",
"bandwidthLimitTitle": "Your bandwidth limit",
"setYourBandwidth": "Your Althea network provides the fastest service possible at any given time. To control costs you may wish to limit this. For more details and advice on how to use this option contact your local operator or call at"
"setYourBandwidth": "Your Althea network provides the fastest service possible at any given time. To control costs you may wish to limit this. For more details and advice on how to use this option contact your local operator or call at",
"devices": "Devices",
"devicesLan": "Devices on LAN",
"refresh" : "Refresh",
"noDevices" : "No devices detected",
"device" : "Device",
"signalStrength" : "Signal strength",
"uploadedBytes" : "Uploaded bytes",
"downloadedBytes" : "Downloaded bytes",
"ipAddr": "Ip address",
"macAddr": "Mac address",
"wired": "Wired",
"true" : "true",
"false" : "false"
}
15 changes: 14 additions & 1 deletion src/locales/es/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -381,5 +381,18 @@
"bandwidthPriceName": "Bandwidth price: ",
"organizerFeeContent": " {{maybeDollarSymbol}}{{readableOperatorPrice}} {{symbol_or_star}}/Mes",
"bandwidthPriceContent": " {{maybeDollarSymbol}}{{readableExitPrice}} {{symbol_or_star}}/GB",
"pricesCopy": "Estas son las tarifas que paga actualmente su enrutador; las determinan otros miembros de su red y su organizador de red."
"pricesCopy": "Estas son las tarifas que paga actualmente su enrutador; las determinan otros miembros de su red y su organizador de red.",
"devices": "Dispositivos",
"devicesLan": "Dispositivos en LAN",
"refresh" : "Actualizar",
"noDevices" : "No se detectaron dispositivos",
"device" : "Device",
"signalStrength" : "Intensidad de señal",
"uploadedBytes" : "Bytes subidos",
"downloadedBytes" : "Bytes descargados",
"ipAddr": "Dirección IP",
"macAddr": "Dirección MAC",
"wired": "Cableado",
"true" : "cierto",
"false" : "falso"
}
15 changes: 14 additions & 1 deletion src/locales/fr/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,18 @@
"lightClientDownloadLinkText": "Télécharger depuis le Play Store",
"lightClientAP": "Althea Mobile",
"meshAPBlurb": "Active le réseau WiFi AltheaMesh. Le réseau sera utilisé pour permettre à ce routeur de se connecter directement à d'autres routeurs à proximité à l'aide de la radio interne. Ceci n'est pas recommandé pour une utilisation en dehors de situations très spécifiques.",
"meshAP": "Direct WiFi Meshing"
"meshAP": "Direct WiFi Meshing",
"devices": "Périphériques",
"devicesLan": "Périphériques sur LAN",
"refresh" : "Rafraîchir",
"noDevices" : "Aucun appareil détecté",
"device" : "Device",
"signalStrength" : "Force du signal",
"uploadedBytes" : "Octets téléchargés",
"downloadedBytes" : "Octets téléchargés",
"ipAddr": "Adresse IP",
"macAddr": "Adresse Mac",
"wired": "Filaire",
"true" : "vrai",
"false" : "faux"
}
1 change: 1 addition & 0 deletions src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as Settings } from "Settings";
export { default as RouterSettings } from "RouterSettings";
export { default as Endpoints } from "Endpoints";
export { default as SellingBandwidth } from "SellingBandwidth";
export { default as DevicesOnLan } from "DevicesOnLan";
Loading

0 comments on commit f0ea558

Please sign in to comment.