Compare commits

...

17 Commits

Author SHA1 Message Date
shamoon
d4a39299c5 Fix k8s traefikingresslist detection (#2030) 2023-09-19 15:00:22 -07:00
shamoon
7d2bfa2d84 Update index.jsx 2023-09-19 14:10:19 -07:00
shamoon
c094bd3d83 Update service-helpers.js 2023-09-19 13:12:03 -07:00
Daniel Li
69ee459e8a Fix: SMART result of OMV should always from monitored devices (#2025) 2023-09-19 08:46:16 -07:00
shamoon
ed0527a3da Fix custom.js not working (#2023) 2023-09-18 21:41:31 -07:00
shamoon
04a1c68ba0 Fix k3d memory specification 2023-09-18 14:35:42 -07:00
Pysta
b74faea449 Translated using Weblate (Slovak)
Currently translated at 24.1% (129 of 534 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/sk/
2023-09-18 14:23:36 +02:00
avb15621
0c9b6480c5 Translated using Weblate (Dutch)
Currently translated at 53.9% (288 of 534 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-09-18 14:23:35 +02:00
Roel van de Wiel
6fbb3bfbb1 Translated using Weblate (Dutch)
Currently translated at 53.9% (288 of 534 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-09-18 14:23:35 +02:00
A Warmerdam
53355561a8 Translated using Weblate (Dutch)
Currently translated at 53.9% (288 of 534 strings)

Translation: Homepage/Homepage
Translate-URL: https://hosted.weblate.org/projects/homepage/homepage/nl/
2023-09-18 14:23:35 +02:00
Jan-Philipp Fischer
6e43194f71 Fix: Kubernetes discovery & Check for Custom Resource Definitions (#2003)
* Implement a CRD existence check

* test adding patch
2023-09-17 16:49:03 -07:00
shamoon
a72a27a8b5 Maybe handle k8s traefik ingress routes returns nothing 2023-09-17 10:05:45 -07:00
Ben Phelps
6c682cb648 Update README.md 2023-09-17 11:00:15 +03:00
Ben Phelps
e7587b8308 update readme image 2023-09-17 10:57:37 +03:00
shamoon
e663994c9b Allow tab name 0 2023-09-16 15:24:32 -07:00
shamoon
898fb88d86 Allow numbers in tab name (#2004) 2023-09-16 14:37:06 -07:00
Ben Phelps
6f5c2a8c1e update readme 2023-09-16 22:16:34 +03:00
9 changed files with 270 additions and 261 deletions

134
README.md
View File

@@ -6,71 +6,58 @@
</p> </p>
<p align="center"> <p align="center">
A modern <em>(fully static, fast)</em>, secure <em>(fully proxied)</em>, highly customizable application dashboard with integrations for more than 25 services and translations for over 15 languages. Easily configured via YAML files (or discovery via docker labels). A modern, <em>fully static, fast</em>, secure <em>fully proxied</em>, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.
</p> </p>
<p align="center"> <p align="center">
<img src="images/1.png" /> <img src="images/1.png?v=2" />
</p> </p>
<p align="center"> <p align="center">
<img src="images/2.png" width="19%" /> <a href="https://github.com/benphelps/homepage/actions/workflows/docker-publish.yml"><img alt="GitHub Workflow Status (with event)" src="https://img.shields.io/github/actions/workflow/status/benphelps/homepage/docker-publish.yml"></a>
<img src="images/3.png" width="19%" /> &nbsp;
<img src="images/4.png" width="19%" />
<img src="images/5.png" width="19%" />
<img src="images/6.png" width="19%" />
</p>
<p align="center">
<a href="https://discord.gg/k4ruYNrudu"><img src="https://img.shields.io/badge/Discord - Chat-blue?logo=discord&logoColor=white" /></a>
<a href="https://paypal.me/phelpsben" title="Donate"><img src="https://img.shields.io/badge/PayPal - Donate-blue?logo=paypal&logoColor=white" alt="Linkedin - phelpsben"></a>
</p>
<p align="center">
<a href="https://github.com/benphelps/homepage/actions/workflows/docker-publish.yml"><img src="https://github.com/benphelps/homepage/actions/workflows/docker-publish.yml/badge.svg" alt="Docker"></a>
<a href="https://hosted.weblate.org/engage/homepage/"><img src="https://hosted.weblate.org/widgets/homepage/-/homepage/svg-badge.svg" alt="Weblate"></a> <a href="https://hosted.weblate.org/engage/homepage/"><img src="https://hosted.weblate.org/widgets/homepage/-/homepage/svg-badge.svg" alt="Weblate"></a>
&nbsp;
<a href="https://discord.gg/k4ruYNrudu"><img alt="Discord" src="https://img.shields.io/discord/1019316731635834932"></a>
&nbsp;
<a href="https://paypal.me/phelpsben" title="Donate"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/benphelps"></a>
</p> </p>
## Features # Features
- **Fast!** The entire site is statically generated at build time, so you can expect instant load times With features like quick search, bookmarks, weather support, a wide range of integrations and widgets, an elegant and modern design, and a focus on performance, Homepage is your ideal start to the day and a handy companion throughout it.
- **Secure!** Every API request to backend services goes through a proxy server, so your API keys are never exposed to the frontend client.
- Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6
- Supports all Raspberry Pi's, most SBCs & Apple Silicon
- Full i18n support with translations for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Malay, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Spanish, Swedish and Yue
- Want to help translate? [Join the Weblate project](https://hosted.weblate.org/engage/homepage/)
- Service & Web Bookmarks
- Docker Integration
- Container status (Running / Stopped) & statistics (CPU, Memory, Network)
- Automatic service discovery (via labels)
- Service Integration
- Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli, Plex and more
- Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent and more
- Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox and more
- Information Providers
- Coin Market Cap, Mastodon and more
- Information & Utility Widgets
- System Stats (Disk, CPU, Memory)
- Weather via [OpenWeatherMap](https://openweathermap.org/) or [Open-Meteo](https://open-meteo.com/)
- Web Search Bar
- UniFi Console, Glances and more
- Instant "Quick-launch" search
- Customizable
- 21 theme colors with light and dark mode support
- Background image support
- Column and Row layout options
## Support & Suggestions - **Fast** - The site is statically generated at build time for instant load times.
- **Secure** - All API requests to backend services are proxied, keeping your API keys hidden. Constantly reviewed for security by the community.
- **For Everyone** - Images built for AMD64, ARM64, ARMv7, and ARMv6.
- **Full i18n** - Support for over 40 languages.
- **Service & Web Bookmarks** - Add custom links to the homepage.
- **Docker Integration** - Container status and stats. Automatic service discovery via labels.
- **Service Integration** - Over 100 service integrations, including popular starr and self-hosted apps.
- **Information & Utility Widgets** - Weather, time, date, search, and more.
- **And much more...**
If you have any questions, suggestions, or general issues, please start a discussion on the [Discussions](https://github.com/benphelps/homepage/discussions) page. ## Docker Integration
For bug reports, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page. Homepage has built-in support for Docker, and can automatically discover and add services to the homepage based on labels. See the [Docker](https://gethomepage.dev/en/installation/docker/) page for more information.
## Getting Started ## Service Widgets
For configuration options, examples and more, [please check out the homepage site](http://gethomepage.dev). Homepage also has support for over 100 3rd party services, including all popular starr apps, and most popular self-hosted apps. Some examples include: Radarr, Sonarr, Lidarr, Bazarr, Ombi, Tautulli, Plex, Jellyfin, Emby, Transmission, qBittorrent, Deluge, Jackett, NZBGet, SABnzbd, etc. As well as service integrations, Homepage also has a number of information providers, sourcing information from a variety of external 3rd party APIs. See the [Service](https://gethomepage.dev/en/configs/service-widgets/) page for more information.
### With Docker ## Information Widgets
Homepage has built-in support for a number of information providers, including weather, time, date, search, glances and more. System and status information presented at the top of the page. See the [Information Providers](https://gethomepage.dev/en/configs/widgets/) page for more information.
## Customization
Homepage is highly customizable, with support for custom themes, custom CSS & JS, custom layouts, formatting, localization and more. See the [Settings](https://gethomepage.dev/en/configs/settings/) page for more information.
# Getting Started
For configuration options, examples and more, [please check out the homepage documentation](http://gethomepage.dev).
## With Docker
Using docker compose: Using docker compose:
@@ -80,22 +67,31 @@ services:
homepage: homepage:
image: ghcr.io/benphelps/homepage:latest image: ghcr.io/benphelps/homepage:latest
container_name: homepage container_name: homepage
environment:
PUID: 1000 -- optional, your user id
PGID: 1000 -- optional, your group id
ports: ports:
- 3000:3000 - 3000:3000
volumes: volumes:
- /path/to/config:/app/config # Make sure your local config directory exists - /path/to/config:/app/config # Make sure your local config directory exists
- /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations - /var/run/docker.sock:/var/run/docker.sock:ro # optional, for docker integrations
# user: 1000:1000 optional, not compatibile with direct socket see https://gethomepage.dev/en/configs/docker/#using-socket-directly
restart: unless-stopped restart: unless-stopped
``` ```
or docker run: or docker run:
```bash ```bash
docker run -p 3000:3000 -v /path/to/config:/app/config -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/benphelps/homepage:latest docker run --name homepage \
-e PUID=1000 \
-e PGID=1000 \
-p 3000:3000 \
-v /path/to/config:/app/config \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--restart unless-stopped \
ghcr.io/benphelps/homepage:latest
``` ```
### With Node ## With Node
First, clone the repository: First, clone the repository:
@@ -112,22 +108,23 @@ pnpm build
If this is your first time starting, copy the `src/skeleton` directory to `config/` to populate initial example config files. If this is your first time starting, copy the `src/skeleton` directory to `config/` to populate initial example config files.
Finally, run the server: Finally, run the server in production mode:
```bash ```bash
pnpm start pnpm start
``` ```
## Configuration or development mode:
Configuration files will be generated and placed on the first request. ```bash
pnpm dev
```
Configuration is done in the /config directory using .yaml files. Refer to each config for # Configuration
the specific configuration options.
You may also check [the homepage site](http://gethomepage.dev) for detailed configuration instructions, examples and more. Please refere to the [homepage documentation](https://gethomepage.dev/) website for more information. Everything you need to know about configuring Homepage is there. Please read everything carefully before asking for help, as most questions are answered there or are simple YAML configuration issues.
## Development # Development
Install NPM packages, this project uses [pnpm](https://pnpm.io/) (and so should you!): Install NPM packages, this project uses [pnpm](https://pnpm.io/) (and so should you!):
@@ -145,19 +142,14 @@ Open [http://localhost:3000](http://localhost:3000) to start.
This is a [Next.js](https://nextjs.org/) application, see their documentation for more information: This is a [Next.js](https://nextjs.org/) application, see their documentation for more information:
## Contributors # Support & Suggestions
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> If you have any questions, suggestions, or general issues, please start a discussion on the [Discussions](https://github.com/benphelps/homepage/discussions) page.
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<!-- markdownlint-restore --> For bug reports, please open an issue on the [Issues](https://github.com/benphelps/homepage/issues) page.
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END --> ## Contributing & Contributers
Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information.
Thanks to the over 200 contributors who have helped make this project what it is today!
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

After

Width:  |  Height:  |  Size: 734 KiB

View File

@@ -36,8 +36,8 @@ options:
switchCurrentContext: false switchCurrentContext: false
runtime: runtime:
gpuRequest: "" gpuRequest: ""
serversMemory: "1024Mi" serversMemory: "1024MiB"
agentsMemory: "1024Mi" agentsMemory: "1024MiB"
labels: labels:
- label: foo=bar - label: foo=bar
nodeFilters: nodeFilters:

View File

@@ -1,20 +1,20 @@
{ {
"widget": { "widget": {
"missing_type": "Missend Widget Type: {{type}}", "missing_type": "Missend Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API fout",
"status": "Status", "status": "Status",
"information": "Informatie", "information": "Informatie",
"url": "URL", "url": "URL",
"raw_error": "Raw Fout", "raw_error": "Raw Error",
"response_data": "Reactiegegevens" "response_data": "Responsgegevens"
}, },
"resources": { "resources": {
"total": "Totaal", "total": "Totaal",
"free": "Vrij", "free": "Vrij",
"used": "Gebruikt", "used": "Gebruikt",
"load": "Laadt", "load": "lading",
"cpu": "CPU", "cpu": "CPU",
"mem": "MEM", "mem": "GEH",
"days": "d", "days": "d",
"hours": "h", "hours": "h",
"temp": "TEMP", "temp": "TEMP",
@@ -31,7 +31,7 @@
"offline": "Offline", "offline": "Offline",
"error": "Fout", "error": "Fout",
"unknown": "Onbekend", "unknown": "Onbekend",
"running": "Running", "running": "Lopend",
"starting": "Starten", "starting": "Starten",
"unhealthy": "Ongezond", "unhealthy": "Ongezond",
"not_found": "Niet Gevonden", "not_found": "Niet Gevonden",
@@ -72,8 +72,8 @@
"playing": "Afspelen", "playing": "Afspelen",
"transcoding": "Transcodering", "transcoding": "Transcodering",
"bitrate": "Bitsnelheid", "bitrate": "Bitsnelheid",
"no_active": "Geen Actieve Streams", "no_active": "Geen actieve streams",
"plex_connection_error": "Check Plex Connection" "plex_connection_error": "Controleer Plex Connectie"
}, },
"rutorrent": { "rutorrent": {
"active": "Actief", "active": "Actief",
@@ -84,16 +84,16 @@
"wanted": "Gezocht", "wanted": "Gezocht",
"queued": "In de wachtrij", "queued": "In de wachtrij",
"series": "Series", "series": "Series",
"queue": "Queue", "queue": "Rij",
"unknown": "Unknown" "unknown": "Onbekend"
}, },
"radarr": { "radarr": {
"movies": "Films", "movies": "Films",
"wanted": "Gezocht", "wanted": "Gezocht",
"queued": "In de wachtrij", "queued": "In de wachtrij",
"missing": "Missend", "missing": "Missend",
"queue": "Queue", "queue": "Rij",
"unknown": "Unknown" "unknown": "Onbekend"
}, },
"readarr": { "readarr": {
"wanted": "Gezocht", "wanted": "Gezocht",
@@ -114,7 +114,7 @@
"queries": "Queries", "queries": "Queries",
"blocked": "Geblokkeerd", "blocked": "Geblokkeerd",
"gravity": "Gravity", "gravity": "Gravity",
"blocked_percent": "Blocked %" "blocked_percent": "Geblokkerde %"
}, },
"traefik": { "traefik": {
"routers": "Routers", "routers": "Routers",
@@ -135,15 +135,15 @@
"sabnzbd": { "sabnzbd": {
"rate": "Rate", "rate": "Rate",
"queue": "Wachtrij", "queue": "Wachtrij",
"timeleft": "Time Left" "timeleft": "Tijd Over"
}, },
"nzbget": { "nzbget": {
"rate": "Rate", "rate": "Tarief",
"remaining": "Resterend", "remaining": "Resterend",
"downloaded": "Gedownload" "downloaded": "Gedownload"
}, },
"coinmarketcap": { "coinmarketcap": {
"configure": "Configure one or more crypto currencies to track", "configure": "Configureer een of meer crypto eenheiden om bij te houden",
"1hour": "1 Uur", "1hour": "1 Uur",
"7days": "7 Dagen", "7days": "7 Dagen",
"1day": "1 Dag", "1day": "1 Dag",
@@ -151,7 +151,7 @@
}, },
"gotify": { "gotify": {
"apps": "Applicaties", "apps": "Applicaties",
"clients": "Clients", "clients": "Cliënten",
"messages": "Berichten" "messages": "Berichten"
}, },
"prowlarr": { "prowlarr": {
@@ -164,7 +164,7 @@
"transmission": { "transmission": {
"download": "Download", "download": "Download",
"upload": "Upload", "upload": "Upload",
"leech": "Leech", "leech": "Bloedzuiger",
"seed": "Seed" "seed": "Seed"
}, },
"jackett": { "jackett": {
@@ -178,28 +178,28 @@
"lidarr": { "lidarr": {
"wanted": "Gezocht", "wanted": "Gezocht",
"queued": "In de wachtrij", "queued": "In de wachtrij",
"artists": "Artists" "artists": "Artiesten"
}, },
"adguard": { "adguard": {
"queries": "Queries", "queries": "Queries",
"blocked": "Geblokkeerd", "blocked": "Geblokkeerd",
"filtered": "Filtered", "filtered": "Gefilterde",
"latency": "Latency" "latency": "Latency"
}, },
"qbittorrent": { "qbittorrent": {
"download": "Download", "download": "Download",
"upload": "Upload", "upload": "Upload",
"leech": "Leech", "leech": "Bloedzuiger",
"seed": "Seed" "seed": "Seed"
}, },
"mastodon": { "mastodon": {
"user_count": "Users", "user_count": "Gebruikers",
"status_count": "Posts", "status_count": "Posts",
"domain_count": "Domeinen" "domain_count": "Domeinen"
}, },
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sessions", "numActiveSessions": "Sessies",
"numConnections": "Connections", "numConnections": "Connecties",
"dataRelayed": "Relayed", "dataRelayed": "Relayed",
"transferRate": "Rate" "transferRate": "Rate"
}, },
@@ -223,13 +223,13 @@
"wlan_users": "WLAN Gebruikers", "wlan_users": "WLAN Gebruikers",
"up": "UP", "up": "UP",
"down": "DOWN", "down": "DOWN",
"wait": "Wachten aub", "wait": "Even geduld",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Apparaten", "devices": "Apparaten",
"lan_devices": "LAN Apparaten", "lan_devices": "LAN Apparaten",
"wlan_devices": "WLAN Apparaten", "wlan_devices": "WLAN Apparaten",
"empty_data": "Subsystem status onbekend" "empty_data": "Subsysteem status onbekend"
}, },
"plex": { "plex": {
"streams": "Actieve Streams", "streams": "Actieve Streams",
@@ -396,7 +396,7 @@
"deluge": { "deluge": {
"download": "Download", "download": "Download",
"upload": "Upload", "upload": "Upload",
"leech": "Leech", "leech": "Bloedzuiger",
"seed": "Seed" "seed": "Seed"
}, },
"flood": { "flood": {
@@ -409,7 +409,7 @@
"queue": "Wachtrij", "queue": "Wachtrij",
"processed": "Processed", "processed": "Processed",
"errored": "Errored", "errored": "Errored",
"saved": "Saved" "saved": "Opgeslagen"
}, },
"miniflux": { "miniflux": {
"read": "Gelezen", "read": "Gelezen",
@@ -424,16 +424,16 @@
"bibitrate": "{{value, rate(bits: true; binary: true)}}" "bibitrate": "{{value, rate(bits: true; binary: true)}}"
}, },
"omada": { "omada": {
"connectedAp": "Connected APs", "connectedAp": "Verbonden APs",
"activeUser": "Actieve apparaten", "activeUser": "Actieve apparaten",
"alerts": "Meldingen", "alerts": "Meldingen",
"connectedGateway": "Connected gateways", "connectedGateway": "Verbonden gateways",
"connectedSwitches": "Connected switches" "connectedSwitches": "Verbonden switches"
}, },
"downloadstation": { "downloadstation": {
"download": "Download", "download": "Download",
"upload": "Upload", "upload": "Upload",
"leech": "Leech", "leech": "Bloedzuiger",
"seed": "Seed" "seed": "Seed"
}, },
"mikrotik": { "mikrotik": {
@@ -460,7 +460,7 @@
"layers": "Layers" "layers": "Layers"
}, },
"medusa": { "medusa": {
"wanted": "Wanted", "wanted": "Gewild",
"queued": "Queued", "queued": "Queued",
"series": "Series" "series": "Series"
}, },
@@ -589,13 +589,13 @@
"switches_on": "Switches On" "switches_on": "Switches On"
}, },
"freshrss": { "freshrss": {
"subscriptions": "Subscriptions", "subscriptions": "Abonnementen",
"unread": "Unread" "unread": "Ongelezen"
}, },
"channelsdvrserver": { "channelsdvrserver": {
"shows": "Shows", "shows": "Shows",
"recordings": "Recordings", "recordings": "Recordings",
"scheduled": "Scheduled", "scheduled": "Geplanned",
"passes": "Passes" "passes": "Passes"
}, },
"whatsupdocker": { "whatsupdocker": {
@@ -604,25 +604,25 @@
}, },
"tailscale": { "tailscale": {
"address": "Address", "address": "Address",
"expires": "Expires", "expires": "Verloopt",
"never": "Never", "never": "Nooit",
"last_seen": "Last Seen", "last_seen": "Laatst Gezien",
"now": "Now", "now": "Nu",
"years": "{{number}}y", "years": "{{number}}y",
"weeks": "{{number}}w", "weeks": "{{number}}w",
"days": "{{number}}d", "days": "{{number}}d",
"hours": "{{number}}h", "hours": "{{number}}h",
"minutes": "{{number}}m", "minutes": "{{number}}m",
"seconds": "{{number}}s", "seconds": "{{number}}s",
"ago": "{{value}} Ago" "ago": "{{value}} Geleden"
}, },
"qnap": { "qnap": {
"cpuUsage": "CPU Usage", "cpuUsage": "CPU Verbruik",
"memUsage": "MEM Usage", "memUsage": "MEM Gebruik",
"systemTempC": "System Temp", "systemTempC": "Systeem Temperatuur",
"poolUsage": "Pool Usage", "poolUsage": "Pool Gebruik",
"volumeUsage": "Volume Usage", "volumeUsage": "Volume Usage",
"invalid": "Invalid" "invalid": "ongeldig"
}, },
"pfsense": { "pfsense": {
"load": "Load Avg", "load": "Load Avg",
@@ -636,21 +636,21 @@
}, },
"caddy": { "caddy": {
"upstreams": "Upstreams", "upstreams": "Upstreams",
"requests": "Current requests", "requests": "Momentele verzoeken",
"requests_failed": "Failed requests" "requests_failed": "Gefaalde verzoeken"
}, },
"evcc": { "evcc": {
"pv_power": "Production", "pv_power": "Productie",
"battery_soc": "Battery", "battery_soc": "Battery",
"grid_power": "Grid", "grid_power": "Grid",
"home_power": "Consumption", "home_power": "Consumption",
"charge_power": "Charger", "charge_power": "Oplader",
"watt_hour": "Wh" "watt_hour": "Wh"
}, },
"pialert": { "pialert": {
"total": "Total", "total": "Total",
"connected": "Connected", "connected": "Verbonden",
"new_devices": "New Devices", "new_devices": "Nieuwe Apparaten",
"down_alerts": "Down Alerts" "down_alerts": "Down Alerts"
}, },
"jdownloader": { "jdownloader": {

View File

@@ -2,18 +2,18 @@
"docker": { "docker": {
"rx": "RX", "rx": "RX",
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "RAM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline", "offline": "Offline",
"error": "Error", "error": "Chyba",
"unknown": "Unknown", "unknown": "Neznáme",
"running": "Running", "running": "Beží",
"starting": "Starting", "starting": "Spúšťa sa",
"unhealthy": "Unhealthy", "unhealthy": "Nezdravý",
"not_found": "Not Found", "not_found": "Nenájdené",
"exited": "Exited", "exited": "Ukončené",
"partial": "Partial", "partial": "Čiastočný",
"healthy": "Healthy" "healthy": "Zdravý"
}, },
"rutorrent": { "rutorrent": {
"active": "Active", "active": "Active",
@@ -21,10 +21,10 @@
"download": "Download" "download": "Download"
}, },
"tdarr": { "tdarr": {
"queue": "Queue", "queue": "Fronta",
"processed": "Processed", "processed": "Spracované",
"errored": "Errored", "errored": "Chybné",
"saved": "Saved" "saved": "Uložené"
}, },
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sessions", "numActiveSessions": "Sessions",
@@ -144,74 +144,74 @@
"bibitrate": "{{value, rate(bits: true; binary: true)}}" "bibitrate": "{{value, rate(bits: true; binary: true)}}"
}, },
"widget": { "widget": {
"api_error": "API Error", "api_error": "Chyba API",
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Chýba typ widgetu: {{type}}",
"information": "Information", "information": "Informácia",
"status": "Status", "status": "Stav",
"url": "URL", "url": "URL",
"raw_error": "Raw Error", "raw_error": "Nevyriešená chyba",
"response_data": "Response Data" "response_data": "Dáta odpovede"
}, },
"weather": { "weather": {
"current": "Current Location", "current": "Aktuálna poloha",
"allow": "Click to allow", "allow": "Klikni pre povolenie",
"updating": "Updating", "updating": "Prebieha aktualizácia",
"wait": "Please wait" "wait": "Počkajte prosím"
}, },
"search": { "search": {
"placeholder": "Search…" "placeholder": "Hľadať…"
}, },
"resources": { "resources": {
"cpu": "CPU", "cpu": "CPU",
"mem": "MEM", "mem": "RAM",
"total": "Total", "total": "Celkovo",
"free": "Free", "free": "Voľné",
"used": "Used", "used": "Využité",
"load": "Load", "load": "Záťaž",
"temp": "TEMP", "temp": "TEPLOTA",
"max": "Max", "max": "Max.",
"uptime": "UP", "uptime": "BEŽÍ",
"months": "mo", "months": "mes.",
"days": "d", "days": "d",
"hours": "h", "hours": "h",
"minutes": "m" "minutes": "m"
}, },
"unifi": { "unifi": {
"users": "Users", "users": "Používatelia",
"uptime": "System Uptime", "uptime": "Doba prevádzky",
"days": "Days", "days": "D",
"wan": "WAN", "wan": "WAN",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Zariadenia",
"lan_devices": "LAN Devices", "lan_devices": "Zariadenia LAN",
"wlan_devices": "WLAN Devices", "wlan_devices": "Zariadenia WLAN",
"lan_users": "LAN Users", "lan_users": "Používatelia LAN",
"wlan_users": "WLAN Users", "wlan_users": "Používatelia WLAN",
"up": "UP", "up": "BEŽÍ",
"down": "DOWN", "down": "NEBEŽÍ",
"wait": "Please wait", "wait": "Počkajte prosím",
"empty_data": "Subsystem status unknown" "empty_data": "Stav podsystému neznámy"
}, },
"ping": { "ping": {
"error": "Error", "error": "Chyba",
"ping": "Ping" "ping": "Odozva"
}, },
"emby": { "emby": {
"playing": "Playing", "playing": "Prehrávané",
"transcoding": "Transcoding", "transcoding": "Prekódovávané",
"bitrate": "Bitrate", "bitrate": "Prenosová rýchlosť",
"no_active": "No Active Streams", "no_active": "Žiadny aktívny stream",
"movies": "Movies", "movies": "Filmy",
"series": "Series", "series": "Seriály",
"episodes": "Episodes", "episodes": "Epizódy",
"songs": "Songs" "songs": "Skladby"
}, },
"flood": { "flood": {
"download": "Download", "download": "Sťahovanie",
"upload": "Upload", "upload": "Odosielanie",
"leech": "Leech", "leech": "Leechovanie",
"seed": "Seed" "seed": "Seedovanie"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Total Observed",
@@ -276,70 +276,70 @@
"queued": "Queued", "queued": "Queued",
"series": "Series", "series": "Series",
"queue": "Queue", "queue": "Queue",
"unknown": "Unknown" "unknown": "Neznáme"
}, },
"radarr": { "radarr": {
"wanted": "Wanted", "wanted": "Chcené",
"missing": "Missing", "missing": "Chýbajúce",
"queued": "Queued", "queued": "Vo fronte",
"movies": "Movies", "movies": "Filmy",
"queue": "Queue", "queue": "Fronta",
"unknown": "Unknown" "unknown": "Neznáme"
}, },
"lidarr": { "lidarr": {
"wanted": "Wanted", "wanted": "Chcené",
"queued": "Queued", "queued": "Vo fronte",
"artists": "Artists" "artists": "Interpreti"
}, },
"readarr": { "readarr": {
"wanted": "Wanted", "wanted": "Chcené",
"queued": "Queued", "queued": "Vo fronte",
"books": "Books" "books": "Knihy"
}, },
"bazarr": { "bazarr": {
"missingEpisodes": "Missing Episodes", "missingEpisodes": "Chýbajúce epizódy",
"missingMovies": "Missing Movies" "missingMovies": "Chýbajúce filmy"
}, },
"ombi": { "ombi": {
"pending": "Pending", "pending": "Čakajúce",
"approved": "Approved", "approved": "Schválené",
"available": "Available" "available": "Dostupné"
}, },
"jellyseerr": { "jellyseerr": {
"pending": "Pending", "pending": "Čakajúce",
"approved": "Approved", "approved": "Schválené",
"available": "Available" "available": "Dostupné"
}, },
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Čakajúce",
"processing": "Processing", "processing": "Spracovávané",
"approved": "Approved", "approved": "Schválené",
"available": "Available" "available": "Dostupné"
}, },
"pihole": { "pihole": {
"queries": "Queries", "queries": "Dopyty",
"blocked": "Blocked", "blocked": "Zablokované",
"gravity": "Gravity", "gravity": "Gravitácia",
"blocked_percent": "Blocked %" "blocked_percent": "Blokované %"
}, },
"adguard": { "adguard": {
"queries": "Queries", "queries": "Dopyty",
"blocked": "Blocked", "blocked": "Blokované",
"filtered": "Filtered", "filtered": "Filtrované",
"latency": "Latency" "latency": "Odozva"
}, },
"speedtest": { "speedtest": {
"upload": "Upload", "upload": "Odosielanie",
"download": "Download", "download": "Sťahovanie",
"ping": "Ping" "ping": "Ping"
}, },
"portainer": { "portainer": {
"running": "Running", "running": "Spustené",
"stopped": "Stopped", "stopped": "Zastavené",
"total": "Total" "total": "Celkovo"
}, },
"traefik": { "traefik": {
"routers": "Routers", "routers": "Routery",
"services": "Services", "services": "Services",
"middleware": "Middleware" "middleware": "Middleware"
}, },
@@ -589,8 +589,8 @@
"switches_on": "Switches On" "switches_on": "Switches On"
}, },
"freshrss": { "freshrss": {
"subscriptions": "Subscriptions", "subscriptions": "Odbery",
"unread": "Unread" "unread": "Neprečítané"
}, },
"channelsdvrserver": { "channelsdvrserver": {
"shows": "Shows", "shows": "Shows",
@@ -603,18 +603,18 @@
"updates": "Updates" "updates": "Updates"
}, },
"tailscale": { "tailscale": {
"address": "Address", "address": "Adresa",
"years": "{{number}}y", "years": "{{number}}r",
"expires": "Expires", "expires": "Vyprší",
"never": "Never", "never": "Nikdy",
"last_seen": "Last Seen", "last_seen": "Naposledy videné",
"now": "Now", "now": "Teraz",
"weeks": "{{number}}w", "weeks": "{{number}}t",
"days": "{{number}}d", "days": "{{number}}d",
"hours": "{{number}}h", "hours": "{{number}}h",
"minutes": "{{number}}m", "minutes": "{{number}}m",
"seconds": "{{number}}s", "seconds": "{{number}}s",
"ago": "{{value}} Ago" "ago": "Pred {{value}}"
}, },
"qnap": { "qnap": {
"cpuUsage": "CPU Usage", "cpuUsage": "CPU Usage",
@@ -635,23 +635,23 @@
"wanIP": "WAN IP" "wanIP": "WAN IP"
}, },
"caddy": { "caddy": {
"upstreams": "Upstreams", "upstreams": "Odosielanie dát",
"requests": "Current requests", "requests": "Current requests",
"requests_failed": "Failed requests" "requests_failed": "Failed requests"
}, },
"evcc": { "evcc": {
"pv_power": "Production", "pv_power": "Produkcia",
"battery_soc": "Battery", "battery_soc": "Batéria",
"grid_power": "Grid", "grid_power": "Mriežka",
"home_power": "Consumption", "home_power": "Spotreba",
"charge_power": "Charger", "charge_power": "Nabíjačka",
"watt_hour": "Wh" "watt_hour": "Wh"
}, },
"pialert": { "pialert": {
"total": "Total", "total": "Celkovo",
"connected": "Connected", "connected": "Pripojené",
"new_devices": "New Devices", "new_devices": "Nové zariadenia",
"down_alerts": "Down Alerts" "down_alerts": "Upozornenia o výpadkoch"
}, },
"jdownloader": { "jdownloader": {
"downloadCount": "Queue Count", "downloadCount": "Queue Count",

View File

@@ -4,7 +4,7 @@ import classNames from "classnames";
import { TabContext } from "utils/contexts/tab"; import { TabContext } from "utils/contexts/tab";
export function slugify(tabName) { export function slugify(tabName) {
return tabName ? encodeURIComponent(tabName.replace(/\s+/g, '-').toLowerCase()) : '' return tabName !== undefined ? encodeURIComponent(tabName.toString().replace(/\s+/g, '-').toLowerCase()) : ''
} }
export default function Tab({ tab }) { export default function Tab({ tab }) {

View File

@@ -239,7 +239,7 @@ function Home({ initialSettings }) {
const tabs = useMemo( () => [ const tabs = useMemo( () => [
...new Set( ...new Set(
Object.keys(settings.layout ?? {}).map( Object.keys(settings.layout ?? {}).map(
(groupName) => settings.layout[groupName]?.tab (groupName) => settings.layout[groupName]?.tab?.toString()
).filter(group => group) ).filter(group => group)
) )
], [settings.layout]); ], [settings.layout]);
@@ -362,13 +362,7 @@ function Home({ initialSettings }) {
/> />
</style> </style>
<link rel="preload" href="/api/config/custom.js" as="fetch" crossOrigin="anonymous" /> <link rel="preload" href="/api/config/custom.js" as="fetch" crossOrigin="anonymous" />
<script data-name="custom.js"> <script data-name="custom.js" src="/api/config/custom.js" async />
<FileContent path="custom.js"
loadingValue="/* Loading custom JS... */"
errorValue="/* Failed to load custom JS... */"
emptyValue="/* No custom JS */"
/>
</script>
<div className="relative container m-auto flex flex-col justify-start z-10 h-full"> <div className="relative container m-auto flex flex-col justify-start z-10 h-full">
<QuickLaunch <QuickLaunch

View File

@@ -4,7 +4,7 @@ import path from "path";
import yaml from "js-yaml"; import yaml from "js-yaml";
import Docker from "dockerode"; import Docker from "dockerode";
import * as shvl from "shvl"; import * as shvl from "shvl";
import { CustomObjectsApi, NetworkingV1Api } from "@kubernetes/client-node"; import { CustomObjectsApi, NetworkingV1Api, ApiextensionsV1Api } from "@kubernetes/client-node";
import createLogger from "utils/logger"; import createLogger from "utils/logger";
import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config"; import checkAndCopyConfig, { CONF_DIR, substituteEnvironmentVars } from "utils/config/config";
@@ -141,6 +141,26 @@ function getUrlFromIngress(ingress) {
return `${urlSchema}://${urlHost}${urlPath}`; return `${urlSchema}://${urlHost}${urlPath}`;
} }
export async function checkCRD(kc, name) {
const apiExtensions = kc.makeApiClient(ApiextensionsV1Api);
const exist = await apiExtensions
.readCustomResourceDefinitionStatus(name)
.then(() => true)
.catch(async (error) => {
if (error.statusCode === 403) {
logger.error(
"Error checking if CRD %s exists. Make sure to add the following permission to your RBAC: %d %s %s",
name,
error.statusCode,
error.body.message
);
}
return false
});
return exist
}
export async function servicesFromKubernetes() { export async function servicesFromKubernetes() {
const ANNOTATION_BASE = "gethomepage.dev"; const ANNOTATION_BASE = "gethomepage.dev";
const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`; const ANNOTATION_WIDGET_BASE = `${ANNOTATION_BASE}/widget.`;
@@ -164,11 +184,14 @@ export async function servicesFromKubernetes() {
return null; return null;
}); });
const traefikContainoExists = await checkCRD(kc, "ingressroutes.traefik.containo.us");
const traefikExists = await checkCRD(kc, "ingressroutes.traefik.io");
const traefikIngressListContaino = await crd const traefikIngressListContaino = await crd
.listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes") .listClusterCustomObject("traefik.containo.us", "v1alpha1", "ingressroutes")
.then((response) => response.body) .then((response) => response.body)
.catch(async (error) => { .catch(async (error) => {
if (![403, 404].includes(error.statusCode)) { if (traefikContainoExists) {
logger.error( logger.error(
"Error getting traefik ingresses from traefik.containo.us: %d %s %s", "Error getting traefik ingresses from traefik.containo.us: %d %s %s",
error.statusCode, error.statusCode,
@@ -184,7 +207,7 @@ export async function servicesFromKubernetes() {
.listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes") .listClusterCustomObject("traefik.io", "v1alpha1", "ingressroutes")
.then((response) => response.body) .then((response) => response.body)
.catch(async (error) => { .catch(async (error) => {
if (![403, 404].includes(error.statusCode)) { if (traefikExists) {
logger.error( logger.error(
"Error getting traefik ingresses from traefik.io: %d %s %s", "Error getting traefik ingresses from traefik.io: %d %s %s",
error.statusCode, error.statusCode,
@@ -196,10 +219,10 @@ export async function servicesFromKubernetes() {
return []; return [];
}); });
const traefikIngressList = [...traefikIngressListContaino, ...traefikIngressListIo]; const traefikIngressList = [...traefikIngressListContaino?.items ?? [], ...traefikIngressListIo?.items ?? []];
if (traefikIngressList?.items?.length > 0) { if (traefikIngressList.length > 0) {
const traefikServices = traefikIngressList.items.filter( const traefikServices = traefikIngressList.filter(
(ingress) => ingress.metadata.annotations && ingress.metadata.annotations[`${ANNOTATION_BASE}/href`] (ingress) => ingress.metadata.annotations && ingress.metadata.annotations[`${ANNOTATION_BASE}/href`]
); );
ingressList.items.push(...traefikServices); ingressList.items.push(...traefikServices);

View File

@@ -3,13 +3,13 @@ import Container from "components/services/widget/container";
import Block from "components/services/widget/block"; import Block from "components/services/widget/block";
const passedReduce = (acc, e) => { const passedReduce = (acc, e) => {
if (e.overallstatus === "GOOD") { if (e.monitor && e.overallstatus === "GOOD") {
return acc + 1; return acc + 1;
} }
return acc; return acc;
}; };
const failedReduce = (acc, e) => { const failedReduce = (acc, e) => {
if (e.overallstatus !== "GOOD") { if (e.monitor && e.overallstatus !== "GOOD") {
return acc + 1; return acc + 1;
} }
return acc; return acc;