Compare commits

..

1 Commits

Author SHA1 Message Date
shamoon
51ae55e25e Documentation: remove IPv6 disabling instructions from troubleshooting
Some checks failed
Docs / Linting Checks (push) Has been cancelled
Docker CI / Linting Checks (push) Has been cancelled
Docker CI / Docker Build & Push (push) Has been cancelled
Docs / Test Build Docs (push) Has been cancelled
Docs / Build & Deploy Docs (push) Has been cancelled
2025-12-25 21:48:17 -08:00
71 changed files with 594 additions and 914 deletions

View File

@@ -84,7 +84,7 @@ jobs:
latest=auto
- name: Next.js build cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: .next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx') }}

View File

@@ -37,7 +37,7 @@ jobs:
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v5
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
@@ -63,7 +63,7 @@ jobs:
with:
python-version: 3.x
- run: echo "cache_id=${{github.sha}}" >> $GITHUB_ENV
- uses: actions/cache@v5
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache

View File

@@ -32,7 +32,7 @@ jobs:
name: 'Lock Old Threads'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v6
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: '30'
pr-inactive-days: '30'

View File

@@ -22,9 +22,7 @@ if [ "$HOSTNAME" = "::" ]; then
fi
# Check ownership before chown
if [ "$PUID" = "0" ]; then
echo "Skipping ownership changes for /app/config"
elif [ -e /app/config ]; then
if [ -e /app/config ]; then
CURRENT_UID=$(stat -c %u /app/config)
CURRENT_GID=$(stat -c %g /app/config)
@@ -41,9 +39,7 @@ else
fi
# Ensure /app/config/logs exists and is owned
if [ "$PUID" = "0" ]; then
echo "Skipping ownership changes for /app/config/logs"
elif [ -n "$PUID" ] && [ -n "$PGID" ]; then
if [ -n "$PUID" ] && [ -n "$PGID" ]; then
mkdir -p /app/config/logs 2>/dev/null || true
if [ -d /app/config/logs ]; then
LOG_UID=$(stat -c %u /app/config/logs)

View File

@@ -189,8 +189,6 @@ labels: ...
- homepage.widgets[1].slug=youreventslughere
```
To pass custom HTTP headers with a widget request when using labels, use the same dot-notation: `homepage.widget.headers.X-Auth-Key=secret` (or `homepage.widgets[0].headers.X-Auth-Key=secret` when multiple widgets are present).
You can add specify fields for e.g. the [CustomAPI](../widgets/services/customapi.md) widget by using array-style dot notation:
```yaml

View File

@@ -94,7 +94,6 @@ metadata:
gethomepage.dev/name: Emby
gethomepage.dev/widget.type: "emby"
gethomepage.dev/widget.url: "https://emby.example.com"
gethomepage.dev/widget.headers.X-Auth-Key: "your-secret-here"
gethomepage.dev/pod-selector: ""
gethomepage.dev/weight: 10 # optional
gethomepage.dev/instance: "public" # optional

View File

@@ -101,25 +101,6 @@ Each service can have multiple widgets attached to it, for example:
Multiple widgets per service are not yet supported with Kubernetes ingress annotations.
#### Custom HTTP headers
Widgets that make HTTP calls support extra request headers via `headers`. This is useful when a reverse proxy expects a secret header.
```yaml
- UptimeRobot:
icon: uptimekuma.png
href: https://uptimerobot.com/
widget:
type: uptimerobot
url: https://api.uptimerobot.com
key: ${UPTIMEROBOT_API_KEY}
headers:
User-Agent: homepage
X-Auth-Key: your-secret-here
```
If you define services via Docker labels or Kubernetes annotations, use the same key with dot-notation (for example `homepage.widget.headers.X-Auth-Key=secret` or `gethomepage.dev/widget.headers.X-Auth-Key: "secret"`).
#### Field Visibility
Each widget can optionally provide a list of which fields should be visible via the `fields` widget property. If no fields are specified, then all fields will be displayed. The `fields` property must be a valid YAML array of strings. As an example, here is the entry for Sonarr showing only a couple of fields.

View File

@@ -12,7 +12,6 @@ hide:
- Check config/logs/homepage.log, on docker simply e.g. `docker logs homepage`. This may provide some insight into the reason for an error.
- Check the browser error console, this can also sometimes provide useful information.
- Consider setting the `ENV` variable `LOG_LEVEL` to `debug`.
- If certain widgets are failing when connecting to public APIs, consider [disabling IPv6](#disabling-ipv6).
## Service Widget Errors
@@ -67,17 +66,3 @@ All service widgets work essentially the same, that is, homepage makes a proxied
## Missing custom icons
If, after correctly adding and mapping your custom icons via the [Icons](../configs/services.md#icons) instructions, you are still unable to see your icons please try recreating your container.
## Disabling IPv6 for http requests {#disabling-ipv6}
If you are having issues with certain widgets that are unable to reach public APIs (e.g. weather), in certain setups you may need to disable IPv6. You can set the environment variable `HOMEPAGE_PROXY_DISABLE_IPV6` to `true` to disable IPv6 for the homepage proxy.
Alternatively, you can use the `sysctls` option in your docker-compose file to disable IPv6 for the homepage container completely:
```yaml
services:
homepage:
...
sysctls:
- net.ipv6.conf.all.disable_ipv6=1
```

View File

@@ -3,8 +3,6 @@ title: Gatus
description: Gatus Widget Configuration
---
Learn more about [Gatus](https://github.com/TwiN/gatus).
Allowed fields: `["up", "down", "uptime"]`.
```yaml

View File

@@ -5,11 +5,6 @@ description: TrueNas Scale Widget Configuration
Learn more about [TrueNas](https://www.truenas.com/).
| TrueNAS Version | Homepage widget version |
| ----------------------- | ----------------------- |
| < 26.04 (REST API) | 1 (default) |
| > 25.04 (Websocket API) | 2 |
Allowed fields: `["load", "uptime", "alerts"]`.
To create an API Key, follow [the official TrueNAS documentation](https://www.truenas.com/docs/scale/scaletutorials/toptoolbar/managingapikeys/).
@@ -22,7 +17,6 @@ To use the `enablePools` option with TrueNAS Core, the `nasType` parameter is re
widget:
type: truenas
url: http://truenas.host.or.ip
version: 2 # optional, defaults to 1
username: user # not required if using api key
password: pass # not required if using api key
key: yourtruenasapikey # not required if using username / password

View File

@@ -20,12 +20,12 @@
"gamedig": "^5.3.2",
"i18next": "^25.5.3",
"ical.js": "^2.1.0",
"js-yaml": "^4.1.1",
"js-yaml": "^4.1.0",
"json-rpc-2.0": "^1.7.0",
"luxon": "^3.6.1",
"memory-cache": "^0.2.0",
"minecraftstatuspinger": "^1.2.2",
"next": "^15.5.9",
"next": "^15.5.7",
"next-i18next": "^12.1.0",
"ping": "^0.4.4",
"pretty-bytes": "^7.1.0",
@@ -33,19 +33,18 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.5.3",
"react-icons": "^5.5.0",
"react-icons": "^5.4.0",
"recharts": "^3.1.2",
"swr": "^2.3.3",
"systeminformation": "^5.27.11",
"tough-cookie": "^6.0.0",
"urbackup-server-api": "^0.91.0",
"urbackup-server-api": "^0.8.9",
"winston": "^3.17.0",
"ws": "^8.18.3",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.18",
"@tailwindcss/postcss": "^4.1.14",
"eslint": "^9.25.1",
"eslint-config-next": "^15.2.4",
"eslint-config-prettier": "^10.1.8",
@@ -66,7 +65,6 @@
},
"pnpm": {
"onlyBuiltDependencies": [
"@tailwindcss/oxide",
"osx-temperature-sensor",
"sharp"
]

382
pnpm-lock.yaml generated
View File

@@ -36,8 +36,8 @@ importers:
specifier: ^2.1.0
version: 2.1.0
js-yaml:
specifier: ^4.1.1
version: 4.1.1
specifier: ^4.1.0
version: 4.1.0
json-rpc-2.0:
specifier: ^1.7.0
version: 1.7.0
@@ -51,11 +51,11 @@ importers:
specifier: ^1.2.2
version: 1.2.2
next:
specifier: ^15.5.9
version: 15.5.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
specifier: ^15.5.7
version: 15.5.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-i18next:
specifier: ^12.1.0
version: 12.1.0(next@15.5.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 12.1.0(next@15.5.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
ping:
specifier: ^0.4.4
version: 0.4.4
@@ -75,8 +75,8 @@ importers:
specifier: ^15.5.3
version: 15.5.3(i18next@25.5.3(typescript@5.7.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)
react-icons:
specifier: ^5.5.0
version: 5.5.0(react@18.3.1)
specifier: ^5.4.0
version: 5.4.0(react@18.3.1)
recharts:
specifier: ^3.1.2
version: 3.1.2(@types/react@19.0.10)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)(redux@5.0.1)
@@ -90,14 +90,11 @@ importers:
specifier: ^6.0.0
version: 6.0.0
urbackup-server-api:
specifier: ^0.91.0
version: 0.91.0
specifier: ^0.8.9
version: 0.8.9
winston:
specifier: ^3.17.0
version: 3.17.0
ws:
specifier: ^8.18.3
version: 8.18.3
xml-js:
specifier: ^1.6.11
version: 1.6.11
@@ -106,8 +103,8 @@ importers:
specifier: ^0.5.10
version: 0.5.10(tailwindcss@4.0.9)
'@tailwindcss/postcss':
specifier: ^4.1.18
version: 4.1.18
specifier: ^4.1.14
version: 4.1.14
eslint:
specifier: ^9.25.1
version: 9.25.1(jiti@2.6.1)
@@ -469,8 +466,8 @@ packages:
'@napi-rs/wasm-runtime@0.2.8':
resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==}
'@next/env@15.5.9':
resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==}
'@next/env@15.5.7':
resolution: {integrity: sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==}
'@next/eslint-plugin-next@15.2.4':
resolution: {integrity: sha512-O8ScvKtnxkp8kL9TpJTTKnMqlkZnS+QxwoQnJwPGBxjBbzd6OVVPEJ5/pMNrktSyXQD/chEfzfFzYLM6JANOOQ==}
@@ -656,65 +653,65 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1'
'@tailwindcss/node@4.1.18':
resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
'@tailwindcss/node@4.1.14':
resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==}
'@tailwindcss/oxide-android-arm64@4.1.18':
resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
'@tailwindcss/oxide-android-arm64@4.1.14':
resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
'@tailwindcss/oxide-darwin-arm64@4.1.18':
resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
'@tailwindcss/oxide-darwin-arm64@4.1.14':
resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@tailwindcss/oxide-darwin-x64@4.1.18':
resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
'@tailwindcss/oxide-darwin-x64@4.1.14':
resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@tailwindcss/oxide-freebsd-x64@4.1.18':
resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
'@tailwindcss/oxide-freebsd-x64@4.1.14':
resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14':
resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
'@tailwindcss/oxide-linux-arm64-gnu@4.1.14':
resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
'@tailwindcss/oxide-linux-arm64-musl@4.1.14':
resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
'@tailwindcss/oxide-linux-x64-gnu@4.1.14':
resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
'@tailwindcss/oxide-linux-x64-musl@4.1.14':
resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
'@tailwindcss/oxide-wasm32-wasi@4.1.14':
resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
bundledDependencies:
@@ -725,24 +722,24 @@ packages:
- '@emnapi/wasi-threads'
- tslib
'@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
'@tailwindcss/oxide-win32-arm64-msvc@4.1.14':
resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@tailwindcss/oxide-win32-x64-msvc@4.1.18':
resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
'@tailwindcss/oxide-win32-x64-msvc@4.1.14':
resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@tailwindcss/oxide@4.1.18':
resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
'@tailwindcss/oxide@4.1.14':
resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==}
engines: {node: '>= 10'}
'@tailwindcss/postcss@4.1.18':
resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
'@tailwindcss/postcss@4.1.14':
resolution: {integrity: sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==}
'@tanstack/react-virtual@3.13.12':
resolution: {integrity: sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==}
@@ -1038,8 +1035,8 @@ packages:
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
engines: {node: '>= 0.4'}
async-mutex@0.5.0:
resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==}
async-mutex@0.3.2:
resolution: {integrity: sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
@@ -1123,8 +1120,8 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
caniuse-lite@1.0.30001760:
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==}
caniuse-lite@1.0.30001759:
resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==}
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
@@ -1323,6 +1320,10 @@ packages:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
detect-libc@2.1.1:
resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==}
engines: {node: '>=8'}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@@ -1361,8 +1362,8 @@ packages:
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
enhanced-resolve@5.18.4:
resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'}
es-abstract@1.23.9:
@@ -1965,8 +1966,8 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
jsep@1.4.0:
@@ -2015,74 +2016,68 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lightningcss-android-arm64@1.30.2:
resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [android]
lightningcss-darwin-arm64@1.30.2:
resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
lightningcss-darwin-arm64@1.30.1:
resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [darwin]
lightningcss-darwin-x64@1.30.2:
resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
lightningcss-darwin-x64@1.30.1:
resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [darwin]
lightningcss-freebsd-x64@1.30.2:
resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
lightningcss-freebsd-x64@1.30.1:
resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [freebsd]
lightningcss-linux-arm-gnueabihf@1.30.2:
resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
lightningcss-linux-arm-gnueabihf@1.30.1:
resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
engines: {node: '>= 12.0.0'}
cpu: [arm]
os: [linux]
lightningcss-linux-arm64-gnu@1.30.2:
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
lightningcss-linux-arm64-gnu@1.30.1:
resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
lightningcss-linux-arm64-musl@1.30.1:
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
lightningcss-linux-x64-gnu@1.30.1:
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
lightningcss-linux-x64-musl@1.30.1:
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
lightningcss-win32-arm64-msvc@1.30.1:
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [win32]
lightningcss-win32-x64-msvc@1.30.2:
resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
lightningcss-win32-x64-msvc@1.30.1:
resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [win32]
lightningcss@1.30.2:
resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
lightningcss@1.30.1:
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
engines: {node: '>= 12.0.0'}
locate-path@6.0.0:
@@ -2117,8 +2112,8 @@ packages:
resolution: {integrity: sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==}
engines: {node: '>=12'}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
magic-string@0.30.19:
resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
@@ -2181,6 +2176,10 @@ packages:
resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==}
engines: {node: '>= 18'}
minizlib@3.1.0:
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
engines: {node: '>= 18'}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
@@ -2213,8 +2212,8 @@ packages:
next: '>= 10.0.0'
react: '>= 16.8.0'
next@15.5.9:
resolution: {integrity: sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==}
next@15.5.7:
resolution: {integrity: sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true
peerDependencies:
@@ -2459,8 +2458,8 @@ packages:
typescript:
optional: true
react-icons@5.5.0:
resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==}
react-icons@5.4.0:
resolution: {integrity: sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==}
peerDependencies:
react: '*'
@@ -2806,11 +2805,11 @@ packages:
tailwindcss@4.0.9:
resolution: {integrity: sha512-12laZu+fv1ONDRoNR9ipTOpUD7RN9essRVkX36sjxuRUInpN7hIiHN4lBd/SIFjbISvnXzp8h/hXzmU8SQQYhw==}
tailwindcss@4.1.18:
resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
tailwindcss@4.1.14:
resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==}
tapable@2.3.0:
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
tapable@2.2.3:
resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
engines: {node: '>=6'}
tar-fs@2.1.3:
@@ -2824,6 +2823,10 @@ packages:
resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
engines: {node: '>=18'}
tar@7.5.1:
resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==}
engines: {node: '>=18'}
telnet-client@2.2.6:
resolution: {integrity: sha512-ZUYrLsPtQupQww3eSEORDVOb6ztdtKEghya6TVXPo2tg/UQq2pn5rHhvwuUvyYpbnsoqdNY1fyD1GNkXHR8dYA==}
@@ -2927,8 +2930,8 @@ packages:
unrs-resolver@1.3.3:
resolution: {integrity: sha512-PFLAGQzYlyjniXdbmQ3dnGMZJXX5yrl2YS4DLRfR3BhgUsE1zpRIrccp9XMOGRfIHpdFvCn/nr5N1KMVda4x3A==}
urbackup-server-api@0.91.0:
resolution: {integrity: sha512-N1CSnGSCSHjwWfGOp6jE56mHYoZor/p++ii8yPsN9P/3cKLBgCvrAZxAbfi+IgK9FZpQEx/kPX1R8OTJRy+x6A==}
urbackup-server-api@0.8.9:
resolution: {integrity: sha512-Igu6A0xSZeMsiN6PWT7zG4aD+iJR5fXT/j5+xwAvnD/vCNfvVrettIsXv6MftxOajvTmtlgaYu8KDoH1EJQ6DQ==}
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -3014,8 +3017,8 @@ packages:
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
ws@8.18.3:
resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
@@ -3125,7 +3128,7 @@ snapshots:
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.1.1
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -3348,8 +3351,8 @@ snapshots:
'@types/tar': 6.1.13
'@types/ws': 8.5.14
form-data: 4.0.2
isomorphic-ws: 5.0.0(ws@8.18.3)
js-yaml: 4.1.1
isomorphic-ws: 5.0.0(ws@8.18.0)
js-yaml: 4.1.0
jsonpath-plus: 10.3.0
node-fetch: 2.7.0
openid-client: 6.3.0
@@ -3358,7 +3361,7 @@ snapshots:
tar: 7.4.3
tmp-promise: 3.0.3
tslib: 2.8.1
ws: 8.18.3
ws: 8.18.0
transitivePeerDependencies:
- bufferutil
- encoding
@@ -3371,7 +3374,7 @@ snapshots:
'@tybys/wasm-util': 0.9.0
optional: true
'@next/env@15.5.9': {}
'@next/env@15.5.7': {}
'@next/eslint-plugin-next@15.2.4':
dependencies:
@@ -3531,74 +3534,77 @@ snapshots:
mini-svg-data-uri: 1.4.4
tailwindcss: 4.0.9
'@tailwindcss/node@4.1.18':
'@tailwindcss/node@4.1.14':
dependencies:
'@jridgewell/remapping': 2.3.5
enhanced-resolve: 5.18.4
enhanced-resolve: 5.18.3
jiti: 2.6.1
lightningcss: 1.30.2
magic-string: 0.30.21
lightningcss: 1.30.1
magic-string: 0.30.19
source-map-js: 1.2.1
tailwindcss: 4.1.18
tailwindcss: 4.1.14
'@tailwindcss/oxide-android-arm64@4.1.18':
'@tailwindcss/oxide-android-arm64@4.1.14':
optional: true
'@tailwindcss/oxide-darwin-arm64@4.1.18':
'@tailwindcss/oxide-darwin-arm64@4.1.14':
optional: true
'@tailwindcss/oxide-darwin-x64@4.1.18':
'@tailwindcss/oxide-darwin-x64@4.1.14':
optional: true
'@tailwindcss/oxide-freebsd-x64@4.1.18':
'@tailwindcss/oxide-freebsd-x64@4.1.14':
optional: true
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14':
optional: true
'@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
'@tailwindcss/oxide-linux-arm64-gnu@4.1.14':
optional: true
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
'@tailwindcss/oxide-linux-arm64-musl@4.1.14':
optional: true
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
'@tailwindcss/oxide-linux-x64-gnu@4.1.14':
optional: true
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
'@tailwindcss/oxide-linux-x64-musl@4.1.14':
optional: true
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
'@tailwindcss/oxide-wasm32-wasi@4.1.14':
optional: true
'@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
'@tailwindcss/oxide-win32-arm64-msvc@4.1.14':
optional: true
'@tailwindcss/oxide-win32-x64-msvc@4.1.18':
'@tailwindcss/oxide-win32-x64-msvc@4.1.14':
optional: true
'@tailwindcss/oxide@4.1.18':
'@tailwindcss/oxide@4.1.14':
dependencies:
detect-libc: 2.1.1
tar: 7.5.1
optionalDependencies:
'@tailwindcss/oxide-android-arm64': 4.1.18
'@tailwindcss/oxide-darwin-arm64': 4.1.18
'@tailwindcss/oxide-darwin-x64': 4.1.18
'@tailwindcss/oxide-freebsd-x64': 4.1.18
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
'@tailwindcss/oxide-linux-arm64-musl': 4.1.18
'@tailwindcss/oxide-linux-x64-gnu': 4.1.18
'@tailwindcss/oxide-linux-x64-musl': 4.1.18
'@tailwindcss/oxide-wasm32-wasi': 4.1.18
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
'@tailwindcss/oxide-win32-x64-msvc': 4.1.18
'@tailwindcss/oxide-android-arm64': 4.1.14
'@tailwindcss/oxide-darwin-arm64': 4.1.14
'@tailwindcss/oxide-darwin-x64': 4.1.14
'@tailwindcss/oxide-freebsd-x64': 4.1.14
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.14
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.14
'@tailwindcss/oxide-linux-arm64-musl': 4.1.14
'@tailwindcss/oxide-linux-x64-gnu': 4.1.14
'@tailwindcss/oxide-linux-x64-musl': 4.1.14
'@tailwindcss/oxide-wasm32-wasi': 4.1.14
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.14
'@tailwindcss/oxide-win32-x64-msvc': 4.1.14
'@tailwindcss/postcss@4.1.18':
'@tailwindcss/postcss@4.1.14':
dependencies:
'@alloc/quick-lru': 5.2.0
'@tailwindcss/node': 4.1.18
'@tailwindcss/oxide': 4.1.18
'@tailwindcss/node': 4.1.14
'@tailwindcss/oxide': 4.1.14
postcss: 8.5.6
tailwindcss: 4.1.18
tailwindcss: 4.1.14
'@tanstack/react-virtual@3.13.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -3925,7 +3931,7 @@ snapshots:
async-function@1.0.0: {}
async-mutex@0.5.0:
async-mutex@0.3.2:
dependencies:
tslib: 2.8.1
@@ -4018,7 +4024,7 @@ snapshots:
callsites@3.1.0: {}
caniuse-lite@1.0.30001760: {}
caniuse-lite@1.0.30001759: {}
chalk@4.1.2:
dependencies:
@@ -4194,7 +4200,10 @@ snapshots:
dequal@2.0.3: {}
detect-libc@2.1.2: {}
detect-libc@2.1.1: {}
detect-libc@2.1.2:
optional: true
docker-modem@5.0.6:
dependencies:
@@ -4241,10 +4250,10 @@ snapshots:
dependencies:
once: 1.4.0
enhanced-resolve@5.18.4:
enhanced-resolve@5.18.3:
dependencies:
graceful-fs: 4.2.11
tapable: 2.3.0
tapable: 2.2.3
es-abstract@1.23.9:
dependencies:
@@ -5036,9 +5045,9 @@ snapshots:
isexe@2.0.0: {}
isomorphic-ws@5.0.0(ws@8.18.3):
isomorphic-ws@5.0.0(ws@8.18.0):
dependencies:
ws: 8.18.3
ws: 8.18.0
iterator.prototype@1.1.5:
dependencies:
@@ -5061,7 +5070,7 @@ snapshots:
js-tokens@4.0.0: {}
js-yaml@4.1.1:
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
@@ -5109,54 +5118,50 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lightningcss-android-arm64@1.30.2:
lightningcss-darwin-arm64@1.30.1:
optional: true
lightningcss-darwin-arm64@1.30.2:
lightningcss-darwin-x64@1.30.1:
optional: true
lightningcss-darwin-x64@1.30.2:
lightningcss-freebsd-x64@1.30.1:
optional: true
lightningcss-freebsd-x64@1.30.2:
lightningcss-linux-arm-gnueabihf@1.30.1:
optional: true
lightningcss-linux-arm-gnueabihf@1.30.2:
lightningcss-linux-arm64-gnu@1.30.1:
optional: true
lightningcss-linux-arm64-gnu@1.30.2:
lightningcss-linux-arm64-musl@1.30.1:
optional: true
lightningcss-linux-arm64-musl@1.30.2:
lightningcss-linux-x64-gnu@1.30.1:
optional: true
lightningcss-linux-x64-gnu@1.30.2:
lightningcss-linux-x64-musl@1.30.1:
optional: true
lightningcss-linux-x64-musl@1.30.2:
lightningcss-win32-arm64-msvc@1.30.1:
optional: true
lightningcss-win32-arm64-msvc@1.30.2:
lightningcss-win32-x64-msvc@1.30.1:
optional: true
lightningcss-win32-x64-msvc@1.30.2:
optional: true
lightningcss@1.30.2:
lightningcss@1.30.1:
dependencies:
detect-libc: 2.1.2
detect-libc: 2.1.1
optionalDependencies:
lightningcss-android-arm64: 1.30.2
lightningcss-darwin-arm64: 1.30.2
lightningcss-darwin-x64: 1.30.2
lightningcss-freebsd-x64: 1.30.2
lightningcss-linux-arm-gnueabihf: 1.30.2
lightningcss-linux-arm64-gnu: 1.30.2
lightningcss-linux-arm64-musl: 1.30.2
lightningcss-linux-x64-gnu: 1.30.2
lightningcss-linux-x64-musl: 1.30.2
lightningcss-win32-arm64-msvc: 1.30.2
lightningcss-win32-x64-msvc: 1.30.2
lightningcss-darwin-arm64: 1.30.1
lightningcss-darwin-x64: 1.30.1
lightningcss-freebsd-x64: 1.30.1
lightningcss-linux-arm-gnueabihf: 1.30.1
lightningcss-linux-arm64-gnu: 1.30.1
lightningcss-linux-arm64-musl: 1.30.1
lightningcss-linux-x64-gnu: 1.30.1
lightningcss-linux-x64-musl: 1.30.1
lightningcss-win32-arm64-msvc: 1.30.1
lightningcss-win32-x64-msvc: 1.30.1
locate-path@6.0.0:
dependencies:
@@ -5187,7 +5192,7 @@ snapshots:
luxon@3.6.1: {}
magic-string@0.30.21:
magic-string@0.30.19:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -5235,6 +5240,10 @@ snapshots:
minipass: 7.1.2
rimraf: 5.0.10
minizlib@3.1.0:
dependencies:
minipass: 7.1.2
mkdirp-classic@0.5.3: {}
mkdirp@3.0.1: {}
@@ -5250,7 +5259,7 @@ snapshots:
net@1.0.2: {}
next-i18next@12.1.0(next@15.5.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next-i18next@12.1.0(next@15.5.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.26.9
'@types/hoist-non-react-statics': 3.3.6
@@ -5258,18 +5267,18 @@ snapshots:
hoist-non-react-statics: 3.3.2
i18next: 21.10.0
i18next-fs-backend: 1.2.0
next: 15.5.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next: 15.5.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-i18next: 11.18.6(i18next@21.10.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
transitivePeerDependencies:
- react-dom
- react-native
next@15.5.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next@15.5.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 15.5.9
'@next/env': 15.5.7
'@swc/helpers': 0.5.15
caniuse-lite: 1.0.30001760
caniuse-lite: 1.0.30001759
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
@@ -5504,7 +5513,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
typescript: 5.7.3
react-icons@5.5.0(react@18.3.1):
react-icons@5.4.0(react@18.3.1):
dependencies:
react: 18.3.1
@@ -5927,9 +5936,9 @@ snapshots:
tailwindcss@4.0.9: {}
tailwindcss@4.1.18: {}
tailwindcss@4.1.14: {}
tapable@2.3.0: {}
tapable@2.2.3: {}
tar-fs@2.1.3:
dependencies:
@@ -5955,6 +5964,14 @@ snapshots:
mkdirp: 3.0.1
yallist: 5.0.0
tar@7.5.1:
dependencies:
'@isaacs/fs-minipass': 4.0.1
chownr: 3.0.0
minipass: 7.1.2
minizlib: 3.1.0
yallist: 5.0.0
telnet-client@2.2.6:
dependencies:
net: 1.0.2
@@ -6080,9 +6097,12 @@ snapshots:
'@unrs/resolver-binding-win32-ia32-msvc': 1.3.3
'@unrs/resolver-binding-win32-x64-msvc': 1.3.3
urbackup-server-api@0.91.0:
urbackup-server-api@0.8.9:
dependencies:
async-mutex: 0.5.0
async-mutex: 0.3.2
node-fetch: 2.7.0
transitivePeerDependencies:
- encoding
uri-js@4.4.1:
dependencies:
@@ -6218,7 +6238,7 @@ snapshots:
wrappy@1.0.2: {}
ws@8.18.3: {}
ws@8.18.0: {}
xml-js@1.6.11:
dependencies:

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Op",
"pending": "Afwagtend",
"down": "Af",
"ok": "Ok"
"down": "Af"
},
"healthchecks": {
"new": "Nuut",
@@ -770,7 +769,7 @@
"gross_percent_today": "Vandag",
"gross_percent_1y": "Een jaar",
"gross_percent_max": "Alle tyd",
"net_worth": "Netto Waarde"
"net_worth": "Net Worth"
},
"audiobookshelf": {
"podcasts": "Podsendinge",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "جديد(ة)",

View File

@@ -63,7 +63,7 @@
"wlan_users": "WLAN Потребители",
"up": "UP",
"down": "DOWN",
"wait": "Моля изчакайте",
"wait": "Please wait",
"empty_data": "Неизвестен статус на подсистема"
},
"docker": {
@@ -83,7 +83,7 @@
"partial": "Частично"
},
"ping": {
"error": "Грешка",
"error": "Error",
"ping": "Пинг",
"down": "Down",
"up": "Up",
@@ -91,11 +91,11 @@
},
"siteMonitor": {
"http_status": "HTTP статус",
"error": "Грешка",
"error": "Error",
"response": "Отговор",
"down": "Down",
"up": "Up",
"not_available": "Не е налично"
"not_available": "Not Available"
},
"emby": {
"playing": "Възпроизвежда",
@@ -111,7 +111,7 @@
"offline": "Offline",
"offline_alt": "Offline",
"online": "Онлайн",
"total": "Общо",
"total": "Total",
"unknown": "Unknown"
},
"evcc": {
@@ -133,7 +133,7 @@
"unread": "Непрочетени"
},
"fritzbox": {
"connectionStatus": "Статус",
"connectionStatus": "Status",
"connectionStatusUnconfigured": "Неконфигуриран",
"connectionStatusConnecting": "Свързване",
"connectionStatusAuthenticating": "Удостоверяване",
@@ -141,7 +141,7 @@
"connectionStatusDisconnecting": "Прекъсване на връзката",
"connectionStatusDisconnected": "Не е свързан",
"connectionStatusConnected": "Свързан",
"uptime": "Време на работа",
"uptime": "Uptime",
"maxDown": "Макс сваляне",
"maxUp": "Макс качване",
"down": "Down",
@@ -170,8 +170,8 @@
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Битрейт",
"no_active": "Няма активни потоци",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Провери връзка с Plex"
},
"omada": {
@@ -189,7 +189,7 @@
"plex": {
"streams": "Активни Потоци",
"albums": "Албуми",
"movies": "Филми",
"movies": "Movies",
"tv": "Сериали"
},
"sabnzbd": {
@@ -362,8 +362,8 @@
},
"trilium": {
"version": "Version",
"notesCount": "Бележки",
"dbSize": "Размер на базата данни",
"notesCount": "Notes",
"dbSize": "Database Size",
"unknown": "Unknown"
},
"navidrome": {
@@ -373,7 +373,7 @@
"npm": {
"enabled": "Активирано",
"disabled": "Деактивирано",
"total": "Общо"
"total": "Total"
},
"coinmarketcap": {
"configure": "Настрой за следене една или повече крипто валути",
@@ -384,7 +384,7 @@
},
"gotify": {
"apps": "Приложения",
"clients": "Клиенти",
"clients": "Clients",
"messages": "Съобщения"
},
"prowlarr": {
@@ -405,7 +405,7 @@
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Потребители",
"user_count": "Users",
"status_count": "Posts",
"domain_count": "Domains"
},
@@ -416,17 +416,17 @@
},
"minecraft": {
"players": "Играчи",
"version": "Версия",
"status": "Статус",
"up": "Онлайн",
"down": "Офлайн"
"version": "Version",
"status": "Status",
"up": "Online",
"down": "Offline"
},
"miniflux": {
"read": "Read",
"unread": "Unread"
},
"authentik": {
"users": "Потребители",
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Нови",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nou",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nové",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Ny",

View File

@@ -45,9 +45,9 @@
"free": "Frei",
"used": "In Benutzung",
"load": "Last",
"temp": "Temp",
"temp": "TEMP",
"max": "Max",
"uptime": "Betriebszeit"
"uptime": "BETRIEBSZEIT"
},
"unifi": {
"users": "Benutzer",
@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Online",
"pending": "Wartend",
"down": "Offline",
"ok": "Ok"
"down": "Offline"
},
"healthchecks": {
"new": "Neu",
@@ -603,7 +602,7 @@
"pangolin": {
"orgs": "Orgs",
"sites": "Sites",
"resources": "Ressourcen",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Activo",
"pending": "Pendiente",
"down": "Inactivo",
"ok": "Ok"
"down": "Inactivo"
},
"healthchecks": {
"new": "Nuevo",
@@ -602,12 +601,12 @@
},
"pangolin": {
"orgs": "Orgs",
"sites": "Sitios",
"resources": "Recursos",
"targets": "Destinos",
"traffic": "Tráfico",
"in": "Entrante",
"out": "Saliente"
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
"peanut": {
"battery_charge": "Carga de la batería",
@@ -770,7 +769,7 @@
"gross_percent_today": "Hoy",
"gross_percent_1y": "Un año",
"gross_percent_max": "Todo el tiempo",
"net_worth": "Patrimonio neto"
"net_worth": "Net Worth"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "En ligne",
"pending": "En attente",
"down": "Hors ligne",
"ok": "Ok"
"down": "Hors ligne"
},
"healthchecks": {
"new": "Nouveau",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "למעלה",
"pending": "ממתין",
"down": "למטה",
"ok": "Ok"
"down": "למטה"
},
"healthchecks": {
"new": "חדש",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Aktivno",
"pending": "U tijeku",
"down": "Neaktivno",
"ok": "Ok"
"down": "Neaktivno"
},
"healthchecks": {
"new": "Novo",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Fut",
"pending": "Függőben lévő",
"down": "Leállt",
"ok": "Ok"
"down": "Leállt"
},
"healthchecks": {
"new": "Új",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Baru",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nuovo",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "新着",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "업",
"pending": "대기 중",
"down": "다운",
"ok": "Ok"
"down": "다운"
},
"healthchecks": {
"new": "신규",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Baharu",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Online",
"pending": "In afwachting",
"down": "Offline",
"ok": "Ok"
"down": "Offline"
},
"healthchecks": {
"new": "Nieuw",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Ny",

View File

@@ -61,7 +61,7 @@
"wlan_devices": "Urządzenia WLAN",
"lan_users": "Użytkownicy LAN",
"wlan_users": "Użytkownicy WLAN",
"up": "DZIAŁA",
"up": "UP",
"down": "Pobieranie",
"wait": "Proszę czekać",
"empty_data": "Status podsystemu nieznany"
@@ -69,7 +69,7 @@
"docker": {
"rx": "Rx",
"tx": "Tx",
"mem": "PAM",
"mem": "MEM",
"cpu": "Procesor",
"running": "Działa",
"offline": "Nieosiągalny",
@@ -93,8 +93,8 @@
"http_status": "Status HTTP",
"error": "Błąd",
"response": "Odpowiedź",
"down": "Nie działa",
"up": "Działa",
"down": "Down",
"up": "Up",
"not_available": "Niedostępny"
},
"emby": {
@@ -111,8 +111,8 @@
"offline": "Offline",
"offline_alt": "Offline",
"online": "Dostępny",
"total": "Razem",
"unknown": "Nieznany"
"total": "Total",
"unknown": "Unknown"
},
"evcc": {
"pv_power": "Produkcja",
@@ -141,11 +141,11 @@
"connectionStatusDisconnecting": "Rozłączanie",
"connectionStatusDisconnected": "Rozłączono",
"connectionStatusConnected": "Połączono",
"uptime": "Czas działania",
"uptime": "Uptime",
"maxDown": "Maks. Pobieranie",
"maxUp": "Maks. Wysyłanie",
"down": "Nie działa",
"up": "Działa",
"down": "Down",
"up": "Up",
"received": "Odebrane",
"sent": "Wysłane",
"externalIPAddress": "Pub. IP",
@@ -168,10 +168,10 @@
"passes": "Przebiegi"
},
"tautulli": {
"playing": "Odtwarza",
"transcoding": "Transkoduje",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "Brak aktywnych strumieni",
"no_active": "No Active Streams",
"plex_connection_error": "Sprawdź połączenie z Plex"
},
"omada": {
@@ -193,24 +193,24 @@
"tv": "Seriale"
},
"sabnzbd": {
"rate": "Szybkość",
"rate": "Rate",
"queue": "Kolejka",
"timeleft": "Pozostało"
},
"rutorrent": {
"active": "Aktywny",
"upload": "Wysyłanie",
"upload": "Upload",
"download": "Pobieranie"
},
"transmission": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -223,8 +223,8 @@
"invalid": "Nieprawidłowy"
},
"deluge": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -233,8 +233,8 @@
"cachemissbytes": "Straty cache'u"
},
"downloadstation": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -251,16 +251,16 @@
"queued": "W kolejce",
"movies": "Filmy",
"queue": "Kolejka",
"unknown": "Nieznane"
"unknown": "Unknown"
},
"lidarr": {
"wanted": "Poszukiwane",
"queued": "W kolejce",
"wanted": "Wanted",
"queued": "Queued",
"artists": "Artyści"
},
"readarr": {
"wanted": "Poszukiwane",
"queued": "W kolejce",
"wanted": "Wanted",
"queued": "Queued",
"books": "Książki"
},
"bazarr": {
@@ -276,7 +276,7 @@
"pending": "Oczekujące",
"approved": "Zaakceptowane",
"available": "Dostępne",
"issues": "Otwarte zgłoszenia"
"issues": "Open Issues"
},
"overseerr": {
"pending": "Oczekujące",
@@ -285,8 +285,8 @@
"available": "Dostępne"
},
"netalertx": {
"total": "Razem",
"connected": "Połączono",
"total": "Total",
"connected": "Connected",
"new_devices": "Nowe urządzenia",
"down_alerts": "Alerty niedostępności"
},
@@ -303,20 +303,20 @@
"latency": "Opóźnienia"
},
"speedtest": {
"upload": "Wysyłanie",
"download": "Pobieranie",
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Działa",
"running": "Running",
"stopped": "Zatrzymane",
"total": "Razem"
"total": "Total"
},
"suwayomi": {
"download": "Pobrano",
"nondownload": "Niepobrane",
"read": "Przeczytane",
"unread": "Nieprzeczytane",
"read": "Read",
"unread": "Unread",
"downloadedread": "Pobrane i przeczytane",
"downloadedunread": "Pobrane i nieprzeczytane",
"nondownloadedread": "Niepobrane i przeczytane",
@@ -337,7 +337,7 @@
"ago": "{{value}} temu"
},
"technitium": {
"totalQueries": "Zapytania",
"totalQueries": "Queries",
"totalNoError": "Sukces",
"totalServerFailure": "Porażki",
"totalNxDomain": "Domeny NX",
@@ -345,12 +345,12 @@
"totalAuthoritative": "Autorytatywne",
"totalRecursive": "Rekursywne",
"totalCached": "Zbuforowane",
"totalBlocked": "Zablokowane",
"totalBlocked": "Blocked",
"totalDropped": "Upuszczone",
"totalClients": "Klienci"
},
"tdarr": {
"queue": "W kolejce",
"queue": "Queue",
"processed": "Przetworzone",
"errored": "Błędne",
"saved": "Zapisane"
@@ -364,7 +364,7 @@
"version": "Wersja",
"notesCount": "Notatki",
"dbSize": "Rozmiar bazy danych",
"unknown": "Nieznane"
"unknown": "Unknown"
},
"navidrome": {
"nothing_streaming": "Brak aktywnych strumieni",
@@ -373,7 +373,7 @@
"npm": {
"enabled": "Włączone",
"disabled": "Wyłączone",
"total": "Razem"
"total": "Total"
},
"coinmarketcap": {
"configure": "Wybierz jedną lub więcej kryptowalut do śledzenia",
@@ -390,19 +390,19 @@
"prowlarr": {
"enableIndexers": "Indeksery",
"numberOfGrabs": "Pochwycenia",
"numberOfQueries": "Zapytania",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Nieudane pochwycenia",
"numberOfFailQueries": "Nieudane zapytania"
},
"jackett": {
"configured": "Skonfigurowane",
"errored": "Z błędami"
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Sesje",
"numConnections": "Połączenia",
"dataRelayed": "Przekazane",
"transferRate": "Szybkość"
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Użytkownicy",
@@ -410,9 +410,9 @@
"domain_count": "Domeny"
},
"medusa": {
"wanted": "Poszukiwane",
"queued": "W kolejce",
"series": "Seriale"
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"minecraft": {
"players": "Gracze",
@@ -423,7 +423,7 @@
},
"miniflux": {
"read": "Przeczytane",
"unread": "Nieprzeczytane"
"unread": "Unread"
},
"authentik": {
"users": "Użytkownicy",
@@ -443,14 +443,14 @@
"temp": "TEMP.",
"_temp": "Temperatura",
"warn": "Ostrzeżenie",
"uptime": "DZIAŁA",
"total": "Razem",
"uptime": "UP",
"total": "Total",
"free": "Wolne",
"used": "Użyte",
"used": "Used",
"days": "d",
"hours": "godz",
"hours": "h",
"crit": "Krytyczyny",
"read": "Odczyt",
"read": "Read",
"write": "Zapis",
"gpu": "GPU",
"mem": "Pamięć",
@@ -530,16 +530,15 @@
"up_to_date": "Aktualny",
"child_bridges": "Mostki podrzędne",
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Działa",
"pending": "Oczekujące",
"down": "Nie działa",
"ok": "Ok"
"up": "Up",
"pending": "Pending",
"down": "Down"
},
"healthchecks": {
"new": "Nowy",
"up": "Działa",
"up": "Up",
"grace": "W okresie karencji",
"down": "Nie działa",
"down": "Down",
"paused": "Wstrzymane",
"status": "Status",
"last_ping": "Ostatni ping",
@@ -551,63 +550,63 @@
"containers_failed": "Niepowodzenie"
},
"autobrr": {
"approvedPushes": "Zaakceptowane",
"approvedPushes": "Approved",
"rejectedPushes": "Odrzucone",
"filters": "Filtry",
"indexers": "Indeksery"
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "W kolejce",
"downloads": "Queue",
"videos": "Pliki wideo",
"channels": "Kanały",
"playlists": "Playlisty"
},
"truenas": {
"load": "Obciążenie systemu",
"uptime": "Czas działania",
"alerts": "Alerty"
"uptime": "Uptime",
"alerts": "Alerts"
},
"pyload": {
"speed": "Prędkość",
"active": "Aktywne",
"queue": "W kolejce",
"total": "Razem"
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Adres publiczny",
"region": "Region",
"country": "Państwo",
"port_forwarded": "Port otwarty"
"port_forwarded": "Port Forwarded"
},
"hdhomerun": {
"channels": "Kanały",
"channels": "Channels",
"hd": "HD",
"tunerCount": "Tunery",
"channelNumber": "Kanał",
"channelNetwork": "Sieć",
"signalStrength": "Siła sygnału",
"signalQuality": "Jakość",
"symbolQuality": "Jakość",
"symbolQuality": "Quality",
"networkRate": "Bitrate",
"clientIP": "Klient"
},
"scrutiny": {
"passed": "Powodzenie",
"failed": "Nieudane",
"unknown": "Nieznane"
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Skrzynka odbiorcza",
"total": "Razem"
"total": "Total"
},
"pangolin": {
"orgs": "Organizacje",
"sites": "Strony",
"resources": "Zasoby",
"targets": "Cele",
"traffic": "Ruch",
"in": "Do",
"out": "Z"
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
"peanut": {
"battery_charge": "Stan baterii",
@@ -618,18 +617,18 @@
"low_battery": "Niski poziom baterii"
},
"nextdns": {
"wait": "Proszę czekać",
"wait": "Please Wait",
"no_devices": "Nie otrzymano danych urządzenia"
},
"mikrotik": {
"cpuLoad": "Obciążenie procesora",
"memoryUsed": "Zużyta pamięć",
"uptime": "Czas działania",
"uptime": "Uptime",
"numberOfLeases": "Dzierżawy"
},
"xteve": {
"streams_all": "Wszystkie strumienie",
"streams_active": "Aktywne strumienie",
"streams_active": "Active Streams",
"streams_xepg": "Kanały XEPG"
},
"opendtu": {
@@ -664,9 +663,9 @@
"load": "Śr. Obciążenie",
"memory": "Użycie pamięci",
"wanStatus": "Status WAN",
"up": "Działa",
"down": "Nie działa",
"temp": "Temperatura",
"up": "Up",
"down": "Down",
"temp": "Temp",
"disk": "Użycie dysku",
"wanIP": "WAN IP"
},
@@ -677,38 +676,38 @@
"memory_usage": "Pamięć"
},
"immich": {
"users": "Użytkownicy",
"users": "Users",
"photos": "Zdjęcia",
"videos": "Filmy",
"videos": "Videos",
"storage": "Pamięć"
},
"uptimekuma": {
"up": "Działające",
"down": "Niedziałające",
"uptime": "Czas działania",
"uptime": "Uptime",
"incident": "Incydent",
"m": "min"
"m": "m"
},
"atsumeru": {
"series": "Serie",
"series": "Series",
"archives": "Archiwa",
"chapters": "Rozdziały",
"categories": "Kategorie"
},
"komga": {
"libraries": "Biblioteki",
"series": "Serie",
"books": "Książki"
"series": "Series",
"books": "Books"
},
"diskstation": {
"days": "Dni",
"uptime": "Czas działania",
"volumeAvailable": "Dostępne"
"days": "Days",
"uptime": "Uptime",
"volumeAvailable": "Available"
},
"mylar": {
"series": "Seriale",
"series": "Series",
"issues": "Zgłoszenia",
"wanted": "Poszukiwane"
"wanted": "Wanted"
},
"photoprism": {
"albums": "Albumy",
@@ -717,9 +716,9 @@
"people": "Ludzie"
},
"fileflows": {
"queue": "W kolejce",
"processing": "Przetwarzane",
"processed": "Przetworzone",
"queue": "Queue",
"processing": "Processing",
"processed": "Processed",
"time": "Czas"
},
"firefly": {
@@ -745,7 +744,7 @@
"size": "Rozmiar",
"lastrun": "Ostatnie uruchomienie",
"nextrun": "Następne uruchomienie",
"failed": "Nieudane"
"failed": "Failed"
},
"unmanic": {
"active_workers": "Aktywni pracownicy",
@@ -762,15 +761,15 @@
"targets_total": "Wszystkich Celi"
},
"gatus": {
"up": "Działające strony",
"down": "Niedziałające strony",
"uptime": "Czas działania"
"up": "Sites Up",
"down": "Sites Down",
"uptime": "Uptime"
},
"ghostfolio": {
"gross_percent_today": "Dzisiaj",
"gross_percent_1y": "Rok",
"gross_percent_max": "Od początku",
"net_worth": "Wartość netto"
"net_worth": "Net Worth"
},
"audiobookshelf": {
"podcasts": "Podcasty",
@@ -785,22 +784,22 @@
},
"whatsupdocker": {
"monitoring": "Monitoring",
"updates": "Aktualizacje"
"updates": "Updates"
},
"calibreweb": {
"books": "Książki",
"authors": "Autorzy",
"categories": "Kategorie",
"series": "Serie"
"series": "Series"
},
"jdownloader": {
"downloadCount": "W kolejce",
"downloadBytesRemaining": "Pozostało",
"downloadTotalBytes": "Rozmiar",
"downloadCount": "Queue",
"downloadBytesRemaining": "Remaining",
"downloadTotalBytes": "Size",
"downloadSpeed": "Prędkość"
},
"kavita": {
"seriesCount": "Serie",
"seriesCount": "Series",
"totalFiles": "Pliki"
},
"azuredevops": {
@@ -814,7 +813,7 @@
"inProgress": "W trakcie",
"totalPrs": "Łącznie PRs",
"myPrs": "Moje PRs",
"approved": "Zaakceptowane"
"approved": "Approved"
},
"gamedig": {
"status": "Status",
@@ -842,33 +841,33 @@
},
"openmediavault": {
"downloading": "Pobieranie",
"total": "Razem",
"running": "Działające",
"stopped": "Zatrzymane",
"passed": "Zaliczony",
"failed": "Nieudany"
"total": "Total",
"running": "Running",
"stopped": "Stopped",
"passed": "Passed",
"failed": "Failed"
},
"openwrt": {
"uptime": "Czas działania",
"uptime": "Uptime",
"cpuLoad": "Śr. obciążenie CPU (5m)",
"up": "Działa",
"down": "Nie działa",
"up": "Up",
"down": "Down",
"bytesTx": "Przesłane",
"bytesRx": "Odebrano"
"bytesRx": "Received"
},
"uptimerobot": {
"status": "Status",
"uptime": "Czas działania",
"uptime": "Uptime",
"lastDown": "Ostatni downtime",
"downDuration": "Długość downtime'u",
"sitesUp": "Działające strony",
"sitesDown": "Niedziałające strony",
"paused": "Zatrzymane",
"sitesUp": "Sites Up",
"sitesDown": "Sites Down",
"paused": "Paused",
"notyetchecked": "Nie sprawdzono",
"up": "Działa",
"up": "Up",
"seemsdown": "Możliwe, że wyłączony",
"down": "Nie działa",
"unknown": "Nieznane"
"down": "Down",
"unknown": "Unknown"
},
"calendar": {
"inCinemas": "W kinach",
@@ -887,10 +886,10 @@
"totalfilesize": "Rozmiar całkowity"
},
"mailcow": {
"domains": "Domeny",
"domains": "Domains",
"mailboxes": "Skrzynki",
"mails": "Poczta",
"storage": "Pamięć"
"storage": "Storage"
},
"netdata": {
"warnings": "Ostrzeżenia",
@@ -899,12 +898,12 @@
"plantit": {
"events": "Wydarzenia",
"plants": "Rośliny",
"photos": "Zdjęcia",
"photos": "Photos",
"species": "Gatunki"
},
"gitea": {
"notifications": "Powiadomienia",
"issues": "Zgłoszenia",
"issues": "Issues",
"pulls": "Żądania Pull",
"repositories": "Repozytoria"
},
@@ -920,13 +919,13 @@
"galleries": "Galerie",
"performers": "Artyści",
"studios": "Studia",
"movies": "Filmy",
"tags": "Tagi",
"movies": "Movies",
"tags": "Tags",
"oCount": "O Licznik"
},
"tandoor": {
"users": "Użytkownicy",
"recipes": "Przepisy",
"users": "Users",
"recipes": "Recipes",
"keywords": "Słowa kluczowe"
},
"homebox": {
@@ -934,18 +933,18 @@
"totalWithWarranty": "Z gwarancją",
"locations": "Lokalizacje",
"labels": "Etykiety",
"users": "Użytkownicy",
"users": "Users",
"totalValue": "Wartość całkowita"
},
"crowdsec": {
"alerts": "Alerty",
"alerts": "Alerts",
"bans": "Bany"
},
"wgeasy": {
"connected": "Połączonych",
"enabled": "Włączone",
"disabled": "Wyłączone",
"total": "Razem"
"connected": "Connected",
"enabled": "Enabled",
"disabled": "Disabled",
"total": "Total"
},
"swagdashboard": {
"proxied": "Proxy",
@@ -967,7 +966,7 @@
},
"frigate": {
"cameras": "Kamery",
"uptime": "Czas działania",
"uptime": "Uptime",
"version": "Wersja"
},
"linkwarden": {
@@ -977,7 +976,7 @@
},
"zabbix": {
"unclassified": "Niezaklasyfikowane",
"information": "Informacja",
"information": "Information",
"warning": "Ostrzeżenie",
"average": "Średnia",
"high": "Wysokie",
@@ -1008,14 +1007,14 @@
"beszel": {
"name": "Nazwa",
"systems": "Systemy",
"up": "Działa",
"down": "Nie działa",
"paused": "Wstrzymane",
"pending": "Oczekujące",
"up": "Up",
"down": "Down",
"paused": "Paused",
"pending": "Pending",
"status": "Status",
"updated": "Zaktualizowane",
"updated": "Updated",
"cpu": "Procesor",
"memory": "PAM",
"memory": "MEM",
"disk": "Dysk",
"network": "NET"
},
@@ -1023,14 +1022,14 @@
"apps": "Aplikacje",
"synced": "Synchronizowane",
"outOfSync": "Bez synchronizacji",
"healthy": "Zdrowe",
"healthy": "Healthy",
"degraded": "Zdegradowane",
"progressing": "Postępujące",
"missing": "Brakujące",
"missing": "Missing",
"suspended": "Zawieszone"
},
"spoolman": {
"loading": "Ładowanie"
"loading": "Loading"
},
"gitlab": {
"groups": "Grupy",
@@ -1040,9 +1039,9 @@
},
"apcups": {
"status": "Status",
"load": "Obciążenie",
"bcharge": "Naładowanie baterii",
"timeleft": "Pozostały czas"
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Time Left"
},
"karakeep": {
"bookmarks": "Zakładki",
@@ -1053,11 +1052,11 @@
"tags": "Tagi"
},
"slskd": {
"slskStatus": "Sieć",
"connected": "Połączono",
"disconnected": "Rozłączono",
"slskStatus": "Network",
"connected": "Connected",
"disconnected": "Disconnected",
"updateStatus": "Aktualizacja",
"update_yes": "Dostępne",
"update_yes": "Available",
"update_no": "Aktualny",
"downloads": "Pobieranie",
"uploads": "Przesyłanie",
@@ -1070,65 +1069,65 @@
"other": "Inne"
},
"checkmk": {
"serviceErrors": "Problem z usługą",
"hostErrors": "Problemy hosta"
"serviceErrors": "Service issues",
"hostErrors": "Host issues"
},
"komodo": {
"total": "Razem",
"running": "Działające",
"stopped": "Zatrzymane",
"down": "Nie działa",
"unhealthy": "Uszkodzony",
"unknown": "Nieznane",
"total": "Total",
"running": "Running",
"stopped": "Stopped",
"down": "Down",
"unhealthy": "Unhealthy",
"unknown": "Unknown",
"servers": "Serwery",
"stacks": "Stosy",
"containers": "Kontenery"
"stacks": "Stacks",
"containers": "Containers"
},
"filebrowser": {
"available": "Dostępne",
"used": "Użyte",
"total": "Razem"
"available": "Available",
"used": "Used",
"total": "Total"
},
"wallos": {
"activeSubscriptions": "Subskrypcje",
"thisMonthlyCost": "Ten Miesiąc",
"nextMonthlyCost": "Następny miesiąc",
"previousMonthlyCost": "Poprzedni miesiąc",
"nextRenewingSubscription": "Następna płatność"
"activeSubscriptions": "Subscriptions",
"thisMonthlyCost": "This Month",
"nextMonthlyCost": "Next Month",
"previousMonthlyCost": "Prev. Month",
"nextRenewingSubscription": "Next Payment"
},
"unraid": {
"STARTED": "Rozpoczęte",
"STOPPED": "Zatrzymane",
"NEW_ARRAY": "Nowa macierz",
"RECON_DISK": "Odbudowa dysku",
"DISABLE_DISK": "Dysk wyłączony",
"SWAP_DSBL": "Przestrzeń wymiany wyłączona",
"INVALID_EXPANSION": "Nieprawidłowe rozszerzenie",
"PARITY_NOT_BIGGEST": "Parzystość nie największa",
"TOO_MANY_MISSING_DISKS": "Zbyt wiele brakujących dysków",
"NEW_DISK_TOO_SMALL": "Nowy dysk zbyt mały",
"NO_DATA_DISKS": "Brak dysków danych",
"notifications": "Powiadomienia",
"STARTED": "Started",
"STOPPED": "Stopped",
"NEW_ARRAY": "New Array",
"RECON_DISK": "Reconstructing Disk",
"DISABLE_DISK": "Disk Disabled",
"SWAP_DSBL": "Swap Disable",
"INVALID_EXPANSION": "Invalid Expansion",
"PARITY_NOT_BIGGEST": "Parity Not Biggest",
"TOO_MANY_MISSING_DISKS": "Too Many Missing Disks",
"NEW_DISK_TOO_SMALL": "New Disk Too Small",
"NO_DATA_DISKS": "No Data Disks",
"notifications": "Notifications",
"status": "Status",
"cpu": "CPU",
"memoryUsed": "Użyta pamięć",
"memoryAvailable": "Dostępna pamięć",
"arrayUsed": "Użyto macierzy",
"arrayFree": "Wolne na macierzy",
"poolUsed": "Użyto {{pool}}",
"poolFree": "{{pool}} Wolne"
"memoryUsed": "Memory Used",
"memoryAvailable": "Memory Available",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
"poolUsed": "{{pool}} Used",
"poolFree": "{{pool}} Free"
},
"backrest": {
"num_plans": "Planowane",
"num_success_30": "Powodzenia",
"num_failure_30": "Niepowodzenia",
"num_success_latest": "Powodzenie",
"num_failure_latest": "Niepowodzenie",
"bytes_added_30": "Dodane bajty"
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
},
"yourspotify": {
"songs": "Piosenki",
"time": "Czas",
"artists": "Wykonawcy"
"songs": "Songs",
"time": "Time",
"artists": "Artists"
}
}

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Novo",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Ativo",
"pending": "Pendente",
"down": "Inativo",
"ok": "Ok"
"down": "Inativo"
},
"healthchecks": {
"new": "Novo",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nou",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "В сети",
"pending": "Ожидают",
"down": "Не в сети",
"ok": "Ok"
"down": "Не в сети"
},
"healthchecks": {
"new": "Новый",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Beží",
"pending": "Čakajúce",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nový",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Nov",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Горе",
"pending": "На чекању",
"down": "Доле",
"ok": "Ok"
"down": "Доле"
},
"healthchecks": {
"new": "Сада",
@@ -601,13 +600,13 @@
"total": "Укупно"
},
"pangolin": {
"orgs": "Организације",
"sites": "Сајтови",
"resources": "Ресурси",
"targets": "Циљеви",
"traffic": "Саобраћај",
"in": "Улазак",
"out": "Излазак"
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
"peanut": {
"battery_charge": "Напуњеност батерије",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Çalışıyor",
"pending": "Bekleyen",
"down": "Çalışmayan",
"ok": "Ok"
"down": "Çalışmayan"
},
"healthchecks": {
"new": "Yeni",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "Новий",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "New",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "新建立",

View File

@@ -364,7 +364,7 @@
"version": "版本",
"notesCount": "笔记",
"dbSize": "数据库大小",
"unknown": "未知"
"unknown": "Unknown"
},
"navidrome": {
"nothing_streaming": "",
@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "新建立",
@@ -801,7 +800,7 @@
},
"kavita": {
"seriesCount": "系列",
"totalFiles": "文件"
"totalFiles": "Files"
},
"azuredevops": {
"result": "Result",
@@ -1098,7 +1097,7 @@
},
"unraid": {
"STARTED": "Started",
"STOPPED": "已停止",
"STOPPED": "Stopped",
"NEW_ARRAY": "New Array",
"RECON_DISK": "Reconstructing Disk",
"DISABLE_DISK": "Disk Disabled",

View File

@@ -532,8 +532,7 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Up",
"pending": "Pending",
"down": "Down",
"ok": "Ok"
"down": "Down"
},
"healthchecks": {
"new": "新建",

View File

@@ -24,12 +24,12 @@ export default function Resource({
wide ? " min-w-[120px]" : "min-w-[85px]"
}`}
>
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between gap-2">
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">{value}</div>
<div className="pr-1">{label}</div>
</div>
{expanded && (
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between gap-2">
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5">{expandedValue}</div>
<div className="pr-1">{expandedLabel}</div>
</div>

View File

@@ -59,7 +59,7 @@ export default async function handler(req, res) {
}
if (type === "network") {
let networkData = await si.networkStats("*");
let networkData = await si.networkStats();
let interfaceDefault;
logger.debug("networkData:", JSON.stringify(networkData));
if (interfaceName && interfaceName !== "default") {

View File

@@ -554,38 +554,48 @@ export default function Wrapper({ initialSettings, fallback }) {
html.classList.add(desiredThemeClass);
}
// Remove any previously applied inline styles
body.style.backgroundImage = "";
body.style.backgroundColor = "";
body.style.backgroundAttachment = "";
if (backgroundImage) {
const safeBackgroundImage = backgroundImage.replace(/'/g, "\\'");
body.style.backgroundImage = `linear-gradient(rgb(var(--bg-color) / ${opacity}), rgb(var(--bg-color) / ${opacity})), url('${safeBackgroundImage}')`;
body.style.backgroundSize = "cover";
body.style.backgroundPosition = "center";
body.style.backgroundAttachment = "fixed";
body.style.backgroundRepeat = "no-repeat";
body.style.backgroundColor = "";
} else {
body.style.backgroundImage = "none";
body.style.backgroundColor = "rgb(var(--bg-color))";
body.style.backgroundSize = "";
body.style.backgroundPosition = "";
body.style.backgroundAttachment = "";
body.style.backgroundRepeat = "";
}
return () => {
body.style.backgroundImage = "";
body.style.backgroundColor = "";
body.style.backgroundSize = "";
body.style.backgroundPosition = "";
body.style.backgroundAttachment = "";
body.style.backgroundRepeat = "";
};
}, [backgroundImage, opacity, theme, color, initialSettings.color]);
return (
<>
{backgroundImage && (
<div
id="background"
aria-hidden="true"
style={{
backgroundImage: `linear-gradient(rgb(var(--bg-color) / ${opacity}), rgb(var(--bg-color) / ${opacity})), url('${backgroundImage}')`,
}}
/>
)}
<div id="page_wrapper" className="relative h-full">
<div
id="inner_wrapper"
tabIndex="-1"
className={classNames(
"w-full h-full overflow-auto",
backgroundBlur &&
`backdrop-blur${initialSettings.background.blur?.length ? `-${initialSettings.background.blur}` : ""}`,
backgroundSaturate && `backdrop-saturate-${initialSettings.background.saturate}`,
backgroundBrightness && `backdrop-brightness-${initialSettings.background.brightness}`,
)}
>
<Index initialSettings={initialSettings} fallback={fallback} />
</div>
<div id="page_wrapper" className="relative min-h-screen">
<div
id="inner_wrapper"
tabIndex="-1"
className={classNames(
"w-full min-h-screen overflow-auto",
backgroundBlur &&
`backdrop-blur${initialSettings.background.blur?.length ? `-${initialSettings.background.blur}` : ""}`,
backgroundSaturate && `backdrop-saturate-${initialSettings.background.saturate}`,
backgroundBrightness && `backdrop-brightness-${initialSettings.background.brightness}`,
)}
>
<Index initialSettings={initialSettings} fallback={fallback} />
</div>
</>
</div>
);
}

View File

@@ -30,18 +30,6 @@ body,
height: 100%;
margin: 0;
padding: 0;
background-color: rgb(var(--bg-color));
}
#background {
position: fixed;
inset: 0;
z-index: 0;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: scroll;
pointer-events: none;
}
html,

View File

@@ -35,7 +35,7 @@ function parseServicesToGroups(services) {
serviceGroupServices.push({
name: entryName,
...entries[entryName],
weight: entries[entryName].weight ?? (serviceGroupServices.length + 1) * 100, // default weight
weight: entries[entryName].weight || serviceGroupServices.length * 100, // default weight
type: "service",
});
}
@@ -107,7 +107,6 @@ export async function servicesFromDocker() {
constructedService = {
container: containerName.replace(/^\//, ""),
server: serverName,
weight: 0,
type: "service",
};
}

View File

@@ -27,9 +27,6 @@ export default async function credentialedProxyHandler(req, res, map) {
const headers = {
"Content-Type": "application/json",
...(widgets[widget.type].headers ?? {}),
...(widget.headers ?? {}),
...(req.extraHeaders ?? {}),
};
if (widget.type === "stocks") {

View File

@@ -25,11 +25,7 @@ export default async function genericProxyHandler(req, res, map) {
}
const url = new URL(urlString);
const headers = {
...(widgets[widget.type].headers ?? {}),
...(widget.headers ?? {}),
...(req.extraHeaders ?? {}),
};
const headers = req.extraHeaders ?? widget.headers ?? widgets[widget.type].headers ?? {};
if (widget.username && widget.password) {
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;

View File

@@ -85,9 +85,6 @@ export default async function fritzboxProxyHandler(req, res) {
requestExternalIPv6Prefix ? requestEndpoint(apiBaseUrl, "WANIPConnection", "X_AVM_DE_GetIPv6Prefix") : null,
])
.then(([statusInfo, linkProperties, addonInfos, externalIPAddress, externalIPv6Address, externalIPv6Prefix]) => {
const ipv6Prefix = externalIPv6Prefix?.NewIPv6Prefix;
const ipv6Len = externalIPv6Prefix?.NewPrefixLength;
res.status(200).json({
connectionStatus: statusInfo?.NewConnectionStatus || "Unconfigured",
uptime: statusInfo?.NewUptime || 0,
@@ -99,7 +96,7 @@ export default async function fritzboxProxyHandler(req, res) {
sent: addonInfos?.NewX_AVM_DE_TotalBytesSent64 || 0,
externalIPAddress: externalIPAddress?.NewExternalIPAddress || null,
externalIPv6Address: externalIPv6Address?.NewExternalIPv6Address || null,
externalIPv6Prefix: ipv6Prefix && ipv6Len != null ? `${ipv6Prefix}/${ipv6Len}` : (ipv6Prefix ?? null),
externalIPv6Prefix: externalIPv6Prefix?.NewIPv6Prefix || null,
});
})
.catch((error) => {

View File

@@ -65,7 +65,7 @@ async function fetchFromPlexAPI(endpoint, widget) {
export default async function plexProxyHandler(req, res) {
const widget = await getWidget(req);
const { service, index } = req.query;
const { service } = req.query;
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
@@ -85,19 +85,19 @@ export default async function plexProxyHandler(req, res) {
streams = apiData.MediaContainer._attributes.size;
}
let libraries = cache.get(`${librariesCacheKey}.${service}.${index}`);
let libraries = cache.get(`${librariesCacheKey}.${service}`);
if (libraries === null) {
logger.debug("Getting libraries from Plex API");
[status, apiData] = await fetchFromPlexAPI("/library/sections", widget);
if (apiData && apiData.MediaContainer) {
libraries = [].concat(apiData.MediaContainer.Directory);
cache.put(`${librariesCacheKey}.${service}.${index}`, libraries, 1000 * 60 * 60 * 6);
cache.put(`${librariesCacheKey}.${service}`, libraries, 1000 * 60 * 60 * 6);
}
}
let albums = cache.get(`${albumsCacheKey}.${service}.${index}`);
let movies = cache.get(`${moviesCacheKey}.${service}.${index}`);
let tv = cache.get(`${tvCacheKey}.${service}.${index}`);
let albums = cache.get(`${albumsCacheKey}.${service}`);
let movies = cache.get(`${moviesCacheKey}.${service}`);
let tv = cache.get(`${tvCacheKey}.${service}`);
if (albums === null || movies === null || tv === null) {
albums = 0;
movies = 0;
@@ -123,9 +123,9 @@ export default async function plexProxyHandler(req, res) {
}
}),
);
cache.put(`${albumsCacheKey}.${service}.${index}`, albums, 1000 * 60 * 10);
cache.put(`${tvCacheKey}.${service}.${index}`, tv, 1000 * 60 * 10);
cache.put(`${moviesCacheKey}.${service}.${index}`, movies, 1000 * 60 * 10);
cache.put(`${albumsCacheKey}.${service}`, albums, 1000 * 60 * 10);
cache.put(`${tvCacheKey}.${service}`, tv, 1000 * 60 * 10);
cache.put(`${moviesCacheKey}.${service}`, movies, 1000 * 60 * 10);
}
const data = {

View File

@@ -11,15 +11,6 @@ const logger = createLogger(proxyName);
const sessionCacheKey = `${proxyName}__sessionId`;
const isNgCacheKey = `${proxyName}__isNg`;
function parsePyloadResponse(url, data) {
try {
return JSON.parse(Buffer.from(data).toString());
} catch (e) {
logger.error(`Error communicating with pyload API at ${url}, returned: ${JSON.stringify(data)}`);
return data;
}
}
async function fetchFromPyloadAPI(url, sessionId, params, service) {
const options = {
body: params
@@ -42,33 +33,13 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) {
// eslint-disable-next-line no-unused-vars
const [status, contentType, data, responseHeaders] = await httpProxy(url, options);
const returnData = parsePyloadResponse(url, data);
return [status, returnData, responseHeaders];
}
async function fetchFromPyloadAPIBasic(url, params, username, password) {
const parsedUrl = new URL(url);
const isGetRequest = !params || Object.keys(params).length === 0;
const options = {
method: isGetRequest ? "GET" : "POST",
headers: {
Authorization: `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`,
},
};
if (isGetRequest) {
if (params) {
Object.keys(params).forEach((key) => parsedUrl.searchParams.append(key, params[key]));
}
} else {
options.headers["Content-Type"] = "application/json";
options.body = JSON.stringify(params);
let returnData;
try {
returnData = JSON.parse(Buffer.from(data).toString());
} catch (e) {
logger.error(`Error communicating with pyload API at ${url}, returned: ${JSON.stringify(data)}`);
returnData = data;
}
// eslint-disable-next-line no-unused-vars
const [status, contentType, data, responseHeaders] = await httpProxy(parsedUrl, options);
const returnData = parsePyloadResponse(parsedUrl, data);
return [status, returnData, responseHeaders];
}
@@ -95,43 +66,24 @@ async function login(loginUrl, service, username, password = "") {
return sessionId;
}
export default async function pyloadProxyHandler(req, res, map = {}) {
export default async function pyloadProxyHandler(req, res) {
const { group, service, endpoint, index } = req.query;
const { ngEndpoint } = map;
try {
if (group && service) {
const widget = await getServiceWidget(group, service, index);
if (widget) {
const apiTemplate = widgets[widget.type].api;
const url = new URL(formatApiCall(apiTemplate, { endpoint, ...widget }));
const ngUrl = ngEndpoint ? new URL(formatApiCall(apiTemplate, { endpoint: ngEndpoint, ...widget })) : url;
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const loginUrl = `${widget.url}/api/login`;
const hasCredentials = widget.username && widget.password;
if (hasCredentials) {
const [status, data] = await fetchFromPyloadAPIBasic(ngUrl, null, widget.username, widget.password);
if (status === 200 && !data?.error) {
cache.put(`${isNgCacheKey}.${service}`, true);
return res.json(data);
}
if (status === 401) {
return res
.status(status)
.send({ error: { message: "Invalid credentials communicating with Pyload API", data } });
}
}
let sessionId =
cache.get(`${sessionCacheKey}.${service}`) ??
(await login(loginUrl, service, widget.username, widget.password));
let [status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);
if (status === 403 || status === 401 || (status === 400 && data?.error?.includes("CSRF token"))) {
logger.info("Failed to retrieve data from Pyload API with session auth, trying to login again...");
if (status === 403 || status === 401) {
logger.info("Failed to retrieve data from Pyload API, trying to login again...");
cache.del(`${sessionCacheKey}.${service}`);
sessionId = await login(loginUrl, service, widget.username, widget.password);
[status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);

View File

@@ -7,7 +7,6 @@ const widget = {
mappings: {
status: {
endpoint: "statusServer",
map: { ngEndpoint: "status_server" },
},
},
};

View File

@@ -12,8 +12,8 @@ export default function Component({ service }) {
const { data: alertData, error: alertError } = useWidgetAPI(widget, "alerts");
const { data: statusData, error: statusError } = useWidgetAPI(widget, "status");
const { data: poolsData, error: poolsError } = useWidgetAPI(widget, widget?.enablePools ? "pools" : "");
const { data: datasetData, error: datasetError } = useWidgetAPI(widget, widget?.enablePools ? "dataset" : "");
const { data: poolsData, error: poolsError } = useWidgetAPI(widget, widget?.enablePools ? "pools" : null);
const { data: datasetData, error: datasetError } = useWidgetAPI(widget, widget?.enablePools ? "dataset" : null);
if (alertError || statusError || poolsError) {
const finalError = alertError ?? statusError ?? poolsError ?? datasetError;

View File

@@ -1,172 +0,0 @@
import WebSocket from "ws";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import { formatApiCall, sanitizeErrorURL } from "utils/proxy/api-helpers";
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
import validateWidgetData from "utils/proxy/validate-widget-data";
import widgets from "widgets/widgets";
const logger = createLogger("truenasProxyHandler");
function waitForEvent(ws, handler, { event = "message", parseJson = true } = {}) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
cleanup();
reject(new Error("TrueNAS websocket wait timed out"));
}, 10000);
const handleEvent = (payload) => {
try {
let parsed = payload;
if (parseJson) {
if (Buffer.isBuffer(payload)) {
parsed = JSON.parse(payload.toString());
} else if (typeof payload === "string") {
parsed = JSON.parse(payload);
}
logger.info("Received TrueNAS websocket message: %o", parsed);
} else {
logger.info("Received TrueNAS websocket message: %o", payload);
}
const handlerResult = handler(parsed);
if (handlerResult !== undefined) {
cleanup();
if (handlerResult instanceof Error) {
reject(handlerResult);
} else {
resolve(handlerResult);
}
}
} catch (err) {
cleanup();
reject(err);
}
};
const handleError = (err) => {
cleanup();
logger.error("TrueNAS websocket error: %s", err?.message ?? err);
reject(err);
};
const handleClose = () => {
cleanup();
logger.error("TrueNAS websocket connection closed unexpectedly");
reject(new Error("TrueNAS websocket closed the connection"));
};
function cleanup() {
clearTimeout(timeout);
ws.off(event, handleEvent);
ws.off("error", handleError);
ws.off("close", handleClose);
}
ws.on(event, handleEvent);
ws.on("error", handleError);
ws.on("close", handleClose);
});
}
let nextId = 1;
async function sendMethod(ws, method, params = []) {
const id = nextId++;
const payload = { jsonrpc: "2.0", id, method, params };
logger.info("Sending TrueNAS websocket method %s with id %d", method, id);
ws.send(JSON.stringify(payload));
return waitForEvent(ws, (message) => {
if (message?.id !== id) return undefined;
if (message?.error) {
return new Error(message.error?.message || JSON.stringify(message.error));
}
return message?.result ?? message;
});
}
async function authenticate(ws, widget) {
if (widget?.key) {
try {
const apiKeyResult = await sendMethod(ws, "auth.login_with_api_key", [widget.key]);
if (apiKeyResult === true) return;
logger.warn("TrueNAS API key authentication failed, falling back to username/password when available.");
} catch (err) {
logger.warn("TrueNAS API key authentication failed: %s", err?.message ?? err);
}
}
if (widget?.username && widget?.password) {
const loginResult = await sendMethod(ws, "auth.login", [widget.username, widget.password]);
if (loginResult === true) return;
logger.warn("TrueNAS username/password authentication failed.");
}
throw new Error("TrueNAS authentication failed");
}
export default async function truenasProxyHandler(req, res, map) {
const { group, service, endpoint, index } = req.query;
if (!group || !service) {
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
const widget = await getServiceWidget(group, service, index);
if (!widget) {
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
if (!endpoint) {
return res.status(204).end();
}
const version = Number(widget.version ?? 1);
if (Number.isNaN(version) || version < 2) {
// Use legacy REST proxy for version 1
return credentialedProxyHandler(req, res, map);
}
const mappingEntry = Object.values(widgets[widget.type].mappings).find((mapping) => mapping.endpoint === endpoint);
const wsMethod = mappingEntry.wsMethod;
if (!wsMethod) {
logger.debug("Missing wsMethod mapping for TrueNAS endpoint %s", endpoint);
return res.status(500).json({ error: "Missing wsMethod mapping." });
}
try {
let data;
const wsUrl = new URL(formatApiCall(widgets[widget.type].wsAPI, { ...widget }));
const useSecure = wsUrl.protocol === "https:" || Boolean(widget.key); // API key requires secure connection
if (useSecure && wsUrl.protocol !== "https:")
logger.info("Upgrading TrueNAS websocket connection to secure wss://");
wsUrl.protocol = useSecure ? "wss:" : "ws:";
logger.info("Connecting to TrueNAS websocket at %s", wsUrl);
const ws = new WebSocket(wsUrl, { rejectUnauthorized: false });
await waitForEvent(ws, () => true, { event: "open", parseJson: false }); // wait for open
logger.info("Connected to TrueNAS websocket at %s", wsUrl);
try {
await authenticate(ws, widget);
data = await sendMethod(ws, wsMethod);
} finally {
ws.close();
}
if (!validateWidgetData(widget, endpoint, data)) {
return res.status(500).json({ error: { message: "Invalid data", url: sanitizeErrorURL(widget.url), data } });
}
if (map) data = map(data);
return res.status(200).json(data);
} catch (err) {
if (err?.status) {
return res.status(err.status).json({ error: err.message });
}
logger.warn("Websocket call for TrueNAS failed: %s", err?.message ?? err);
return res.status(500).json({ error: err?.message ?? "TrueNAS websocket call failed" });
}
}

View File

@@ -1,43 +1,32 @@
import truenasProxyHandler from "./proxy";
import { asJson, jsonArrayFilter } from "utils/proxy/api-helpers";
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
const widget = {
api: "{url}/api/v2.0/{endpoint}",
wsAPI: "{url}/api/current",
proxyHandler: truenasProxyHandler,
proxyHandler: credentialedProxyHandler,
mappings: {
alerts: {
endpoint: "alert/list",
wsMethod: "alert.list",
map: (data) => {
if (Array.isArray(data)) {
return { pending: data.filter((item) => item?.dismissed === false).length };
}
return { pending: jsonArrayFilter(data, (item) => item?.dismissed === false).length };
},
map: (data) => ({
pending: jsonArrayFilter(data, (item) => item?.dismissed === false).length,
}),
},
status: {
endpoint: "system/info",
wsMethod: "system.info",
validate: ["loadavg", "uptime_seconds"],
},
pools: {
endpoint: "pool",
wsMethod: "pool.query",
map: (data) => {
const list = Array.isArray(data) ? data : asJson(data);
return list.map((entry) => ({
map: (data) =>
asJson(data).map((entry) => ({
id: entry.name,
name: entry.name,
healthy: entry.healthy,
}));
},
})),
},
dataset: {
endpoint: "pool/dataset",
wsMethod: "pool.dataset.query",
},
},
};

View File

@@ -49,12 +49,10 @@ export default function Component({ service }) {
// single monitor
const monitor = uptimerobotData.monitors[0];
const logs = Array.isArray(monitor.logs) ? monitor.logs : [];
const lastUpLog = logs.find((log) => log.type === 2);
const lastDownLog = logs.find((log) => log.type === 1);
let status;
let uptime = 0;
let logIndex = 0;
const hasLogs = Array.isArray(monitor.logs) && monitor.logs.length > 0;
switch (monitor.status) {
case 0:
@@ -65,7 +63,8 @@ export default function Component({ service }) {
break;
case 2:
status = t("uptimerobot.up");
uptime = t("common.duration", { value: lastUpLog?.duration ?? 0 });
uptime = t("common.duration", { value: hasLogs ? monitor.logs[0].duration : 0 });
logIndex = 1;
break;
case 8:
status = t("uptimerobot.seemsdown");
@@ -78,14 +77,14 @@ export default function Component({ service }) {
break;
}
const lastDown = lastDownLog ? new Date(lastDownLog.datetime * 1000).toLocaleString() : "";
const downDuration = t("common.duration", { value: lastDownLog?.duration ?? 0 });
const hideDown = !lastDownLog;
const lastDown = hasLogs ? new Date(monitor.logs[logIndex].datetime * 1000).toLocaleString() : "";
const downDuration = t("common.duration", { value: hasLogs ? monitor.logs[logIndex].duration : 0 });
const hideDown = !hasLogs || (logIndex === 1 && monitor.logs[logIndex].type !== 1);
return (
<Container service={service}>
<Block label="uptimerobot.status" value={status} />
<Block label="uptimerobot.uptime" value={uptime} />
{hasLogs && <Block label="uptimerobot.uptime" value={uptime} />}
{!hideDown && <Block label="uptimerobot.lastDown" value={lastDown} />}
{!hideDown && <Block label="uptimerobot.downDuration" value={downDuration} />}
</Container>

View File

@@ -6,17 +6,8 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const MAX_ALLOWED_FIELDS = 4;
const todayDate = new Date();
function toApiMonthYear(offset = 0) {
// API expects 1-indexed months, wrap around if needed
const m = todayDate.getMonth() + 1 + offset;
return {
month: ((m + 11) % 12) + 1,
year: todayDate.getFullYear() + Math.floor((m - 1) / 12),
};
}
export default function Component({ service }) {
const todayDate = new Date();
const { t } = useTranslation();
const { widget } = service;
@@ -38,19 +29,28 @@ export default function Component({ service }) {
const { data: subscriptionsThisMonthlyCostData, error: subscriptionsThisMonthlyCostError } = useWidgetAPI(
widget,
subscriptionsThisMonthlyEndpoint,
toApiMonthYear(), // this month
{
month: todayDate.getMonth(),
year: todayDate.getFullYear(),
},
);
const subscriptionsNextMonthlyEndpoint = widget.fields.includes("nextMonthlyCost") ? "get_monthly_cost" : "";
const { data: subscriptionsNextMonthlyCostData, error: subscriptionsNextMonthlyCostError } = useWidgetAPI(
widget,
subscriptionsNextMonthlyEndpoint,
toApiMonthYear(1), // next month
{
month: todayDate.getMonth() + 1,
year: todayDate.getFullYear(),
},
);
const subscriptionsPreviousMonthlyEndpoint = widget.fields.includes("previousMonthlyCost") ? "get_monthly_cost" : "";
const { data: subscriptionsPreviousMonthlyCostData, error: subscriptionsPreviousMonthlyCostError } = useWidgetAPI(
widget,
subscriptionsPreviousMonthlyEndpoint,
toApiMonthYear(-1), // previous month
{
month: todayDate.getMonth() - 1,
year: todayDate.getFullYear(),
},
);
if (