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
65 changed files with 372 additions and 493 deletions

View File

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

View File

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

View File

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

View File

@@ -189,8 +189,6 @@ labels: ...
- homepage.widgets[1].slug=youreventslughere - 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: You can add specify fields for e.g. the [CustomAPI](../widgets/services/customapi.md) widget by using array-style dot notation:
```yaml ```yaml

View File

@@ -94,7 +94,6 @@ metadata:
gethomepage.dev/name: Emby gethomepage.dev/name: Emby
gethomepage.dev/widget.type: "emby" gethomepage.dev/widget.type: "emby"
gethomepage.dev/widget.url: "https://emby.example.com" gethomepage.dev/widget.url: "https://emby.example.com"
gethomepage.dev/widget.headers.X-Auth-Key: "your-secret-here"
gethomepage.dev/pod-selector: "" gethomepage.dev/pod-selector: ""
gethomepage.dev/weight: 10 # optional gethomepage.dev/weight: 10 # optional
gethomepage.dev/instance: "public" # 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. 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 #### 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. 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 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. - Check the browser error console, this can also sometimes provide useful information.
- Consider setting the `ENV` variable `LOG_LEVEL` to `debug`. - 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 ## Service Widget Errors
@@ -67,17 +66,3 @@ All service widgets work essentially the same, that is, homepage makes a proxied
## Missing custom icons ## 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. 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

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

365
pnpm-lock.yaml generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,12 +24,12 @@ export default function Resource({
wide ? " min-w-[120px]" : "min-w-[85px]" 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="pl-0.5">{value}</div>
<div className="pr-1">{label}</div> <div className="pr-1">{label}</div>
</div> </div>
{expanded && ( {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="pl-0.5">{expandedValue}</div>
<div className="pr-1">{expandedLabel}</div> <div className="pr-1">{expandedLabel}</div>
</div> </div>

View File

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

View File

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

View File

@@ -30,18 +30,6 @@ body,
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 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, html,

View File

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

View File

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

View File

@@ -25,11 +25,7 @@ export default async function genericProxyHandler(req, res, map) {
} }
const url = new URL(urlString); const url = new URL(urlString);
const headers = { const headers = req.extraHeaders ?? widget.headers ?? widgets[widget.type].headers ?? {};
...(widgets[widget.type].headers ?? {}),
...(widget.headers ?? {}),
...(req.extraHeaders ?? {}),
};
if (widget.username && widget.password) { if (widget.username && widget.password) {
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`; 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, requestExternalIPv6Prefix ? requestEndpoint(apiBaseUrl, "WANIPConnection", "X_AVM_DE_GetIPv6Prefix") : null,
]) ])
.then(([statusInfo, linkProperties, addonInfos, externalIPAddress, externalIPv6Address, externalIPv6Prefix]) => { .then(([statusInfo, linkProperties, addonInfos, externalIPAddress, externalIPv6Address, externalIPv6Prefix]) => {
const ipv6Prefix = externalIPv6Prefix?.NewIPv6Prefix;
const ipv6Len = externalIPv6Prefix?.NewPrefixLength;
res.status(200).json({ res.status(200).json({
connectionStatus: statusInfo?.NewConnectionStatus || "Unconfigured", connectionStatus: statusInfo?.NewConnectionStatus || "Unconfigured",
uptime: statusInfo?.NewUptime || 0, uptime: statusInfo?.NewUptime || 0,
@@ -99,7 +96,7 @@ export default async function fritzboxProxyHandler(req, res) {
sent: addonInfos?.NewX_AVM_DE_TotalBytesSent64 || 0, sent: addonInfos?.NewX_AVM_DE_TotalBytesSent64 || 0,
externalIPAddress: externalIPAddress?.NewExternalIPAddress || null, externalIPAddress: externalIPAddress?.NewExternalIPAddress || null,
externalIPv6Address: externalIPv6Address?.NewExternalIPv6Address || null, externalIPv6Address: externalIPv6Address?.NewExternalIPv6Address || null,
externalIPv6Prefix: ipv6Prefix && ipv6Len != null ? `${ipv6Prefix}/${ipv6Len}` : (ipv6Prefix ?? null), externalIPv6Prefix: externalIPv6Prefix?.NewIPv6Prefix || null,
}); });
}) })
.catch((error) => { .catch((error) => {

View File

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

View File

@@ -11,15 +11,6 @@ const logger = createLogger(proxyName);
const sessionCacheKey = `${proxyName}__sessionId`; const sessionCacheKey = `${proxyName}__sessionId`;
const isNgCacheKey = `${proxyName}__isNg`; 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) { async function fetchFromPyloadAPI(url, sessionId, params, service) {
const options = { const options = {
body: params body: params
@@ -42,33 +33,13 @@ async function fetchFromPyloadAPI(url, sessionId, params, service) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const [status, contentType, data, responseHeaders] = await httpProxy(url, options); const [status, contentType, data, responseHeaders] = await httpProxy(url, options);
const returnData = parsePyloadResponse(url, data); let returnData;
return [status, returnData, responseHeaders]; try {
} returnData = JSON.parse(Buffer.from(data).toString());
} catch (e) {
async function fetchFromPyloadAPIBasic(url, params, username, password) { logger.error(`Error communicating with pyload API at ${url}, returned: ${JSON.stringify(data)}`);
const parsedUrl = new URL(url); returnData = data;
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);
} }
// 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]; return [status, returnData, responseHeaders];
} }
@@ -95,43 +66,24 @@ async function login(loginUrl, service, username, password = "") {
return sessionId; 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 { group, service, endpoint, index } = req.query;
const { ngEndpoint } = map;
try { try {
if (group && service) { if (group && service) {
const widget = await getServiceWidget(group, service, index); const widget = await getServiceWidget(group, service, index);
if (widget) { if (widget) {
const apiTemplate = widgets[widget.type].api; const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const url = new URL(formatApiCall(apiTemplate, { endpoint, ...widget }));
const ngUrl = ngEndpoint ? new URL(formatApiCall(apiTemplate, { endpoint: ngEndpoint, ...widget })) : url;
const loginUrl = `${widget.url}/api/login`; 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 = let sessionId =
cache.get(`${sessionCacheKey}.${service}`) ?? cache.get(`${sessionCacheKey}.${service}`) ??
(await login(loginUrl, service, widget.username, widget.password)); (await login(loginUrl, service, widget.username, widget.password));
let [status, data] = await fetchFromPyloadAPI(url, sessionId, null, service); let [status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);
if (status === 403 || status === 401 || (status === 400 && data?.error?.includes("CSRF token"))) { if (status === 403 || status === 401) {
logger.info("Failed to retrieve data from Pyload API with session auth, trying to login again..."); logger.info("Failed to retrieve data from Pyload API, trying to login again...");
cache.del(`${sessionCacheKey}.${service}`); cache.del(`${sessionCacheKey}.${service}`);
sessionId = await login(loginUrl, service, widget.username, widget.password); sessionId = await login(loginUrl, service, widget.username, widget.password);
[status, data] = await fetchFromPyloadAPI(url, sessionId, null, service); [status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);

View File

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

View File

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

View File

@@ -6,17 +6,8 @@ import useWidgetAPI from "utils/proxy/use-widget-api";
const MAX_ALLOWED_FIELDS = 4; 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 }) { export default function Component({ service }) {
const todayDate = new Date();
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
@@ -38,19 +29,28 @@ export default function Component({ service }) {
const { data: subscriptionsThisMonthlyCostData, error: subscriptionsThisMonthlyCostError } = useWidgetAPI( const { data: subscriptionsThisMonthlyCostData, error: subscriptionsThisMonthlyCostError } = useWidgetAPI(
widget, widget,
subscriptionsThisMonthlyEndpoint, subscriptionsThisMonthlyEndpoint,
toApiMonthYear(), // this month {
month: todayDate.getMonth(),
year: todayDate.getFullYear(),
},
); );
const subscriptionsNextMonthlyEndpoint = widget.fields.includes("nextMonthlyCost") ? "get_monthly_cost" : ""; const subscriptionsNextMonthlyEndpoint = widget.fields.includes("nextMonthlyCost") ? "get_monthly_cost" : "";
const { data: subscriptionsNextMonthlyCostData, error: subscriptionsNextMonthlyCostError } = useWidgetAPI( const { data: subscriptionsNextMonthlyCostData, error: subscriptionsNextMonthlyCostError } = useWidgetAPI(
widget, widget,
subscriptionsNextMonthlyEndpoint, subscriptionsNextMonthlyEndpoint,
toApiMonthYear(1), // next month {
month: todayDate.getMonth() + 1,
year: todayDate.getFullYear(),
},
); );
const subscriptionsPreviousMonthlyEndpoint = widget.fields.includes("previousMonthlyCost") ? "get_monthly_cost" : ""; const subscriptionsPreviousMonthlyEndpoint = widget.fields.includes("previousMonthlyCost") ? "get_monthly_cost" : "";
const { data: subscriptionsPreviousMonthlyCostData, error: subscriptionsPreviousMonthlyCostError } = useWidgetAPI( const { data: subscriptionsPreviousMonthlyCostData, error: subscriptionsPreviousMonthlyCostError } = useWidgetAPI(
widget, widget,
subscriptionsPreviousMonthlyEndpoint, subscriptionsPreviousMonthlyEndpoint,
toApiMonthYear(-1), // previous month {
month: todayDate.getMonth() - 1,
year: todayDate.getFullYear(),
},
); );
if ( if (