Merge branch 'main' of github.com:GodD6366/homepage
This commit is contained in:
commit
8e8d578a66
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"**/.next": true,
|
||||
"**/node_modules": true
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@
|
||||
- Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6
|
||||
- Supports all Raspberry Pi's, most SBCs & Apple Silicon
|
||||
- Full i18n support with automatic language detection
|
||||
- Translantions for Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romainian, Russian, Spanish, Swedish and Yue
|
||||
- Translantions for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romainian, Russian, Spanish, Swedish and Yue
|
||||
- Want to help translate? [Join the Weblate project](https://hosted.weblate.org/engage/homepage/)
|
||||
- Service & Web Bookmarks
|
||||
- Docker Integration
|
||||
|
||||
@ -177,8 +177,19 @@
|
||||
},
|
||||
"proxmox": {
|
||||
"vms": "VMs",
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"mem": "Memòria",
|
||||
"cpu": "Processador",
|
||||
"lxc": "LXC"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,17 @@
|
||||
"used": "Used",
|
||||
"load": "Load"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "RX",
|
||||
"tx": "TX",
|
||||
|
||||
@ -176,9 +176,20 @@
|
||||
"failedLoginsLast24H": "Inicios de sesión fallidos (24h)"
|
||||
},
|
||||
"proxmox": {
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"mem": "Memoria",
|
||||
"cpu": "Procesador",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"up": "UP",
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,9 +176,20 @@
|
||||
"failedLoginsLast24H": "Epäonnistuneita kirjautumisia (24h)"
|
||||
},
|
||||
"proxmox": {
|
||||
"mem": "MEM",
|
||||
"mem": "RAM",
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
"vms": "VKt"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"wait": "Please wait",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"up": "UP",
|
||||
"down": "DOWN"
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,9 +176,20 @@
|
||||
"failedLoginsLast24H": "Cnx. échouées (24h)"
|
||||
},
|
||||
"proxmox": {
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"mem": "Mém",
|
||||
"cpu": "Cpu",
|
||||
"lxc": "LxC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wait": "Please wait",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"lan_users": "LAN Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,5 +191,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
195
public/locales/te/common.json
Normal file
195
public/locales/te/common.json
Normal file
@ -0,0 +1,195 @@
|
||||
{
|
||||
"readarr": {
|
||||
"books": "పుస్తకాలు",
|
||||
"wanted": "కావలెను",
|
||||
"queued": "క్యూయూఎడ్"
|
||||
},
|
||||
"adguard": {
|
||||
"blocked": "నిరోధించబడింది",
|
||||
"filtered": "ఫిల్టర్ చేయబడింది",
|
||||
"latency": "జాప్యం",
|
||||
"queries": "ప్రశ్నలు"
|
||||
},
|
||||
"strelaysrv": {
|
||||
"numActiveSessions": "సెషన్స్",
|
||||
"numConnections": "కనెక్షన్లు",
|
||||
"dataRelayed": "రెలయెడఁ",
|
||||
"transferRate": "రేటు"
|
||||
},
|
||||
"widget": {
|
||||
"missing_type": "విడ్జెట్ లేదు: {{type}}",
|
||||
"api_error": "API లోపం",
|
||||
"status": "హోదా"
|
||||
},
|
||||
"weather": {
|
||||
"current": "ప్రస్తుత స్తలం",
|
||||
"allow": "అనుమతించడానికి క్లిక్ చేయండి",
|
||||
"updating": "నవీకరిస్తోంది",
|
||||
"wait": "దయచేసి వేచి ఉండండి"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "వెతకండి…"
|
||||
},
|
||||
"resources": {
|
||||
"cpu": "సీ పి యూ",
|
||||
"total": "మొత్తం",
|
||||
"free": "ఉచిత",
|
||||
"used": "ఉపయోగించబడిన",
|
||||
"load": "లోడ్"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "RX",
|
||||
"tx": "TX",
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"offline": "ఆఫ్లైన్"
|
||||
},
|
||||
"emby": {
|
||||
"playing": "ఆడుతున్నారు",
|
||||
"transcoding": "ట్రాన్స్కోడింగ్",
|
||||
"bitrate": "బిట్రేట్",
|
||||
"no_active": "యాక్టివ్ స్ట్రీమ్లు లేవు"
|
||||
},
|
||||
"tautulli": {
|
||||
"playing": "ఆడుతున్నారు",
|
||||
"transcoding": "ట్రాన్స్కోడింగ్",
|
||||
"bitrate": "బిట్రేట్",
|
||||
"no_active": "యాక్టివ్ స్ట్రీమ్లు లేవు"
|
||||
},
|
||||
"nzbget": {
|
||||
"rate": "రేట్",
|
||||
"remaining": "మిగిలింది",
|
||||
"downloaded": "డౌన్లోడ్ చేయబడింది"
|
||||
},
|
||||
"sabnzbd": {
|
||||
"rate": "రేట్",
|
||||
"queue": "వరుస",
|
||||
"timeleft": "మిగిలి వున్న సమయం"
|
||||
},
|
||||
"rutorrent": {
|
||||
"active": "చురుకుగా",
|
||||
"upload": "అప్లోడ్",
|
||||
"download": "డౌన్లోడ్"
|
||||
},
|
||||
"transmission": {
|
||||
"download": "డౌన్లోడ్",
|
||||
"upload": "అప్లోడ్",
|
||||
"leech": "జలగ",
|
||||
"seed": "సీడ్"
|
||||
},
|
||||
"qbittorrent": {
|
||||
"download": "డౌన్లోడ్",
|
||||
"upload": "అప్లోడ్",
|
||||
"leech": "లీచ్",
|
||||
"seed": "సీడ్"
|
||||
},
|
||||
"sonarr": {
|
||||
"wanted": "కావలెను",
|
||||
"queued": "క్యూయూఎడ్",
|
||||
"series": "సిరీస్"
|
||||
},
|
||||
"radarr": {
|
||||
"wanted": "కావలెను",
|
||||
"queued": "క్యూయూఎడ్",
|
||||
"movies": "సినిమాలు"
|
||||
},
|
||||
"lidarr": {
|
||||
"wanted": "కావలెను",
|
||||
"queued": "క్యూయూఎడ్",
|
||||
"albums": "ఆల్బములు"
|
||||
},
|
||||
"bazarr": {
|
||||
"missingEpisodes": "ఎపిసోడ్లు లేవు",
|
||||
"missingMovies": "సినిమాలు లేవు"
|
||||
},
|
||||
"ombi": {
|
||||
"pending": "పెండింగ్",
|
||||
"approved": "ఆమోదించబడింది",
|
||||
"available": "అందుబాటులో వున్నవి"
|
||||
},
|
||||
"jellyseerr": {
|
||||
"pending": "పెండింగ్",
|
||||
"approved": "ఆమోదించబడింది",
|
||||
"available": "అందుబాటులో"
|
||||
},
|
||||
"overseerr": {
|
||||
"pending": "పెండింగ్",
|
||||
"approved": "ఆమోదించబడింది",
|
||||
"available": "అందుబాటులో"
|
||||
},
|
||||
"pihole": {
|
||||
"queries": "ప్రశ్నలు",
|
||||
"blocked": "నిరోధించబడింది",
|
||||
"gravity": "గురుత్వాకర్షణ"
|
||||
},
|
||||
"speedtest": {
|
||||
"upload": "అప్లోడ్",
|
||||
"download": "డౌన్లోడ్",
|
||||
"ping": "పింగ్"
|
||||
},
|
||||
"portainer": {
|
||||
"running": "నడుస్తోంది",
|
||||
"stopped": "ఆగిపోయింది",
|
||||
"total": "మొత్తం"
|
||||
},
|
||||
"traefik": {
|
||||
"routers": "రౌటర్లు",
|
||||
"services": "సేవలు",
|
||||
"middleware": "మిడిల్వేర్"
|
||||
},
|
||||
"npm": {
|
||||
"enabled": "ప్రారంభించబడింది",
|
||||
"disabled": "Disabled",
|
||||
"total": "మొత్తం"
|
||||
},
|
||||
"coinmarketcap": {
|
||||
"configure": "ట్రాక్ చేయడానికి ఒకటి లేదా అంతకంటే ఎక్కువ క్రిప్టో కరెన్సీలను కాన్ఫిగర్ చేయండి",
|
||||
"1hour": "1 గంట",
|
||||
"1day": "1 రోజు",
|
||||
"7days": "7 రోజులు",
|
||||
"30days": "30 రోజులు"
|
||||
},
|
||||
"gotify": {
|
||||
"apps": "అప్లికేషన్లు",
|
||||
"clients": "ఖాతాదారులు",
|
||||
"messages": "సందేశాలు"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "సూచికలు",
|
||||
"numberOfGrabs": "గ్రాబ్స్",
|
||||
"numberOfQueries": "ప్రశ్నలు",
|
||||
"numberOfFailGrabs": "ఫెయిల్ గ్రాబ్స్",
|
||||
"numberOfFailQueries": "విఫలమైన ప్రశ్నలు"
|
||||
},
|
||||
"jackett": {
|
||||
"configured": "కాన్ఫిగర్ చేయబడింది",
|
||||
"errored": "పొరపాటు జరిగింది"
|
||||
},
|
||||
"mastodon": {
|
||||
"user_count": "వినియోగదారులు",
|
||||
"status_count": "పోస్ట్లు",
|
||||
"domain_count": "డొమైన్లు"
|
||||
},
|
||||
"authentik": {
|
||||
"users": "వినియోగదారులు",
|
||||
"loginsLast24H": "లాగిన్లు (24గం)",
|
||||
"failedLoginsLast24H": "విఫలమైన లాగిన్లు (24గం)"
|
||||
},
|
||||
"proxmox": {
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,23 +162,34 @@
|
||||
"mastodon": {
|
||||
"user_count": "用户",
|
||||
"status_count": "Posts",
|
||||
"domain_count": "Domains"
|
||||
"domain_count": "域"
|
||||
},
|
||||
"strelaysrv": {
|
||||
"numActiveSessions": "Sessions",
|
||||
"dataRelayed": "Relayed",
|
||||
"numConnections": "Connections",
|
||||
"transferRate": "Rate"
|
||||
"numActiveSessions": "会话",
|
||||
"dataRelayed": "中继",
|
||||
"numConnections": "连接",
|
||||
"transferRate": "速度"
|
||||
},
|
||||
"authentik": {
|
||||
"users": "Users",
|
||||
"loginsLast24H": "Logins (24h)",
|
||||
"failedLoginsLast24H": "Failed Logins (24h)"
|
||||
"users": "用户",
|
||||
"loginsLast24H": "登录 (24h)",
|
||||
"failedLoginsLast24H": "登录失败 (24h)"
|
||||
},
|
||||
"proxmox": {
|
||||
"mem": "MEM",
|
||||
"cpu": "CPU",
|
||||
"mem": "内存",
|
||||
"cpu": "处理器",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,5 +180,16 @@
|
||||
"cpu": "CPU",
|
||||
"lxc": "LXC",
|
||||
"vms": "VMs"
|
||||
},
|
||||
"unifi": {
|
||||
"users": "Users",
|
||||
"uptime": "System Uptime",
|
||||
"days": "Days",
|
||||
"wan": "WAN",
|
||||
"lan_users": "LAN Users",
|
||||
"wlan_users": "WLAN Users",
|
||||
"up": "UP",
|
||||
"down": "DOWN",
|
||||
"wait": "Please wait"
|
||||
}
|
||||
}
|
||||
|
||||
119
src/components/widgets/unifi_console/unifi_console.jsx
Normal file
119
src/components/widgets/unifi_console/unifi_console.jsx
Normal file
@ -0,0 +1,119 @@
|
||||
import { BiError, BiWifi, BiCheckCircle, BiXCircle } from "react-icons/bi";
|
||||
import { MdSettingsEthernet } from "react-icons/md";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { SiUbiquiti } from "react-icons/si";
|
||||
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
|
||||
export default function Widget({ options }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options.type = "unifi_console";
|
||||
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites");
|
||||
|
||||
if (statsError || statsData?.error) {
|
||||
return (
|
||||
<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-col items-center">
|
||||
<BiError className="w-8 h-8 text-theme-800 dark:text-theme-200" />
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-sm">{t("widget.api_error")}</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const defaultSite = statsData?.data?.find(s => s.name === "default");
|
||||
|
||||
if (!defaultSite) {
|
||||
return (
|
||||
<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-col items-center">
|
||||
<SiUbiquiti className="w-5 h-5 text-theme-800 dark:text-theme-200" />
|
||||
</div>
|
||||
<div className="flex flex-col ml-3 text-left">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs">{t("unifi.wait")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const wan = defaultSite.health.find(h => h.subsystem === "wan");
|
||||
const lan = defaultSite.health.find(h => h.subsystem === "lan");
|
||||
const wlan = defaultSite.health.find(h => h.subsystem === "wlan");
|
||||
const data = {
|
||||
name: wan.gw_name,
|
||||
uptime: wan["gw_system-stats"].uptime,
|
||||
up: wan.status === 'ok',
|
||||
wlan: {
|
||||
users: wlan.num_user,
|
||||
status: wlan.status
|
||||
},
|
||||
lan: {
|
||||
users: lan.num_user,
|
||||
status: lan.status
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row ml-3">
|
||||
<SiUbiquiti className="text-theme-800 dark:text-theme-200 w-3 h-3 mr-1" />
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs font-bold flex flex-row justify-between">
|
||||
{data.name}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row ml-3 text-[10px] justify-between">
|
||||
<div className="flex flex-row" title={t("unifi.uptime")}>
|
||||
<div className="pr-0.5 text-theme-800 dark:text-theme-200">
|
||||
{t("common.number", {
|
||||
value: data.uptime / 86400,
|
||||
maximumFractionDigits: 1,
|
||||
})}
|
||||
</div>
|
||||
<div className="pr-1 text-theme-800 dark:text-theme-200">{t("unifi.days")}</div>
|
||||
</div>
|
||||
<div className="flex flex-row">
|
||||
<div className="pr-1 text-theme-800 dark:text-theme-200">{t("unifi.wan")}</div>
|
||||
{ data.up
|
||||
? <BiCheckCircle className="text-theme-800 dark:text-theme-200 h-4 w-3" />
|
||||
: <BiXCircle className="text-theme-800 dark:text-theme-200 h-4 w-3" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-row ml-3 py-0.5">
|
||||
<BiWifi className="text-theme-800 dark:text-theme-200 w-4 h-4 mr-1" />
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between" title={t("unifi.users")}>
|
||||
<div className="pr-0.5">
|
||||
{t("common.number", {
|
||||
value: data.wlan.users,
|
||||
maximumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row ml-3 pb-0.5">
|
||||
<MdSettingsEthernet className="text-theme-800 dark:text-theme-200 w-4 h-4 mr-1" />
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between" title={t("unifi.users")}>
|
||||
<div className="pr-0.5">
|
||||
{t("common.number", {
|
||||
value: data.lan.users,
|
||||
maximumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -10,6 +10,7 @@ const widgetMappings = {
|
||||
greeting: dynamic(() => import("components/widgets/greeting/greeting")),
|
||||
datetime: dynamic(() => import("components/widgets/datetime/datetime")),
|
||||
logo: dynamic(() => import("components/widgets/logo/logo"), { ssr: false }),
|
||||
unifi_console: dynamic(() => import("components/widgets/unifi_console/unifi_console")),
|
||||
};
|
||||
|
||||
export default function Widget({ widget }) {
|
||||
|
||||
@ -263,8 +263,6 @@ function Home({ initialSettings }) {
|
||||
export default function Wrapper({ initialSettings, fallback }) {
|
||||
const wrappedStyle = {};
|
||||
if (initialSettings && initialSettings.background) {
|
||||
// wrappedStyle.backgroundImage = `url(${initialSettings.background})`;
|
||||
// wrappedStyle.backgroundSize = "cover";
|
||||
const opacity = initialSettings.backgroundOpacity ?? 1;
|
||||
const opacityValue = 1 - opacity;
|
||||
wrappedStyle.backgroundImage = `
|
||||
|
||||
@ -1,16 +1,36 @@
|
||||
import checkAndCopyConfig, { getSettings } from "utils/config/config";
|
||||
import themes from "utils/styles/themes";
|
||||
import { servicesResponse, bookmarksResponse } from "utils/config/api-response";
|
||||
|
||||
export async function getServerSideProps({ res }) {
|
||||
checkAndCopyConfig("settings.yaml");
|
||||
const settings = getSettings();
|
||||
const services = await servicesResponse();
|
||||
const bookmarks = await bookmarksResponse();
|
||||
|
||||
const color = settings.color || "slate";
|
||||
const theme = settings.theme || "dark";
|
||||
|
||||
const serviceShortcuts = services.map((group) =>
|
||||
group.services.map((service) => ({
|
||||
name: service.name,
|
||||
url: service.href,
|
||||
description: service.description,
|
||||
}))
|
||||
);
|
||||
|
||||
const bookmarkShortcuts = bookmarks.map((group) =>
|
||||
group.bookmarks.map((service) => ({
|
||||
name: service.name,
|
||||
url: service.href,
|
||||
}))
|
||||
);
|
||||
|
||||
const shortcuts = [...serviceShortcuts, ...bookmarkShortcuts].flat();
|
||||
|
||||
const manifest = {
|
||||
name: "Homepage",
|
||||
short_name: "Homepage",
|
||||
name: settings.title || "Homepage",
|
||||
short_name: settings.title || "Homepage",
|
||||
icons: [
|
||||
{
|
||||
src: "/android-chrome-192x192.png?v=2",
|
||||
@ -23,6 +43,7 @@ export async function getServerSideProps({ res }) {
|
||||
type: "image/png",
|
||||
},
|
||||
],
|
||||
shortcuts,
|
||||
theme_color: themes[color][theme],
|
||||
background_color: themes[color][theme],
|
||||
display: "standalone",
|
||||
|
||||
@ -2,7 +2,7 @@ export function formatApiCall(url, args) {
|
||||
const find = /\{.*?\}/g;
|
||||
const replace = (match) => {
|
||||
const key = match.replace(/\{|\}/g, "");
|
||||
return args[key];
|
||||
return args[key] || "";
|
||||
};
|
||||
|
||||
return url.replace(/\/+$/, "").replace(find, replace);
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import cache from "memory-cache";
|
||||
|
||||
const defaultDuration = 5;
|
||||
|
||||
export default async function cachedFetch(url, duration) {
|
||||
const cached = cache.get(url);
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
duration = duration || defaultDuration;
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ const components = {
|
||||
tautulli: dynamic(() => import("./tautulli/component")),
|
||||
traefik: dynamic(() => import("./traefik/component")),
|
||||
transmission: dynamic(() => import("./transmission/component")),
|
||||
unifi: dynamic(() => import("./unifi/component")),
|
||||
};
|
||||
|
||||
export default components;
|
||||
|
||||
@ -40,14 +40,16 @@ export default function Component({ service }) {
|
||||
);
|
||||
}
|
||||
|
||||
const network = statsData.stats.networks?.eth0 || statsData.stats.networks?.network;
|
||||
|
||||
return (
|
||||
<Container service={service}>
|
||||
<Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
|
||||
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.memory_stats.usage })} />
|
||||
{statsData.stats.networks && (
|
||||
{network && (
|
||||
<>
|
||||
<Block label="docker.rx" value={t("common.bytes", { value: statsData.stats.networks.eth0.rx_bytes })} />
|
||||
<Block label="docker.tx" value={t("common.bytes", { value: statsData.stats.networks.eth0.tx_bytes })} />
|
||||
<Block label="docker.rx" value={t("common.bytes", { value: network.rx_bytes })} />
|
||||
<Block label="docker.tx" value={t("common.bytes", { value: network.tx_bytes })} />
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
58
src/widgets/unifi/component.jsx
Normal file
58
src/widgets/unifi/component.jsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
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 { t } = useTranslation();
|
||||
|
||||
const { widget } = service;
|
||||
|
||||
const { data: statsData, error: statsError } = useWidgetAPI(widget, "stat/sites");
|
||||
|
||||
if (statsError || statsData?.error) {
|
||||
return <Container error={t("widget.api_error")} />;
|
||||
}
|
||||
|
||||
const defaultSite = statsData?.data?.find(s => s.name === "default");
|
||||
|
||||
if (!defaultSite) {
|
||||
return (
|
||||
<Container service={service}>
|
||||
<Block label="unifi.uptime" />
|
||||
<Block label="unifi.wan" />
|
||||
<Block label="unifi.lan_users" />
|
||||
<Block label="unifi.wlan_users" />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const wan = defaultSite.health.find(h => h.subsystem === "wan");
|
||||
const lan = defaultSite.health.find(h => h.subsystem === "lan");
|
||||
const wlan = defaultSite.health.find(h => h.subsystem === "wlan");
|
||||
const data = {
|
||||
name: wan.gw_name,
|
||||
uptime: wan["gw_system-stats"].uptime,
|
||||
up: wan.status === 'ok',
|
||||
wlan: {
|
||||
users: wlan.num_user,
|
||||
status: wlan.status
|
||||
},
|
||||
lan: {
|
||||
users: lan.num_user,
|
||||
status: lan.status
|
||||
},
|
||||
};
|
||||
|
||||
const uptime = `${t("common.number", { value: data.uptime / 86400, maximumFractionDigits: 1 })} ${t("unifi.days")}`;
|
||||
|
||||
return (
|
||||
<Container service={service}>
|
||||
<Block label="unifi.uptime" value={ uptime } />
|
||||
<Block label="unifi.wan" value={ data.up ? t("unifi.up") : t("unifi.down") } />
|
||||
<Block label="unifi.lan_users" value={ t("common.number", { value: data.lan.users }) } />
|
||||
<Block label="unifi.wlan_users" value={ t("common.number", { value: data.wlan.users }) } />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
119
src/widgets/unifi/proxy.js
Normal file
119
src/widgets/unifi/proxy.js
Normal file
@ -0,0 +1,119 @@
|
||||
import cache from "memory-cache";
|
||||
|
||||
import { formatApiCall } from "utils/proxy/api-helpers";
|
||||
import { httpProxy } from "utils/proxy/http";
|
||||
import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
|
||||
import { getSettings } from "utils/config/config";
|
||||
import getServiceWidget from "utils/config/service-helpers";
|
||||
import createLogger from "utils/logger";
|
||||
import widgets from "widgets/widgets";
|
||||
|
||||
const udmpPrefix = "/proxy/network";
|
||||
const proxyName = "unifiProxyHandler";
|
||||
const prefixCacheKey = `${proxyName}__prefix`;
|
||||
const logger = createLogger(proxyName);
|
||||
|
||||
async function getWidget(req) {
|
||||
const { group, service, type } = req.query;
|
||||
|
||||
let widget = null;
|
||||
if (type === "unifi_console") {
|
||||
const settings = getSettings();
|
||||
widget = settings.unifi_console;
|
||||
if (!widget) {
|
||||
logger.debug("There is no unifi_console section in settings.yaml");
|
||||
return null;
|
||||
}
|
||||
widget.type = "unifi";
|
||||
} else {
|
||||
if (!group || !service) {
|
||||
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
|
||||
return null;
|
||||
}
|
||||
|
||||
widget = await getServiceWidget(group, service);
|
||||
|
||||
if (!widget) {
|
||||
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
async function login(widget) {
|
||||
const endpoint = (widget.prefix === udmpPrefix) ? "auth/login" : "login";
|
||||
const api = widgets?.[widget.type]?.api?.replace("{prefix}", ""); // no prefix for login url
|
||||
const loginUrl = new URL(formatApiCall(api, { endpoint, ...widget }));
|
||||
const loginBody = { username: widget.username, password: widget.password, remember: true };
|
||||
const headers = { "Content-Type": "application/json" };
|
||||
const [status, contentType, data, responseHeaders] = await httpProxy(loginUrl, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(loginBody),
|
||||
headers,
|
||||
});
|
||||
return [status, contentType, data, responseHeaders];
|
||||
}
|
||||
|
||||
export default async function unifiProxyHandler(req, res) {
|
||||
const widget = await getWidget(req);
|
||||
if (!widget) {
|
||||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
||||
const api = widgets?.[widget.type]?.api;
|
||||
if (!api) {
|
||||
return res.status(403).json({ error: "Service does not support API calls" });
|
||||
}
|
||||
|
||||
let [status, contentType, data, responseHeaders] = [];
|
||||
let prefix = cache.get(prefixCacheKey);
|
||||
if (prefix === null) {
|
||||
// auto detect if we're talking to a UDM Pro, and cache the result so that we
|
||||
// don't make two requests each time data from Unifi is required
|
||||
[status, contentType, data, responseHeaders] = await httpProxy(widget.url);
|
||||
prefix = "";
|
||||
if (responseHeaders["x-csrf-token"]) {
|
||||
prefix = udmpPrefix;
|
||||
}
|
||||
cache.put(prefixCacheKey, prefix);
|
||||
}
|
||||
|
||||
widget.prefix = prefix;
|
||||
|
||||
const { endpoint } = req.query;
|
||||
const url = new URL(formatApiCall(api, { endpoint, ...widget }));
|
||||
const params = { method: "GET", headers: {} };
|
||||
setCookieHeader(url, params);
|
||||
|
||||
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
|
||||
if (status === 401) {
|
||||
logger.debug("Unifi isn't logged in or rejected the reqeust, attempting login.");
|
||||
[status, contentType, data, responseHeaders] = await login(widget);
|
||||
|
||||
if (status !== 200) {
|
||||
logger.error("HTTP %d logging in to Unifi. Data: %s", status, data);
|
||||
return res.status(status).end(data);
|
||||
}
|
||||
|
||||
const json = JSON.parse(data.toString());
|
||||
if (!(json?.meta?.rc === "ok" || json.login_time)) {
|
||||
logger.error("Error logging in to Unifi: Data: %s", data);
|
||||
return res.status(401).end(data);
|
||||
}
|
||||
|
||||
addCookieToJar(url, responseHeaders);
|
||||
setCookieHeader(url, params);
|
||||
|
||||
logger.debug("Retrying Unifi request after login.");
|
||||
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
|
||||
}
|
||||
|
||||
if (status !== 200) {
|
||||
logger.error("HTTP %d getting data from Unifi endpoint %s. Data: %s", status, url.href, data);
|
||||
}
|
||||
|
||||
if (contentType) res.setHeader("Content-Type", contentType);
|
||||
return res.status(status).send(data);
|
||||
}
|
||||
14
src/widgets/unifi/widget.js
Normal file
14
src/widgets/unifi/widget.js
Normal file
@ -0,0 +1,14 @@
|
||||
import unifiProxyHandler from "./proxy";
|
||||
|
||||
const widget = {
|
||||
api: "{url}{prefix}/api/{endpoint}",
|
||||
proxyHandler: unifiProxyHandler,
|
||||
|
||||
mappings: {
|
||||
"stat/sites": {
|
||||
endpoint: "stat/sites",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default widget;
|
||||
@ -27,6 +27,7 @@ import strelaysrv from "./strelaysrv/widget";
|
||||
import tautulli from "./tautulli/widget";
|
||||
import traefik from "./traefik/widget";
|
||||
import transmission from "./transmission/widget";
|
||||
import unifi from "./unifi/widget";
|
||||
|
||||
const widgets = {
|
||||
adguard,
|
||||
@ -59,6 +60,8 @@ const widgets = {
|
||||
tautulli,
|
||||
traefik,
|
||||
transmission,
|
||||
unifi,
|
||||
unifi_console: unifi
|
||||
};
|
||||
|
||||
export default widgets;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user