Merge branch 'benphelps:main' into add-whatsupdocker-widget
This commit is contained in:
commit
d2ea719cc8
@ -18,13 +18,13 @@
|
|||||||
"load": "Carga",
|
"load": "Carga",
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"mem": "MEM",
|
"mem": "MEM",
|
||||||
"temp": "TEMP",
|
"temp": "TEMPORAL",
|
||||||
"max": "Max",
|
"max": "Máximo",
|
||||||
"uptime": "UP",
|
"uptime": "ARRIBA",
|
||||||
"months": "mo",
|
"months": "Meses",
|
||||||
"days": "d",
|
"days": "Días",
|
||||||
"hours": "h",
|
"hours": "Horas",
|
||||||
"minutes": "m"
|
"minutes": "Minutos"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "Recibido",
|
"rx": "Recibido",
|
||||||
@ -234,10 +234,10 @@
|
|||||||
"cpu": "Procesador",
|
"cpu": "Procesador",
|
||||||
"mem": "Memoria",
|
"mem": "Memoria",
|
||||||
"wait": "Espere por favor",
|
"wait": "Espere por favor",
|
||||||
"temp": "TEMP",
|
"temp": "TEMPORAL",
|
||||||
"uptime": "UP",
|
"uptime": "ARRIBA",
|
||||||
"days": "d",
|
"days": "Días",
|
||||||
"hours": "h"
|
"hours": "Horas"
|
||||||
},
|
},
|
||||||
"changedetectionio": {
|
"changedetectionio": {
|
||||||
"totalObserved": "Total Observados",
|
"totalObserved": "Total Observados",
|
||||||
|
|||||||
@ -42,13 +42,13 @@
|
|||||||
"free": "남음",
|
"free": "남음",
|
||||||
"used": "사용",
|
"used": "사용",
|
||||||
"load": "부하",
|
"load": "부하",
|
||||||
"temp": "TEMP",
|
"temp": "온도",
|
||||||
"max": "Max",
|
"max": "최대",
|
||||||
"uptime": "UP",
|
"uptime": "가동",
|
||||||
"months": "mo",
|
"months": "달",
|
||||||
"days": "d",
|
"days": "일",
|
||||||
"hours": "h",
|
"hours": "시간",
|
||||||
"minutes": "m"
|
"minutes": "분"
|
||||||
},
|
},
|
||||||
"unifi": {
|
"unifi": {
|
||||||
"users": "사용자",
|
"users": "사용자",
|
||||||
|
|||||||
@ -131,11 +131,11 @@
|
|||||||
"mem": "Пам'ять",
|
"mem": "Пам'ять",
|
||||||
"temp": "TEMP",
|
"temp": "TEMP",
|
||||||
"max": "Max",
|
"max": "Max",
|
||||||
"uptime": "UP",
|
"uptime": "Відправка",
|
||||||
"months": "mo",
|
"months": "міс",
|
||||||
"days": "d",
|
"days": "д",
|
||||||
"hours": "h",
|
"hours": "г",
|
||||||
"minutes": "m"
|
"minutes": "хв"
|
||||||
},
|
},
|
||||||
"unifi": {
|
"unifi": {
|
||||||
"users": "Користувачі",
|
"users": "Користувачі",
|
||||||
@ -359,9 +359,9 @@
|
|||||||
"mem": "Пам'ять",
|
"mem": "Пам'ять",
|
||||||
"wait": "Будь ласка, зачекайте",
|
"wait": "Будь ласка, зачекайте",
|
||||||
"temp": "TEMP",
|
"temp": "TEMP",
|
||||||
"uptime": "UP",
|
"uptime": "Відправка",
|
||||||
"days": "d",
|
"days": "д",
|
||||||
"hours": "h"
|
"hours": "г"
|
||||||
},
|
},
|
||||||
"quicklaunch": {
|
"quicklaunch": {
|
||||||
"bookmark": "Закладка",
|
"bookmark": "Закладка",
|
||||||
|
|||||||
@ -18,13 +18,13 @@
|
|||||||
"load": "负载",
|
"load": "负载",
|
||||||
"cpu": "处理器",
|
"cpu": "处理器",
|
||||||
"mem": "内存",
|
"mem": "内存",
|
||||||
"temp": "TEMP",
|
"temp": "温度",
|
||||||
"max": "Max",
|
"max": "最大",
|
||||||
"uptime": "UP",
|
"uptime": "运行时间",
|
||||||
"months": "mo",
|
"months": "月",
|
||||||
"days": "d",
|
"days": "天",
|
||||||
"hours": "h",
|
"hours": "时",
|
||||||
"minutes": "m"
|
"minutes": "分"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "接收",
|
"rx": "接收",
|
||||||
@ -236,8 +236,8 @@
|
|||||||
"wait": "请稍等",
|
"wait": "请稍等",
|
||||||
"temp": "TEMP",
|
"temp": "TEMP",
|
||||||
"uptime": "UP",
|
"uptime": "UP",
|
||||||
"days": "d",
|
"days": "天",
|
||||||
"hours": "h"
|
"hours": "时"
|
||||||
},
|
},
|
||||||
"changedetectionio": {
|
"changedetectionio": {
|
||||||
"totalObserved": "观察到的总数",
|
"totalObserved": "观察到的总数",
|
||||||
|
|||||||
@ -6,6 +6,12 @@ import { useTranslation } from "next-i18next";
|
|||||||
|
|
||||||
import UsageBar from "../resources/usage-bar";
|
import UsageBar from "../resources/usage-bar";
|
||||||
|
|
||||||
|
const cpuSensorLabels = ["cpu_thermal", "Core"];
|
||||||
|
|
||||||
|
function convertToFahrenheit(t) {
|
||||||
|
return t * 9/5 + 32
|
||||||
|
}
|
||||||
|
|
||||||
export default function Widget({ options }) {
|
export default function Widget({ options }) {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
@ -65,10 +71,22 @@ export default function Widget({ options }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const unit = options.units === "imperial" ? "fahrenheit" : "celsius";
|
const unit = options.units === "imperial" ? "fahrenheit" : "celsius";
|
||||||
let mainTemp;
|
let mainTemp = 0;
|
||||||
if (options.cputemp && data.sensors) {
|
let maxTemp = 80;
|
||||||
mainTemp = unit === "celsius" ? data.sensors.find(s => s.label.includes("cpu_thermal")).value : data.sensors.find(s => s.label.includes("cpu_thermal")).value * 5/9 + 32;
|
const cpuSensors = data.sensors?.filter(s => cpuSensorLabels.some(label => s.label.startsWith(label)) && s.type === "temperature_core");
|
||||||
|
if (options.cputemp && cpuSensors) {
|
||||||
|
try {
|
||||||
|
mainTemp = cpuSensors.reduce((acc, s) => acc + s.value, 0) / cpuSensors.length;
|
||||||
|
maxTemp = Math.max(cpuSensors.reduce((acc, s) => acc + s.warning, 0) / cpuSensors.length, maxTemp);
|
||||||
|
if (unit === "fahrenheit") {
|
||||||
|
mainTemp = convertToFahrenheit(mainTemp);
|
||||||
|
maxTemp = convertToFahrenheit(maxTemp);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// cpu sensor retrieval failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tempPercent = Math.round((mainTemp / maxTemp) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4">
|
<div className="flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap ml-4">
|
||||||
@ -107,7 +125,7 @@ export default function Widget({ options }) {
|
|||||||
<UsageBar percent={data.quicklook.mem} />
|
<UsageBar percent={data.quicklook.mem} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{options.cputemp && mainTemp &&
|
{options.cputemp && mainTemp > 0 &&
|
||||||
(<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
(<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||||
<FaThermometerHalf className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
<FaThermometerHalf className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||||
@ -122,6 +140,7 @@ export default function Widget({ options }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pr-1">{t("glances.temp")}</div>
|
<div className="pr-1">{t("glances.temp")}</div>
|
||||||
</span>
|
</span>
|
||||||
|
<UsageBar percent={tempPercent} />
|
||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
{options.uptime && data.uptime &&
|
{options.uptime && data.uptime &&
|
||||||
@ -134,6 +153,7 @@ export default function Widget({ options }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pr-1">{t("glances.uptime")}</div>
|
<div className="pr-1">{t("glances.uptime")}</div>
|
||||||
</span>
|
</span>
|
||||||
|
<UsageBar percent={Math.round((new Date().getSeconds() / 60) * 100)} />
|
||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,6 +3,12 @@ import { FaThermometerHalf } from "react-icons/fa";
|
|||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
|
import UsageBar from "./usage-bar";
|
||||||
|
|
||||||
|
function convertToFahrenheit(t) {
|
||||||
|
return t * 9/5 + 32
|
||||||
|
}
|
||||||
|
|
||||||
export default function CpuTemp({ expanded, units }) {
|
export default function CpuTemp({ expanded, units }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -21,7 +27,7 @@ export default function CpuTemp({ expanded, units }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data || !data.cputemp) {
|
||||||
return (
|
return (
|
||||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5 animate-pulse">
|
<div className="flex-none flex flex-row items-center mr-3 py-1.5 animate-pulse">
|
||||||
<FaThermometerHalf className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
<FaThermometerHalf className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||||
@ -41,9 +47,16 @@ export default function CpuTemp({ expanded, units }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let minTemp = 0;
|
||||||
|
let mainTemp = data.cputemp.main;
|
||||||
|
if (data.cputemp.cores?.length) {
|
||||||
|
mainTemp = data.cputemp.cores.reduce((a, b) => a + b) / data.cputemp.cores.length;
|
||||||
|
minTemp = Math.min(...data.cputemp.cores);
|
||||||
|
}
|
||||||
const unit = units === "imperial" ? "fahrenheit" : "celsius";
|
const unit = units === "imperial" ? "fahrenheit" : "celsius";
|
||||||
const mainTemp = (unit === "celsius") ? data.cputemp.main : data.cputemp.main * 5/9 + 32;
|
mainTemp = (unit === "celsius") ? mainTemp : convertToFahrenheit(mainTemp);
|
||||||
const maxTemp = (unit === "celsius") ? data.cputemp.max : data.cputemp.max * 5/9 + 32;
|
const maxTemp = (unit === "celsius") ? data.cputemp.max : convertToFahrenheit(data.cputemp.max);
|
||||||
|
const percent = Math.round(((mainTemp - minTemp) / (maxTemp - minTemp)) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||||
@ -73,6 +86,7 @@ export default function CpuTemp({ expanded, units }) {
|
|||||||
<div className="pr-1">{t("resources.max")}</div>
|
<div className="pr-1">{t("resources.max")}</div>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
<UsageBar percent={percent} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -44,7 +44,8 @@ export default function Disk({ options, expanded }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const percent = Math.round((data.drive.used / data.drive.size) * 100);
|
// data.drive.used not accurate?
|
||||||
|
const percent = Math.round(((data.drive.size - data.drive.available) / data.drive.size) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||||
|
|||||||
@ -44,7 +44,7 @@ export default function Memory({ expanded }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const percent = Math.round((data.memory.used / data.memory.total) * 100);
|
const percent = Math.round((data.memory.active / data.memory.total) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||||
@ -52,7 +52,7 @@ export default function Memory({ expanded }) {
|
|||||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||||
<div className="pl-0.5 pr-1">
|
<div className="pl-0.5 pr-1">
|
||||||
{t("common.bytes", { value: data.memory.free, maximumFractionDigits: 1, binary: true })}
|
{t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })}
|
||||||
</div>
|
</div>
|
||||||
<div className="pr-1">{t("resources.free")}</div>
|
<div className="pr-1">{t("resources.free")}</div>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { FaRegClock } from "react-icons/fa";
|
|||||||
import { BiError } from "react-icons/bi";
|
import { BiError } from "react-icons/bi";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
|
import UsageBar from "./usage-bar";
|
||||||
|
|
||||||
export default function Uptime() {
|
export default function Uptime() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -45,6 +47,8 @@ export default function Uptime() {
|
|||||||
else if (d > 0) uptime = `${d}${t("resources.days")} ${h}${t("resources.hours")}`;
|
else if (d > 0) uptime = `${d}${t("resources.days")} ${h}${t("resources.hours")}`;
|
||||||
else uptime = `${h}${t("resources.hours")} ${m}${t("resources.minutes")}`;
|
else uptime = `${h}${t("resources.hours")} ${m}${t("resources.minutes")}`;
|
||||||
|
|
||||||
|
const percent = Math.round((new Date().getSeconds() / 60) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||||
<FaRegClock className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
<FaRegClock className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||||
@ -55,6 +59,7 @@ export default function Uptime() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pr-1">{t("resources.uptime")}</div>
|
<div className="pr-1">{t("resources.uptime")}</div>
|
||||||
</span>
|
</span>
|
||||||
|
<UsageBar percent={percent} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerNames = containers.map((container) => container.Names[0].replace(/^\//, ""));
|
const containerNames = containers.map((container) => container.Names[0]?.replace(/^\//, ""));
|
||||||
const containerExists = containerNames.includes(containerName);
|
const containerExists = containerNames.includes(containerName);
|
||||||
|
|
||||||
if (containerExists) {
|
if (containerExists) {
|
||||||
@ -75,7 +75,7 @@ export default async function handler(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(404).send({
|
||||||
error: "not found",
|
error: "not found",
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerNames = containers.map((container) => container.Names[0].replace(/^\//, ""));
|
const containerNames = containers.map((container) => container.Names[0]?.replace(/^\//, ""));
|
||||||
const containerExists = containerNames.includes(containerName);
|
const containerExists = containerNames.includes(containerName);
|
||||||
|
|
||||||
if (containerExists) {
|
if (containerExists) {
|
||||||
|
|||||||
@ -249,7 +249,8 @@ export function cleanServiceGroups(groups) {
|
|||||||
podSelector,
|
podSelector,
|
||||||
wan, // opnsense widget,
|
wan, // opnsense widget,
|
||||||
enableBlocks, // emby/jellyfin
|
enableBlocks, // emby/jellyfin
|
||||||
enableNowPlaying
|
enableNowPlaying,
|
||||||
|
volume // diskstation widget
|
||||||
} = cleanedService.widget;
|
} = cleanedService.widget;
|
||||||
|
|
||||||
const fieldsList = typeof fields === 'string' ? JSON.parse(fields) : fields;
|
const fieldsList = typeof fields === 'string' ? JSON.parse(fields) : fields;
|
||||||
@ -281,8 +282,11 @@ export function cleanServiceGroups(groups) {
|
|||||||
if (wan) cleanedService.widget.wan = wan;
|
if (wan) cleanedService.widget.wan = wan;
|
||||||
}
|
}
|
||||||
if (type === "emby" || type === "jellyfin") {
|
if (type === "emby" || type === "jellyfin") {
|
||||||
if (enableBlocks) cleanedService.widget.enableBlocks = enableBlocks === 'true';
|
if (enableBlocks) cleanedService.widget.enableBlocks = enableBlocks;
|
||||||
if (enableNowPlaying) cleanedService.widget.enableNowPlaying = enableNowPlaying === 'true';
|
if (enableNowPlaying) cleanedService.widget.enableNowPlaying = enableNowPlaying;
|
||||||
|
}
|
||||||
|
if (type === "diskstation") {
|
||||||
|
if (volume) cleanedService.widget.volume = volume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,8 +33,7 @@ export default function Component({ service }) {
|
|||||||
const uptime = `${ t("common.number", { value: days }) } ${ t("diskstation.days") }`;
|
const uptime = `${ t("common.number", { value: days }) } ${ t("diskstation.days") }`;
|
||||||
|
|
||||||
// storage info
|
// storage info
|
||||||
// TODO: figure out how to display info for more than one volume
|
const volume = widget.volume ? storageData.data.vol_info?.find(vol => vol.name === widget.volume) : storageData.data.vol_info?.[0];
|
||||||
const volume = storageData.data.vol_info?.[0];
|
|
||||||
const usedBytes = parseFloat(volume?.used_size);
|
const usedBytes = parseFloat(volume?.used_size);
|
||||||
const totalBytes = parseFloat(volume?.total_size);
|
const totalBytes = parseFloat(volume?.total_size);
|
||||||
const freeBytes = totalBytes - usedBytes;
|
const freeBytes = totalBytes - usedBytes;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user