Merge branch 'gethomepage:dev' into integration

This commit is contained in:
djeinstine 2024-12-22 08:50:54 +01:00 committed by GitHub
commit 797cc52359
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
70 changed files with 337 additions and 242 deletions

View File

@ -1,3 +1,14 @@
<!--
==== STOP ====================
======== STOP ================
============ STOP ============
================ STOP ========
==================== STOP ====
⚠️ Before opening this pull request please review the guidelines in the checklist below.
If this PR does not meet those guidelines it will not be accepted, and everyone will be sad.
-->
## Proposed change ## Proposed change
<!-- <!--

View File

@ -118,7 +118,7 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
push: ${{ github.event_name != 'pull_request' && !(github.event_name == 'push' && startsWith(github.ref, 'refs/heads/feature')) }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: | build-args: |

View File

@ -212,9 +212,9 @@ jobs:
} }
const CUTOFF_1_DAYS = 180; const CUTOFF_1_DAYS = 180;
const CUTOFF_1_COUNT = 5; const CUTOFF_1_COUNT = 10;
const CUTOFF_2_DAYS = 365; const CUTOFF_2_DAYS = 365;
const CUTOFF_2_COUNT = 10; const CUTOFF_2_COUNT = 20;
const cutoff1Date = new Date(); const cutoff1Date = new Date();
cutoff1Date.setDate(cutoff1Date.getDate() - CUTOFF_1_DAYS); cutoff1Date.setDate(cutoff1Date.getDate() - CUTOFF_1_DAYS);

View File

@ -210,7 +210,7 @@ rules:
- get - get
- list - list
- apiGroups: - apiGroups:
- traefik.containo.us - traefik.io
resources: resources:
- ingressroutes - ingressroutes
verbs: verbs:

View File

@ -55,7 +55,7 @@ self-hosted / open-source alternative, we ask that any widgets, etc. are develop
To ensure cohesiveness of various widgets, the following should be used as a guide for developing new widgets: To ensure cohesiveness of various widgets, the following should be used as a guide for developing new widgets:
- Please only submit widgets that target a feature request discussion with at least 10 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users. - Please only submit widgets that target a feature request discussion with at least 20 'up-votes'. The purpose of this requirement is to avoid the addition (and maintenance) of service widgets that might only benefit a small number of users.
- Note that we reserve the right to decline widgets for projects that are very young (eg < ~1y) or those with a small reach (eg low GitHub stars). Again, this is in an effort to keep overall widget maintenance under control. - Note that we reserve the right to decline widgets for projects that are very young (eg < ~1y) or those with a small reach (eg low GitHub stars). Again, this is in an effort to keep overall widget maintenance under control.
- Widgets should be only one row of blocks - Widgets should be only one row of blocks
- Widgets should be no more than 4 blocks wide and generally conform to the styling / design choices of other widgets - Widgets should be no more than 4 blocks wide and generally conform to the styling / design choices of other widgets

View File

@ -12,6 +12,11 @@ The `systemID` in the `id` field on the collections page of Beszel.
Allowed fields for 'overview' mode: `["systems", "up"]` Allowed fields for 'overview' mode: `["systems", "up"]`
Allowed fields for a single system: `["name", "status", "updated", "cpu", "memory", "disk", "network"]` Allowed fields for a single system: `["name", "status", "updated", "cpu", "memory", "disk", "network"]`
| Beszel Version | Homepage Widget Version |
| -------------- | ----------------------- |
| < 0.9.0 | 1 (default) |
| >= 0.9.0 | 2 |
```yaml ```yaml
widget: widget:
type: beszel type: beszel
@ -19,4 +24,5 @@ widget:
username: username # email username: username # email
password: password password: password
systemId: systemId # optional systemId: systemId # optional
version: 2 # optional, default is 1
``` ```

View File

@ -14,4 +14,5 @@ widget:
type: deluge type: deluge
url: http://deluge.host.or.ip url: http://deluge.host.or.ip
password: password # webui password password: password # webui password
enableLeechProgress: true # optional, defaults to false
``` ```

View File

@ -16,5 +16,6 @@ To group both `offline` and `unknown` devices together, users should use the `of
widget: widget:
type: esphome type: esphome
url: http://esphome.host.or.ip:port url: http://esphome.host.or.ip:port
key: myesphomecookie # only if auth enabled, get the value from a request from the frontend e.g. `authenticated=myesphomecookie` username: myesphomeuser # only if auth enabled
password: myesphomepass # only if auth enabled
``` ```

View File

@ -14,6 +14,7 @@ Allowed fields: `["name", "address", "last_seen", "status"]`.
```yaml ```yaml
widget: widget:
type: headscale type: headscale
url: http://headscale.host.or.ip:port
nodeId: nodeid nodeId: nodeid
key: headscaleapiaccesstoken key: headscaleapiaccesstoken
``` ```

View File

@ -15,4 +15,5 @@ widget:
url: http://qbittorrent.host.or.ip url: http://qbittorrent.host.or.ip
username: username username: username
password: password password: password
enableLeechProgress: true # optional, defaults to false
``` ```

21
package-lock.json generated
View File

@ -34,7 +34,7 @@
"recharts": "^2.12.6", "recharts": "^2.12.6",
"rrule": "^2.8.1", "rrule": "^2.8.1",
"swr": "^1.3.0", "swr": "^1.3.0",
"systeminformation": "^5.23.2", "systeminformation": "^5.23.8",
"tough-cookie": "^4.1.3", "tough-cookie": "^4.1.3",
"urbackup-server-api": "^0.52.1", "urbackup-server-api": "^0.52.1",
"winston": "^3.11.0", "winston": "^3.11.0",
@ -2115,9 +2115,9 @@
} }
}, },
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
@ -5510,9 +5510,9 @@
"optional": true "optional": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.7", "version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -7680,10 +7680,9 @@
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/systeminformation": { "node_modules/systeminformation": {
"version": "5.23.5", "version": "5.23.8",
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.23.5.tgz", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.23.8.tgz",
"integrity": "sha512-PEpJwhRYxZgBCAlWZhWIgfMTjXLqfcaZ1pJsJn9snWNfBW/Z1YQg1mbIUSWrEV3ErAHF7l/OoVLQeaZDlPzkpA==", "integrity": "sha512-Osd24mNKe6jr/YoXLLK3k8TMdzaxDffhpCxgkfgBHcapykIkd50HXThM3TCEuHO2pPuCsSx2ms/SunqhU5MmsQ==",
"license": "MIT",
"os": [ "os": [
"darwin", "darwin",
"linux", "linux",

View File

@ -36,7 +36,7 @@
"recharts": "^2.12.6", "recharts": "^2.12.6",
"rrule": "^2.8.1", "rrule": "^2.8.1",
"swr": "^1.3.0", "swr": "^1.3.0",
"systeminformation": "^5.23.2", "systeminformation": "^5.23.8",
"tough-cookie": "^4.1.3", "tough-cookie": "^4.1.3",
"urbackup-server-api": "^0.52.1", "urbackup-server-api": "^0.52.1",
"winston": "^3.11.0", "winston": "^3.11.0",

View File

@ -87,8 +87,8 @@ importers:
specifier: ^1.3.0 specifier: ^1.3.0
version: 1.3.0(react@18.3.1) version: 1.3.0(react@18.3.1)
systeminformation: systeminformation:
specifier: ^5.23.2 specifier: ^5.23.8
version: 5.23.5 version: 5.23.8
tough-cookie: tough-cookie:
specifier: ^4.1.3 specifier: ^4.1.3
version: 4.1.4 version: 4.1.4
@ -783,8 +783,8 @@ packages:
resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
cross-spawn@7.0.3: cross-spawn@7.0.6:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
css-select@5.1.0: css-select@5.1.0:
@ -2528,8 +2528,8 @@ packages:
resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
systeminformation@5.23.5: systeminformation@5.23.8:
resolution: {integrity: sha512-PEpJwhRYxZgBCAlWZhWIgfMTjXLqfcaZ1pJsJn9snWNfBW/Z1YQg1mbIUSWrEV3ErAHF7l/OoVLQeaZDlPzkpA==} resolution: {integrity: sha512-Osd24mNKe6jr/YoXLLK3k8TMdzaxDffhpCxgkfgBHcapykIkd50HXThM3TCEuHO2pPuCsSx2ms/SunqhU5MmsQ==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android]
hasBin: true hasBin: true
@ -3462,7 +3462,7 @@ snapshots:
nan: 2.20.0 nan: 2.20.0
optional: true optional: true
cross-spawn@7.0.3: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
shebang-command: 2.0.0 shebang-command: 2.0.0
@ -4003,7 +4003,7 @@ snapshots:
'@ungap/structured-clone': 1.2.0 '@ungap/structured-clone': 1.2.0
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.6
debug: 4.3.6 debug: 4.3.6
doctrine: 3.0.0 doctrine: 3.0.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
@ -4058,7 +4058,7 @@ snapshots:
execa@5.0.0: execa@5.0.0:
dependencies: dependencies:
cross-spawn: 7.0.3 cross-spawn: 7.0.6
get-stream: 6.0.1 get-stream: 6.0.1
human-signals: 2.1.0 human-signals: 2.1.0
is-stream: 2.0.1 is-stream: 2.0.1
@ -4127,7 +4127,7 @@ snapshots:
foreground-child@3.3.0: foreground-child@3.3.0:
dependencies: dependencies:
cross-spawn: 7.0.3 cross-spawn: 7.0.6
signal-exit: 4.1.0 signal-exit: 4.1.0
forever-agent@0.6.1: {} forever-agent@0.6.1: {}
@ -5420,7 +5420,7 @@ snapshots:
'@pkgr/core': 0.1.1 '@pkgr/core': 0.1.1
tslib: 2.7.0 tslib: 2.7.0
systeminformation@5.23.5: {} systeminformation@5.23.8: {}
tailwind-scrollbar@3.1.0(tailwindcss@3.4.14): tailwind-scrollbar@3.1.0(tailwindcss@3.4.14):
dependencies: dependencies:

View File

@ -120,7 +120,7 @@
"grid_power": "Rooster", "grid_power": "Rooster",
"home_power": "Verbruik", "home_power": "Verbruik",
"charge_power": "Laaier", "charge_power": "Laaier",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Aflaai", "download": "Aflaai",
@ -990,22 +990,22 @@
"network": "NET" "network": "NET"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Programme",
"synced": "Synced", "synced": "Gesinkroniseer",
"outOfSync": "Out Of Sync", "outOfSync": "Nie Gesinchroniseer Nie",
"healthy": "Gesond", "healthy": "Gesond",
"degraded": "Degraded", "degraded": "Gedegradeer",
"progressing": "Progressing", "progressing": "Vorderend",
"missing": "Vermis", "missing": "Vermis",
"suspended": "Suspended" "suspended": "Geskors"
}, },
"spoolman": { "spoolman": {
"loading": "Laai" "loading": "Laai"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Groepe",
"issues": "Kwessies", "issues": "Kwessies",
"merges": "Merge Requests", "merges": "Saamvleg Versoeke",
"projects": "Projects" "projects": "Projekte"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "شبكة", "grid_power": "شبكة",
"home_power": "الاستهلاك", "home_power": "الاستهلاك",
"charge_power": "شاحن", "charge_power": "شاحن",
"watt_hour": "واط ساعة" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "التنزيل", "download": "التنزيل",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Xarxa", "grid_power": "Xarxa",
"home_power": "Consum", "home_power": "Consum",
"charge_power": "Carregador", "charge_power": "Carregador",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Descarregar", "download": "Descarregar",
@ -350,7 +350,7 @@
"queue": "Cua", "queue": "Cua",
"processed": "Processat", "processed": "Processat",
"errored": "Error", "errored": "Error",
"saved": "Desat" "saved": "Estalviat"
}, },
"traefik": { "traefik": {
"routers": "Encaminadors", "routers": "Encaminadors",
@ -581,7 +581,7 @@
"clientIP": "Client" "clientIP": "Client"
}, },
"scrutiny": { "scrutiny": {
"passed": "Aprobat", "passed": "Aprovat",
"failed": "Error", "failed": "Error",
"unknown": "Desconegut" "unknown": "Desconegut"
}, },
@ -820,7 +820,7 @@
"total": "Total", "total": "Total",
"running": "En execució", "running": "En execució",
"stopped": "Aturat", "stopped": "Aturat",
"passed": "Aprobat", "passed": "Aprovat",
"failed": "Error" "failed": "Error"
}, },
"openwrt": { "openwrt": {
@ -991,21 +991,21 @@
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Apps",
"synced": "Synced", "synced": "Sincronitzats",
"outOfSync": "Out Of Sync", "outOfSync": "Dessincronitzats",
"healthy": "Saludable", "healthy": "Saludable",
"degraded": "Degraded", "degraded": "Degradats",
"progressing": "Progressing", "progressing": "Progressant",
"missing": "Falten", "missing": "Falten",
"suspended": "Suspended" "suspended": "Suspesos"
}, },
"spoolman": { "spoolman": {
"loading": "Carregant" "loading": "Carregant"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Grups",
"issues": "Problemes", "issues": "Problemes",
"merges": "Merge Requests", "merges": "Merge Requests",
"projects": "Projects" "projects": "Projectes"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Mřížka", "grid_power": "Mřížka",
"home_power": "Spotřeba", "home_power": "Spotřeba",
"charge_power": "Nabíječka", "charge_power": "Nabíječka",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Stahování", "download": "Stahování",

View File

@ -120,7 +120,7 @@
"grid_power": "Gitter", "grid_power": "Gitter",
"home_power": "Forbrug", "home_power": "Forbrug",
"charge_power": "Oplader", "charge_power": "Oplader",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Netz", "grid_power": "Netz",
"home_power": "verbauch", "home_power": "verbauch",
"charge_power": "Ladegerät", "charge_power": "Ladegerät",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",
@ -1003,9 +1003,9 @@
"loading": "Wird geladen" "loading": "Wird geladen"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Gruppen",
"issues": "Probleme", "issues": "Probleme",
"merges": "Merge Requests", "merges": "Merge Requests",
"projects": "Projects" "projects": "Projekte"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Πλέγμα", "grid_power": "Πλέγμα",
"home_power": "Κατανάλωση", "home_power": "Κατανάλωση",
"charge_power": "Φορτιστής", "charge_power": "Φορτιστής",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Λήξη", "download": "Λήξη",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Elŝuti", "download": "Elŝuti",

View File

@ -120,7 +120,7 @@
"grid_power": "Red", "grid_power": "Red",
"home_power": "Consumo", "home_power": "Consumo",
"charge_power": "Cargador", "charge_power": "Cargador",
"watt_hour": "vatio-hora (Wh)" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Descarga", "download": "Descarga",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grille", "grid_power": "Grille",
"home_power": "Consommation", "home_power": "Consommation",
"charge_power": "Chargeur", "charge_power": "Chargeur",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Récep.", "download": "Récep.",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Raspored", "grid_power": "Raspored",
"home_power": "Potrošnja", "home_power": "Potrošnja",
"charge_power": "Punjač", "charge_power": "Punjač",
"watt_hour": "Kilovat-sat" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Preuzimanje", "download": "Preuzimanje",

View File

@ -25,7 +25,7 @@
"api_error": "API Hiba", "api_error": "API Hiba",
"information": "Információ", "information": "Információ",
"status": "Státusz", "status": "Státusz",
"url": "LINK", "url": "URL",
"raw_error": "Nyers hiba", "raw_error": "Nyers hiba",
"response_data": "Válaszadatok" "response_data": "Válaszadatok"
}, },
@ -120,7 +120,7 @@
"grid_power": "Rács", "grid_power": "Rács",
"home_power": "Fogyasztás", "home_power": "Fogyasztás",
"charge_power": "Töltő", "charge_power": "Töltő",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Letöltés", "download": "Letöltés",
@ -227,8 +227,8 @@
"seed": "Seed" "seed": "Seed"
}, },
"develancacheui": { "develancacheui": {
"cachehitbytes": "Cache Hit Bytes", "cachehitbytes": "Gyorsítótárban Sikeres Bitek",
"cachemissbytes": "Cache Miss Bytes" "cachemissbytes": "Gyorsítótárban Hibás Bitek"
}, },
"downloadstation": { "downloadstation": {
"download": "Letöltés", "download": "Letöltés",
@ -311,13 +311,13 @@
}, },
"suwayomi": { "suwayomi": {
"download": "Letöltött", "download": "Letöltött",
"nondownload": "Non-Downloaded", "nondownload": "Nem Letöltött",
"read": "Olvasott", "read": "Olvasott",
"unread": "Olvasatlan", "unread": "Olvasatlan",
"downloadedread": "Downloaded & Read", "downloadedread": "Letöltött & Olvasott",
"downloadedunread": "Downloaded & Unread", "downloadedunread": "Letöltött & Olvasatlan",
"nondownloadedread": "Non-Downloaded & Read", "nondownloadedread": "Nem Letöltött & Olvasatlan",
"nondownloadedunread": "Non-Downloaded & Unread" "nondownloadedunread": "Nem Letöltött & Olvasatlan"
}, },
"tailscale": { "tailscale": {
"address": "Cím", "address": "Cím",
@ -335,15 +335,15 @@
}, },
"technitium": { "technitium": {
"totalQueries": "Lekérdezések", "totalQueries": "Lekérdezések",
"totalNoError": "Success", "totalNoError": "Sikerek",
"totalServerFailure": "Failures", "totalServerFailure": "Hibák",
"totalNxDomain": "NX Domains", "totalNxDomain": "NX Domainek",
"totalRefused": "Refused", "totalRefused": "Elutasított",
"totalAuthoritative": "Authoritative", "totalAuthoritative": "Irányadó",
"totalRecursive": "Recursive", "totalRecursive": "Rekurzív",
"totalCached": "Cached", "totalCached": "Gyorsítótárazott",
"totalBlocked": "Blokkolt", "totalBlocked": "Blokkolt",
"totalDropped": "Dropped", "totalDropped": "Eldobott",
"totalClients": "Kliensek" "totalClients": "Kliensek"
}, },
"tdarr": { "tdarr": {
@ -453,7 +453,7 @@
"search": "Keresés", "search": "Keresés",
"custom": "Egyedi", "custom": "Egyedi",
"visit": "Megnéz", "visit": "Megnéz",
"url": "LINK", "url": "URL",
"searchsuggestion": "Javaslat" "searchsuggestion": "Javaslat"
}, },
"wmo": { "wmo": {
@ -854,16 +854,16 @@
}, },
"romm": { "romm": {
"platforms": "Felület", "platforms": "Felület",
"totalRoms": "Games", "totalRoms": "Játékok",
"saves": "Saves", "saves": "Mentések",
"states": "States", "states": "Állapotok",
"screenshots": "Screenshots", "screenshots": "Képernyőképek",
"totalfilesize": "Total Size" "totalfilesize": "Teljes méret"
}, },
"mailcow": { "mailcow": {
"domains": "Domainek", "domains": "Domainek",
"mailboxes": "Mailboxes", "mailboxes": "E-mail fiókok",
"mails": "Mails", "mails": "Mailek",
"storage": "Tárhely" "storage": "Tárhely"
}, },
"netdata": { "netdata": {
@ -912,7 +912,7 @@
}, },
"crowdsec": { "crowdsec": {
"alerts": "Riasztások", "alerts": "Riasztások",
"bans": "Bans" "bans": "Kitiltások"
}, },
"wgeasy": { "wgeasy": {
"connected": "Csatlakozva", "connected": "Csatlakozva",
@ -921,10 +921,10 @@
"total": "Összes" "total": "Összes"
}, },
"swagdashboard": { "swagdashboard": {
"proxied": "Proxied", "proxied": "Proxyzott",
"auth": "With Auth", "auth": "Hitelesítéssel",
"outdated": "Outdated", "outdated": "Elavult",
"banned": "Banned" "banned": "Kitiltott"
}, },
"myspeed": { "myspeed": {
"ping": "Ping", "ping": "Ping",
@ -932,29 +932,29 @@
"upload": "Feltöltés" "upload": "Feltöltés"
}, },
"stocks": { "stocks": {
"stocks": "Stocks", "stocks": "Tőzsde",
"loading": "Loading", "loading": "Betöltés",
"open": "Open - US Market", "open": "Nyitva - US Piac",
"closed": "Closed - US Market", "closed": "Zárva - US Piac",
"invalidConfiguration": "Invalid Configuration" "invalidConfiguration": "Érvénytelen konfiguráció"
}, },
"frigate": { "frigate": {
"cameras": "Cameras", "cameras": "Kamerák",
"uptime": "Üzemidő", "uptime": "Üzemidő",
"version": "Verzió" "version": "Verzió"
}, },
"linkwarden": { "linkwarden": {
"links": "Links", "links": "Linkek",
"collections": "Collections", "collections": "Gyűjtemény",
"tags": "Címkék" "tags": "Címkék"
}, },
"zabbix": { "zabbix": {
"unclassified": "Not classified", "unclassified": "Nem titkosított",
"information": "Információ", "information": "Információ",
"warning": "Warning", "warning": "Figyelmeztetés",
"average": "Average", "average": "Átlag",
"high": "High", "high": "Magas",
"disaster": "Disaster" "disaster": "Katasztrófa"
}, },
"lubelogger": { "lubelogger": {
"vehicle": "Jármű", "vehicle": "Jármű",
@ -962,13 +962,13 @@
"serviceRecords": "Szolgáltatások nyílvántartása", "serviceRecords": "Szolgáltatások nyílvántartása",
"reminders": "Emlékeztetők", "reminders": "Emlékeztetők",
"nextReminder": "Következő emlékeztető", "nextReminder": "Következő emlékeztető",
"none": "None" "none": "Semmi"
}, },
"vikunja": { "vikunja": {
"projects": "Active Projects", "projects": "Aktív Projektek",
"tasks7d": "Tasks Due This Week", "tasks7d": "Hátralévő feladatok a héten",
"tasksOverdue": "Overdue Tasks", "tasksOverdue": "Lejárt feladatok",
"tasksInProgress": "Tasks In Progress" "tasksInProgress": "Folyamatban levő Feladatok"
}, },
"headscale": { "headscale": {
"name": "Név", "name": "Név",
@ -980,32 +980,32 @@
}, },
"beszel": { "beszel": {
"name": "Név", "name": "Név",
"systems": "Systems", "systems": "Rendszerek",
"up": "Fel", "up": "Fel",
"status": "Státusz", "status": "Státusz",
"updated": "Frissített", "updated": "Frissített",
"cpu": "Processzor", "cpu": "Processzor",
"memory": "RAM", "memory": "RAM",
"disk": "Disk", "disk": "Lemez",
"network": "NET" "network": "Hálózat"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Alkalmazások",
"synced": "Synced", "synced": "Szinkronizált",
"outOfSync": "Out Of Sync", "outOfSync": "Nincs szinkronban",
"healthy": "Egészséges", "healthy": "Egészséges",
"degraded": "Degraded", "degraded": "Leépült",
"progressing": "Progressing", "progressing": "Halad",
"missing": "Hiányzik", "missing": "Hiányzik",
"suspended": "Suspended" "suspended": "Felfüggesztett"
}, },
"spoolman": { "spoolman": {
"loading": "Loading" "loading": "Betöltés"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Csoportok",
"issues": "Problémák", "issues": "Problémák",
"merges": "Merge Requests", "merges": "Merge kérések",
"projects": "Projects" "projects": "Projektek"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Konsumsi", "home_power": "Konsumsi",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Watt/jam" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Unduh", "download": "Unduh",

View File

@ -120,7 +120,7 @@
"grid_power": "Griglia", "grid_power": "Griglia",
"home_power": "Consumo", "home_power": "Consumo",
"charge_power": "Caricatore", "charge_power": "Caricatore",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "グリッド", "grid_power": "グリッド",
"home_power": "消費", "home_power": "消費",
"charge_power": "チャージャー", "charge_power": "チャージャー",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "ダウンロード", "download": "ダウンロード",
@ -804,7 +804,7 @@
"ping": "Ping" "ping": "Ping"
}, },
"urbackup": { "urbackup": {
"ok": "はい", "ok": "正常",
"errored": "エラー", "errored": "エラー",
"noRecent": "期限切れ", "noRecent": "期限切れ",
"totalUsed": "使用済みストレージ" "totalUsed": "使用済みストレージ"
@ -957,7 +957,7 @@
"disaster": "災害" "disaster": "災害"
}, },
"lubelogger": { "lubelogger": {
"vehicle": "Vehicle", "vehicle": "車両",
"vehicles": "Vehicles", "vehicles": "Vehicles",
"serviceRecords": "Service Records", "serviceRecords": "Service Records",
"reminders": "Reminders", "reminders": "Reminders",

View File

@ -120,7 +120,7 @@
"grid_power": "눈금", "grid_power": "눈금",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "다운로드", "download": "다운로드",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Lejupielāde", "download": "Lejupielāde",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Penggunaan", "home_power": "Penggunaan",
"charge_power": "Pengecas", "charge_power": "Pengecas",
"watt_hour": "Wj" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Muat turun", "download": "Muat turun",

View File

@ -120,7 +120,7 @@
"grid_power": "Netstroom", "grid_power": "Netstroom",
"home_power": "Consumptie", "home_power": "Consumptie",
"charge_power": "Oplader", "charge_power": "Oplader",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Nett", "grid_power": "Nett",
"home_power": "Forbruk", "home_power": "Forbruk",
"charge_power": "Lader", "charge_power": "Lader",
"watt_hour": "W/t" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Last ned", "download": "Last ned",

View File

@ -13,7 +13,7 @@
"ms": "{{value, number}}", "ms": "{{value, number}}",
"date": "{{value, date}}", "date": "{{value, date}}",
"relativeDate": "{{value, relativeDate}}", "relativeDate": "{{value, relativeDate}}",
"duration": "{{value, duration}}", "duration": "{value, duration}",
"months": "mc", "months": "mc",
"days": "d", "days": "d",
"hours": "g", "hours": "g",
@ -120,7 +120,7 @@
"grid_power": "Siatka", "grid_power": "Siatka",
"home_power": "Zużycie", "home_power": "Zużycie",
"charge_power": "Ładowarka", "charge_power": "Ładowarka",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Pobieranie", "download": "Pobieranie",
@ -311,13 +311,13 @@
}, },
"suwayomi": { "suwayomi": {
"download": "Pobrano", "download": "Pobrano",
"nondownload": "Non-Downloaded", "nondownload": "Niepobrane",
"read": "Przeczytane", "read": "Przeczytane",
"unread": "Nieprzeczytane", "unread": "Nieprzeczytane",
"downloadedread": "Downloaded & Read", "downloadedread": "Pobrane i przeczytane",
"downloadedunread": "Downloaded & Unread", "downloadedunread": "Pobrane i nieprzeczytane",
"nondownloadedread": "Non-Downloaded & Read", "nondownloadedread": "Niepobrane i przeczytane",
"nondownloadedunread": "Non-Downloaded & Unread" "nondownloadedunread": "Niepobrane i nieprzeczytane"
}, },
"tailscale": { "tailscale": {
"address": "Adres", "address": "Adres",
@ -957,18 +957,18 @@
"disaster": "Katastrofa" "disaster": "Katastrofa"
}, },
"lubelogger": { "lubelogger": {
"vehicle": "Vehicle", "vehicle": "Pojazd",
"vehicles": "Vehicles", "vehicles": "Pojazdy",
"serviceRecords": "Service Records", "serviceRecords": "Wpisy serwisowe",
"reminders": "Reminders", "reminders": "Przypomnienia",
"nextReminder": "Next Reminder", "nextReminder": "Następne przypomnienie",
"none": "None" "none": "Brak"
}, },
"vikunja": { "vikunja": {
"projects": "Active Projects", "projects": "Aktywne Projekty",
"tasks7d": "Tasks Due This Week", "tasks7d": "Zadania w tym tygodniu",
"tasksOverdue": "Overdue Tasks", "tasksOverdue": "Zaległe zadania",
"tasksInProgress": "Tasks In Progress" "tasksInProgress": "Zadania w toku"
}, },
"headscale": { "headscale": {
"name": "Nazwa", "name": "Nazwa",
@ -980,32 +980,32 @@
}, },
"beszel": { "beszel": {
"name": "Nazwa", "name": "Nazwa",
"systems": "Systems", "systems": "Systemy",
"up": "Dostępny", "up": "Dostępny",
"status": "Stan", "status": "Stan",
"updated": "Zaktualizowane", "updated": "Zaktualizowane",
"cpu": "Procesor", "cpu": "Procesor",
"memory": "RAM", "memory": "RAM",
"disk": "Disk", "disk": "Dysk",
"network": "NET" "network": "NET"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Aplikacje",
"synced": "Synced", "synced": "Synchronizowane",
"outOfSync": "Out Of Sync", "outOfSync": "Bez synchronizacji",
"healthy": "Zdrowy", "healthy": "Zdrowy",
"degraded": "Degraded", "degraded": "Zdegradowane",
"progressing": "Progressing", "progressing": "Postępujące",
"missing": "Brakujące", "missing": "Brakujące",
"suspended": "Suspended" "suspended": "Zawieszone"
}, },
"spoolman": { "spoolman": {
"loading": "Wczytywanie" "loading": "Wczytywanie"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Grupy",
"issues": "Zgłoszenia", "issues": "Zgłoszenia",
"merges": "Merge Requests", "merges": "Żądania scaleń",
"projects": "Projects" "projects": "Projekty"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Grelha", "grid_power": "Grelha",
"home_power": "Consumo", "home_power": "Consumo",
"charge_power": "Carregador", "charge_power": "Carregador",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Descarregar", "download": "Descarregar",

View File

@ -120,7 +120,7 @@
"grid_power": "Grade", "grid_power": "Grade",
"home_power": "Consumo", "home_power": "Consumo",
"charge_power": "Carregador", "charge_power": "Carregador",
"watt_hour": "Kw" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Descarregar", "download": "Descarregar",

View File

@ -120,7 +120,7 @@
"grid_power": "Grilă", "grid_power": "Grilă",
"home_power": "Consum", "home_power": "Consum",
"charge_power": "Încărcător", "charge_power": "Încărcător",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Descarcă", "download": "Descarcă",

View File

@ -120,7 +120,7 @@
"grid_power": "Сетка", "grid_power": "Сетка",
"home_power": "Потребление", "home_power": "Потребление",
"charge_power": "Зарядка", "charge_power": "Зарядка",
"watt_hour": "Вт" "kilowatt": "кВт"
}, },
"flood": { "flood": {
"download": "Скачивание", "download": "Скачивание",
@ -990,22 +990,22 @@
"network": "Сеть" "network": "Сеть"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Приложения",
"synced": "Synced", "synced": "Синхронизированные",
"outOfSync": "Out Of Sync", "outOfSync": "Не синхронизированные",
"healthy": "Здоровый", "healthy": "Здоровый",
"degraded": "Degraded", "degraded": "Деградированные",
"progressing": "Progressing", "progressing": "Выполняются",
"missing": "Отсутствует", "missing": "Отсутствует",
"suspended": "Suspended" "suspended": "Приостановленные"
}, },
"spoolman": { "spoolman": {
"loading": "Загрузка" "loading": "Загрузка"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Группы",
"issues": "Вопросы", "issues": "Вопросы",
"merges": "Merge Requests", "merges": "Мердж-реквесты",
"projects": "Projects" "projects": "Проекты"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Mriežka", "grid_power": "Mriežka",
"home_power": "Spotreba", "home_power": "Spotreba",
"charge_power": "Nabíjačka", "charge_power": "Nabíjačka",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Sťahovanie", "download": "Sťahovanie",

View File

@ -120,7 +120,7 @@
"grid_power": "Omrežje", "grid_power": "Omrežje",
"home_power": "Poraba", "home_power": "Poraba",
"charge_power": "Polnilec", "charge_power": "Polnilec",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Prenos", "download": "Prenos",
@ -1003,9 +1003,9 @@
"loading": "Nalaganje" "loading": "Nalaganje"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Skupine",
"issues": "Težave", "issues": "Težave",
"merges": "Merge Requests", "merges": "Združi zahtevke",
"projects": "Projects" "projects": "Projekti"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "ดาวน์โหลด", "download": "ดาวน์โหลด",

View File

@ -120,7 +120,7 @@
"grid_power": "Güç", "grid_power": "Güç",
"home_power": "Tüketim", "home_power": "Tüketim",
"charge_power": "Şarj", "charge_power": "Şarj",
"watt_hour": "Watt/Saat" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "İndirme", "download": "İndirme",

View File

@ -120,7 +120,7 @@
"grid_power": "Сітка", "grid_power": "Сітка",
"home_power": "Споживання", "home_power": "Споживання",
"charge_power": "Зарядний пристрій", "charge_power": "Зарядний пристрій",
"watt_hour": "Вт/год" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Завантажено", "download": "Завантажено",
@ -311,13 +311,13 @@
}, },
"suwayomi": { "suwayomi": {
"download": "Завантажено", "download": "Завантажено",
"nondownload": "Non-Downloaded", "nondownload": "Не завантажено",
"read": "Прочитано", "read": "Прочитано",
"unread": "Не прочитано", "unread": "Не прочитано",
"downloadedread": "Downloaded & Read", "downloadedread": "Завантажено та Прочитано",
"downloadedunread": "Downloaded & Unread", "downloadedunread": "Завантажено та Непрочитано",
"nondownloadedread": "Non-Downloaded & Read", "nondownloadedread": "Не завантажено та Прочитано",
"nondownloadedunread": "Non-Downloaded & Unread" "nondownloadedunread": "Не завантажено та Не прочитано"
}, },
"tailscale": { "tailscale": {
"address": "Адреса", "address": "Адреса",
@ -965,10 +965,10 @@
"none": "Жодного" "none": "Жодного"
}, },
"vikunja": { "vikunja": {
"projects": "Active Projects", "projects": "Активні проекти",
"tasks7d": "Tasks Due This Week", "tasks7d": "Завдання цього тижня",
"tasksOverdue": "Overdue Tasks", "tasksOverdue": "Прострочені завдання",
"tasksInProgress": "Tasks In Progress" "tasksInProgress": "Завдання в процесі"
}, },
"headscale": { "headscale": {
"name": "Назва", "name": "Назва",
@ -980,32 +980,32 @@
}, },
"beszel": { "beszel": {
"name": "Назва", "name": "Назва",
"systems": "Systems", "systems": "Системи",
"up": "Онлайн", "up": "Онлайн",
"status": "Стан", "status": "Стан",
"updated": "Оновлено", "updated": "Оновлено",
"cpu": "ЦП", "cpu": "ЦП",
"memory": "ОЗП", "memory": "ОЗП",
"disk": "Disk", "disk": "Диск",
"network": "NET" "network": "МЕРЕЖА"
}, },
"argocd": { "argocd": {
"apps": "Apps", "apps": "Додатки",
"synced": "Synced", "synced": "Синхронізовано",
"outOfSync": "Out Of Sync", "outOfSync": "Не синхронізовано",
"healthy": "Здоровий", "healthy": "Здоровий",
"degraded": "Degraded", "degraded": "Деградує",
"progressing": "Progressing", "progressing": "Прогрес",
"missing": "Відсутній", "missing": "Відсутній",
"suspended": "Suspended" "suspended": "Призупинено"
}, },
"spoolman": { "spoolman": {
"loading": "Завантажую" "loading": "Завантажую"
}, },
"gitlab": { "gitlab": {
"groups": "Groups", "groups": "Групи",
"issues": "Питання", "issues": "Питання",
"merges": "Merge Requests", "merges": "Запити на злиття",
"projects": "Projects" "projects": "Проєкти"
} }
} }

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "Download", "download": "Download",

View File

@ -120,7 +120,7 @@
"grid_power": "電網", "grid_power": "電網",
"home_power": "電源使用率", "home_power": "電源使用率",
"charge_power": "充電", "charge_power": "充電",
"watt_hour": "瓦時 (Wh)" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "下載速率", "download": "下載速率",

View File

@ -120,7 +120,7 @@
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Charger",
"watt_hour": "Wh" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "下载", "download": "下载",

View File

@ -120,7 +120,7 @@
"grid_power": "電網", "grid_power": "電網",
"home_power": "電源使用率", "home_power": "電源使用率",
"charge_power": "充電", "charge_power": "充電",
"watt_hour": "瓦時 (Wh)" "kilowatt": "kW"
}, },
"flood": { "flood": {
"download": "下載速率", "download": "下載速率",

View File

@ -129,7 +129,7 @@ export default function QuickLaunch({ servicesAndBookmarks, searchString, setSea
useEffect(() => { useEffect(() => {
const abortController = new AbortController(); const abortController = new AbortController();
if (searchString.length === 0) setResults([]); if (searchString.trim().length === 0) setResults([]);
else { else {
let newResults = servicesAndBookmarks.filter((r) => { let newResults = servicesAndBookmarks.filter((r) => {
const nameMatch = r.name.toLowerCase().includes(searchString); const nameMatch = r.name.toLowerCase().includes(searchString);

View File

@ -94,6 +94,7 @@ export default function Search({ options }) {
if ( if (
options.showSearchSuggestions && options.showSearchSuggestions &&
(selectedProvider.suggestionUrl || options.suggestionUrl) && // custom providers pass url via options (selectedProvider.suggestionUrl || options.suggestionUrl) && // custom providers pass url via options
query.trim().length > 0 &&
query.trim() !== searchSuggestions[0] query.trim() !== searchSuggestions[0]
) { ) {
fetch(`/api/search/searchSuggestion?query=${encodeURIComponent(query)}&providerName=${selectedProvider.name}`, { fetch(`/api/search/searchSuggestion?query=${encodeURIComponent(query)}&providerName=${selectedProvider.name}`, {

View File

@ -51,7 +51,9 @@ export default function Widget({ options }) {
key={stock.ticker} key={stock.ticker}
className="rounded h-full text-xs px-1 w-[4.75rem] flex flex-col items-center justify-center" className="rounded h-full text-xs px-1 w-[4.75rem] flex flex-col items-center justify-center"
> >
<span className="text-theme-800 dark:text-theme-200 text-xs">{stock.ticker}</span> <span className="text-theme-800 dark:text-theme-200 text-xs">
{stock.ticker.split(":").pop()}
</span>
{!viewingPercentChange ? ( {!viewingPercentChange ? (
<span <span
className={ className={

View File

@ -1,9 +1,14 @@
import cachedFetch from "utils/proxy/cached-fetch"; import cachedFetch from "utils/proxy/cached-fetch";
import { getSettings } from "utils/config/config"; import { getSettings } from "utils/config/config";
import createLogger from "utils/logger";
const logger = createLogger("stocks");
export default async function handler(req, res) { export default async function handler(req, res) {
const { watchlist, provider, cache } = req.query; const { watchlist, provider, cache } = req.query;
logger.debug("Stocks API request: %o", { watchlist, provider, cache });
if (!watchlist) { if (!watchlist) {
return res.status(400).json({ error: "Missing watchlist" }); return res.status(400).json({ error: "Missing watchlist" });
} }
@ -56,6 +61,7 @@ export default async function handler(req, res) {
// Finnhub free accounts allow up to 60 calls/minute // Finnhub free accounts allow up to 60 calls/minute
// https://finnhub.io/pricing // https://finnhub.io/pricing
const { c, dp } = await cachedFetch(apiUrl, cache || 1); const { c, dp } = await cachedFetch(apiUrl, cache || 1);
logger.debug("Finnhub API response for %s: %o", ticker, { c, dp });
// API sometimes returns 200, but values returned are `null` // API sometimes returns 200, but values returned are `null`
if (c === null || dp === null) { if (c === null || dp === null) {

View File

@ -359,7 +359,7 @@ function Home({ initialSettings }) {
return ( return (
<> <>
<Head> <Head>
<title>{settings.title || "Homepage"}</title> <title>{initialSettings.title || "Homepage"}</title>
{settings.base && <base href={settings.base} />} {settings.base && <base href={settings.base} />}
{settings.favicon ? ( {settings.favicon ? (
<> <>

View File

@ -158,7 +158,7 @@ export async function servicesResponse() {
const discoveredKubernetesGroup = findGroupByName(discoveredKubernetesServices, groupName) || { const discoveredKubernetesGroup = findGroupByName(discoveredKubernetesServices, groupName) || {
services: [], services: [],
}; };
const configuredGroup = findGroupByName(configuredServices, groupName) || { services: [] }; const configuredGroup = findGroupByName(configuredServices, groupName) || { services: [], groups: [] };
const mergedGroup = { const mergedGroup = {
name: groupName, name: groupName,
@ -171,7 +171,7 @@ export async function servicesResponse() {
if (definedLayouts) { if (definedLayouts) {
const layoutIndex = definedLayouts.findIndex((layout) => layout === mergedGroup.name); const layoutIndex = definedLayouts.findIndex((layout) => layout === mergedGroup.name);
if (layoutIndex > -1) sortedGroups[layoutIndex] = mergedGroup; if (layoutIndex > -1) sortedGroups[layoutIndex] = mergedGroup;
else if (configuredGroup.name) { else if (configuredGroup.parent) {
// this is a nested group, so find the parent group and merge the services // this is a nested group, so find the parent group and merge the services
mergeSubgroups(configuredServices, mergedGroup); mergeSubgroups(configuredServices, mergedGroup);
} else unsortedGroups.push(mergedGroup); } else unsortedGroups.push(mergedGroup);

View File

@ -24,6 +24,10 @@ function parseServicesToGroups(services) {
const serviceGroupServices = []; const serviceGroupServices = [];
serviceGroup[name].forEach((entries) => { serviceGroup[name].forEach((entries) => {
const entryName = Object.keys(entries)[0]; const entryName = Object.keys(entries)[0];
if (!entries[entryName]) {
logger.warn(`Error parsing service "${entryName}" from config. Ensure required fields are present.`);
return;
}
if (Array.isArray(entries[entryName])) { if (Array.isArray(entries[entryName])) {
groups = groups.concat(parseServicesToGroups([{ [entryName]: entries[entryName] }])); groups = groups.concat(parseServicesToGroups([{ [entryName]: entries[entryName] }]));
} else { } else {
@ -105,7 +109,11 @@ export async function servicesFromDocker() {
type: "service", type: "service",
}; };
} }
shvl.set(constructedService, value, substituteEnvironmentVars(containerLabels[label])); let substitutedVal = substituteEnvironmentVars(containerLabels[label]);
if (value === "widget.version") {
substitutedVal = parseInt(substitutedVal, 10);
}
shvl.set(constructedService, value, substitutedVal);
} }
}); });
@ -316,6 +324,9 @@ export function cleanServiceGroups(groups) {
mappings, mappings,
display, display,
// deluge, qbittorrent
enableLeechProgress,
// diskstation // diskstation
volume, volume,
@ -335,7 +346,7 @@ export function cleanServiceGroups(groups) {
// frigate // frigate
enableRecentEvents, enableRecentEvents,
// glances, immich, mealie, pihole, pfsense // beszel, glances, immich, mealie, pihole, pfsense
version, version,
// glances // glances
@ -483,6 +494,9 @@ export function cleanServiceGroups(groups) {
if (allowScrolling) widget.allowScrolling = allowScrolling; if (allowScrolling) widget.allowScrolling = allowScrolling;
if (refreshInterval) widget.refreshInterval = refreshInterval; if (refreshInterval) widget.refreshInterval = refreshInterval;
} }
if (["deluge", "qbittorrent"].includes(type)) {
if (enableLeechProgress !== undefined) widget.enableLeechProgress = JSON.parse(enableLeechProgress);
}
if (["opnsense", "pfsense"].includes(type)) { if (["opnsense", "pfsense"].includes(type)) {
if (wan) widget.wan = wan; if (wan) widget.wan = wan;
} }
@ -510,7 +524,7 @@ export function cleanServiceGroups(groups) {
if (snapshotHost) widget.snapshotHost = snapshotHost; if (snapshotHost) widget.snapshotHost = snapshotHost;
if (snapshotPath) widget.snapshotPath = snapshotPath; if (snapshotPath) widget.snapshotPath = snapshotPath;
} }
if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) { if (["beszel", "glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) {
if (version) widget.version = parseInt(version, 10); if (version) widget.version = parseInt(version, 10);
} }
if (type === "glances") { if (type === "glances") {
@ -603,6 +617,7 @@ export function findGroupByName(groups, name) {
} else if (group.groups) { } else if (group.groups) {
const foundGroup = findGroupByName(group.groups, name); const foundGroup = findGroupByName(group.groups, name);
if (foundGroup) { if (foundGroup) {
foundGroup.parent = group;
return foundGroup; return foundGroup;
} }
} }

View File

@ -89,7 +89,9 @@ export default async function credentialedProxyHandler(req, res, map) {
} else if (widget.type === "myspeed") { } else if (widget.type === "myspeed") {
headers.Password = `${widget.password}`; headers.Password = `${widget.password}`;
} else if (widget.type === "esphome") { } else if (widget.type === "esphome") {
if (widget.key) { if (widget.username && widget.password) {
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
} else if (widget.key) {
headers.Cookie = `authenticated=${widget.key}`; headers.Cookie = `authenticated=${widget.key}`;
} }
} else if (widget.type === "wgeasy") { } else if (widget.type === "wgeasy") {

View File

@ -45,7 +45,12 @@ export default async function beszelProxyHandler(req, res) {
if (widget) { if (widget) {
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const loginUrl = formatApiCall(widgets[widget.type].api, { endpoint: "admins/auth-with-password", ...widget }); let authEndpointVersion = "authv1";
if (widget.version === 2) authEndpointVersion = "authv2";
const loginUrl = formatApiCall(widgets[widget.type].api, {
endpoint: widgets[widget.type].mappings[authEndpointVersion].endpoint,
...widget,
});
let status; let status;
let data; let data;
@ -54,7 +59,7 @@ export default async function beszelProxyHandler(req, res) {
if (!token) { if (!token) {
[status, token] = await login(loginUrl, widget.username, widget.password, service); [status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) { if (status !== 200) {
logger.debug(`HTTP ${status} logging into npm api: ${token}`); logger.debug(`HTTP ${status} logging into Beszel: ${token}`);
return res.status(status).send(token); return res.status(status).send(token);
} }
} }
@ -68,12 +73,12 @@ export default async function beszelProxyHandler(req, res) {
}); });
if (status === 403) { if (status === 403) {
logger.debug(`HTTP ${status} retrieving data from npm api, logging in and trying again.`); logger.debug(`HTTP ${status} retrieving data from Beszel, logging in and trying again.`);
cache.del(`${tokenCacheKey}.${service}`); cache.del(`${tokenCacheKey}.${service}`);
[status, token] = await login(loginUrl, widget.username, widget.password, service); [status, token] = await login(loginUrl, widget.username, widget.password, service);
if (status !== 200) { if (status !== 200) {
logger.debug(`HTTP ${status} logging into npm api: ${data}`); logger.debug(`HTTP ${status} logging into Beszel: ${data}`);
return res.status(status).send(data); return res.status(status).send(data);
} }

View File

@ -5,6 +5,12 @@ const widget = {
proxyHandler: beszelProxyHandler, proxyHandler: beszelProxyHandler,
mappings: { mappings: {
authv1: {
endpoint: "admins/auth-with-password",
},
authv2: {
endpoint: "collections/_superusers/auth-with-password",
},
systems: { systems: {
endpoint: "collections/systems/records?page=1&perPage=500&sort=%2Bcreated", endpoint: "collections/systems/records?page=1&perPage=500&sort=%2Bcreated",
}, },

View File

@ -1,5 +1,7 @@
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import QueueEntry from "../../components/widgets/queue/queueEntry";
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import Block from "components/services/widget/block"; import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api"; import useWidgetAPI from "utils/proxy/use-widget-api";
@ -32,21 +34,38 @@ export default function Component({ service }) {
let rateDl = 0; let rateDl = 0;
let rateUl = 0; let rateUl = 0;
let completed = 0; let completed = 0;
const leechTorrents = [];
for (let i = 0; i < keys.length; i += 1) { for (let i = 0; i < keys.length; i += 1) {
const torrent = torrents[keys[i]]; const torrent = torrents[keys[i]];
rateDl += torrent.download_payload_rate; rateDl += torrent.download_payload_rate;
rateUl += torrent.upload_payload_rate; rateUl += torrent.upload_payload_rate;
completed += torrent.total_remaining === 0 ? 1 : 0; completed += torrent.total_remaining === 0 ? 1 : 0;
if (torrent.state === "Downloading") {
leechTorrents.push(torrent);
}
} }
const leech = keys.length - completed || 0; const leech = keys.length - completed || 0;
return ( return (
<>
<Container service={service}> <Container service={service}>
<Block label="deluge.leech" value={t("common.number", { value: leech })} /> <Block label="deluge.leech" value={t("common.number", { value: leech })} />
<Block label="deluge.download" value={t("common.byterate", { value: rateDl })} /> <Block label="deluge.download" value={t("common.byterate", { value: rateDl })} />
<Block label="deluge.seed" value={t("common.number", { value: completed })} /> <Block label="deluge.seed" value={t("common.number", { value: completed })} />
<Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} /> <Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} />
</Container> </Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (
<QueueEntry
progress={queueEntry.progress}
timeLeft={t("common.duration", { value: queueEntry.eta })}
title={queueEntry.name}
activity={queueEntry.state}
key={`${queueEntry.name}-${queueEntry.total_remaining}`}
/>
))}
</>
); );
} }

View File

@ -17,6 +17,7 @@ const dataParams = [
"download_payload_rate", "download_payload_rate",
"upload_payload_rate", "upload_payload_rate",
"total_remaining", "total_remaining",
"eta",
], ],
{}, {},
]; ];

View File

@ -1,4 +1,5 @@
import { useContext } from "react"; import { useContext } from "react";
import classNames from "classnames";
import Error from "./error"; import Error from "./error";
@ -17,7 +18,7 @@ export default function Container({ children, widget, error = null, chart = true
} }
return ( return (
<div> <div className={classNames("service-container", chart ? "chart relative h-[120px]" : "")}>
{children} {children}
<div className={`absolute top-0 right-0 bottom-0 left-0 overflow-clip pointer-events-none ${className}`} /> <div className={`absolute top-0 right-0 bottom-0 left-0 overflow-clip pointer-events-none ${className}`} />
{chart && <div className="h-[68px] overflow-clip" />} {chart && <div className="h-[68px] overflow-clip" />}

View File

@ -63,7 +63,7 @@ export default function Component({ service }) {
<div className="opacity-25 w-14 text-right">{item.cpu_percent.toFixed(1)}%</div> <div className="opacity-25 w-14 text-right">{item.cpu_percent.toFixed(1)}%</div>
<div className="opacity-25 w-14 text-right"> <div className="opacity-25 w-14 text-right">
{t("common.bytes", { {t("common.bytes", {
value: item.memory_info[memoryInfoKey], value: item.memory_info[memoryInfoKey] ?? item.memory_info.wset,
maximumFractionDigits: 0, maximumFractionDigits: 0,
})} })}
</div> </div>

View File

@ -1,12 +1,13 @@
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import QueueEntry from "../../components/widgets/queue/queueEntry";
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import Block from "components/services/widget/block"; import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api"; import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents"); const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents");
@ -29,6 +30,7 @@ export default function Component({ service }) {
let rateDl = 0; let rateDl = 0;
let rateUl = 0; let rateUl = 0;
let completed = 0; let completed = 0;
const leechTorrents = [];
for (let i = 0; i < torrentData.length; i += 1) { for (let i = 0; i < torrentData.length; i += 1) {
const torrent = torrentData[i]; const torrent = torrentData[i];
@ -37,16 +39,31 @@ export default function Component({ service }) {
if (torrent.progress === 1) { if (torrent.progress === 1) {
completed += 1; completed += 1;
} }
if (torrent.state.includes("DL") || torrent.state === "downloading") {
leechTorrents.push(torrent);
}
} }
const leech = torrentData.length - completed; const leech = torrentData.length - completed;
return ( return (
<>
<Container service={service}> <Container service={service}>
<Block label="qbittorrent.leech" value={t("common.number", { value: leech })} /> <Block label="qbittorrent.leech" value={t("common.number", { value: leech })} />
<Block label="qbittorrent.download" value={t("common.bibyterate", { value: rateDl, decimals: 1 })} /> <Block label="qbittorrent.download" value={t("common.bibyterate", { value: rateDl, decimals: 1 })} />
<Block label="qbittorrent.seed" value={t("common.number", { value: completed })} /> <Block label="qbittorrent.seed" value={t("common.number", { value: completed })} />
<Block label="qbittorrent.upload" value={t("common.bibyterate", { value: rateUl, decimals: 1 })} /> <Block label="qbittorrent.upload" value={t("common.bibyterate", { value: rateUl, decimals: 1 })} />
</Container> </Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (
<QueueEntry
progress={queueEntry.progress * 100}
timeLeft={t("common.duration", { value: queueEntry.eta })}
title={queueEntry.name}
activity={queueEntry.state}
key={`${queueEntry.name}-${queueEntry.amount_left}`}
/>
))}
</>
); );
} }