From c5b6dcc1e08eb6fd1a8c01c776970a9f873545b5 Mon Sep 17 00:00:00 2001 From: Denis Papec Date: Sun, 16 Apr 2023 00:05:50 +0100 Subject: [PATCH 01/50] Add optional boxed styling and error component to information widgets Signed-off-by: Denis Papec --- src/components/widgets/datetime/datetime.jsx | 8 +++-- src/components/widgets/error.jsx | 23 +++++++++++++ src/components/widgets/glances/glances.jsx | 30 +++++++--------- src/components/widgets/greeting/greeting.jsx | 7 +++- .../widgets/kubernetes/kubernetes.jsx | 29 +++++++--------- src/components/widgets/logo/logo.jsx | 7 +++- src/components/widgets/longhorn/longhorn.jsx | 25 +++++++------- .../widgets/openmeteo/openmeteo.jsx | 34 +++++++++---------- .../widgets/openweathermap/weather.jsx | 33 +++++++++--------- .../widgets/resources/resources.jsx | 7 +++- src/components/widgets/search/search.jsx | 11 +++--- .../widgets/unifi_console/unifi_console.jsx | 26 +++++++------- src/components/widgets/weather/weather.jsx | 33 +++++++++--------- src/pages/api/widgets/longhorn.js | 2 +- 14 files changed, 153 insertions(+), 122 deletions(-) create mode 100644 src/components/widgets/error.jsx diff --git a/src/components/widgets/datetime/datetime.jsx b/src/components/widgets/datetime/datetime.jsx index 86983473..fc883ec3 100644 --- a/src/components/widgets/datetime/datetime.jsx +++ b/src/components/widgets/datetime/datetime.jsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import { useTranslation } from "next-i18next"; +import classNames from "classnames"; const textSizes = { "4xl": "text-4xl", @@ -17,7 +18,7 @@ export default function DateTime({ options }) { const { i18n } = useTranslation(); const [date, setDate] = useState(""); const dateLocale = locale ?? i18n.language; - + useEffect(() => { const dateFormat = new Intl.DateTimeFormat(dateLocale, { ...format }); const interval = setInterval(() => { @@ -27,7 +28,10 @@ export default function DateTime({ options }) { }, [date, setDate, dateLocale, format]); return ( -
+
{date} diff --git a/src/components/widgets/error.jsx b/src/components/widgets/error.jsx new file mode 100644 index 00000000..92e0076a --- /dev/null +++ b/src/components/widgets/error.jsx @@ -0,0 +1,23 @@ +import { useTranslation } from "react-i18next"; +import { BiError } from "react-icons/bi"; +import classNames from "classnames"; + +export default function Error({ options }) { + const { t } = useTranslation(); + + return ( +
+
+
+ +
+ {t("widget.api_error")} +
+
+
+
+ ); +} diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx index 85dd44c0..b6daba7b 100644 --- a/src/components/widgets/glances/glances.jsx +++ b/src/components/widgets/glances/glances.jsx @@ -1,11 +1,12 @@ import useSWR from "swr"; import { useContext } from "react"; -import { BiError } from "react-icons/bi"; import { FaMemory, FaRegClock, FaThermometerHalf } from "react-icons/fa"; import { FiCpu, FiHardDrive } from "react-icons/fi"; import { useTranslation } from "next-i18next"; +import classNames from "classnames"; import UsageBar from "../resources/usage-bar"; +import Error from "../error"; import { SettingsContext } from "utils/contexts/settings"; @@ -26,23 +27,15 @@ export default function Widget({ options }) { ); if (error || data?.error) { - return ( -
-
-
- -
- {t("widget.api_error")} -
-
-
-
- ); + return } if (!data) { return ( -
+
@@ -101,7 +94,10 @@ export default function Widget({ options }) { } return ( - +
@@ -184,7 +180,7 @@ export default function Widget({ options }) {
- {t("common.number", { + {t("common.number", { value: mainTemp, maximumFractionDigits: 1, style: "unit", @@ -196,7 +192,7 @@ export default function Widget({ options }) { {options.expanded && (
- {t("common.number", { + {t("common.number", { value: maxTemp, maximumFractionDigits: 1, style: "unit", diff --git a/src/components/widgets/greeting/greeting.jsx b/src/components/widgets/greeting/greeting.jsx index da0f063d..2e129560 100644 --- a/src/components/widgets/greeting/greeting.jsx +++ b/src/components/widgets/greeting/greeting.jsx @@ -1,3 +1,5 @@ +import classNames from "classnames"; + const textSizes = { "4xl": "text-4xl", "3xl": "text-3xl", @@ -12,7 +14,10 @@ const textSizes = { export default function Greeting({ options }) { if (options.text) { return ( -
+
{options.text} diff --git a/src/components/widgets/kubernetes/kubernetes.jsx b/src/components/widgets/kubernetes/kubernetes.jsx index 78c4caaf..514993da 100644 --- a/src/components/widgets/kubernetes/kubernetes.jsx +++ b/src/components/widgets/kubernetes/kubernetes.jsx @@ -1,12 +1,14 @@ import useSWR from "swr"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import classNames from "classnames"; + +import Error from "../error"; import Node from "./node"; export default function Widget({ options }) { const { cluster, nodes } = options; - const { t, i18n } = useTranslation(); + const { i18n } = useTranslation(); const defaultData = { cpu: { @@ -29,23 +31,15 @@ export default function Widget({ options }) { ); if (error || data?.error) { - return ( -
-
-
- -
- {t("widget.api_error")} -
-
-
-
- ); + return } if (!data) { return ( -
+
{cluster.show && @@ -59,7 +53,10 @@ export default function Widget({ options }) { } return ( -
+
{cluster.show && diff --git a/src/components/widgets/logo/logo.jsx b/src/components/widgets/logo/logo.jsx index 96e8569f..6cba17bf 100644 --- a/src/components/widgets/logo/logo.jsx +++ b/src/components/widgets/logo/logo.jsx @@ -1,8 +1,13 @@ +import classNames from "classnames"; + import ResolvedIcon from "components/resolvedicon" export default function Logo({ options }) { return ( -
+
{options.icon ? : // fallback to homepage logo diff --git a/src/components/widgets/longhorn/longhorn.jsx b/src/components/widgets/longhorn/longhorn.jsx index 9fcb21b4..5139f00a 100644 --- a/src/components/widgets/longhorn/longhorn.jsx +++ b/src/components/widgets/longhorn/longhorn.jsx @@ -1,37 +1,36 @@ import useSWR from "swr"; -import { BiError } from "react-icons/bi"; -import { useTranslation } from "next-i18next"; +import classNames from "classnames"; + +import Error from "../error"; import Node from "./node"; export default function Longhorn({ options }) { const { expanded, total, labels, include, nodes } = options; - const { t } = useTranslation(); const { data, error } = useSWR(`/api/widgets/longhorn`, { refreshInterval: 1500 }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data) { return ( -
+
); } return ( -
+
{data.nodes .filter((node) => { diff --git a/src/components/widgets/openmeteo/openmeteo.jsx b/src/components/widgets/openmeteo/openmeteo.jsx index 0d29aef5..1381cc55 100644 --- a/src/components/widgets/openmeteo/openmeteo.jsx +++ b/src/components/widgets/openmeteo/openmeteo.jsx @@ -1,9 +1,11 @@ import useSWR from "swr"; import { useState } from "react"; -import { BiError } from "react-icons/bi"; import { WiCloudDown } from "react-icons/wi"; import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; import { useTranslation } from "next-i18next"; +import classNames from "classnames"; + +import Error from "../error"; import Icon from "./icon"; @@ -15,24 +17,15 @@ function Widget({ options }) { ); if (error || data?.error) { - return ( -
-
-
- -
- {t("widget.api_error")} - - -
-
-
-
- ); + return } if (!data) { return ( -
+
@@ -50,7 +43,10 @@ function Widget({ options }) { const timeOfDay = data.current_weather.time > data.daily.sunrise[0] && data.current_weather.time < data.daily.sunset[0] ? "day" : "night"; return ( -
+
@@ -107,8 +103,10 @@ export default function OpenMeteo({ options }) { - ); + return + {t("weather.current")} + {t("weather.allow")} + + ; } return ; diff --git a/src/components/widgets/openweathermap/weather.jsx b/src/components/widgets/openweathermap/weather.jsx index b404039f..30531513 100644 --- a/src/components/widgets/openweathermap/weather.jsx +++ b/src/components/widgets/openweathermap/weather.jsx @@ -3,12 +3,17 @@ import { useState } from "react"; import { WiCloudDown } from "react-icons/wi"; import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; import { useTranslation } from "next-i18next"; -import classNames from "classnames"; -import Error from "../error"; +import Error from "../widget/error"; +import Container from "../widget/container"; +import ContainerButton from "../widget/container_button"; +import PrimaryText from "../widget/primary_text"; +import SecondaryText from "../widget/secondary_text"; +import WidgetIcon from "../widget/widget_icon"; import Icon from "./icon"; + function Widget({ options }) { const { t, i18n } = useTranslation(); @@ -21,48 +26,26 @@ function Widget({ options }) { } if (!data) { - return ( -
-
-
- -
-
- {t("weather.updating")} - {t("weather.wait")} -
-
-
- ); + return + {t("weather.updating")} + {t("weather.wait")} + + ; } const unit = options.units === "metric" ? "celsius" : "fahrenheit"; - return ( -
-
-
- data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night"} - /> -
-
- - {options.label && `${options.label}, `} - {t("common.number", { value: data.main.temp, style: "unit", unit })} - - {data.weather[0].description} -
-
-
- ); + const weatherInfo = { + condition: data.weather[0].id, + timeOfDay: data.dt > data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night" + }; + + return + {options.label && `${options.label}, `} + {t("common.number", { value: data.main.temp, style: "unit", unit })} + {data.weather[0].description} + + ; } export default function OpenWeatherMap({ options }) { @@ -94,33 +77,12 @@ export default function OpenWeatherMap({ options }) { } }; - // if (!requesting && !location) requestLocation(); - if (!location) { - return ( - - ); + return + {t("weather.current")} + {t("weather.allow")} + + ; } return ; diff --git a/src/components/widgets/resources/cpu.jsx b/src/components/widgets/resources/cpu.jsx index 7069e3c4..242e7a3d 100644 --- a/src/components/widgets/resources/cpu.jsx +++ b/src/components/widgets/resources/cpu.jsx @@ -1,8 +1,13 @@ import useSWR from "swr"; import { FiCpu } from "react-icons/fi"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import SingleResource from "../widget/single_resource"; +import WidgetIcon from "../widget/widget_icon"; +import ResourceValue from "../widget/resource_value"; +import ResourceLabel from "../widget/resource_label"; +import Error from "../widget/error"; + import UsageBar from "./usage-bar"; export default function Cpu({ expanded }) { @@ -13,67 +18,38 @@ export default function Cpu({ expanded }) { }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data) { - return ( -
- -
-
-
-
-
{t("resources.cpu")}
-
- {expanded && ( -
-
-
-
{t("resources.load")}
-
- )} - -
-
- ); + return + + - + {t("resources.cpu")} + - + {t("resources.load")} + + } - const percent = data.cpu.usage; - - return ( -
- -
-
-
- {t("common.number", { - value: data.cpu.usage, - style: "unit", - unit: "percent", - maximumFractionDigits: 0, - })} -
-
{t("resources.cpu")}
-
- {expanded && ( -
-
- {t("common.number", { - value: data.cpu.load, - maximumFractionDigits: 2, - })} -
-
{t("resources.load")}
-
- )} - -
-
- ); + return + + + {t("common.number", { + value: data.cpu.usage, + style: "unit", + unit: "percent", + maximumFractionDigits: 0, + })} + + {t("resources.cpu")} + + {t("common.number", { + value: data.cpu.load, + maximumFractionDigits: 2, + })} + + {t("resources.load")} + + } diff --git a/src/components/widgets/resources/cputemp.jsx b/src/components/widgets/resources/cputemp.jsx index 571e6c8a..1a62aa31 100644 --- a/src/components/widgets/resources/cputemp.jsx +++ b/src/components/widgets/resources/cputemp.jsx @@ -1,8 +1,13 @@ import useSWR from "swr"; import { FaThermometerHalf } from "react-icons/fa"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import SingleResource from "../widget/single_resource"; +import WidgetIcon from "../widget/widget_icon"; +import ResourceValue from "../widget/resource_value"; +import ResourceLabel from "../widget/resource_label"; +import Error from "../widget/error"; + import UsageBar from "./usage-bar"; function convertToFahrenheit(t) { @@ -17,34 +22,17 @@ export default function CpuTemp({ expanded, units }) { }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data || !data.cputemp) { - return ( -
- -
- -
-
-
{t("resources.temp")}
-
- {expanded && ( - -
-
-
{t("resources.max")}
-
- )} -
-
- ); + return + + - + {t("resources.temp")} + - + {t("resources.max")} + } let mainTemp = data.cputemp.main; @@ -54,38 +42,27 @@ export default function CpuTemp({ expanded, units }) { const unit = units === "imperial" ? "fahrenheit" : "celsius"; mainTemp = (unit === "celsius") ? mainTemp : convertToFahrenheit(mainTemp); const maxTemp = (unit === "celsius") ? data.cputemp.max : convertToFahrenheit(data.cputemp.max); - const percent = Math.round((mainTemp / maxTemp) * 100); - return ( -
- -
- -
- {t("common.number", { - value: mainTemp, - maximumFractionDigits: 1, - style: "unit", - unit - })} -
-
{t("resources.temp")}
-
- {expanded && ( - -
- {t("common.number", { - value: maxTemp, - maximumFractionDigits: 1, - style: "unit", - unit - })} -
-
{t("resources.max")}
-
- )} - -
-
- ); + return + + + {t("common.number", { + value: mainTemp, + maximumFractionDigits: 1, + style: "unit", + unit + })} + + {t("resources.temp")} + + {t("common.number", { + value: maxTemp, + maximumFractionDigits: 1, + style: "unit", + unit + })} + + {t("resources.max")} + + ; } diff --git a/src/components/widgets/resources/disk.jsx b/src/components/widgets/resources/disk.jsx index ca09c095..742ff9d7 100644 --- a/src/components/widgets/resources/disk.jsx +++ b/src/components/widgets/resources/disk.jsx @@ -1,8 +1,13 @@ import useSWR from "swr"; import { FiHardDrive } from "react-icons/fi"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import SingleResource from "../widget/single_resource"; +import WidgetIcon from "../widget/widget_icon"; +import ResourceValue from "../widget/resource_value"; +import ResourceLabel from "../widget/resource_label"; +import Error from "../widget/error"; + import UsageBar from "./usage-bar"; export default function Disk({ options, expanded }) { @@ -13,56 +18,29 @@ export default function Disk({ options, expanded }) { }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data) { - return ( -
- -
- -
-
-
{t("resources.free")}
-
- {expanded && ( - -
-
-
{t("resources.total")}
-
- )} - -
-
- ); + return + + - + {t("resources.free")} + - + {t("resources.total")} + + ; } // data.drive.used not accurate? const percent = Math.round(((data.drive.size - data.drive.available) / data.drive.size) * 100); - return ( -
- -
- -
{t("common.bytes", { value: data.drive.available })}
-
{t("resources.free")}
-
- {expanded && ( - -
{t("common.bytes", { value: data.drive.size })}
-
{t("resources.total")}
-
- )} - -
-
- ); + return + + {t("common.bytes", { value: data.drive.available })} + {t("resources.free")} + {t("common.bytes", { value: data.drive.size })} + {t("resources.total")} + + ; } diff --git a/src/components/widgets/resources/memory.jsx b/src/components/widgets/resources/memory.jsx index 30b7c8eb..97c74acc 100644 --- a/src/components/widgets/resources/memory.jsx +++ b/src/components/widgets/resources/memory.jsx @@ -1,8 +1,13 @@ import useSWR from "swr"; import { FaMemory } from "react-icons/fa"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import SingleResource from "../widget/single_resource"; +import WidgetIcon from "../widget/widget_icon"; +import ResourceValue from "../widget/resource_value"; +import ResourceLabel from "../widget/resource_label"; +import Error from "../widget/error"; + import UsageBar from "./usage-bar"; export default function Memory({ expanded }) { @@ -13,63 +18,34 @@ export default function Memory({ expanded }) { }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data) { - return ( -
- -
- -
-
-
{t("resources.free")}
-
- {expanded && ( - -
-
-
{t("resources.total")}
-
- )} - -
-
- ); + return + + - + {t("resources.free")} + - + {t("resources.total")} + + ; } const percent = Math.round((data.memory.active / data.memory.total) * 100); - return ( -
- -
- -
- {t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })} -
-
{t("resources.free")}
-
- {expanded && ( - -
- {t("common.bytes", { - value: data.memory.total, - maximumFractionDigits: 1, - binary: true, - })} -
-
{t("resources.total")}
-
- )} - -
-
- ); + return + + {t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })} + {t("resources.free")} + + {t("common.bytes", { + value: data.memory.total, + maximumFractionDigits: 1, + binary: true, + })} + + {t("resources.total")} + + ; } diff --git a/src/components/widgets/resources/resources.jsx b/src/components/widgets/resources/resources.jsx index 5727a2a0..0cc2c301 100644 --- a/src/components/widgets/resources/resources.jsx +++ b/src/components/widgets/resources/resources.jsx @@ -1,4 +1,5 @@ -import classNames from "classnames"; +import Container from "../widget/container"; +import Raw from "../widget/raw"; import Disk from "./disk"; import Cpu from "./cpu"; @@ -8,11 +9,8 @@ import Uptime from "./uptime"; export default function Resources({ options }) { const { expanded, units } = options; - return ( -
+ return +
{options.cpu && } {options.memory && } @@ -25,6 +23,6 @@ export default function Resources({ options }) { {options.label && (
{options.label}
)} -
- ); +
+
; } diff --git a/src/components/widgets/resources/uptime.jsx b/src/components/widgets/resources/uptime.jsx index 3bf785b1..6cc2b8c5 100644 --- a/src/components/widgets/resources/uptime.jsx +++ b/src/components/widgets/resources/uptime.jsx @@ -1,8 +1,13 @@ import useSWR from "swr"; import { FaRegClock } from "react-icons/fa"; -import { BiError } from "react-icons/bi"; import { useTranslation } from "next-i18next"; +import SingleResource from "../widget/single_resource"; +import WidgetIcon from "../widget/widget_icon"; +import ResourceValue from "../widget/resource_value"; +import ResourceLabel from "../widget/resource_label"; +import Error from "../widget/error"; + import UsageBar from "./usage-bar"; export default function Uptime() { @@ -13,35 +18,22 @@ export default function Uptime() { }); if (error || data?.error) { - return ( -
- -
- {t("widget.api_error")} -
-
- ); + return } if (!data) { - return ( -
- -
- -
-
-
{t("resources.temp")}
-
-
-
- ); + return + + - + {t("resources.uptime")} + ; } const mo = Math.floor(data.uptime / (3600 * 24 * 31)); const d = Math.floor(data.uptime % (3600 * 24 * 31) / (3600 * 24)); const h = Math.floor(data.uptime % (3600 * 24) / 3600); const m = Math.floor(data.uptime % 3600 / 60); - + let uptime; if (mo > 0) uptime = `${mo}${t("resources.months")} ${d}${t("resources.days")}`; else if (d > 0) uptime = `${d}${t("resources.days")} ${h}${t("resources.hours")}`; @@ -49,18 +41,10 @@ export default function Uptime() { const percent = Math.round((new Date().getSeconds() / 60) * 100); - return ( -
- -
- -
- {uptime} -
-
{t("resources.uptime")}
-
- -
-
- ); + return + + {uptime} + {t("resources.uptime")} + + ; } diff --git a/src/components/widgets/search/search.jsx b/src/components/widgets/search/search.jsx index bca3eb58..1bac4a61 100644 --- a/src/components/widgets/search/search.jsx +++ b/src/components/widgets/search/search.jsx @@ -1,10 +1,13 @@ -import { useState, useEffect, Fragment } from "react"; +import { useState, useEffect, useCallback, Fragment } from "react"; import { useTranslation } from "next-i18next"; import { FiSearch } from "react-icons/fi"; import { SiDuckduckgo, SiMicrosoftbing, SiGoogle, SiBaidu, SiBrave } from "react-icons/si"; import { Listbox, Transition } from "@headlessui/react"; import classNames from "classnames"; +import ContainerForm from "../widget/container_form"; +import Raw from "../widget/raw"; + export const searchProviders = { google: { name: "Google", @@ -77,13 +80,8 @@ export default function Search({ options }) { } }, [availableProviderIds]); - if (!availableProviderIds) { - return null; - } - - function handleSubmit(event) { + const submitCallback = useCallback(event => { const q = encodeURIComponent(query); - const { url } = selectedProvider; if (url) { window.open(`${url}${q}`, options.target || "_blank"); @@ -94,6 +92,10 @@ export default function Search({ options }) { event.preventDefault(); event.target.reset(); setQuery(""); + }, [options.target, options.url, query, selectedProvider]); + + if (!availableProviderIds) { + return null; } const onChangeProvider = (provider) => { @@ -101,80 +103,79 @@ export default function Search({ options }) { localStorage.setItem(localStorageKey, provider.name); } - return ( - -
- setQuery(s.currentTarget.value)} - required - autoCapitalize="off" - autoCorrect="off" - autoComplete="off" - // eslint-disable-next-line jsx-a11y/no-autofocus - autoFocus={options.focus} - /> - -
- + +
+
+ setQuery(s.currentTarget.value)} + required + autoCapitalize="off" + autoCorrect="off" + autoComplete="off" + // eslint-disable-next-line jsx-a11y/no-autofocus + autoFocus={options.focus} + /> + +
+ + + {t("search.search")} + +
+ - - {t("search.search")} - -
- - -
- {availableProviderIds.map((providerId) => { - const p = searchProviders[providerId]; - return ( - - {({ active }) => ( -
  • - -
  • - )} -
    - ); - })} -
    -
    -
    - - - ); + +
    + {availableProviderIds.map((providerId) => { + const p = searchProviders[providerId]; + return ( + + {({ active }) => ( +
  • + +
  • + )} +
    + ); + })} +
    +
    + + +
    +
    + ; } diff --git a/src/components/widgets/unifi_console/unifi_console.jsx b/src/components/widgets/unifi_console/unifi_console.jsx index 1896771f..dad92cc7 100644 --- a/src/components/widgets/unifi_console/unifi_console.jsx +++ b/src/components/widgets/unifi_console/unifi_console.jsx @@ -2,9 +2,12 @@ import { BiError, BiWifi, BiCheckCircle, BiXCircle, BiNetworkChart } from "react import { MdSettingsEthernet } from "react-icons/md"; import { useTranslation } from "next-i18next"; import { SiUbiquiti } from "react-icons/si"; -import classNames from "classnames"; -import Error from "../error"; +import Error from "../widget/error"; +import Container from "../widget/container"; +import Raw from "../widget/raw"; +import WidgetIcon from "../widget/widget_icon"; +import PrimaryText from "../widget/primary_text"; import useWidgetAPI from "utils/proxy/use-widget-api"; @@ -22,21 +25,10 @@ export default function Widget({ options }) { const defaultSite = options.site ? statsData?.data.find(s => s.desc === options.site) : statsData?.data?.find(s => s.name === "default"); if (!defaultSite) { - return ( -
    -
    -
    - -
    -
    - {t("unifi.wait")} -
    -
    -
    - ); + return + {t("unifi.wait")} + + ; } const wan = defaultSite.health.find(h => h.subsystem === "wan"); @@ -51,11 +43,9 @@ export default function Widget({ options }) { const dataEmpty = !(wan.show || lan.show || wlan.show || uptime); - return ( -
    + return + +
    @@ -139,6 +129,7 @@ export default function Widget({ options }) {
    }
    -
    - ); +
    + + } diff --git a/src/components/widgets/weather/weather.jsx b/src/components/widgets/weather/weather.jsx index 51801455..702ea669 100644 --- a/src/components/widgets/weather/weather.jsx +++ b/src/components/widgets/weather/weather.jsx @@ -3,9 +3,13 @@ import { useState } from "react"; import { WiCloudDown } from "react-icons/wi"; import { MdLocationDisabled, MdLocationSearching } from "react-icons/md"; import { useTranslation } from "next-i18next"; -import classNames from "classnames"; -import Error from "../error"; +import Error from "../widget/error"; +import Container from "../widget/container"; +import PrimaryText from "../widget/primary_text"; +import SecondaryText from "../widget/secondary_text"; +import WidgetIcon from "../widget/widget_icon"; +import ContainerButton from "../widget/container_button"; import Icon from "./icon"; @@ -21,49 +25,31 @@ function Widget({ options }) { } if (!data) { - return ( -
    -
    -
    - -
    -
    - {t("weather.updating")} - {t("weather.wait")} -
    -
    -
    - ); + return + {t("weather.updating")} + {t("weather.wait")} + + ; } const unit = options.units === "metric" ? "celsius" : "fahrenheit"; + const weatherInfo = { + condition: data.current.condition.code, + timeOfDay: data.current.is_day ? "day" : "night", + }; - return ( -
    -
    -
    - -
    -
    - - {options.label && `${options.label}, `} - {t("common.number", { - value: options.units === "metric" ? data.current.temp_c : data.current.temp_f, - style: "unit", - unit, - })} - - {data.current.condition.text} -
    -
    -
    - ); + return + + {options.label && `${options.label}, `} + {t("common.number", { + value: options.units === "metric" ? data.current.temp_c : data.current.temp_f, + style: "unit", + unit, + })} + + {data.current.condition.text} + + ; } export default function WeatherApi({ options }) { @@ -95,33 +81,12 @@ export default function WeatherApi({ options }) { } }; - // if (!requesting && !location) requestLocation(); - if (!location) { - return ( - - ); + return + {t("weather.current")} + {t("weather.allow")} + + ; } return ; diff --git a/src/components/widgets/widget.jsx b/src/components/widgets/widget.jsx index 47141887..b4fdb143 100644 --- a/src/components/widgets/widget.jsx +++ b/src/components/widgets/widget.jsx @@ -17,13 +17,13 @@ const widgetMappings = { kubernetes: dynamic(() => import("components/widgets/kubernetes/kubernetes")), }; -export default function Widget({ widget }) { +export default function Widget({ widget, style }) { const InfoWidget = widgetMappings[widget.type]; if (InfoWidget) { return ( - + ); } diff --git a/src/components/widgets/widget/container.jsx b/src/components/widgets/widget/container.jsx new file mode 100644 index 00000000..3a4a9f57 --- /dev/null +++ b/src/components/widgets/widget/container.jsx @@ -0,0 +1,42 @@ +import classNames from "classnames"; + +import WidgetIcon from "./widget_icon"; +import PrimaryText from "./primary_text"; +import SecondaryText from "./secondary_text"; +import Raw from "./raw"; + +export function getAllClasses(options, additionalClassNames = '') { + return classNames( + "flex flex-col justify-center first:ml-0 ml-4 mr-2", + additionalClassNames, + options?.style === "boxedWidgets" && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3", + ); +} + +export function getInnerBlock(children) { + // children won't be an array if it's Raw component + return Array.isArray(children) &&
    +
    {children.find(child => child.type === WidgetIcon)}
    +
    + {children.find(child => child.type === PrimaryText)} + {children.find(child => child.type === SecondaryText)} +
    +
    ; +} + +export function getBottomBlock(children) { + if (children.type !== Raw) { + return children.find(child => child.type === Raw) || []; + } + + return [children]; +} + +export default function Container({ children = [], options, additionalClassNames = '' }) { + return ( +
    + {getInnerBlock(children)} + {getBottomBlock(children)} +
    + ); +} diff --git a/src/components/widgets/widget/container_button.jsx b/src/components/widgets/widget/container_button.jsx new file mode 100644 index 00000000..92d8a416 --- /dev/null +++ b/src/components/widgets/widget/container_button.jsx @@ -0,0 +1,10 @@ +import { getAllClasses, getInnerBlock, getBottomBlock } from "./container"; + +export default function ContainerButton ({ children = [], options, additionalClassNames = '', callback }) { + return ( + + ); +} diff --git a/src/components/widgets/widget/container_form.jsx b/src/components/widgets/widget/container_form.jsx new file mode 100644 index 00000000..7d28a1bb --- /dev/null +++ b/src/components/widgets/widget/container_form.jsx @@ -0,0 +1,10 @@ +import { getAllClasses, getInnerBlock, getBottomBlock } from "./container"; + +export default function ContainerForm ({ children = [], options, additionalClassNames = '', callback }) { + return ( +
    + {getInnerBlock(children)} + {getBottomBlock(children)} +
    + ); +} diff --git a/src/components/widgets/widget/container_link.jsx b/src/components/widgets/widget/container_link.jsx new file mode 100644 index 00000000..8ef0e80a --- /dev/null +++ b/src/components/widgets/widget/container_link.jsx @@ -0,0 +1,10 @@ +import { getAllClasses, getInnerBlock, getBottomBlock } from "./container"; + +export default function ContainerLink ({ children = [], options, additionalClassNames = '', target }) { + return ( + + {getInnerBlock(children)} + {getBottomBlock(children)} + + ); +} diff --git a/src/components/widgets/widget/error.jsx b/src/components/widgets/widget/error.jsx new file mode 100644 index 00000000..a3dbab85 --- /dev/null +++ b/src/components/widgets/widget/error.jsx @@ -0,0 +1,15 @@ +import { useTranslation } from "react-i18next"; +import { BiError } from "react-icons/bi"; + +import Container from "./container"; +import PrimaryText from "./primary_text"; +import WidgetIcon from "./widget_icon"; + +export default function Error({ options }) { + const { t } = useTranslation(); + + return + {t("widget.api_error")} + + ; +} diff --git a/src/components/widgets/widget/primary_text.jsx b/src/components/widgets/widget/primary_text.jsx new file mode 100644 index 00000000..3418b92c --- /dev/null +++ b/src/components/widgets/widget/primary_text.jsx @@ -0,0 +1,5 @@ +export default function PrimaryText({ children }) { + return ( + {children} + ); +} diff --git a/src/components/widgets/widget/raw.jsx b/src/components/widgets/widget/raw.jsx new file mode 100644 index 00000000..44e3dddc --- /dev/null +++ b/src/components/widgets/widget/raw.jsx @@ -0,0 +1,7 @@ +export default function Raw({ children }) { + if (children.type === Raw) { + return [children]; + } + + return children; +} diff --git a/src/components/widgets/widget/resource_label.jsx b/src/components/widgets/widget/resource_label.jsx new file mode 100644 index 00000000..87f2ad22 --- /dev/null +++ b/src/components/widgets/widget/resource_label.jsx @@ -0,0 +1,5 @@ +export default function ResourceLabel({ children }) { + return ( +
    {children}
    + ); +} diff --git a/src/components/widgets/widget/resource_value.jsx b/src/components/widgets/widget/resource_value.jsx new file mode 100644 index 00000000..8971c748 --- /dev/null +++ b/src/components/widgets/widget/resource_value.jsx @@ -0,0 +1,5 @@ +export default function ResourceValue({ children }) { + return ( +
    {children}
    + ); +} diff --git a/src/components/widgets/widget/resources.jsx b/src/components/widgets/widget/resources.jsx new file mode 100644 index 00000000..0771ec5e --- /dev/null +++ b/src/components/widgets/widget/resources.jsx @@ -0,0 +1,15 @@ +import ContainerLink from "./container_link"; +import SingleResource from "./single_resource"; +import Raw from "./raw"; +import WidgetLabel from "./widget_label"; + +export default function Resources({ options, children, target }) { + return + +
    + {children.filter(child => child && child.type === SingleResource)} +
    + {children.filter(child => child && child.type === WidgetLabel)} +
    +
    ; +} diff --git a/src/components/widgets/widget/secondary_text.jsx b/src/components/widgets/widget/secondary_text.jsx new file mode 100644 index 00000000..363d1bd0 --- /dev/null +++ b/src/components/widgets/widget/secondary_text.jsx @@ -0,0 +1,5 @@ +export default function SecondaryText({ children }) { + return ( + {children} + ); +} diff --git a/src/components/widgets/widget/single_resource.jsx b/src/components/widgets/widget/single_resource.jsx new file mode 100644 index 00000000..7a83d8be --- /dev/null +++ b/src/components/widgets/widget/single_resource.jsx @@ -0,0 +1,28 @@ +import UsageBar from "../resources/usage-bar"; + +import WidgetIcon from "./widget_icon"; +import ResourceValue from "./resource_value"; +import ResourceLabel from "./resource_label"; +import Raw from "./raw"; + +export default function SingleResource({ children, key, expanded = false }) { + const values = children.filter(child => child.type === ResourceValue); + const labels = children.filter(child => child.type === ResourceLabel); + + return
    + {children.find(child => child.type === WidgetIcon)} +
    +
    + {values.pop()} + {labels.pop()} +
    + { expanded &&
    + {values.pop()} + {labels.pop()} +
    + } + {children.find(child => child.type === UsageBar)} +
    + {children.find(child => child.type === Raw)} +
    ; +} diff --git a/src/components/widgets/widget/widget_icon.jsx b/src/components/widgets/widget/widget_icon.jsx new file mode 100644 index 00000000..9766a879 --- /dev/null +++ b/src/components/widgets/widget/widget_icon.jsx @@ -0,0 +1,18 @@ +export default function WidgetIcon({ icon, size = "s", pulse = false, weatherInfo = {} }) { + const Icon = icon; + const { condition, timeOfDay } = weatherInfo; + let additionalClasses = "text-theme-800 dark:text-theme-200 "; + + switch (size) { + case "m": additionalClasses += "w-6 h-6 "; break; + case "l": additionalClasses += "w-8 h-8 "; break; + case "xl": additionalClasses += "w-10 h-10 "; break; + default: additionalClasses += "w-5 h-5 "; + } + + if (pulse) { + additionalClasses += "animate-pulse "; + } + + return ; +} diff --git a/src/components/widgets/widget/widget_label.jsx b/src/components/widgets/widget/widget_label.jsx new file mode 100644 index 00000000..dcb9b9e9 --- /dev/null +++ b/src/components/widgets/widget/widget_label.jsx @@ -0,0 +1,3 @@ +export default function WidgetLabel({ label = "" }) { + return
    {label}
    +} diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 6180ff51..7611aed5 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -160,6 +160,7 @@ const headerStyles = { "m-4 mb-0 sm:m-8 sm:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-3", underlined: "m-4 mb-0 sm:m-8 sm:mb-1 border-b-2 pb-4 border-theme-800 dark:border-theme-200/50", clean: "m-4 mb-0 sm:m-8 sm:mb-0", + boxedWidgets: "m-4 mb-0 sm:m-8 sm:mb-0 sm:mt-1", }; function Home({ initialSettings }) { @@ -208,6 +209,7 @@ function Home({ initialSettings }) { searchProvider = searchProviders[searchWidget.options?.provider]; } } + const headerStyle = initialSettings?.headerStyle || "underlined"; useEffect(() => { function handleKeyDown(e) { @@ -256,7 +258,7 @@ function Home({ initialSettings }) {
    !rightAlignedWidgets.includes(widget.type)) .map((widget, i) => ( - + ))} -
    +
    {widgets .filter((widget) => rightAlignedWidgets.includes(widget.type)) .map((widget, i) => ( - + ))}
    From 6f750dd83cfdfb2c5784811e1c091fa814b68ff4 Mon Sep 17 00:00:00 2001 From: Denis Papec Date: Mon, 5 Jun 2023 23:18:18 +0100 Subject: [PATCH 03/50] Further improvements to simplify information widgets Signed-off-by: Denis Papec --- src/components/widgets/glances/glances.jsx | 130 ++++++++---------- src/components/widgets/longhorn/node.jsx | 25 ++-- src/components/widgets/resources/cpu.jsx | 54 +++----- src/components/widgets/resources/cputemp.jsx | 63 ++++----- src/components/widgets/resources/disk.jsx | 41 +++--- src/components/widgets/resources/memory.jsx | 47 +++---- src/components/widgets/resources/uptime.jsx | 22 +-- src/components/widgets/widget/resource.jsx | 22 +++ .../widgets/widget/resource_label.jsx | 5 - .../widgets/widget/resource_value.jsx | 5 - src/components/widgets/widget/resources.jsx | 6 +- .../widgets/widget/single_resource.jsx | 28 ---- 12 files changed, 181 insertions(+), 267 deletions(-) create mode 100644 src/components/widgets/widget/resource.jsx delete mode 100644 src/components/widgets/widget/resource_label.jsx delete mode 100644 src/components/widgets/widget/resource_value.jsx delete mode 100644 src/components/widgets/widget/single_resource.jsx diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx index debb09c7..b45dfefe 100644 --- a/src/components/widgets/glances/glances.jsx +++ b/src/components/widgets/glances/glances.jsx @@ -4,12 +4,8 @@ import { FaMemory, FaRegClock, FaThermometerHalf } from "react-icons/fa"; import { FiCpu, FiHardDrive } from "react-icons/fi"; import { useTranslation } from "next-i18next"; -import UsageBar from "../resources/usage-bar"; import Error from "../widget/error"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Resources from "../widget/resources"; import WidgetLabel from "../widget/widget_label"; @@ -37,31 +33,11 @@ export default function Widget({ options }) { if (!data) { return - - - {t("glances.wait")} - - - - - {t("glances.wait")} - - - {options.cputemp && - - - {t("glances.wait")} - - - } - {options.uptime && - - - {t("glances.wait")} - - - } - {options.label && } + + + { options.cputemp && } + { options.uptime && } + { options.label && } ; } @@ -93,77 +69,81 @@ export default function Widget({ options }) { return ( - - - {t("common.number", { + - {t("glances.cpu")} - {t("common.number", { + })} + label={t("glances.cpu")} + expandedValue={t("common.number", { value: data.load.min15, style: "unit", unit: "percent", - maximumFractionDigits: 0, - })} - {t("glances.load")} - - - - - {t("common.bytes", { + maximumFractionDigits: 0 + })} + expandedLabel={t("glances.load")} + percentage={data.cpu.total} + expanded={options.expanded} + /> + - {t("glances.free")} - {t("common.bytes", { + })} + label={t("glances.free")} + expandedValue={t("common.bytes", { value: data.mem.total, maximumFractionDigits: 1, binary: true, - })} - {t("glances.total")} - - + })} + expandedLabel={t("glances.total")} + percentage={data.mem.percent} + expanded={options.expanded} + /> {disks.map((disk) => ( - - - {t("common.bytes", { value: disk.free })} - {t("glances.free")} - {t("common.bytes", { value: disk.size })} - {t("glances.total")} - - + ))} {options.cputemp && mainTemp > 0 && - - - {t("common.number", { + - {t("glances.temp")} - {t("common.number", { + })} + label={t("glances.temp")} + expandedValue={t("common.number", { value: maxTemp, maximumFractionDigits: 1, style: "unit", unit - })} - {t("glances.warn")} - - + })} + expandedLabel={t("glances.warn")} + percentage={tempPercent} + expanded={options.expanded} + /> } {options.uptime && data.uptime && - - - {data.uptime.replace(" days,", t("glances.days")).replace(/:\d\d:\d\d$/g, t("glances.hours"))} - {t("glances.uptime")} - - + } {options.label && } diff --git a/src/components/widgets/longhorn/node.jsx b/src/components/widgets/longhorn/node.jsx index 9983486e..5235698a 100644 --- a/src/components/widgets/longhorn/node.jsx +++ b/src/components/widgets/longhorn/node.jsx @@ -1,23 +1,20 @@ import { useTranslation } from "next-i18next"; import { FaThermometerHalf } from "react-icons/fa"; -import UsageBar from "../resources/usage-bar"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import WidgetLabel from "../widget/widget_label"; export default function Node({ data, expanded, labels }) { const { t } = useTranslation(); - return - - {t("common.bytes", { value: data.node.available })} - {t("resources.free")} - {t("common.bytes", { value: data.node.maximum })} - {t("resources.total")} - - { labels && } - + return { labels && } + } diff --git a/src/components/widgets/resources/cpu.jsx b/src/components/widgets/resources/cpu.jsx index 242e7a3d..12972fe8 100644 --- a/src/components/widgets/resources/cpu.jsx +++ b/src/components/widgets/resources/cpu.jsx @@ -2,14 +2,9 @@ import useSWR from "swr"; import { FiCpu } from "react-icons/fi"; import { useTranslation } from "next-i18next"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Error from "../widget/error"; -import UsageBar from "./usage-bar"; - export default function Cpu({ expanded }) { const { t } = useTranslation(); @@ -22,34 +17,25 @@ export default function Cpu({ expanded }) { } if (!data) { - return - - - - {t("resources.cpu")} - - - {t("resources.load")} - - + return } - return - - - {t("common.number", { - value: data.cpu.usage, - style: "unit", - unit: "percent", - maximumFractionDigits: 0, - })} - - {t("resources.cpu")} - - {t("common.number", { - value: data.cpu.load, - maximumFractionDigits: 2, - })} - - {t("resources.load")} - - + return } diff --git a/src/components/widgets/resources/cputemp.jsx b/src/components/widgets/resources/cputemp.jsx index 1a62aa31..ba6d9b73 100644 --- a/src/components/widgets/resources/cputemp.jsx +++ b/src/components/widgets/resources/cputemp.jsx @@ -2,14 +2,9 @@ import useSWR from "swr"; import { FaThermometerHalf } from "react-icons/fa"; import { useTranslation } from "next-i18next"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Error from "../widget/error"; -import UsageBar from "./usage-bar"; - function convertToFahrenheit(t) { return t * 9/5 + 32 } @@ -26,13 +21,14 @@ export default function CpuTemp({ expanded, units }) { } if (!data || !data.cputemp) { - return - - - - {t("resources.temp")} - - - {t("resources.max")} - + return ; } let mainTemp = data.cputemp.main; @@ -43,26 +39,23 @@ export default function CpuTemp({ expanded, units }) { mainTemp = (unit === "celsius") ? mainTemp : convertToFahrenheit(mainTemp); const maxTemp = (unit === "celsius") ? data.cputemp.max : convertToFahrenheit(data.cputemp.max); - return - - - {t("common.number", { - value: mainTemp, - maximumFractionDigits: 1, - style: "unit", - unit - })} - - {t("resources.temp")} - - {t("common.number", { - value: maxTemp, - maximumFractionDigits: 1, - style: "unit", - unit - })} - - {t("resources.max")} - - ; + return ; } diff --git a/src/components/widgets/resources/disk.jsx b/src/components/widgets/resources/disk.jsx index 742ff9d7..ab56624d 100644 --- a/src/components/widgets/resources/disk.jsx +++ b/src/components/widgets/resources/disk.jsx @@ -2,14 +2,9 @@ import useSWR from "swr"; import { FiHardDrive } from "react-icons/fi"; import { useTranslation } from "next-i18next"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Error from "../widget/error"; -import UsageBar from "./usage-bar"; - export default function Disk({ options, expanded }) { const { t } = useTranslation(); @@ -22,25 +17,27 @@ export default function Disk({ options, expanded }) { } if (!data) { - return - - - - {t("resources.free")} - - - {t("resources.total")} - - ; + return ; } // data.drive.used not accurate? const percent = Math.round(((data.drive.size - data.drive.available) / data.drive.size) * 100); - return - - {t("common.bytes", { value: data.drive.available })} - {t("resources.free")} - {t("common.bytes", { value: data.drive.size })} - {t("resources.total")} - - ; + return ; } diff --git a/src/components/widgets/resources/memory.jsx b/src/components/widgets/resources/memory.jsx index 97c74acc..19ae8687 100644 --- a/src/components/widgets/resources/memory.jsx +++ b/src/components/widgets/resources/memory.jsx @@ -2,14 +2,9 @@ import useSWR from "swr"; import { FaMemory } from "react-icons/fa"; import { useTranslation } from "next-i18next"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Error from "../widget/error"; -import UsageBar from "./usage-bar"; - export default function Memory({ expanded }) { const { t } = useTranslation(); @@ -22,30 +17,26 @@ export default function Memory({ expanded }) { } if (!data) { - return - - - - {t("resources.free")} - - - {t("resources.total")} - - ; + return ; } const percent = Math.round((data.memory.active / data.memory.total) * 100); - return - - {t("common.bytes", { value: data.memory.available, maximumFractionDigits: 1, binary: true })} - {t("resources.free")} - - {t("common.bytes", { - value: data.memory.total, - maximumFractionDigits: 1, - binary: true, - })} - - {t("resources.total")} - - ; + return ; } diff --git a/src/components/widgets/resources/uptime.jsx b/src/components/widgets/resources/uptime.jsx index 6cc2b8c5..3984975f 100644 --- a/src/components/widgets/resources/uptime.jsx +++ b/src/components/widgets/resources/uptime.jsx @@ -2,14 +2,9 @@ import useSWR from "swr"; import { FaRegClock } from "react-icons/fa"; import { useTranslation } from "next-i18next"; -import SingleResource from "../widget/single_resource"; -import WidgetIcon from "../widget/widget_icon"; -import ResourceValue from "../widget/resource_value"; -import ResourceLabel from "../widget/resource_label"; +import Resource from "../widget/resource"; import Error from "../widget/error"; -import UsageBar from "./usage-bar"; - export default function Uptime() { const { t } = useTranslation(); @@ -22,11 +17,7 @@ export default function Uptime() { } if (!data) { - return - - - - {t("resources.uptime")} - ; + return ; } const mo = Math.floor(data.uptime / (3600 * 24 * 31)); @@ -39,12 +30,7 @@ export default function Uptime() { else if (d > 0) uptime = `${d}${t("resources.days")} ${h}${t("resources.hours")}`; else uptime = `${h}${t("resources.hours")} ${m}${t("resources.minutes")}`; - const percent = Math.round((new Date().getSeconds() / 60) * 100); + const percent = Math.round((new Date().getSeconds() / 60) * 100).toString(); - return - - {uptime} - {t("resources.uptime")} - - ; + return ; } diff --git a/src/components/widgets/widget/resource.jsx b/src/components/widgets/widget/resource.jsx new file mode 100644 index 00000000..e77bcb5a --- /dev/null +++ b/src/components/widgets/widget/resource.jsx @@ -0,0 +1,22 @@ +import UsageBar from "../resources/usage-bar"; + +export default function Resource({ children, icon, value, label, expandedValue, expandedLabel, percentage, key, expanded = false }) { + const Icon = icon; + + return
    + +
    +
    +
    {value}
    +
    {label}
    +
    + { expanded &&
    +
    {expandedValue}
    +
    {expandedLabel}
    +
    + } + { percentage && } + { children } +
    +
    ; +} diff --git a/src/components/widgets/widget/resource_label.jsx b/src/components/widgets/widget/resource_label.jsx deleted file mode 100644 index 87f2ad22..00000000 --- a/src/components/widgets/widget/resource_label.jsx +++ /dev/null @@ -1,5 +0,0 @@ -export default function ResourceLabel({ children }) { - return ( -
    {children}
    - ); -} diff --git a/src/components/widgets/widget/resource_value.jsx b/src/components/widgets/widget/resource_value.jsx deleted file mode 100644 index 8971c748..00000000 --- a/src/components/widgets/widget/resource_value.jsx +++ /dev/null @@ -1,5 +0,0 @@ -export default function ResourceValue({ children }) { - return ( -
    {children}
    - ); -} diff --git a/src/components/widgets/widget/resources.jsx b/src/components/widgets/widget/resources.jsx index 0771ec5e..19fb021d 100644 --- a/src/components/widgets/widget/resources.jsx +++ b/src/components/widgets/widget/resources.jsx @@ -1,5 +1,5 @@ import ContainerLink from "./container_link"; -import SingleResource from "./single_resource"; +import Resource from "./resource"; import Raw from "./raw"; import WidgetLabel from "./widget_label"; @@ -7,9 +7,9 @@ export default function Resources({ options, children, target }) { return
    - {children.filter(child => child && child.type === SingleResource)} + { children.filter(child => child && child.type === Resource) }
    - {children.filter(child => child && child.type === WidgetLabel)} + { children.filter(child => child && child.type === WidgetLabel) }
    ; } diff --git a/src/components/widgets/widget/single_resource.jsx b/src/components/widgets/widget/single_resource.jsx deleted file mode 100644 index 7a83d8be..00000000 --- a/src/components/widgets/widget/single_resource.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import UsageBar from "../resources/usage-bar"; - -import WidgetIcon from "./widget_icon"; -import ResourceValue from "./resource_value"; -import ResourceLabel from "./resource_label"; -import Raw from "./raw"; - -export default function SingleResource({ children, key, expanded = false }) { - const values = children.filter(child => child.type === ResourceValue); - const labels = children.filter(child => child.type === ResourceLabel); - - return
    - {children.find(child => child.type === WidgetIcon)} -
    -
    - {values.pop()} - {labels.pop()} -
    - { expanded &&
    - {values.pop()} - {labels.pop()} -
    - } - {children.find(child => child.type === UsageBar)} -
    - {children.find(child => child.type === Raw)} -
    ; -} From 1622069063691bebefb37202d3383ddfe81b67fb Mon Sep 17 00:00:00 2001 From: Denis Papec Date: Mon, 12 Jun 2023 00:23:01 +0100 Subject: [PATCH 04/50] Fixes for existing header styles, fix for glances Signed-off-by: Denis Papec --- src/components/widgets/glances/glances.jsx | 2 ++ .../widgets/openweathermap/weather.jsx | 3 +-- src/components/widgets/widget/container.jsx | 22 ++++++++++++++----- src/components/widgets/widget/resource.jsx | 4 ++-- src/components/widgets/widget/resources.jsx | 6 +++-- .../widgets/widget/widget_label.jsx | 2 +- src/pages/index.jsx | 11 ++++++---- 7 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/components/widgets/glances/glances.jsx b/src/components/widgets/glances/glances.jsx index b45dfefe..e5cf3fbd 100644 --- a/src/components/widgets/glances/glances.jsx +++ b/src/components/widgets/glances/glances.jsx @@ -36,6 +36,8 @@ export default function Widget({ options }) { { options.cputemp && } + { options.disk && !Array.isArray(options.disk) && } + { options.disk && Array.isArray(options.disk) && options.disk.map((disk) => )} { options.uptime && } { options.label && } ; diff --git a/src/components/widgets/openweathermap/weather.jsx b/src/components/widgets/openweathermap/weather.jsx index 30531513..a857f13a 100644 --- a/src/components/widgets/openweathermap/weather.jsx +++ b/src/components/widgets/openweathermap/weather.jsx @@ -41,8 +41,7 @@ function Widget({ options }) { }; return - {options.label && `${options.label}, `} - {t("common.number", { value: data.main.temp, style: "unit", unit })} + {options.label && `${options.label}, ` }{t("common.number", { value: data.main.temp, style: "unit", unit })} {data.weather[0].description} ; diff --git a/src/components/widgets/widget/container.jsx b/src/components/widgets/widget/container.jsx index 3a4a9f57..59ea5684 100644 --- a/src/components/widgets/widget/container.jsx +++ b/src/components/widgets/widget/container.jsx @@ -6,10 +6,22 @@ import SecondaryText from "./secondary_text"; import Raw from "./raw"; export function getAllClasses(options, additionalClassNames = '') { + if (options?.style?.header === "boxedWidgets") { + return classNames( + "flex flex-col justify-center first:ml-0 ml-2 mr-2", + "mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3 pr-3", + additionalClassNames + ); + } + + let widgetAlignedClasses = "flex flex-col max-w:full sm:basis-auto self-center grow-0 flex-wrap"; + if (options?.style?.isRightAligned) { + widgetAlignedClasses = "flex flex-col justify-center first:ml-auto ml-2 mr-2 "; + } + return classNames( - "flex flex-col justify-center first:ml-0 ml-4 mr-2", - additionalClassNames, - options?.style === "boxedWidgets" && " ml-4 mt-2 m:mb-0 rounded-md shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 dark:bg-white/5 p-2 pl-3", + widgetAlignedClasses, + additionalClassNames ); } @@ -18,8 +30,8 @@ export function getInnerBlock(children) { return Array.isArray(children) &&
    {children.find(child => child.type === WidgetIcon)}
    - {children.find(child => child.type === PrimaryText)} - {children.find(child => child.type === SecondaryText)} + {children.find(child => child.type === PrimaryText)} + {children.find(child => child.type === SecondaryText)}
    ; } diff --git a/src/components/widgets/widget/resource.jsx b/src/components/widgets/widget/resource.jsx index e77bcb5a..18e7c800 100644 --- a/src/components/widgets/widget/resource.jsx +++ b/src/components/widgets/widget/resource.jsx @@ -1,9 +1,9 @@ import UsageBar from "../resources/usage-bar"; -export default function Resource({ children, icon, value, label, expandedValue, expandedLabel, percentage, key, expanded = false }) { +export default function Resource({ children, icon, value, label, expandedValue = "", expandedLabel = "", percentage, expanded = false }) { const Icon = icon; - return
    + return
    diff --git a/src/components/widgets/widget/resources.jsx b/src/components/widgets/widget/resources.jsx index 19fb021d..394a3058 100644 --- a/src/components/widgets/widget/resources.jsx +++ b/src/components/widgets/widget/resources.jsx @@ -4,12 +4,14 @@ import Raw from "./raw"; import WidgetLabel from "./widget_label"; export default function Resources({ options, children, target }) { + const widgetParts = [].concat(...children); + return
    - { children.filter(child => child && child.type === Resource) } + { widgetParts.filter(child => child && child.type === Resource) }
    - { children.filter(child => child && child.type === WidgetLabel) } + { widgetParts.filter(child => child && child.type === WidgetLabel) }
    ; } diff --git a/src/components/widgets/widget/widget_label.jsx b/src/components/widgets/widget/widget_label.jsx index dcb9b9e9..5fc6ced0 100644 --- a/src/components/widgets/widget/widget_label.jsx +++ b/src/components/widgets/widget/widget_label.jsx @@ -1,3 +1,3 @@ export default function WidgetLabel({ label = "" }) { - return
    {label}
    + return
    {label}
    } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 7611aed5..d91a8339 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -274,14 +274,17 @@ function Home({ initialSettings }) { {widgets .filter((widget) => !rightAlignedWidgets.includes(widget.type)) .map((widget, i) => ( - + ))} -
    +
    {widgets .filter((widget) => rightAlignedWidgets.includes(widget.type)) .map((widget, i) => ( - + ))}
    @@ -361,7 +364,7 @@ export default function Wrapper({ initialSettings, fallback }) { style={wrappedStyle} >
    Date: Tue, 13 Jun 2023 21:02:06 +0200 Subject: [PATCH 05/50] Fixes #1606 --- src/utils/config/service-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index d4f7bc4e..fb47951a 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -158,7 +158,7 @@ export async function servicesFromKubernetes() { return null; }); - const traefikIngressList = await crd.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes") + const traefikIngressList = await crd.listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes") .then((response) => response.body) .catch((error) => { logger.error("Error getting traefik ingresses: %d %s %s", error.statusCode, error.body, error.response); From f1d6a990ac0eeb538a853e5965e646ce124522b9 Mon Sep 17 00:00:00 2001 From: Karl Hudgell Date: Tue, 13 Jun 2023 20:30:09 +0100 Subject: [PATCH 06/50] Working Jdownloader --- public/locales/en/common.json | 5 + src/widgets/components.js | 3 +- src/widgets/jdownloader/component.jsx | 37 +++++ src/widgets/jdownloader/proxy.js | 191 ++++++++++++++++++++++++++ src/widgets/jdownloader/tools.js | 55 ++++++++ src/widgets/jdownloader/widget.js | 15 ++ src/widgets/widgets.js | 2 + 7 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 src/widgets/jdownloader/component.jsx create mode 100644 src/widgets/jdownloader/proxy.js create mode 100644 src/widgets/jdownloader/tools.js create mode 100644 src/widgets/jdownloader/widget.js diff --git a/public/locales/en/common.json b/public/locales/en/common.json index c90287da..437088bd 100755 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -653,5 +653,10 @@ "whatsupdocker": { "monitoring": "Monitoring", "updates": "Updates" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } diff --git a/src/widgets/components.js b/src/widgets/components.js index 589a93ad..97760d36 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -31,6 +31,7 @@ const components = { healthchecks: dynamic(() => import("./healthchecks/component")), immich: dynamic(() => import("./immich/component")), jackett: dynamic(() => import("./jackett/component")), + jdownloader: dynamic(() => import("./jdownloader/component")), jellyfin: dynamic(() => import("./emby/component")), jellyseerr: dynamic(() => import("./jellyseerr/component")), komga: dynamic(() => import("./komga/component")), @@ -91,4 +92,4 @@ const components = { xteve: dynamic(() => import("./xteve/component")), }; -export default components; +export default components; \ No newline at end of file diff --git a/src/widgets/jdownloader/component.jsx b/src/widgets/jdownloader/component.jsx new file mode 100644 index 00000000..d8fea9ca --- /dev/null +++ b/src/widgets/jdownloader/component.jsx @@ -0,0 +1,37 @@ +import { useTranslation } from "next-i18next"; + +import Block from "components/services/widget/block"; +import Container from "components/services/widget/container"; +import useWidgetAPI from "utils/proxy/use-widget-api"; + +export default function Component({ service }) { + const { t } = useTranslation(); + + const { widget } = service; + + const { data: jdownloaderData, error: jdownloaderAPIError } = useWidgetAPI(widget, "unified", { + refreshInterval: 30000, + }); + + if (jdownloaderAPIError) { + return ; + } + + if (!jdownloaderData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} \ No newline at end of file diff --git a/src/widgets/jdownloader/proxy.js b/src/widgets/jdownloader/proxy.js new file mode 100644 index 00000000..353192ac --- /dev/null +++ b/src/widgets/jdownloader/proxy.js @@ -0,0 +1,191 @@ +/* eslint-disable no-underscore-dangle */ +import crypto from 'crypto'; +import querystring from 'querystring'; + +import { sha256, uniqueRid, validateRid, createEncryptionToken, decrypt, encrypt } from "./tools" + +import getServiceWidget from "utils/config/service-helpers"; +import { httpProxy } from "utils/proxy/http"; +import createLogger from "utils/logger"; + +const proxyName = "jdownloaderProxyHandler"; +const logger = createLogger(proxyName); + +async function getWidget(req) { + const { group, service } = req.query; + if (!group || !service) { + logger.debug("Invalid or missing service '%s' or group '%s'", service, group); + return null; + } + const widget = await getServiceWidget(group, service); + if (!widget) { + logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); + return null; + } + + return widget; +} + +async function login(loginSecret, deviceSecret, params) { + const rid = uniqueRid(); + const path = `/my/connect?${querystring.stringify({...params, rid})}`; + + const signature = crypto + .createHmac('sha256', loginSecret) + .update(path) + .digest('hex'); + const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}` + + const [status, contentType, data] = await httpProxy(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (status !== 200) { + logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString()); + return [status, data]; + } + + try { + const decryptedData = JSON.parse(decrypt(data.toString(), loginSecret)) + const sessionToken = decryptedData.sessiontoken; + validateRid(decryptedData, rid); + const serverEncryptionToken = createEncryptionToken(loginSecret, sessionToken); + const deviceEncryptionToken = createEncryptionToken(deviceSecret, sessionToken); + return [status, decryptedData, contentType, serverEncryptionToken, deviceEncryptionToken, sessionToken]; + } catch (e) { + logger.error("Error decoding jdownloader API data. Data: %s", data.toString()); + return [status, null]; + } +} + + +async function getDevice(serverEncryptionToken, deviceName, params) { + const rid = uniqueRid(); + const path = `/my/listdevices?${querystring.stringify({...params, rid})}`; + const signature = crypto + .createHmac('sha256', serverEncryptionToken) + .update(path) + .digest('hex'); + const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}` + + const [status, , data] = await httpProxy(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (status !== 200) { + logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString()); + return [status, data]; + } + + try { + const decryptedData = JSON.parse(decrypt(data.toString(), serverEncryptionToken)) + const filteredDevice = decryptedData.list.filter(device => device.name === deviceName); + return [status, filteredDevice[0].id]; + } catch (e) { + logger.error("Error decoding jdownloader API data. Data: %s", data.toString()); + return [status, null]; + } + +} + +function createBody(rid, query, params) { + const baseBody = { + apiVer: 1, + rid, + url: query + }; + return params ? {...baseBody, params: [JSON.stringify(params)] } : baseBody; +} + +async function queryPackages(deviceEncryptionToken, deviceId, sessionToken, params) { + const rid = uniqueRid(); + const body = encrypt(JSON.stringify(createBody(rid, '/downloadsV2/queryPackages', params)), deviceEncryptionToken); + const url = `${new URL(`https://api.jdownloader.org/t_${encodeURI(sessionToken)}_${encodeURI(deviceId)}/downloadsV2/queryPackages`)}` + const [status, , data] = await httpProxy(url, { + method: 'POST', + body, + }); + + if (status !== 200) { + logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString()); + return [status, data]; + } + + try { + const decryptedData = JSON.parse(decrypt(data.toString(), deviceEncryptionToken)) + return decryptedData.data; + } catch (e) { + logger.error("Error decoding JDRss jdownloader data. Data: %s", data.toString()); + return [status, null]; + } + +} + + +export default async function jdownloaderProxyHandler(req, res) { + const widget = await getWidget(req); + + if (!widget) { + return res.status(400).json({ error: "Invalid proxy service type" }); + } + logger.debug("Getting data from JDRss API"); + const {username} = widget + const {password} = widget + + const appKey = "homepage" + const loginSecret = sha256(`${username}${password}server`) + const deviceSecret = sha256(`${username}${password}device`) + const email = username; + + const loginData = await login(loginSecret, deviceSecret, { + appKey, + email + }) + + const deviceData = await getDevice(loginData[3], widget.client, { + sessiontoken: loginData[5] + }) + + const packageStatus = await queryPackages(loginData[4], deviceData[1], loginData[5], { + "bytesLoaded": false, + "bytesTotal": true, + "comment": false, + "enabled": true, + "eta": false, + "priority": false, + "finished": true, + "running": true, + "speed": true, + "status": true, + "childCount": false, + "hosts": false, + "saveTo": false, + "maxResults": -1, + "startAt": 0, + } + ) + + let totalBytes = 0; + let totalSpeed = 0; + packageStatus.forEach(file => { + totalBytes += file.bytesTotal; + if (file.speed) { + totalSpeed += file.speed; + } + }); + + const data = { + downloadCount: packageStatus.length, + totalBytes, + totalSpeed + }; + + return res.send(data); + +} \ No newline at end of file diff --git a/src/widgets/jdownloader/tools.js b/src/widgets/jdownloader/tools.js new file mode 100644 index 00000000..d678b072 --- /dev/null +++ b/src/widgets/jdownloader/tools.js @@ -0,0 +1,55 @@ +import crypto from 'crypto'; + +export function sha256(data) { + return crypto + .createHash('sha256') + .update(data) + .digest(); +} + +export function uniqueRid() { + return Math.floor(Math.random() * 10e12); +} + +export function validateRid(decryptedData, rid) { + if (decryptedData.rid !== rid) { + throw new Error('RequestID mismatch'); + } + return decryptedData; + +} + +export function decrypt(data, ivKey) { + const iv = ivKey.slice(0, ivKey.length / 2); + const key = ivKey.slice(ivKey.length / 2, ivKey.length); + const cipher = crypto.createDecipheriv('aes-128-cbc', key, iv); + return Buffer.concat([ + cipher.update(data, 'base64'), + cipher.final() + ]).toString(); +} + +export function createEncryptionToken(oldTokenBuff, updateToken) { + const updateTokenBuff = Buffer.from(updateToken, 'hex'); + const mergedBuffer = Buffer.concat([oldTokenBuff, updateTokenBuff], oldTokenBuff.length + updateTokenBuff.length); + return sha256(mergedBuffer); +} + +export function encrypt(data, ivKey) { + if (typeof data !== 'string') { + throw new Error('data no es un string'); + } + if (!(ivKey instanceof Buffer)) { + throw new Error('ivKey no es un buffer'); + } + if (ivKey.length !== 32) { + throw new Error('ivKey tiene que tener tamaño 32'); + } + const stringIVKey = ivKey.toString('hex'); + const stringIV = stringIVKey.substring(0, stringIVKey.length / 2); + const stringKey = stringIVKey.substring(stringIVKey.length / 2, stringIVKey.length); + const iv = Buffer.from(stringIV, 'hex'); + const key = Buffer.from(stringKey, 'hex'); + const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); + return cipher.update(data, 'utf8', 'base64') + cipher.final('base64'); +} \ No newline at end of file diff --git a/src/widgets/jdownloader/widget.js b/src/widgets/jdownloader/widget.js new file mode 100644 index 00000000..acd25d74 --- /dev/null +++ b/src/widgets/jdownloader/widget.js @@ -0,0 +1,15 @@ +import jdownloaderProxyHandler from "./proxy"; + +const widget = { + api: "https://api.jdownloader.org/{endpoint}/&signature={signature}", + proxyHandler: jdownloaderProxyHandler, + + mappings: { + unified: { + endpoint: "/", + signature: "", + }, + }, +}; + +export default widget; \ No newline at end of file diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index f843a168..86c4266f 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -27,6 +27,7 @@ import healthchecks from "./healthchecks/widget"; import immich from "./immich/widget"; import jackett from "./jackett/widget"; import jellyseerr from "./jellyseerr/widget"; +import jdownloader from "./jdownloader/widget"; import komga from "./komga/widget"; import kopia from "./kopia/widget"; import lidarr from "./lidarr/widget"; @@ -113,6 +114,7 @@ const widgets = { healthchecks, immich, jackett, + jdownloader, jellyfin: emby, jellyseerr, komga, From 4a97fce841aea990b523f6ebb9abd47940d05026 Mon Sep 17 00:00:00 2001 From: Dan5py Date: Tue, 13 Jun 2023 22:04:56 +0200 Subject: [PATCH 07/50] Support old traefik CRD group --- src/utils/config/service-helpers.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index fb47951a..f73a3f3b 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -160,9 +160,18 @@ export async function servicesFromKubernetes() { const traefikIngressList = await crd.listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes") .then((response) => response.body) - .catch((error) => { - logger.error("Error getting traefik ingresses: %d %s %s", error.statusCode, error.body, error.response); - return null; + .catch(async (error) => { + logger.error("Error getting traefik ingresses from traefik.io: %d %s %s", error.statusCode, error.body, error.response); + + // Fallback to the old traefik CRD group + const fallbackIngressList = await crd.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes") + .then((response) => response.body) + .catch((fallbackError) => { + logger.error("Error getting traefik ingresses from traefik.containo.us: %d %s %s", fallbackError.statusCode, fallbackError.body, fallbackError.response); + return null; + }); + + return fallbackIngressList; }); if (traefikIngressList && traefikIngressList.items.length > 0) { From 3ee6650e6d55d5ff78a1b407c05a6db6ebf4911d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:16:49 -0700 Subject: [PATCH 08/50] fix homebridge proxy logging --- src/widgets/homebridge/proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/homebridge/proxy.js b/src/widgets/homebridge/proxy.js index b0a75a03..a9e1ac97 100644 --- a/src/widgets/homebridge/proxy.js +++ b/src/widgets/homebridge/proxy.js @@ -63,7 +63,7 @@ async function apiCall(widget, endpoint, service) { } if (status !== 200) { - logger.error("Error getting data from Homebridge: %s status %d. Data: %s", url, status, data); + logger.error("Error getting data from Homebridge: %s status %d. Data: %s", url, status, JSON.stringify(data)); return { status, contentType, data: null, responseHeaders }; } From abcea88d0a0381db7aaedcd5aaa2444560967df6 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:23:19 -0700 Subject: [PATCH 09/50] Try to handle zlib errors --- src/utils/proxy/http.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index f869cd0b..3c637427 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -33,6 +33,13 @@ function handleRequest(requestor, url, params) { const contentEncoding = response.headers['content-encoding']?.trim().toLowerCase(); let responseContent = response; + + // zlib errors + responseContent.on("error", (e) => { + logger.error(e); + responseContent = response; // fallback + }); + if (contentEncoding === 'gzip' || contentEncoding === 'deflate') { responseContent = createUnzip(); response.pipe(responseContent); From b437ccde2fee407b8709106f38b28a13ff1da2c7 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 13 Jun 2023 19:21:12 -0700 Subject: [PATCH 10/50] Another attempt to catch zlib decompression errors --- src/utils/proxy/http.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index 3c637427..72f65be3 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -33,15 +33,13 @@ function handleRequest(requestor, url, params) { const contentEncoding = response.headers['content-encoding']?.trim().toLowerCase(); let responseContent = response; - - // zlib errors - responseContent.on("error", (e) => { - logger.error(e); - responseContent = response; // fallback - }); - if (contentEncoding === 'gzip' || contentEncoding === 'deflate') { responseContent = createUnzip(); + // zlib errors + responseContent.on("error", (e) => { + logger.error(e); + responseContent = response; // fallback + }); response.pipe(responseContent); } From 3f25df954fc3dce6b003b9660c1c604931bef991 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:53 +0000 Subject: [PATCH 11/50] Translated using Weblate (German) Currently translated at 97.6% (457 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/de/ --- public/locales/de/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/de/common.json b/public/locales/de/common.json index dc06f5d3..76ec612f 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -644,5 +644,10 @@ "connected": "Verbunden", "new_devices": "Neue Geräte", "down_alerts": "Down Alarme" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 250b1a3c53d1293e59042c936c0c2f9cc1c1b951 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:54 +0000 Subject: [PATCH 12/50] Translated using Weblate (Spanish) Currently translated at 99.3% (465 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/es/ --- public/locales/es/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 32fa7e6e..c3e0d857 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -644,5 +644,10 @@ "connected": "Conectado", "new_devices": "Nuevos dispositivos", "down_alerts": "Alertas" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 1e7a2cbbc4afc08bee60af9d3e3c5e775a8b1420 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:54 +0000 Subject: [PATCH 13/50] Translated using Weblate (French) Currently translated at 99.3% (465 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fr/ --- public/locales/fr/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 985f3747..e33601a8 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -644,5 +644,10 @@ "connected": "Connecté", "new_devices": "Nouvel Appareil", "down_alerts": "Alertes" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 28335ca3afcf855adef3e4ab4b538103f23b8a4c Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:54 +0000 Subject: [PATCH 14/50] Translated using Weblate (Portuguese) Currently translated at 88.6% (415 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt/ --- public/locales/pt/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index ab38ab2f..84b2cc7c 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -653,5 +653,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 8d41834c2a124621b31dc9169ac02aeff1c6c88d Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:48 +0000 Subject: [PATCH 15/50] Translated using Weblate (Russian) Currently translated at 88.2% (413 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ru/ --- public/locales/ru/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index f89313db..8c1e2853 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From a6a9180aa021ca9512ec02fb1ff33ad90d8ba733 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:48 +0000 Subject: [PATCH 16/50] Translated using Weblate (Chinese (Simplified)) Currently translated at 94.6% (443 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hans/ --- public/locales/zh-CN/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index 50e36395..beac59df 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 1582ba94384323b0aaa27ad6d0ca42bf8697b3f7 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:45 +0000 Subject: [PATCH 17/50] Translated using Weblate (Italian) Currently translated at 61.1% (286 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/it/ --- public/locales/it/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/it/common.json b/public/locales/it/common.json index 2e666af4..ed9a140b 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 9a6a580953737d26424037fc042d5aa7d0576bdc Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:45 +0000 Subject: [PATCH 18/50] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 16.8% (79 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nb_NO/ --- public/locales/nb-NO/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/nb-NO/common.json b/public/locales/nb-NO/common.json index cdcda4a8..4bf6b86c 100644 --- a/public/locales/nb-NO/common.json +++ b/public/locales/nb-NO/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 03ba36c59397f43a4623ce3bad9b6f5934ddc4c2 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:46 +0000 Subject: [PATCH 19/50] Translated using Weblate (Vietnamese) Currently translated at 9.4% (44 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/vi/ --- public/locales/vi/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index ef39cd2d..71310254 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 368032c931f6a4b2036c5a3114509dfcf9672fc7 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:46 +0000 Subject: [PATCH 20/50] Translated using Weblate (Dutch) Currently translated at 51.4% (241 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/ --- public/locales/nl/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index 2afed425..087ee1c9 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 8cc044544ee2ba3db02f7254773ecb299e5013b9 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:50 +0000 Subject: [PATCH 21/50] Translated using Weblate (Chinese (Traditional)) Currently translated at 98.2% (460 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/zh_Hant/ --- public/locales/zh-Hant/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/zh-Hant/common.json b/public/locales/zh-Hant/common.json index 75aff10e..c208f0bc 100644 --- a/public/locales/zh-Hant/common.json +++ b/public/locales/zh-Hant/common.json @@ -644,5 +644,10 @@ "connected": "已連線", "new_devices": "新裝置", "down_alerts": "離線警告" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From ae1d7e0866aa01465c790372aaa63bdf3165f4bc Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:47 +0000 Subject: [PATCH 22/50] Translated using Weblate (Catalan) Currently translated at 55.5% (260 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ca/ --- public/locales/ca/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json index 41391cd5..aaa9f4a5 100644 --- a/public/locales/ca/common.json +++ b/public/locales/ca/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From e0a6a88ba1a46e1c8a5d6854c8bc9914dc64a3cb Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:40 +0000 Subject: [PATCH 23/50] Translated using Weblate (Polish) Currently translated at 79.9% (374 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pl/ --- public/locales/pl/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json index d43f9859..b8f8d997 100644 --- a/public/locales/pl/common.json +++ b/public/locales/pl/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From f92c5aa1e3978229a8a7d3a7a3b659849c156ef7 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:47 +0000 Subject: [PATCH 24/50] Translated using Weblate (Swedish) Currently translated at 27.7% (130 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sv/ --- public/locales/sv/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json index 962a57be..4a67136b 100644 --- a/public/locales/sv/common.json +++ b/public/locales/sv/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From f3176a25ad7b61cab48ed605b39462fbf9d86399 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:49 +0000 Subject: [PATCH 25/50] Translated using Weblate (Croatian) Currently translated at 97.8% (458 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hr/ --- public/locales/hr/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/hr/common.json b/public/locales/hr/common.json index 9a05a55c..e2f2dab6 100644 --- a/public/locales/hr/common.json +++ b/public/locales/hr/common.json @@ -644,5 +644,10 @@ "connected": "Povezano", "new_devices": "Novi uređaji", "down_alerts": "Obavijest o rušenju" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 9d2df383917777262301ca681a58b50de656ccbb Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:52 +0000 Subject: [PATCH 26/50] Translated using Weblate (Hungarian) Currently translated at 22.8% (107 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hu/ --- public/locales/hu/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/hu/common.json b/public/locales/hu/common.json index a8218e73..89d010ba 100644 --- a/public/locales/hu/common.json +++ b/public/locales/hu/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadSpeed": "Download Speed", + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size" } } From 1021e562d8af1fd4b41befd314dd273e733b8546 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:51 +0000 Subject: [PATCH 27/50] Translated using Weblate (Hebrew) Currently translated at 21.3% (100 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/he/ --- public/locales/he/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/he/common.json b/public/locales/he/common.json index dfe2cb84..b8392aed 100644 --- a/public/locales/he/common.json +++ b/public/locales/he/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 26cff34634c4cd1e34707af26e88e0e94b2ba1bc Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:50 +0000 Subject: [PATCH 28/50] Translated using Weblate (Romanian) Currently translated at 32.0% (150 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ro/ --- public/locales/ro/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ro/common.json b/public/locales/ro/common.json index 3ca5004e..f0529f63 100644 --- a/public/locales/ro/common.json +++ b/public/locales/ro/common.json @@ -644,5 +644,10 @@ "down_alerts": "Down Alerts", "total": "Total", "connected": "Connected" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 452d36c158626c35e2374dbc7fc3030e69bb28ff Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:49 +0000 Subject: [PATCH 29/50] Translated using Weblate (Portuguese (Brazil)) Currently translated at 86.3% (404 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/pt_BR/ --- public/locales/pt-BR/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/pt-BR/common.json b/public/locales/pt-BR/common.json index 716ac875..a0955eac 100644 --- a/public/locales/pt-BR/common.json +++ b/public/locales/pt-BR/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From fd93df77aa5f37343facc3b052492c6ac5036a8f Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:57 +0000 Subject: [PATCH 30/50] Translated using Weblate (Yue (Traditional)) Currently translated at 25.0% (117 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/yue_Hant/ --- public/locales/yue/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/yue/common.json b/public/locales/yue/common.json index 73e5998b..c3090694 100644 --- a/public/locales/yue/common.json +++ b/public/locales/yue/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From f3a7c1164babf2d7ddc555045b76a3b08f71cdb8 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:55 +0000 Subject: [PATCH 31/50] Translated using Weblate (Finnish) Currently translated at 37.8% (177 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/fi/ --- public/locales/fi/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index f403b6d4..cb727d6f 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From a6320bc794a31bbee40d7a694de48b246fbf748c Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:55 +0000 Subject: [PATCH 32/50] Translated using Weblate (Telugu) Currently translated at 45.9% (215 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/te/ --- public/locales/te/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/te/common.json b/public/locales/te/common.json index 3d0deb15..357040b4 100644 --- a/public/locales/te/common.json +++ b/public/locales/te/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 91b828e97cda33b0dfd0d33577f6cd0dea9660d2 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:56 +0000 Subject: [PATCH 33/50] Translated using Weblate (Bulgarian) Currently translated at 9.8% (46 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/bg/ --- public/locales/bg/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index bb6bacbb..25757852 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From f3708189ef74bfe717753d2b5331d8a67c26f505 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:56 +0000 Subject: [PATCH 34/50] Translated using Weblate (Turkish) Currently translated at 83.9% (393 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/tr/ --- public/locales/tr/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json index 09639f67..654d1f74 100644 --- a/public/locales/tr/common.json +++ b/public/locales/tr/common.json @@ -644,5 +644,10 @@ "connected": "Bağlandı", "new_devices": "Yeni Cihazlar", "down_alerts": "Düşme Uyarıları" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 211c723f04f042c4b3bed0ca5a1b7d0d5f09ba5f Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:51 +0000 Subject: [PATCH 35/50] Translated using Weblate (Serbian) Currently translated at 1.9% (9 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sr/ --- public/locales/sr/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/sr/common.json b/public/locales/sr/common.json index 8ce72d5c..77ee5d8e 100644 --- a/public/locales/sr/common.json +++ b/public/locales/sr/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 543573fbdb59d79f7f1a0a83151b95283df755ef Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:51 +0000 Subject: [PATCH 36/50] Translated using Weblate (Arabic) Currently translated at 55.5% (260 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ar/ --- public/locales/ar/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ar/common.json b/public/locales/ar/common.json index 7f118dc1..c611852a 100644 --- a/public/locales/ar/common.json +++ b/public/locales/ar/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 0f6a4c624c90cf67366214cc2501ec482bbe89a5 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:43 +0000 Subject: [PATCH 37/50] Translated using Weblate (Czech) Currently translated at 94.8% (444 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/cs/ --- public/locales/cs/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/cs/common.json b/public/locales/cs/common.json index 940ec67e..690591fb 100644 --- a/public/locales/cs/common.json +++ b/public/locales/cs/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadSpeed": "Download Speed", + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size" } } From 626d636aaecbe5a4ce9e6e689d369f3e554ae512 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:41 +0000 Subject: [PATCH 38/50] Translated using Weblate (Danish) Currently translated at 42.0% (197 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/da/ --- public/locales/da/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/da/common.json b/public/locales/da/common.json index d1c41aaa..f2fa88e6 100644 --- a/public/locales/da/common.json +++ b/public/locales/da/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadSpeed": "Download Speed", + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size" } } From a8d130d5cb6f1e42c541495bbe2c3fb6bcafe591 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:41 +0000 Subject: [PATCH 39/50] Translated using Weblate (Malay) Currently translated at 53.6% (251 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ms/ --- public/locales/ms/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ms/common.json b/public/locales/ms/common.json index e249cf43..aaf65d0d 100644 --- a/public/locales/ms/common.json +++ b/public/locales/ms/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 3d19d65cb62ecf96b31d5d3a545840ebdd87e644 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:42 +0000 Subject: [PATCH 40/50] Translated using Weblate (Hindi) Currently translated at 1.9% (9 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/hi/ --- public/locales/hi/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index 623775c2..f5bf9e2b 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From d353166b59496f6ed1c74ea03e0f08054eeba06e Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:43 +0000 Subject: [PATCH 41/50] Translated using Weblate (Esperanto) Currently translated at 30.9% (145 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/eo/ --- public/locales/eo/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/eo/common.json b/public/locales/eo/common.json index 4ed593be..596aefb3 100644 --- a/public/locales/eo/common.json +++ b/public/locales/eo/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 3d1b18f66029cb599fdb92eafbcfc37f6c595ae6 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:42 +0000 Subject: [PATCH 42/50] Translated using Weblate (Ukrainian) Currently translated at 99.3% (465 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/uk/ --- public/locales/uk/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/uk/common.json b/public/locales/uk/common.json index 1e1ac9b4..62db97ec 100644 --- a/public/locales/uk/common.json +++ b/public/locales/uk/common.json @@ -644,5 +644,10 @@ "connected": "Підключено", "new_devices": "Нові пристрої", "down_alerts": "Сповіщення про збій" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 3423bbc0ee4275841d4c0afbf7dfc449d464eacd Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:42 +0000 Subject: [PATCH 43/50] Translated using Weblate (Japanese) Currently translated at 82.0% (384 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ja/ --- public/locales/ja/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index 72d7d8ae..d10e70e1 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From fb7f32589bb5d3e32634446cb90cc683fac6ff91 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:44 +0000 Subject: [PATCH 44/50] Translated using Weblate (Latvian) Currently translated at 25.2% (118 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/lv/ --- public/locales/lv/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/lv/common.json b/public/locales/lv/common.json index d8d63388..47d619dd 100644 --- a/public/locales/lv/common.json +++ b/public/locales/lv/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From f00e26f7ab754cbc6ab4b6b4453414c19ef4e26e Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:38 +0000 Subject: [PATCH 45/50] Translated using Weblate (Thai) Currently translated at 10.0% (47 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/th/ --- public/locales/th/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/th/common.json b/public/locales/th/common.json index 3981f0f8..d77b8c32 100644 --- a/public/locales/th/common.json +++ b/public/locales/th/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 622255d2eca47a88cd401dfc6895db5f960c9726 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:52 +0000 Subject: [PATCH 46/50] Translated using Weblate (Slovak) Currently translated at 1.9% (9 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sk/ --- public/locales/sk/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/sk/common.json b/public/locales/sk/common.json index ee08f212..5826ee4c 100644 --- a/public/locales/sk/common.json +++ b/public/locales/sk/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From dbfa14cb51300713a1ce923c8770faee27950e46 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:53 +0000 Subject: [PATCH 47/50] Translated using Weblate (Korean) Currently translated at 36.9% (173 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/ko/ --- public/locales/ko/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/ko/common.json b/public/locales/ko/common.json index 6a58072f..456953a8 100644 --- a/public/locales/ko/common.json +++ b/public/locales/ko/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "down_alerts": "Down Alerts", "new_devices": "New Devices" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From c5b044d196bf4606ecb79343d6ec0e717d203979 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:39 +0000 Subject: [PATCH 48/50] Translated using Weblate (Greek) Currently translated at 30.5% (143 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/el/ --- public/locales/el/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/el/common.json b/public/locales/el/common.json index 3492bdd1..ab26247c 100644 --- a/public/locales/el/common.json +++ b/public/locales/el/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 315bda6ba1cb0c191eeee05c0f7d41a4860df6b4 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:44 +0000 Subject: [PATCH 49/50] Translated using Weblate (Slovenian) Currently translated at 95.9% (449 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sl/ --- public/locales/sl/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/sl/common.json b/public/locales/sl/common.json index fe5fe631..ef4e4109 100644 --- a/public/locales/sl/common.json +++ b/public/locales/sl/common.json @@ -644,5 +644,10 @@ "connected": "Connected", "new_devices": "New Devices", "down_alerts": "Down Alerts" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } } From 2807575283c6ad8958a48f0629c1ebc5315e4f41 Mon Sep 17 00:00:00 2001 From: Anonymous Date: Wed, 14 Jun 2023 03:46:40 +0000 Subject: [PATCH 50/50] Translated using Weblate (Indonesian) Currently translated at 3.2% (15 of 468 strings) Translation: Homepage/Homepage Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/id/ --- public/locales/id/common.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/locales/id/common.json b/public/locales/id/common.json index d54218c4..c0bb65d1 100644 --- a/public/locales/id/common.json +++ b/public/locales/id/common.json @@ -644,5 +644,10 @@ "transcoding": "Transcoding", "bitrate": "Bitrate", "no_active": "No Active Streams" + }, + "jdownloader": { + "downloadCount": "Queue Count", + "downloadQueueSize": "Queue Size", + "downloadSpeed": "Download Speed" } }