Browse Source

Merge branch 'master' into fix/icon

GodD6366 2 years ago
parent
commit
78a75a1ff9

+ 1 - 1
README.md

@@ -38,7 +38,7 @@
 - Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6
   - Supports all Raspberry Pi's, most SBCs & Apple Silicon
 - Full i18n support with automatic language detection
-  - Translantions for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romainian, Russian, Spanish, Swedish and Yue
+  - Translations for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romainian, Russian, Spanish, Swedish and Yue
   - Want to help translate? [Join the Weblate project](https://hosted.weblate.org/engage/homepage/)
 - Service & Web Bookmarks
 - Docker Integration

+ 18 - 18
public/locales/de/common.json

@@ -11,7 +11,7 @@
         "total": "Gesamt",
         "free": "Frei",
         "used": "Gebraucht",
-        "load": "Belastung",
+        "load": "Last",
         "cpu": "CPU"
     },
     "docker": {
@@ -25,13 +25,13 @@
         "playing": "Spielen",
         "transcoding": "Transcodierung",
         "bitrate": "Bitrate",
-        "no_active": "Keine aktive Streams"
+        "no_active": "Keine aktiven Streams"
     },
     "tautulli": {
         "playing": "Spielen",
         "transcoding": "Transcodierung",
         "bitrate": "Bitrate",
-        "no_active": "Keine aktiven streamen"
+        "no_active": "Keine aktiven Streams"
     },
     "rutorrent": {
         "active": "Aktiv",
@@ -41,7 +41,7 @@
     "sonarr": {
         "wanted": "Gesucht",
         "queued": "In Warteschlange",
-        "series": "Serie"
+        "series": "Serien"
     },
     "radarr": {
         "wanted": "Gesucht",
@@ -176,30 +176,30 @@
         "failedLoginsLast24H": "fehlerhafte Anmeldungen (24h)"
     },
     "proxmox": {
-        "mem": "MEM",
+        "mem": "RAM",
         "cpu": "CPU",
         "lxc": "LXC",
         "vms": "VMs"
     },
     "unifi": {
-        "users": "Users",
-        "uptime": "System Uptime",
-        "days": "Days",
+        "users": "Benutzer",
+        "uptime": "System-Betriebszeit",
+        "days": "Tage",
         "wan": "WAN",
-        "lan_users": "LAN Users",
-        "wlan_users": "WLAN Users",
-        "up": "UP",
-        "down": "DOWN",
-        "wait": "Please wait"
+        "lan_users": "LAN Benutzer",
+        "wlan_users": "WLAN Benutzer",
+        "up": "SENDEN",
+        "down": "EMPFANGEN",
+        "wait": "Bitte warten"
     },
     "plex": {
-        "streams": "Active Streams",
-        "movies": "Movies",
-        "tv": "TV Shows"
+        "streams": "Aktive Streams",
+        "movies": "Filme",
+        "tv": "TV Sendungen"
     },
     "glances": {
         "cpu": "CPU",
-        "mem": "MEM",
-        "wait": "Please wait"
+        "mem": "RAM",
+        "wait": "Bitte warten"
     }
 }

+ 17 - 17
public/locales/es/common.json

@@ -178,28 +178,28 @@
     "proxmox": {
         "mem": "Memoria",
         "cpu": "Procesador",
-        "lxc": "LXC",
-        "vms": "VMs"
+        "lxc": "Contenedores Linux",
+        "vms": "Máquinas Virtuales"
     },
     "unifi": {
-        "up": "UP",
-        "users": "Users",
-        "uptime": "System Uptime",
-        "days": "Days",
-        "wan": "WAN",
-        "lan_users": "LAN Users",
-        "wlan_users": "WLAN Users",
-        "down": "DOWN",
-        "wait": "Please wait"
+        "up": "LEVANTADO",
+        "users": "Usuarios",
+        "uptime": "Tiempo de actividad",
+        "days": "Días",
+        "wan": "Red WAN",
+        "lan_users": "Usuarios LAN",
+        "wlan_users": "Usuarios WLAN",
+        "down": "CAÍDO",
+        "wait": "Espere por favor"
     },
     "plex": {
-        "streams": "Active Streams",
-        "movies": "Movies",
-        "tv": "TV Shows"
+        "streams": "Transmisiones Activas",
+        "movies": "Peliculas",
+        "tv": "Programas TV"
     },
     "glances": {
-        "cpu": "CPU",
-        "mem": "MEM",
-        "wait": "Please wait"
+        "cpu": "Procesador",
+        "mem": "Memoria",
+        "wait": "Espere por favor"
     }
 }

+ 3 - 3
public/locales/fr/common.json

@@ -198,8 +198,8 @@
         "tv": "Séries TV"
     },
     "glances": {
-        "cpu": "CPU",
-        "mem": "MEM",
-        "wait": "Please wait"
+        "cpu": "Cpu",
+        "mem": "Mém",
+        "wait": "Merci de patienter"
     }
 }

+ 15 - 15
public/locales/zh-CN/common.json

@@ -161,7 +161,7 @@
     },
     "mastodon": {
         "user_count": "用户",
-        "status_count": "Posts",
+        "status_count": "帖子",
         "domain_count": "域"
     },
     "strelaysrv": {
@@ -182,24 +182,24 @@
         "vms": "VMs"
     },
     "unifi": {
-        "users": "Users",
-        "uptime": "System Uptime",
-        "days": "Days",
-        "wan": "WAN",
-        "lan_users": "LAN Users",
-        "wlan_users": "WLAN Users",
-        "up": "UP",
-        "down": "DOWN",
+        "users": "用户",
+        "uptime": "系统运行时间",
+        "days": "",
+        "wan": "广域网",
+        "lan_users": "局域网用户",
+        "wlan_users": "无线局域网用户",
+        "up": "向上",
+        "down": "向下",
         "wait": "请稍候"
     },
     "plex": {
-        "streams": "Active Streams",
-        "movies": "Movies",
-        "tv": "TV Shows"
+        "streams": "活动流",
+        "movies": "电影",
+        "tv": "电视节目"
     },
     "glances": {
-        "cpu": "CPU",
-        "mem": "MEM",
-        "wait": "Please wait"
+        "cpu": "处理器",
+        "mem": "内存",
+        "wait": "请稍等"
     }
 }

+ 17 - 1
src/components/version.jsx

@@ -31,7 +31,23 @@ export default function Version() {
   return (
     <div className="flex flex-row items-center">
       <span className="text-xs text-theme-500 dark:text-theme-400">
-        {version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
+        {version === "main" || version === "dev" || version === "nightly" ? (
+          <>
+            {version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
+          </>
+        ) : (
+          releaseData &&
+          compareVersions(latestRelease.tag_name, version) > 0 && (
+            <a
+              href={`https://github.com/benphelps/homepage/releases/tag/${version}`}
+              target="_blank"
+              rel="noopener noreferrer"
+              className="ml-2 text-xs text-theme-500 dark:text-theme-400 flex flex-row items-center"
+            >
+              {version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
+            </a>
+          )
+        )}
       </span>
       {version === "main" || version === "dev" || version === "nightly"
         ? null

+ 1 - 1
src/components/widgets/unifi_console/unifi_console.jsx

@@ -10,7 +10,7 @@ export default function Widget({ options }) {
 
   // eslint-disable-next-line no-param-reassign
   options.type = "unifi_console";
-  const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites");
+  const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
 
   if (statsError || statsData?.error) {
     return (

+ 7 - 19
src/pages/api/widgets/glances.js

@@ -1,29 +1,17 @@
 import { httpProxy } from "utils/proxy/http";
 import createLogger from "utils/logger";
-import { getSettings } from "utils/config/config";
+import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
 
 const logger = createLogger("glances");
 
 export default async function handler(req, res) {
-  const { id } = req.query;
+  const { index } = req.query;
 
-  let errorMessage;
-
-  let instanceID = "glances";
-  if (id) { // multiple instances
-    instanceID = id;
-  }
-  const settings = getSettings();
-  const instanceSettings = settings[instanceID];
-  if (!instanceSettings) {
-    errorMessage = id ? `There is no glances section with id '${id}' in settings.yaml` : "There is no glances section in settings.yaml";
-    logger.error(errorMessage);
-    return res.status(400).json({ error: errorMessage });
-  }
+  const privateWidgetOptions = await getPrivateWidgetOptions("glances", index);
   
-  const url = instanceSettings?.url;
+  const url = privateWidgetOptions?.url;
   if (!url) {
-    errorMessage = "Missing Glances URL";
+    const errorMessage = "Missing Glances URL";
     logger.error(errorMessage);
     return res.status(400).json({ error: errorMessage });
   }
@@ -32,8 +20,8 @@ export default async function handler(req, res) {
   const headers = {
     "Accept-Encoding": "application/json"
   };
-  if (instanceSettings.username && instanceSettings.password) {
-    headers.Authorization = `Basic ${Buffer.from(`${instanceSettings.username}:${instanceSettings.password}`).toString("base64")}`
+  if (privateWidgetOptions.username && privateWidgetOptions.password) {
+    headers.Authorization = `Basic ${Buffer.from(`${privateWidgetOptions.username}:${privateWidgetOptions.password}`).toString("base64")}`
   }
   const params = { method: "GET", headers };
 

+ 10 - 13
src/utils/config/api-response.js

@@ -6,6 +6,7 @@ import yaml from "js-yaml";
 
 import checkAndCopyConfig from "utils/config/config";
 import { servicesFromConfig, servicesFromDocker, cleanServiceGroups } from "utils/config/service-helpers";
+import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";
 
 export async function bookmarksResponse() {
   checkAndCopyConfig("bookmarks.yaml");
@@ -29,21 +30,17 @@ export async function bookmarksResponse() {
 }
 
 export async function widgetsResponse() {
-  checkAndCopyConfig("widgets.yaml");
+  let configuredWidgets;
 
-  const widgetsYaml = path.join(process.cwd(), "config", "widgets.yaml");
-  const fileContents = await fs.readFile(widgetsYaml, "utf8");
-  const widgets = yaml.load(fileContents);
-
-  if (!widgets) return [];
-
-  // map easy to write YAML objects into easy to consume JS arrays
-  const widgetsArray = widgets.map((group) => ({
-    type: Object.keys(group)[0],
-    options: { ...group[Object.keys(group)[0]] },
-  }));
+  try {
+    configuredWidgets = cleanWidgetGroups(await widgetsFromConfig());
+  } catch (e) {
+    console.error("Failed to load widgets, please check widgets.yaml for errors or remove example entries.");
+    if (e) console.error(e);
+    configuredWidgets = [];
+  }
 
-  return widgetsArray;
+  return configuredWidgets;
 }
 
 export async function servicesResponse() {

+ 1 - 1
src/utils/config/config.js

@@ -33,4 +33,4 @@ export function getSettings() {
   const settingsYaml = join(process.cwd(), "config", "settings.yaml");
   const fileContents = readFileSync(settingsYaml, "utf8");
   return yaml.load(fileContents);
-}
+}

+ 1 - 1
src/utils/config/service-helpers.js

@@ -165,4 +165,4 @@ export default async function getServiceWidget(group, service) {
   }
 
   return false;
-}
+}

+ 73 - 0
src/utils/config/widget-helpers.js

@@ -0,0 +1,73 @@
+import { promises as fs } from "fs";
+import path from "path";
+
+import yaml from "js-yaml";
+
+import checkAndCopyConfig from "utils/config/config";
+
+export async function widgetsFromConfig() {
+    checkAndCopyConfig("widgets.yaml");
+
+    const widgetsYaml = path.join(process.cwd(), "config", "widgets.yaml");
+    const fileContents = await fs.readFile(widgetsYaml, "utf8");
+    const widgets = yaml.load(fileContents);
+
+    if (!widgets) return [];
+
+    // map easy to write YAML objects into easy to consume JS arrays
+    const widgetsArray = widgets.map((group, index) => ({
+        type: Object.keys(group)[0],
+        options: {
+            index,
+            ...group[Object.keys(group)[0]]
+        },
+    }));
+    return widgetsArray;
+}
+
+export async function cleanWidgetGroups(widgets) {
+    return widgets.map((widget, index) => {
+        const sanitizedOptions = widget.options;
+        const optionKeys = Object.keys(sanitizedOptions);
+        ["url", "username", "password", "key"].forEach((pO) => { 
+            if (optionKeys.includes(pO)) {
+                delete sanitizedOptions[pO];
+            }
+        });
+
+        return {
+            type: widget.type,
+            options: {
+                index,
+                ...sanitizedOptions
+            },
+        }
+    });
+}
+
+export async function getPrivateWidgetOptions(type, widgetIndex) {
+    const widgets = await widgetsFromConfig();
+  
+    const privateOptions = widgets.map((widget) => {
+        const {
+            index,
+            url,
+            username,
+            password,
+            key
+        } = widget.options;
+
+        return {
+            type: widget.type,
+            options: {
+                index,
+                url,
+                username,
+                password,
+                key
+            },
+        }
+    });
+  
+    return (type !== undefined && widgetIndex !== undefined) ? privateOptions.find(o => o.type === type && o.options.index === parseInt(widgetIndex, 10))?.options : privateOptions;
+}

+ 6 - 6
src/widgets/unifi/proxy.js

@@ -3,8 +3,8 @@ import cache from "memory-cache";
 import { formatApiCall } from "utils/proxy/api-helpers";
 import { httpProxy } from "utils/proxy/http";
 import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
-import { getSettings } from "utils/config/config";
 import getServiceWidget from "utils/config/service-helpers";
+import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
 import createLogger from "utils/logger";
 import widgets from "widgets/widgets";
 
@@ -15,13 +15,13 @@ const logger = createLogger(proxyName);
 
 async function getWidget(req) {
   const { group, service, type } = req.query;
-
+  
   let widget = null;
-  if (type === "unifi_console") {
-    const settings = getSettings();
-    widget = settings.unifi_console;
+  if (type === "unifi_console") { // info widget
+    const index = req.query?.query ? JSON.parse(req.query.query).index : undefined;
+    widget = await getPrivateWidgetOptions(type, index);
     if (!widget) {
-      logger.debug("There is no unifi_console section in settings.yaml");
+      logger.debug("Error retrieving settings for this Unifi widget");
       return null;
     }
     widget.type = "unifi";