mirror of
https://github.com/karl0ss/homepage.git
synced 2025-04-29 12:03:41 +01:00
Merge branch 'main' into kubernetes
This commit is contained in:
commit
a1f2003a77
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "نوع القطعة مفقود: {{type}}",
|
"missing_type": "نوع القطعة مفقود: {{type}}",
|
||||||
"api_error": "API خطأ",
|
"api_error": "API خطأ",
|
||||||
"status": "الحالة"
|
"status": "الحالة",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "الموقع الحالي",
|
"current": "الموقع الحالي",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Липсваща приставка: {{type}}",
|
"missing_type": "Липсваща приставка: {{type}}",
|
||||||
"api_error": "API Грешка",
|
"api_error": "API Грешка",
|
||||||
"status": "Статус"
|
"status": "Статус",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Текущо местоположение",
|
"current": "Текущо местоположение",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Falta el tipus de widget: {{type}}",
|
"missing_type": "Falta el tipus de widget: {{type}}",
|
||||||
"api_error": "Error d'API",
|
"api_error": "Error d'API",
|
||||||
"status": "Estat"
|
"status": "Estat",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"allow": "Feu clic per permetre",
|
"allow": "Feu clic per permetre",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Chybí typ widgetu: {{type}}",
|
"missing_type": "Chybí typ widgetu: {{type}}",
|
||||||
"api_error": "Chyba API",
|
"api_error": "Chyba API",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Aktuální poloha",
|
"current": "Aktuální poloha",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Manglende Widget Type: {{type}}",
|
"missing_type": "Manglende Widget Type: {{type}}",
|
||||||
"api_error": "API fejl",
|
"api_error": "API fejl",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Nuværende lokation",
|
"current": "Nuværende lokation",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Fehlender Widget-Typ: {{type}}",
|
"missing_type": "Fehlender Widget-Typ: {{type}}",
|
||||||
"api_error": "API-Fehler",
|
"api_error": "API-Fehler",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"url": "URL",
|
||||||
|
"information": "Information",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Suche…"
|
"placeholder": "Suche…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Missing Widget Type: {{type}}",
|
"missing_type": "Missing Widget Type: {{type}}",
|
||||||
"api_error": "API Error",
|
"api_error": "API Error",
|
||||||
"status": "Status"
|
"information": "Information",
|
||||||
|
"status": "Status",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Current Location",
|
"current": "Current Location",
|
||||||
@ -330,5 +334,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Falta el tipo de widget: {{type}}",
|
"missing_type": "Falta el tipo de widget: {{type}}",
|
||||||
"api_error": "Error de API",
|
"api_error": "Error de API",
|
||||||
"status": "Estado"
|
"status": "Estado",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Buscar…"
|
"placeholder": "Buscar…"
|
||||||
@ -316,8 +320,12 @@
|
|||||||
"total": "Total"
|
"total": "Total"
|
||||||
},
|
},
|
||||||
"gluetun": {
|
"gluetun": {
|
||||||
"public_ip": "Public IP",
|
"public_ip": "IP pública",
|
||||||
"region": "Region",
|
"region": "Región",
|
||||||
"country": "Country"
|
"country": "País"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Puuttuva härpäkkeen tyyppi: {{type}}",
|
"missing_type": "Puuttuva härpäkkeen tyyppi: {{type}}",
|
||||||
"api_error": "API-virhe",
|
"api_error": "API-virhe",
|
||||||
"status": "Tila"
|
"status": "Tila",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Nykyinen sijainti",
|
"current": "Nykyinen sijainti",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Type de widget manquant: {{type}}",
|
"missing_type": "Type de widget manquant: {{type}}",
|
||||||
"api_error": "Erreur de l'API",
|
"api_error": "Erreur de l'API",
|
||||||
"status": "Statut"
|
"status": "Statut",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Recherche…"
|
"placeholder": "Recherche…"
|
||||||
@ -316,8 +320,12 @@
|
|||||||
"total": "Total"
|
"total": "Total"
|
||||||
},
|
},
|
||||||
"gluetun": {
|
"gluetun": {
|
||||||
"public_ip": "Public IP",
|
"public_ip": "IP Publique",
|
||||||
"region": "Region",
|
"region": "Région",
|
||||||
"country": "Country"
|
"country": "Pays"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "סוג ווידג'ט חסר: {{type}}",
|
"missing_type": "סוג ווידג'ט חסר: {{type}}",
|
||||||
"api_error": "שגיאת API",
|
"api_error": "שגיאת API",
|
||||||
"status": "סטטוס"
|
"status": "סטטוס",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "מיקום נוכחי",
|
"current": "מיקום נוכחי",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Missing Widget Type: {{type}}",
|
"missing_type": "Missing Widget Type: {{type}}",
|
||||||
"api_error": "API Error",
|
"api_error": "API Error",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Current Location",
|
"current": "Current Location",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Nedostajuća vrsta widgeta: {{type}}",
|
"missing_type": "Nedostajuća vrsta widgeta: {{type}}",
|
||||||
"api_error": "API greška",
|
"api_error": "API greška",
|
||||||
"status": "Stanje"
|
"status": "Stanje",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Hiányzó Widget Típus: {{type}}",
|
"missing_type": "Hiányzó Widget Típus: {{type}}",
|
||||||
"api_error": "API Hiba",
|
"api_error": "API Hiba",
|
||||||
"status": "Státusz"
|
"status": "Státusz",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Aktuális hely",
|
"current": "Aktuális hely",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Tipo del Widget Mancante: {{type}}",
|
"missing_type": "Tipo del Widget Mancante: {{type}}",
|
||||||
"api_error": "Errore API",
|
"api_error": "Errore API",
|
||||||
"status": "Stato"
|
"status": "Stato",
|
||||||
|
"url": "URL",
|
||||||
|
"information": "Information",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Cerca…"
|
"placeholder": "Cerca…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Jenis Widget Hilang: {{type}}",
|
"missing_type": "Jenis Widget Hilang: {{type}}",
|
||||||
"api_error": "Masalah API",
|
"api_error": "Masalah API",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Lokasi Sekarang",
|
"current": "Lokasi Sekarang",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Manglende miniprogramstype: {{type}}",
|
"missing_type": "Manglende miniprogramstype: {{type}}",
|
||||||
"api_error": "API-feil",
|
"api_error": "API-feil",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Søk …"
|
"placeholder": "Søk …"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Missing Widget Type: {{type}}",
|
"missing_type": "Missing Widget Type: {{type}}",
|
||||||
"api_error": "API Error",
|
"api_error": "API Error",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"total": "Totaal",
|
"total": "Totaal",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Brakujący typ widżetu: {{type}}",
|
"missing_type": "Brakujący typ widżetu: {{type}}",
|
||||||
"api_error": "Błąd API",
|
"api_error": "Błąd API",
|
||||||
"status": "Stan"
|
"status": "Stan",
|
||||||
|
"url": "URL",
|
||||||
|
"information": "Information",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Tipo de Widget ausente: {{type}}",
|
"missing_type": "Tipo de Widget ausente: {{type}}",
|
||||||
"api_error": "Erro da API",
|
"api_error": "Erro da API",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Localização atual",
|
"current": "Localização atual",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Widget ausente: {{type}}",
|
"missing_type": "Widget ausente: {{type}}",
|
||||||
"api_error": "Erro da API",
|
"api_error": "Erro da API",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Pesquisar…"
|
"placeholder": "Pesquisar…"
|
||||||
@ -330,5 +334,9 @@
|
|||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country",
|
"country": "Country",
|
||||||
"public_ip": "Public IP"
|
"public_ip": "Public IP"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Lipsește Tipul de Widget: {{type}}",
|
"missing_type": "Lipsește Tipul de Widget: {{type}}",
|
||||||
"api_error": "Eroare API",
|
"api_error": "Eroare API",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Caută…"
|
"placeholder": "Caută…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Отсутствует тип виджета: {{type}}",
|
"missing_type": "Отсутствует тип виджета: {{type}}",
|
||||||
"api_error": "Ошибка API",
|
"api_error": "Ошибка API",
|
||||||
"status": "Статус"
|
"status": "Статус",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Поиск…"
|
"placeholder": "Поиск…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Missing Widget Type: {{type}}",
|
"missing_type": "Missing Widget Type: {{type}}",
|
||||||
"api_error": "API Error",
|
"api_error": "API Error",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Current Location",
|
"current": "Current Location",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Saknar Widget-typ: {{type}}",
|
"missing_type": "Saknar Widget-typ: {{type}}",
|
||||||
"api_error": "API-fel",
|
"api_error": "API-fel",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Nuvarande plats",
|
"current": "Nuvarande plats",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "విడ్జెట్ లేదు: {{type}}",
|
"missing_type": "విడ్జెట్ లేదు: {{type}}",
|
||||||
"api_error": "API లోపం",
|
"api_error": "API లోపం",
|
||||||
"status": "హోదా"
|
"status": "హోదా",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "ప్రస్తుత స్తలం",
|
"current": "ప్రస్తుత స్తలం",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Kayıp Araç Türü: {{type}}",
|
"missing_type": "Kayıp Araç Türü: {{type}}",
|
||||||
"api_error": "API Hatası",
|
"api_error": "API Hatası",
|
||||||
"status": "Durum"
|
"status": "Durum",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Mevcut Konum",
|
"current": "Mevcut Konum",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Thiếu loại Widget: {{type}}",
|
"missing_type": "Thiếu loại Widget: {{type}}",
|
||||||
"api_error": "Lỗi API",
|
"api_error": "Lỗi API",
|
||||||
"status": "Trạng thái"
|
"status": "Trạng thái",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Tìm kiếm…"
|
"placeholder": "Tìm kiếm…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "缺少小部件類型:{{type}}",
|
"missing_type": "缺少小部件類型:{{type}}",
|
||||||
"api_error": "API 錯誤",
|
"api_error": "API 錯誤",
|
||||||
"status": "狀況"
|
"status": "狀況",
|
||||||
|
"url": "URL",
|
||||||
|
"information": "Information",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "依家位置",
|
"current": "依家位置",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "缺少小部件类型:{{type}}",
|
"missing_type": "缺少小部件类型:{{type}}",
|
||||||
"api_error": "API错误",
|
"api_error": "API错误",
|
||||||
"status": "状态"
|
"status": "状态",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "搜索…"
|
"placeholder": "搜索…"
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Missing Widget Type: {{type}}",
|
"missing_type": "Missing Widget Type: {{type}}",
|
||||||
"api_error": "API Error",
|
"api_error": "API Error",
|
||||||
"status": "Status"
|
"status": "Status",
|
||||||
|
"information": "Information",
|
||||||
|
"url": "URL",
|
||||||
|
"raw_error": "Raw Error",
|
||||||
|
"response_data": "Response Data"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"current": "Current Location",
|
"current": "Current Location",
|
||||||
@ -319,5 +323,9 @@
|
|||||||
"public_ip": "Public IP",
|
"public_ip": "Public IP",
|
||||||
"region": "Region",
|
"region": "Region",
|
||||||
"country": "Country"
|
"country": "Country"
|
||||||
|
},
|
||||||
|
"hdhomerun": {
|
||||||
|
"channels": "Channels",
|
||||||
|
"hd": "HD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ export default function Item({ service }) {
|
|||||||
{service.container && service.server && (
|
{service.container && service.server && (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
statsOpen && !statsClosing ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0",
|
statsOpen && !statsClosing ? "max-h-[110px] opacity-100" : " max-h-[0] opacity-0",
|
||||||
"w-full overflow-hidden transition-all duration-300 ease-in-out"
|
"w-full overflow-hidden transition-all duration-300 ease-in-out"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
|
import Error from "./error";
|
||||||
|
|
||||||
export default function Container({ error = false, children, service }) {
|
export default function Container({ error = false, children, service }) {
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return <Error error={error} />
|
||||||
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1">
|
|
||||||
<div className="font-thin text-sm">{error}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let visibleChildren = children;
|
let visibleChildren = children;
|
||||||
|
50
src/components/services/widget/error.jsx
Normal file
50
src/components/services/widget/error.jsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { IoAlertCircle } from "react-icons/io5";
|
||||||
|
|
||||||
|
function displayError(error) {
|
||||||
|
return JSON.stringify(error[1] ? error[1] : error, null, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayData(data) {
|
||||||
|
return (data.type === 'Buffer') ? Buffer.from(data).toString() : JSON.stringify(data, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Error({ error }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
if (error?.data?.error) {
|
||||||
|
error = error.data.error; // eslint-disable-line no-param-reassign
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<details className="px-1 pb-1">
|
||||||
|
<summary className="block text-center mt-1 mb-0 mx-auto p-3 rounded bg-rose-900/80 hover:bg-rose-900/95 text-theme-900 cursor-pointer">
|
||||||
|
<div className="flex items-center justify-center text-xs font-bold">
|
||||||
|
<IoAlertCircle className="mr-1 w-5 h-5"/>{t("widget.api_error")} {error.message && t("widget.information")}
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<div className="bg-white dark:bg-theme-200/50 mt-2 rounded text-rose-900 text-xs font-mono whitespace-pre-wrap break-all">
|
||||||
|
<ul className="p-4">
|
||||||
|
{error.message && <li>
|
||||||
|
<span className="text-black">{t("widget.api_error")}:</span> {error.message}
|
||||||
|
</li>}
|
||||||
|
{error.url && <li className="mt-2">
|
||||||
|
<span className="text-black">{t("widget.url")}:</span> {error.url}
|
||||||
|
</li>}
|
||||||
|
{error.rawError && <li className="mt-2">
|
||||||
|
<span className="text-black">{t("widget.raw_error")}:</span>
|
||||||
|
<div className="ml-2">
|
||||||
|
{displayError(error.rawError)}
|
||||||
|
</div>
|
||||||
|
</li>}
|
||||||
|
{error.data && <li className="mt-2">
|
||||||
|
<span className="text-black">{t("widget.response_data")}:</span>
|
||||||
|
<div className="ml-2">
|
||||||
|
{displayData(error.data)}
|
||||||
|
</div>
|
||||||
|
</li>}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
}
|
@ -12,7 +12,7 @@ export default function Widget({ options }) {
|
|||||||
options.type = "unifi_console";
|
options.type = "unifi_console";
|
||||||
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
|
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
|
||||||
|
|
||||||
if (statsError || statsData?.error) {
|
if (statsError) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
<div className="flex flex-col justify-center first:ml-0 ml-4">
|
||||||
<div className="flex flex-row items-center justify-end">
|
<div className="flex flex-row items-center justify-end">
|
||||||
|
@ -9,9 +9,6 @@ export default function Document() {
|
|||||||
content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations."
|
content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations."
|
||||||
/>
|
/>
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=4" />
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=4" />
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" />
|
|
||||||
<link rel="manifest" href="/site.webmanifest?v=4" />
|
<link rel="manifest" href="/site.webmanifest?v=4" />
|
||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=4" color="#1e9cd7" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=4" color="#1e9cd7" />
|
||||||
</Head>
|
</Head>
|
||||||
|
@ -46,7 +46,7 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
res.status(500).send({
|
res.status(500).send({
|
||||||
error: "unknown error",
|
error: {message: "Unknown error"},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,9 +219,17 @@ function Home({ initialSettings }) {
|
|||||||
<title>{initialSettings.title || "Homepage"}</title>
|
<title>{initialSettings.title || "Homepage"}</title>
|
||||||
{initialSettings.base && <base href={initialSettings.base} />}
|
{initialSettings.base && <base href={initialSettings.base} />}
|
||||||
{initialSettings.favicon ? (
|
{initialSettings.favicon ? (
|
||||||
|
<>
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href={initialSettings.favicon} />
|
||||||
<link rel="icon" href={initialSettings.favicon} />
|
<link rel="icon" href={initialSettings.favicon} />
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
<>
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=4" />
|
||||||
<link rel="shortcut icon" href="/homepage.ico" />
|
<link rel="shortcut icon" href="/homepage.ico" />
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=4" />
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<meta
|
<meta
|
||||||
name="msapplication-TileColor"
|
name="msapplication-TileColor"
|
||||||
|
@ -54,3 +54,7 @@ body {
|
|||||||
background-color: var(--scrollbar-thumb);
|
background-color: var(--scrollbar-thumb);
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
@ -4,7 +4,7 @@ import path from "path";
|
|||||||
|
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
|
|
||||||
import checkAndCopyConfig from "utils/config/config";
|
import checkAndCopyConfig, { getSettings } from "utils/config/config";
|
||||||
import {
|
import {
|
||||||
servicesFromConfig,
|
servicesFromConfig,
|
||||||
servicesFromDocker,
|
servicesFromDocker,
|
||||||
@ -52,6 +52,7 @@ export async function servicesResponse() {
|
|||||||
let discoveredDockerServices;
|
let discoveredDockerServices;
|
||||||
let discoveredKubernetesServices;
|
let discoveredKubernetesServices;
|
||||||
let configuredServices;
|
let configuredServices;
|
||||||
|
let initialSettings;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
discoveredDockerServices = cleanServiceGroups(await servicesFromDocker());
|
discoveredDockerServices = cleanServiceGroups(await servicesFromDocker());
|
||||||
@ -77,6 +78,14 @@ export async function servicesResponse() {
|
|||||||
configuredServices = [];
|
configuredServices = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
initialSettings = await getSettings();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to load settings.yaml, please check for errors");
|
||||||
|
if (e) console.error(e);
|
||||||
|
initialSettings = {};
|
||||||
|
}
|
||||||
|
|
||||||
const mergedGroupsNames = [
|
const mergedGroupsNames = [
|
||||||
...new Set([
|
...new Set([
|
||||||
discoveredDockerServices.map((group) => group.name),
|
discoveredDockerServices.map((group) => group.name),
|
||||||
@ -86,6 +95,7 @@ export async function servicesResponse() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const mergedGroups = [];
|
const mergedGroups = [];
|
||||||
|
const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null;
|
||||||
|
|
||||||
mergedGroupsNames.forEach((groupName) => {
|
mergedGroupsNames.forEach((groupName) => {
|
||||||
const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || { services: [] };
|
const discoveredDockerGroup = discoveredDockerServices.find((group) => group.name === groupName) || { services: [] };
|
||||||
@ -101,7 +111,13 @@ export async function servicesResponse() {
|
|||||||
].filter((service) => service),
|
].filter((service) => service),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (definedLayouts) {
|
||||||
|
const layoutIndex = definedLayouts.findIndex(layout => layout === mergedGroup.name);
|
||||||
|
if (layoutIndex > -1) mergedGroups.splice(layoutIndex, 0, mergedGroup);
|
||||||
|
else mergedGroups.push(mergedGroup);
|
||||||
|
} else {
|
||||||
mergedGroups.push(mergedGroup);
|
mergedGroups.push(mergedGroup);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return mergedGroups;
|
return mergedGroups;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import getServiceWidget from "utils/config/service-helpers";
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
import { formatApiCall } from "utils/proxy/api-helpers";
|
import { formatApiCall } from "utils/proxy/api-helpers";
|
||||||
|
import validateWidgetData from "utils/proxy/validate-widget-data";
|
||||||
import { httpProxy } from "utils/proxy/http";
|
import { httpProxy } from "utils/proxy/http";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
import widgets from "widgets/widgets";
|
import widgets from "widgets/widgets";
|
||||||
@ -51,7 +52,11 @@ export default async function credentialedProxyHandler(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status >= 400) {
|
if (status >= 400) {
|
||||||
logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname);
|
logger.error("HTTP Error %d calling %s", status, url.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateWidgetData(widget, endpoint, data)) {
|
||||||
|
return res.status(500).json({error: {message: "Invalid data", url, data}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType) res.setHeader("Content-Type", contentType);
|
if (contentType) res.setHeader("Content-Type", contentType);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import getServiceWidget from "utils/config/service-helpers";
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
import { formatApiCall } from "utils/proxy/api-helpers";
|
import { formatApiCall } from "utils/proxy/api-helpers";
|
||||||
|
import validateWidgetData from "utils/proxy/validate-widget-data";
|
||||||
import { httpProxy } from "utils/proxy/http";
|
import { httpProxy } from "utils/proxy/http";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
import widgets from "widgets/widgets";
|
import widgets from "widgets/widgets";
|
||||||
@ -32,6 +33,11 @@ export default async function genericProxyHandler(req, res, map) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let resultData = data;
|
let resultData = data;
|
||||||
|
|
||||||
|
if (!validateWidgetData(widget, endpoint, resultData)) {
|
||||||
|
return res.status(status).json({error: {message: "Invalid data", url, data: resultData}});
|
||||||
|
}
|
||||||
|
|
||||||
if (status === 200 && map) {
|
if (status === 200 && map) {
|
||||||
resultData = map(data);
|
resultData = map(data);
|
||||||
}
|
}
|
||||||
@ -44,6 +50,7 @@ export default async function genericProxyHandler(req, res, map) {
|
|||||||
|
|
||||||
if (status >= 400) {
|
if (status >= 400) {
|
||||||
logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname);
|
logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname);
|
||||||
|
return res.status(status).json({error: {message: "HTTP Error", url, data}});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(status).send(resultData);
|
return res.status(status).send(resultData);
|
||||||
|
@ -98,6 +98,6 @@ export async function httpProxy(url, params = {}) {
|
|||||||
catch (err) {
|
catch (err) {
|
||||||
logger.error("Error calling %s//%s%s...", url.protocol, url.hostname, url.pathname);
|
logger.error("Error calling %s//%s%s...", url.protocol, url.hostname, url.pathname);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
return [500, "application/json", { error: "Unexpected error" }, null];
|
return [500, "application/json", { error: {message: err?.message ?? "Unknown error", url, rawError: err} }, null];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,11 @@ import useSWR from "swr";
|
|||||||
import { formatProxyUrl } from "./api-helpers";
|
import { formatProxyUrl } from "./api-helpers";
|
||||||
|
|
||||||
export default function useWidgetAPI(widget, ...options) {
|
export default function useWidgetAPI(widget, ...options) {
|
||||||
return useSWR(formatProxyUrl(widget, ...options));
|
const config = {};
|
||||||
|
if (options?.refreshInterval) {
|
||||||
|
config.refreshInterval = options.refreshInterval;
|
||||||
|
}
|
||||||
|
const { data, error } = useSWR(formatProxyUrl(widget, ...options), config);
|
||||||
|
// make the data error the top-level error
|
||||||
|
return { data, error: data?.error ?? error }
|
||||||
}
|
}
|
||||||
|
22
src/utils/proxy/validate-widget-data.js
Normal file
22
src/utils/proxy/validate-widget-data.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import widgets from "widgets/widgets";
|
||||||
|
|
||||||
|
export default function validateWidgetData(widget, endpoint, data) {
|
||||||
|
let valid = true;
|
||||||
|
let dataParsed;
|
||||||
|
try {
|
||||||
|
dataParsed = JSON.parse(data);
|
||||||
|
} catch (e) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataParsed && Object.entries(dataParsed).length) {
|
||||||
|
const validate = widgets[widget.type]?.mappings?.[endpoint]?.validate;
|
||||||
|
validate?.forEach(key => {
|
||||||
|
if (dataParsed[key] === undefined) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: adguardData, error: adguardError } = useWidgetAPI(widget, "stats");
|
const { data: adguardData, error: adguardError } = useWidgetAPI(widget, "stats");
|
||||||
|
|
||||||
if (adguardError) {
|
if (adguardError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={adguardError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!adguardData) {
|
if (!adguardData) {
|
||||||
|
@ -14,7 +14,8 @@ export default function Component({ service }) {
|
|||||||
const { data: failedLoginsData, error: failedLoginsError } = useWidgetAPI(widget, "login_failed");
|
const { data: failedLoginsData, error: failedLoginsError } = useWidgetAPI(widget, "login_failed");
|
||||||
|
|
||||||
if (usersError || loginsError || failedLoginsError) {
|
if (usersError || loginsError || failedLoginsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = usersError ?? loginsError ?? failedLoginsError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!usersData || !loginsData || !failedLoginsData) {
|
if (!usersData || !loginsData || !failedLoginsData) {
|
||||||
|
@ -14,7 +14,8 @@ export default function Component({ service }) {
|
|||||||
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexers");
|
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexers");
|
||||||
|
|
||||||
if (statsError || filtersError || indexersError) {
|
if (statsError || filtersError || indexersError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = statsError ?? filtersError ?? indexersError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData || !filtersData || !indexersData) {
|
if (!statsData || !filtersData || !indexersData) {
|
||||||
|
@ -7,6 +7,10 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
stats: {
|
stats: {
|
||||||
endpoint: "release/stats",
|
endpoint: "release/stats",
|
||||||
|
validate: [
|
||||||
|
"push_approved_count",
|
||||||
|
"push_rejected_count"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
endpoint: "filters",
|
endpoint: "filters",
|
||||||
|
@ -12,8 +12,9 @@ export default function Component({ service }) {
|
|||||||
const { data: episodesData, error: episodesError } = useWidgetAPI(widget, "episodes");
|
const { data: episodesData, error: episodesError } = useWidgetAPI(widget, "episodes");
|
||||||
const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movies");
|
const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movies");
|
||||||
|
|
||||||
if (episodesError || moviesError) {
|
if (moviesError || episodesError) {
|
||||||
return <Container error="widget.api_error" />;
|
const finalError = moviesError ?? episodesError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!episodesData || !moviesData) {
|
if (!episodesData || !moviesData) {
|
||||||
|
@ -9,12 +9,11 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data } = useWidgetAPI(widget, "info");
|
const { data, error } = useWidgetAPI(widget, "info");
|
||||||
|
|
||||||
if (!data) {
|
if (error) {
|
||||||
return <Container error="widget.api_error" />;
|
return <Container error={error} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalObserved = Object.keys(data).length;
|
const totalObserved = Object.keys(data).length;
|
||||||
let diffsDetected = 0;
|
let diffsDetected = 0;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export default function Component({ service }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData || !dateRange) {
|
if (!statsData || !dateRange) {
|
||||||
|
@ -12,6 +12,7 @@ const components = {
|
|||||||
emby: dynamic(() => import("./emby/component")),
|
emby: dynamic(() => import("./emby/component")),
|
||||||
gluetun: dynamic(() => import("./gluetun/component")),
|
gluetun: dynamic(() => import("./gluetun/component")),
|
||||||
gotify: dynamic(() => import("./gotify/component")),
|
gotify: dynamic(() => import("./gotify/component")),
|
||||||
|
hdhomerun: dynamic(() => import("./hdhomerun/component")),
|
||||||
homebridge: dynamic(() => import("./homebridge/component")),
|
homebridge: dynamic(() => import("./homebridge/component")),
|
||||||
jackett: dynamic(() => import("./jackett/component")),
|
jackett: dynamic(() => import("./jackett/component")),
|
||||||
jellyfin: dynamic(() => import("./emby/component")),
|
jellyfin: dynamic(() => import("./emby/component")),
|
||||||
|
@ -17,8 +17,9 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { data: statsData, error: statsError } = useSWR(`/api/docker/stats/${widget.container}/${widget.server || ""}`);
|
const { data: statsData, error: statsError } = useSWR(`/api/docker/stats/${widget.container}/${widget.server || ""}`);
|
||||||
|
|
||||||
if (statsError || statusError) {
|
if (statsError || statsData?.error || statusError || statusData?.error) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = statsError ?? statsData?.error ?? statusError ?? statusData?.error;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statusData && statusData.status !== "running") {
|
if (statusData && statusData.status !== "running") {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import useSWR from "swr";
|
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
|
import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
|
||||||
import { MdOutlineSmartDisplay } from "react-icons/md";
|
import { MdOutlineSmartDisplay } from "react-icons/md";
|
||||||
|
|
||||||
import Container from "components/services/widget/container";
|
import Container from "components/services/widget/container";
|
||||||
import { formatProxyUrl, formatProxyUrlWithSegments } from "utils/proxy/api-helpers";
|
import { formatProxyUrlWithSegments } from "utils/proxy/api-helpers";
|
||||||
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
function ticksToTime(ticks) {
|
function ticksToTime(ticks) {
|
||||||
const milliseconds = ticks / 10000;
|
const milliseconds = ticks / 10000;
|
||||||
@ -157,7 +157,7 @@ export default function Component({ service }) {
|
|||||||
data: sessionsData,
|
data: sessionsData,
|
||||||
error: sessionsError,
|
error: sessionsError,
|
||||||
mutate: sessionMutate,
|
mutate: sessionMutate,
|
||||||
} = useSWR(formatProxyUrl(widget, "Sessions"), {
|
} = useWidgetAPI(widget, "Sessions", {
|
||||||
refreshInterval: 5000,
|
refreshInterval: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -171,8 +171,8 @@ export default function Component({ service }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessionsError || sessionsData?.error) {
|
if (sessionsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={sessionsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sessionsData) {
|
if (!sessionsData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: gluetunData, error: gluetunError } = useWidgetAPI(widget, "ip");
|
const { data: gluetunData, error: gluetunError } = useWidgetAPI(widget, "ip");
|
||||||
|
|
||||||
if (gluetunError) {
|
if (gluetunError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={gluetunError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gluetunData) {
|
if (!gluetunData) {
|
||||||
|
@ -7,6 +7,11 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
ip: {
|
ip: {
|
||||||
endpoint: "publicip/ip",
|
endpoint: "publicip/ip",
|
||||||
|
validate: [
|
||||||
|
"public_ip",
|
||||||
|
"region",
|
||||||
|
"country"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: appsData, error: appsError } = useWidgetAPI(widget, "application");
|
const { data: appsData, error: appsError } = useWidgetAPI(widget, "application");
|
||||||
@ -14,7 +10,8 @@ export default function Component({ service }) {
|
|||||||
const { data: clientsData, error: clientsError } = useWidgetAPI(widget, "client");
|
const { data: clientsData, error: clientsError } = useWidgetAPI(widget, "client");
|
||||||
|
|
||||||
if (appsError || messagesError || clientsError) {
|
if (appsError || messagesError || clientsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = appsError ?? messagesError ?? clientsError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
32
src/widgets/hdhomerun/component.jsx
Normal file
32
src/widgets/hdhomerun/component.jsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import Container from "components/services/widget/container";
|
||||||
|
import Block from "components/services/widget/block";
|
||||||
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
|
export default function Component({ service }) {
|
||||||
|
const { widget } = service;
|
||||||
|
|
||||||
|
const { data: channelsData, error: channelsError } = useWidgetAPI(widget, "lineup");
|
||||||
|
|
||||||
|
if (channelsError) {
|
||||||
|
return <Container error={channelsError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!channelsData) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="hdhomerun.channels" />
|
||||||
|
<Block label="hdhomerun.hd" />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hdChannels = channelsData?.filter((channel) => channel.HD === 1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="hdhomerun.channels" value={channelsData.length } />
|
||||||
|
<Block label="hdhomerun.hd" value={hdChannels.length} />
|
||||||
|
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
14
src/widgets/hdhomerun/widget.js
Normal file
14
src/widgets/hdhomerun/widget.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import genericProxyHandler from "utils/proxy/handlers/generic";
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/{endpoint}",
|
||||||
|
proxyHandler: genericProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
"lineup": {
|
||||||
|
endpoint: "lineup.json",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
@ -11,8 +11,8 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { data: homebridgeData, error: homebridgeError } = useWidgetAPI(widget, "info");
|
const { data: homebridgeData, error: homebridgeError } = useWidgetAPI(widget, "info");
|
||||||
|
|
||||||
if (homebridgeError || homebridgeData?.error) {
|
if (homebridgeError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={homebridgeError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!homebridgeData) {
|
if (!homebridgeData) {
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexers");
|
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexers");
|
||||||
|
|
||||||
if (indexersError) {
|
if (indexersError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={indexersError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!indexersData) {
|
if (!indexersData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "request/count");
|
const { data: statsData, error: statsError } = useWidgetAPI(widget, "request/count");
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData) {
|
if (!statsData) {
|
||||||
|
@ -7,6 +7,11 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
"request/count": {
|
"request/count": {
|
||||||
endpoint: "request/count",
|
endpoint: "request/count",
|
||||||
|
validate: [
|
||||||
|
"pending",
|
||||||
|
"approved",
|
||||||
|
"available"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,8 @@ export default function Component({ service }) {
|
|||||||
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue/status");
|
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue/status");
|
||||||
|
|
||||||
if (albumsError || wantedError || queueError) {
|
if (albumsError || wantedError || queueError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = albumsError ?? wantedError ?? queueError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!albumsData || !wantedData || !queueData) {
|
if (!albumsData || !wantedData || !queueData) {
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "instance");
|
const { data: statsData, error: statsError } = useWidgetAPI(widget, "instance");
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData) {
|
if (!statsData) {
|
||||||
|
@ -26,8 +26,8 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { data: navidromeData, error: navidromeError } = useWidgetAPI(widget, "getNowPlaying");
|
const { data: navidromeData, error: navidromeError } = useWidgetAPI(widget, "getNowPlaying");
|
||||||
|
|
||||||
if (navidromeError || navidromeData?.error || navidromeData?.["subsonic-response"]?.error) {
|
if (navidromeError || navidromeData?.["subsonic-response"]?.error) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={navidromeError ?? navidromeData?.["subsonic-response"]?.error} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!navidromeData) {
|
if (!navidromeData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: infoData, error: infoError } = useWidgetAPI(widget, "nginx/proxy-hosts");
|
const { data: infoData, error: infoError } = useWidgetAPI(widget, "nginx/proxy-hosts");
|
||||||
|
|
||||||
if (infoError || infoData?.error) {
|
if (infoError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={infoError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!infoData) {
|
if (!infoData) {
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
|
const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
|
||||||
|
|
||||||
if (statusError) {
|
if (statusError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statusError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statusData) {
|
if (!statusData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "Request/count");
|
const { data: statsData, error: statsError } = useWidgetAPI(widget, "Request/count");
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData) {
|
if (!statsData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "request/count");
|
const { data: statsData, error: statsError } = useWidgetAPI(widget, "request/count");
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData) {
|
if (!statsData) {
|
||||||
|
@ -7,6 +7,11 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
"request/count": {
|
"request/count": {
|
||||||
endpoint: "request/count",
|
endpoint: "request/count",
|
||||||
|
validate: [
|
||||||
|
"pending",
|
||||||
|
"approved",
|
||||||
|
"available",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: piholeData, error: piholeError } = useWidgetAPI(widget, "api.php");
|
const { data: piholeData, error: piholeError } = useWidgetAPI(widget, "api.php");
|
||||||
|
|
||||||
if (piholeError) {
|
if (piholeError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={piholeError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!piholeData) {
|
if (!piholeData) {
|
||||||
|
@ -7,6 +7,11 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
"api.php": {
|
"api.php": {
|
||||||
endpoint: "api.php",
|
endpoint: "api.php",
|
||||||
|
validate: [
|
||||||
|
"dns_queries_today",
|
||||||
|
"ads_blocked_today",
|
||||||
|
"domains_being_blocked"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
import useSWR from "swr";
|
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
import Block from "components/services/widget/block";
|
import Block from "components/services/widget/block";
|
||||||
import Container from "components/services/widget/container";
|
import Container from "components/services/widget/container";
|
||||||
import { formatProxyUrl } from "utils/proxy/api-helpers";
|
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: plexData, error: plexAPIError } = useSWR(formatProxyUrl(widget, "unified"), {
|
const { data: plexData, error: plexAPIError } = useWidgetAPI(widget, "unified", {
|
||||||
refreshInterval: 5000,
|
refreshInterval: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (plexAPIError) {
|
if (plexAPIError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={plexAPIError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!plexData) {
|
if (!plexData) {
|
||||||
|
@ -44,7 +44,7 @@ async function fetchFromPlexAPI(endpoint, widget) {
|
|||||||
|
|
||||||
if (status !== 200) {
|
if (status !== 200) {
|
||||||
logger.error("HTTP %d communicating with Plex. Data: %s", status, data.toString());
|
logger.error("HTTP %d communicating with Plex. Data: %s", status, data.toString());
|
||||||
return [status, data.toString()];
|
return [status, data];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -65,6 +65,11 @@ export default async function plexProxyHandler(req, res) {
|
|||||||
logger.debug("Getting streams from Plex API");
|
logger.debug("Getting streams from Plex API");
|
||||||
let streams;
|
let streams;
|
||||||
let [status, apiData] = await fetchFromPlexAPI("/status/sessions", widget);
|
let [status, apiData] = await fetchFromPlexAPI("/status/sessions", widget);
|
||||||
|
|
||||||
|
if (status !== 200) {
|
||||||
|
return res.status(status).json({error: {message: "HTTP error communicating with Plex API", data: Buffer.from(apiData).toString()}});
|
||||||
|
}
|
||||||
|
|
||||||
if (apiData && apiData.MediaContainer) {
|
if (apiData && apiData.MediaContainer) {
|
||||||
streams = apiData.MediaContainer._attributes.size;
|
streams = apiData.MediaContainer._attributes.size;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ export default function Component({ service }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (containersError) {
|
if (containersError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={containersError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!containersData) {
|
if (!containersData) {
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexer");
|
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexer");
|
||||||
const { data: grabsData, error: grabsError } = useWidgetAPI(widget, "indexerstats");
|
const { data: grabsData, error: grabsError } = useWidgetAPI(widget, "indexerstats");
|
||||||
|
|
||||||
if (indexersError || grabsError) {
|
if (indexersError || grabsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = indexersError ?? grabsError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!indexersData || !grabsData) {
|
if (!indexersData || !grabsData) {
|
||||||
|
@ -16,7 +16,7 @@ export default function Component({ service }) {
|
|||||||
const { data: clusterData, error: clusterError } = useWidgetAPI(widget, "cluster/resources");
|
const { data: clusterData, error: clusterError } = useWidgetAPI(widget, "cluster/resources");
|
||||||
|
|
||||||
if (clusterError) {
|
if (clusterError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={clusterError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clusterData || !clusterData.data) {
|
if (!clusterData || !clusterData.data) {
|
||||||
|
@ -9,8 +9,8 @@ export default function Component({ service }) {
|
|||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
const { data: pyloadData, error: pyloadError } = useWidgetAPI(widget, "status");
|
const { data: pyloadData, error: pyloadError } = useWidgetAPI(widget, "status");
|
||||||
|
|
||||||
if (pyloadError || pyloadData?.error) {
|
if (pyloadError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={pyloadError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pyloadData) {
|
if (!pyloadData) {
|
||||||
|
@ -84,9 +84,9 @@ export default async function pyloadProxyHandler(req, res) {
|
|||||||
|
|
||||||
if (data?.error || status !== 200) {
|
if (data?.error || status !== 200) {
|
||||||
try {
|
try {
|
||||||
return res.status(status).send(Buffer.from(data).toString());
|
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data: Buffer.from(data).toString()}});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res.status(status).send(data);
|
return res.status(status).send({error: {message: "HTTP error communicating with Plex API", data}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ export default async function pyloadProxyHandler(req, res) {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
return res.status(500).send(e.toString());
|
return res.status(500).send({error: {message: `Error communicating with Plex API: ${e.toString()}`}});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(400).json({ error: 'Invalid proxy service type' });
|
return res.status(400).json({ error: 'Invalid proxy service type' });
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents/info");
|
const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents/info");
|
||||||
|
|
||||||
if (torrentError) {
|
if (torrentError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={torrentError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!torrentData) {
|
if (!torrentData) {
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movie");
|
const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movie");
|
||||||
const { data: queuedData, error: queuedError } = useWidgetAPI(widget, "queue/status");
|
const { data: queuedData, error: queuedError } = useWidgetAPI(widget, "queue/status");
|
||||||
|
|
||||||
if (moviesError || queuedError) {
|
if (moviesError || queuedError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = moviesError ?? queuedError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moviesData || !queuedData) {
|
if (!moviesData || !queuedData) {
|
||||||
|
@ -16,6 +16,9 @@ const widget = {
|
|||||||
},
|
},
|
||||||
"queue/status": {
|
"queue/status": {
|
||||||
endpoint: "queue/status",
|
endpoint: "queue/status",
|
||||||
|
validate: [
|
||||||
|
"totalCount"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,8 @@ export default function Component({ service }) {
|
|||||||
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue/status");
|
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue/status");
|
||||||
|
|
||||||
if (booksError || wantedError || queueError) {
|
if (booksError || wantedError || queueError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = booksError ?? wantedError ?? queueError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!booksData || !wantedData || !queueData) {
|
if (!booksData || !wantedData || !queueData) {
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: statusData, error: statusError } = useWidgetAPI(widget);
|
const { data: statusData, error: statusError } = useWidgetAPI(widget);
|
||||||
|
|
||||||
if (statusError) {
|
if (statusError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statusError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statusData) {
|
if (!statusData) {
|
||||||
|
@ -22,7 +22,7 @@ export default function Component({ service }) {
|
|||||||
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue");
|
const { data: queueData, error: queueError } = useWidgetAPI(widget, "queue");
|
||||||
|
|
||||||
if (queueError) {
|
if (queueError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={queueError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!queueData) {
|
if (!queueData) {
|
||||||
|
@ -7,6 +7,9 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
queue: {
|
queue: {
|
||||||
endpoint: "queue",
|
endpoint: "queue",
|
||||||
|
validate: [
|
||||||
|
"queue"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: wantedData, error: wantedError } = useWidgetAPI(widget, "wanted/missing");
|
const { data: wantedData, error: wantedError } = useWidgetAPI(widget, "wanted/missing");
|
||||||
@ -14,7 +10,8 @@ export default function Component({ service }) {
|
|||||||
const { data: seriesData, error: seriesError } = useWidgetAPI(widget, "series");
|
const { data: seriesData, error: seriesError } = useWidgetAPI(widget, "series");
|
||||||
|
|
||||||
if (wantedError || queuedError || seriesError) {
|
if (wantedError || queuedError || seriesError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = wantedError ?? queuedError ?? seriesError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wantedData || !queuedData || !seriesData) {
|
if (!wantedData || !queuedData || !seriesData) {
|
||||||
|
@ -10,13 +10,19 @@ const widget = {
|
|||||||
endpoint: "series",
|
endpoint: "series",
|
||||||
map: (data) => ({
|
map: (data) => ({
|
||||||
total: asJson(data).length,
|
total: asJson(data).length,
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
queue: {
|
queue: {
|
||||||
endpoint: "queue",
|
endpoint: "queue",
|
||||||
|
validate: [
|
||||||
|
"totalRecords"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"wanted/missing": {
|
"wanted/missing": {
|
||||||
endpoint: "wanted/missing",
|
endpoint: "wanted/missing",
|
||||||
|
validate: [
|
||||||
|
"totalRecords"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -11,8 +11,8 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { data: speedtestData, error: speedtestError } = useWidgetAPI(widget, "speedtest/latest");
|
const { data: speedtestData, error: speedtestError } = useWidgetAPI(widget, "speedtest/latest");
|
||||||
|
|
||||||
if (speedtestError || (speedtestData && !speedtestData.data)) {
|
if (speedtestError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={speedtestError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!speedtestData) {
|
if (!speedtestData) {
|
||||||
|
@ -7,6 +7,9 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
"speedtest/latest": {
|
"speedtest/latest": {
|
||||||
endpoint: "speedtest/latest",
|
endpoint: "speedtest/latest",
|
||||||
|
validate: [
|
||||||
|
"data"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "status");
|
const { data: statsData, error: statsError } = useWidgetAPI(widget, "status");
|
||||||
|
|
||||||
if (statsError) {
|
if (statsError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={statsError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!statsData) {
|
if (!statsData) {
|
||||||
|
@ -7,6 +7,11 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
status: {
|
status: {
|
||||||
endpoint: "status",
|
endpoint: "status",
|
||||||
|
validate: [
|
||||||
|
"numActiveSessions",
|
||||||
|
"numConnections",
|
||||||
|
"bytesProxied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
import useSWR from "swr";
|
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import { BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
|
import { BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
|
||||||
import { MdOutlineSmartDisplay, MdSmartDisplay } from "react-icons/md";
|
import { MdOutlineSmartDisplay, MdSmartDisplay } from "react-icons/md";
|
||||||
|
|
||||||
import Container from "components/services/widget/container";
|
import Container from "components/services/widget/container";
|
||||||
import { formatProxyUrl } from "utils/proxy/api-helpers";
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
function millisecondsToTime(milliseconds) {
|
function millisecondsToTime(milliseconds) {
|
||||||
const seconds = Math.floor((milliseconds / 1000) % 60);
|
const seconds = Math.floor((milliseconds / 1000) % 60);
|
||||||
@ -119,12 +118,12 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: activityData, error: activityError } = useSWR(formatProxyUrl(widget, "get_activity"), {
|
const { data: activityData, error: activityError } = useWidgetAPI(widget, "get_activity", {
|
||||||
refreshInterval: 5000,
|
refreshInterval: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (activityError) {
|
if (activityError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={activityError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!activityData) {
|
if (!activityData) {
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import { useTranslation } from "next-i18next";
|
|
||||||
|
|
||||||
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 { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: traefikData, error: traefikError } = useWidgetAPI(widget, "overview");
|
const { data: traefikData, error: traefikError } = useWidgetAPI(widget, "overview");
|
||||||
|
|
||||||
if (traefikError) {
|
if (traefikError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={traefikError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!traefikData) {
|
if (!traefikData) {
|
||||||
|
@ -7,6 +7,9 @@ const widget = {
|
|||||||
mappings: {
|
mappings: {
|
||||||
overview: {
|
overview: {
|
||||||
endpoint: "overview",
|
endpoint: "overview",
|
||||||
|
validate: [
|
||||||
|
"http"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ export default function Component({ service }) {
|
|||||||
const { data: torrentData, error: torrentError } = useWidgetAPI(widget);
|
const { data: torrentData, error: torrentError } = useWidgetAPI(widget);
|
||||||
|
|
||||||
if (torrentError) {
|
if (torrentError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
return <Container error={torrentError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!torrentData) {
|
if (!torrentData) {
|
||||||
|
@ -68,6 +68,7 @@ export default async function transmissionProxyHandler(req, res) {
|
|||||||
|
|
||||||
if (status !== 200) {
|
if (status !== 200) {
|
||||||
logger.error("Error getting data from Transmission: %d. Data: %s", status, data);
|
logger.error("Error getting data from Transmission: %d. Data: %s", status, data);
|
||||||
|
return res.status(500).send({error: {message:"Error getting data from Transmission", url, data}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType) res.setHeader("Content-Type", contentType);
|
if (contentType) res.setHeader("Content-Type", contentType);
|
||||||
|
@ -42,7 +42,8 @@ export default function Component({ service }) {
|
|||||||
const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
|
const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
|
||||||
|
|
||||||
if (alertError || statusError) {
|
if (alertError || statusError) {
|
||||||
return <Container error={t("widget.api_error")} />;
|
const finalError = alertError ?? statusError;
|
||||||
|
return <Container error={finalError} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alertData || !statusData) {
|
if (!alertData || !statusData) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user