Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51cc1684f9 | ||
|
|
8a97e38393 | ||
|
|
9628256887 | ||
|
|
89b0d20655 | ||
|
|
d20a5c5322 | ||
|
|
84721f2769 | ||
|
|
11ca29104a | ||
|
|
6bf81a78f3 | ||
|
|
4a38eea1b0 | ||
|
|
347d34c08c | ||
|
|
f63901f51b | ||
|
|
03ad0e5d30 | ||
|
|
447c4f1467 | ||
|
|
f54bcf4ef3 | ||
|
|
739c2ae551 | ||
|
|
9c6e621951 | ||
|
|
68db3aec7d | ||
|
|
eb3f97a58f | ||
|
|
97db55ab36 | ||
|
|
fec0f5d8b2 | ||
|
|
1a4c4f0db5 | ||
|
|
904e895fec | ||
|
|
8ec79250e6 | ||
|
|
d41f56feb5 | ||
|
|
666869ca0c | ||
|
|
6ba7e487d7 | ||
|
|
ed83113bf2 | ||
|
|
cdb8282dd7 | ||
|
|
b0f2561560 | ||
|
|
d39b7da27a | ||
|
|
82ccdd38df | ||
|
|
9c73c329c4 | ||
|
|
dec0176d49 | ||
|
|
3dc3ccccc3 | ||
|
|
277d0e4405 | ||
|
|
9ae584f0ec | ||
|
|
8d39113bbe | ||
|
|
8f32d61920 | ||
|
|
d001910e86 | ||
|
|
18a5c4ad73 | ||
|
|
83d7fe2556 | ||
|
|
9669a68995 | ||
|
|
b1935ed8a0 | ||
|
|
c5a218c39a | ||
|
|
2e287402c4 | ||
|
|
40082f798d | ||
|
|
db480ca991 | ||
|
|
a7a4378a40 | ||
|
|
d1c1ee7a1e | ||
|
|
e0be80085e | ||
|
|
b8ed72a03f | ||
|
|
ebff6f4a7d | ||
|
|
e890b544dc | ||
|
|
f7666df9d8 |
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: crowdin action
|
- name: crowdin action
|
||||||
uses: crowdin/github-action@71fdb8814261dd703be4ca7c6450d21b1868da4b # v3.0.1
|
uses: crowdin/github-action@9c23991700c0ec5256fd41089b9d9d7d540e424e # v3.3.0
|
||||||
with:
|
with:
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
download_translations: true
|
download_translations: true
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ jobs:
|
|||||||
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
@@ -99,14 +99,14 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Setup QEMU
|
- name: Setup QEMU
|
||||||
uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0
|
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
|
||||||
|
|
||||||
- name: Setup Docker buildx
|
- name: Setup Docker buildx
|
||||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4
|
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
id: build-and-push
|
id: build-and-push
|
||||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7
|
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version-file: ".python-version"
|
python-version-file: ".python-version"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
- run: sudo apt-get install pngquant
|
- run: sudo apt-get install pngquant
|
||||||
- name: Test Docs Build
|
- name: Test Docs Build
|
||||||
run: uv run --frozen zensical build --clean
|
run: uv run --frozen zensical build --clean
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version-file: ".python-version"
|
python-version-file: ".python-version"
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||||
- run: sudo apt-get install pngquant
|
- run: sudo apt-get install pngquant
|
||||||
- name: Build Docs
|
- name: Build Docs
|
||||||
run: uv run --frozen zensical build --clean
|
run: uv run --frozen zensical build --clean
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ jobs:
|
|||||||
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
|
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
||||||
uses: release-drafter/release-drafter@eada3c96a64734dd381cfbda23511034e328ddb0 # v7
|
uses: release-drafter/release-drafter@978bb0b30c5ee8cdd332ced253758157150d43f0 # v7
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
version: ${{ github.event.inputs.version }}
|
version: ${{ github.event.inputs.version }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
|
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
|
||||||
uses: release-drafter/release-drafter@eada3c96a64734dd381cfbda23511034e328ddb0 # v7
|
uses: release-drafter/release-drafter@978bb0b30c5ee8cdd332ced253758157150d43f0 # v7
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter/autolabeler@eada3c96a64734dd381cfbda23511034e328ddb0
|
- uses: release-drafter/release-drafter/autolabeler@978bb0b30c5ee8cdd332ced253758157150d43f0
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
|
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||||
with:
|
with:
|
||||||
version: 9
|
version: 9
|
||||||
|
|
||||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
# Run Vitest directly so `--shard` is parsed as an option
|
# Run Vitest directly so `--shard` is parsed as an option
|
||||||
- run: pnpm -s exec vitest run --coverage --shard ${{ matrix.shard }}/4 --pool forks
|
- run: pnpm -s exec vitest run --coverage --shard ${{ matrix.shard }}/4 --pool forks
|
||||||
- name: Upload coverage reports to Codecov
|
- name: Upload coverage reports to Codecov
|
||||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./coverage/lcov.info
|
files: ./coverage/lcov.info
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
A modern, <em>fully static, fast</em>, secure <em>fully proxied</em>, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.
|
A modern, <em>fast</em>, secure <em>fully proxied</em>, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
With features like quick search, bookmarks, weather support, a wide range of integrations and widgets, an elegant and modern design, and a focus on performance, Homepage is your ideal start to the day and a handy companion throughout it.
|
With features like quick search, bookmarks, weather support, a wide range of integrations and widgets, an elegant and modern design, and a focus on performance, Homepage is your ideal start to the day and a handy companion throughout it.
|
||||||
|
|
||||||
- **Fast** - The site is statically generated at build time for instant load times.
|
- **Fast** - Cached dashboard data and optimized assets keep page loads quick.
|
||||||
- **Secure** - All API requests to backend services are proxied, keeping your API keys hidden. Constantly reviewed for security by the community.
|
- **Secure** - All API requests to backend services are proxied, keeping your API keys hidden. Constantly reviewed for security by the community.
|
||||||
- **For Everyone** - Images built for AMD64, ARM64.
|
- **For Everyone** - Images built for AMD64, ARM64.
|
||||||
- **Full i18n** - Support for over 40 languages.
|
- **Full i18n** - Support for over 40 languages.
|
||||||
|
|||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 794 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 337 KiB |
@@ -3,7 +3,7 @@ title: Settings
|
|||||||
description: Service Configuration
|
description: Service Configuration
|
||||||
---
|
---
|
||||||
|
|
||||||
The `settings.yaml` file allows you to define application level options. For changes made to this file to take effect, you will need to regenerate the static HTML, this can be done by clicking the refresh icon in the bottom right of the page.
|
The `settings.yaml` file allows you to define application level options. After making changes, click the refresh icon in the bottom right of the page to clear the cached dashboard data and reload the page.
|
||||||
|
|
||||||
## Title
|
## Title
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ startUrl: https://custom.url
|
|||||||
|
|
||||||
!!! warning "Heads Up!"
|
!!! warning "Heads Up!"
|
||||||
|
|
||||||
You will need to restart the container any time you add new images, this is a limitation of the Next.js static site server.
|
You will need to restart the container any time you add new local images so the server can discover them.
|
||||||
|
|
||||||
!!! warning "Heads Up!"
|
!!! warning "Heads Up!"
|
||||||
|
|
||||||
@@ -430,6 +430,64 @@ headerStyle: clean
|
|||||||
headerStyle: boxedWidgets
|
headerStyle: boxedWidgets
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Card Style
|
||||||
|
|
||||||
|
Service and bookmark cards use a drop shadow by default. The `hairline` style replaces it with a thin border that brightens on hover.
|
||||||
|
|
||||||
|
<img width="896" alt="default cards" src="../../assets/style-default.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# default, shadowed cards
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img width="896" alt="hairline cards" src="../../assets/card-style-hairline.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
cardStyle: hairline
|
||||||
|
```
|
||||||
|
|
||||||
|
## Block Style
|
||||||
|
|
||||||
|
Widget blocks (the value / label pairs inside a service card) can use the `refined` style to make values heavier and easier to read.
|
||||||
|
|
||||||
|
<img width="896" alt="default blocks" src="../../assets/style-default.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# default, standard blocks
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img width="896" alt="refined blocks" src="../../assets/block-style-refined.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
blockStyle: refined
|
||||||
|
```
|
||||||
|
|
||||||
|
## Font
|
||||||
|
|
||||||
|
Homepage uses Manrope by default. You can switch to IBM Plex Mono instead, either everywhere or for data only.
|
||||||
|
|
||||||
|
<img width="896" alt="IBM Plex Mono everywhere" src="../../assets/font-plex.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
font: plex # the whole dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<img width="896" alt="IBM Plex Mono for data only" src="../../assets/font-plex-data.webp">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
font: plexData # only values, stats, the clock and status tags
|
||||||
|
```
|
||||||
|
|
||||||
|
With `plexData`, labels and names stay in Manrope while numbers line up in columns.
|
||||||
|
|
||||||
|
Both fonts are bundled with Homepage, so no external requests are made.
|
||||||
|
|
||||||
## Base URL
|
## Base URL
|
||||||
|
|
||||||
In some proxy configurations, it may be necessary to set the documents base URL. You can do this by providing a `base` value, like so:
|
In some proxy configurations, it may be necessary to set the documents base URL. You can do this by providing a `base` value, like so:
|
||||||
@@ -554,6 +612,8 @@ logpath: /logfile/path
|
|||||||
|
|
||||||
By default, logs are sent both to `stdout` and to a file at the path specified. This can be changed by setting the `LOG_TARGETS` environment variable to one of `both` (default), `stdout` or `file`.
|
By default, logs are sent both to `stdout` and to a file at the path specified. This can be changed by setting the `LOG_TARGETS` environment variable to one of `both` (default), `stdout` or `file`.
|
||||||
|
|
||||||
|
Log files rotate automatically when they reach 10 MiB. Up to five files are retained: the current `homepage.log` and four rotated files (`homepage1.log` through `homepage4.log`). The oldest rotated file is removed when a new one is created.
|
||||||
|
|
||||||
## Show Container Stats
|
## Show Container Stats
|
||||||
|
|
||||||
You can show all docker or proxmox stats expanded in `settings.yaml`:
|
You can show all docker or proxmox stats expanded in `settings.yaml`:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: Home
|
title: Home
|
||||||
description: A modern, fully static, fast, secure, fully proxied, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages.
|
description: A modern, fast, secure, fully proxied, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages.
|
||||||
icon: material/home
|
icon: material/home
|
||||||
hide:
|
hide:
|
||||||
- navigation
|
- navigation
|
||||||
@@ -18,7 +18,7 @@ hide:
|
|||||||
|
|
||||||
<img src="assets/homepage_demo_clip.webp" alt="homepage" style="max-width: 100%; margin: 0 auto; display: block;" />
|
<img src="assets/homepage_demo_clip.webp" alt="homepage" style="max-width: 100%; margin: 0 auto; display: block;" />
|
||||||
|
|
||||||
<p style="margin: 0 0 30px;">A modern, <em>fully static, fast</em>, secure <em>fully proxied</em>, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.</p>
|
<p style="margin: 0 0 30px;">A modern, <em>fast</em>, secure <em>fully proxied</em>, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,6 @@ Finally, run the server:
|
|||||||
HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev:1234 pnpm start
|
HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev:1234 pnpm start
|
||||||
```
|
```
|
||||||
|
|
||||||
When updating homepage versions you will need to re-build the static files i.e. repeat the process above.
|
When updating Homepage versions, rebuild the production bundle by repeating the steps above.
|
||||||
|
|
||||||
See [HOMEPAGE_ALLOWED_HOSTS](index.md#homepage_allowed_hosts) for more information on this environment variable.
|
See [HOMEPAGE_ALLOWED_HOSTS](index.md#homepage_allowed_hosts) for more information on this environment variable.
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
title: Custom API
|
||||||
|
description: Custom API Information Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
_(Find the Custom API service widget [here](../services/customapi.md))_
|
||||||
|
|
||||||
|
The Custom API information widget shows values from a custom self-hosted or third party API in your Homepage header, alongside an icon.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- customapi:
|
||||||
|
url: http://custom.api.host.or.ip:port/path/to/exact/api/endpoint
|
||||||
|
icon: mdi-api # optional, see below
|
||||||
|
label: My API # optional, shown below the values
|
||||||
|
href: https://custom.api.host # optional, makes the widget a link
|
||||||
|
refreshInterval: 10000 # optional - in milliseconds, defaults to 10s
|
||||||
|
username: username # auth - optional
|
||||||
|
password: password # auth - optional
|
||||||
|
method: GET # optional, e.g. POST
|
||||||
|
headers: # optional, must be object
|
||||||
|
X-API-Token: token
|
||||||
|
requestBody: # optional, can be string or object
|
||||||
|
mappings:
|
||||||
|
- field: key
|
||||||
|
label: Field 1
|
||||||
|
- field: path.to.key2
|
||||||
|
label: Field 2
|
||||||
|
format: number # optional - defaults to text
|
||||||
|
- field: path.to.key3
|
||||||
|
label: Field 3
|
||||||
|
format: percent
|
||||||
|
```
|
||||||
|
|
||||||
|
The `icon` accepts the same values as [service icons](../../configs/services.md#icons), e.g. `mdi-api`, `si-github`, `sh-homepage`, a dashboard icon name like `homepage.png`, or a full URL. If no icon is set, a generic API icon is shown.
|
||||||
|
|
||||||
|
Mappings support the same `field`, `format`, `remap`, `scale`, `prefix` and `suffix` options as the [Custom API service widget](../services/customapi.md). The `additionalField` option and the `display` modes are not supported.
|
||||||
@@ -7,6 +7,7 @@ search:
|
|||||||
|
|
||||||
You can also find a list of all available info widgets in the sidebar navigation.
|
You can also find a list of all available info widgets in the sidebar navigation.
|
||||||
|
|
||||||
|
- [Custom API](customapi.md)
|
||||||
- [Date & Time](datetime.md)
|
- [Date & Time](datetime.md)
|
||||||
- [Glances](glances.md)
|
- [Glances](glances.md)
|
||||||
- [Greeting](greeting.md)
|
- [Greeting](greeting.md)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ description: Arcane Widget Configuration
|
|||||||
Learn more about [Arcane](https://github.com/getarcaneapp/arcane).
|
Learn more about [Arcane](https://github.com/getarcaneapp/arcane).
|
||||||
|
|
||||||
**Allowed fields** (max 4): `running`, `stopped`, `total`, `images`, `images_used`, `images_unused`, `image_updates`.
|
**Allowed fields** (max 4): `running`, `stopped`, `total`, `images`, `images_used`, `images_unused`, `image_updates`.
|
||||||
|
|
||||||
**Default fields**: `running`, `stopped`, `total`, `image_updates`.
|
**Default fields**: `running`, `stopped`, `total`, `image_updates`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -17,4 +18,4 @@ widget:
|
|||||||
fields: ["running", "stopped", "total", "image_updates"] # optional
|
fields: ["running", "stopped", "total", "image_updates"] # optional
|
||||||
```
|
```
|
||||||
|
|
||||||
Using an api key for the widget requires permissions for: `containers:list` `images:list and `image-updates:read`
|
Using an API key for the widget requires permissions for: `containers:list`, `images:list`, and `image-updates:read`.
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: BookOrbit
|
||||||
|
description: BookOrbit Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [BookOrbit](https://github.com/bookorbit/bookorbit).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: bookorbit
|
||||||
|
url: http://bookorbit.host.or.ip:3000
|
||||||
|
username: username
|
||||||
|
password: password
|
||||||
|
fields: ["books", "authors", "reading", "finished"] # optional
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
Allowed fields: `["books", "authors", "series", "storage", "reading", "finished"]` (maximum of 4).
|
||||||
|
|
||||||
|
Default fields: `["books", "authors", "reading", "finished"]`.
|
||||||
@@ -3,6 +3,8 @@ title: Custom API
|
|||||||
description: Custom Widget Configuration from the API
|
description: Custom Widget Configuration from the API
|
||||||
---
|
---
|
||||||
|
|
||||||
|
_(Find the Custom API information widget [here](../info/customapi.md))_
|
||||||
|
|
||||||
This widget can show information from custom self-hosted or third party API.
|
This widget can show information from custom self-hosted or third party API.
|
||||||
|
|
||||||
Fields need to be defined in the `mappings` section YAML object to correlate with the value in the APIs JSON object. Final field definition needs to be the key with the desired value information.
|
Fields need to be defined in the `mappings` section YAML object to correlate with the value in the APIs JSON object. Final field definition needs to be the key with the desired value information.
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
title: Feed
|
||||||
|
description: RSS / Atom feed widget
|
||||||
|
---
|
||||||
|
|
||||||
|
This widget shows the latest items from an RSS 2.0 or Atom feed.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: feed
|
||||||
|
url: https://feeds.bbci.co.uk/news/rss.xml
|
||||||
|
maxItems: 5 # optional - defaults to 5
|
||||||
|
layout: list # optional - possible values list, grid - defaults to list
|
||||||
|
images: true # optional - set to false to hide images - defaults to true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layouts
|
||||||
|
|
||||||
|
`list` shows one row per item. Items with an image get a small thumbnail.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`grid` shows image tiles that re-flow to fit the width of the widget, e.g.:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- NASA Image of the Day:
|
||||||
|
widget:
|
||||||
|
type: feed
|
||||||
|
url: https://www.nasa.gov/feeds/iotd-feed/
|
||||||
|
layout: grid
|
||||||
|
maxItems: 8
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Images
|
||||||
|
|
||||||
|
Images are taken from the feed's `media:thumbnail` / `media:content` tags or image enclosures, falling back to the first image in the item's content. Some feeds do not include images at all.
|
||||||
|
|
||||||
|
Images are loaded by your browser directly from the feed's host, at whatever size the feed provides. Feeds that link full-size originals can be slow to load; set `images: false` for those.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Feeds are fetched by homepage, not your browser, and cached for 10 minutes.
|
||||||
@@ -5,10 +5,19 @@ description: Fileflows Widget Configuration
|
|||||||
|
|
||||||
Learn more about [FileFlows](https://github.com/revenz/FileFlows).
|
Learn more about [FileFlows](https://github.com/revenz/FileFlows).
|
||||||
|
|
||||||
Allowed fields: `["queue", "processing", "processed", "time"]`.
|
Allowed fields: `["queue", "processing", "processed", "time"]` (version 1) or `["queue", "processing", "processed", "failed"]` (version 2).
|
||||||
|
|
||||||
|
| FileFlows Version | Homepage Widget Version |
|
||||||
|
| ----------------- | ----------------------- |
|
||||||
|
| < 26.10 | 1 (default) |
|
||||||
|
| >= 26.10 | 2 |
|
||||||
|
|
||||||
|
Version 2 uses the ["Fenrus Dashboard Endpoint"](https://fileflows.com/docs/webconsole/config/settings/general#fenrus-dashboard-endpoint), which must be enabled. Use the token shown there as the `key`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
widget:
|
widget:
|
||||||
type: fileflows
|
type: fileflows
|
||||||
url: http://your.fileflows.host:port
|
url: http://your.fileflows.host:port
|
||||||
|
version: 2 # optional, defaults to 1
|
||||||
|
key: yourfenrustoken # required for version 2
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ You can also find a list of all available service widgets in the sidebar navigat
|
|||||||
- [Backrest](backrest.md)
|
- [Backrest](backrest.md)
|
||||||
- [Bazarr](bazarr.md)
|
- [Bazarr](bazarr.md)
|
||||||
- [Booklore](booklore.md)
|
- [Booklore](booklore.md)
|
||||||
|
- [BookOrbit](bookorbit.md)
|
||||||
- [Beszel](beszel.md)
|
- [Beszel](beszel.md)
|
||||||
- [Caddy](caddy.md)
|
- [Caddy](caddy.md)
|
||||||
- [Calendar](calendar.md)
|
- [Calendar](calendar.md)
|
||||||
@@ -39,6 +40,7 @@ You can also find a list of all available service widgets in the sidebar navigat
|
|||||||
- [Emby](emby.md)
|
- [Emby](emby.md)
|
||||||
- [ESPHome](esphome.md)
|
- [ESPHome](esphome.md)
|
||||||
- [EVCC](evcc.md)
|
- [EVCC](evcc.md)
|
||||||
|
- [Feed](feed.md)
|
||||||
- [Filebrowser](filebrowser.md)
|
- [Filebrowser](filebrowser.md)
|
||||||
- [Fileflows](fileflows.md)
|
- [Fileflows](fileflows.md)
|
||||||
- [Firefly III](firefly.md)
|
- [Firefly III](firefly.md)
|
||||||
@@ -119,6 +121,7 @@ You can also find a list of all available service widgets in the sidebar navigat
|
|||||||
- [PyLoad](pyload.md)
|
- [PyLoad](pyload.md)
|
||||||
- [qBittorrent](qbittorrent.md)
|
- [qBittorrent](qbittorrent.md)
|
||||||
- [QNAP](qnap.md)
|
- [QNAP](qnap.md)
|
||||||
|
- [qui](qui.md)
|
||||||
- [Radarr](radarr.md)
|
- [Radarr](radarr.md)
|
||||||
- [Readarr](readarr.md)
|
- [Readarr](readarr.md)
|
||||||
- [ROMM](romm.md)
|
- [ROMM](romm.md)
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
title: qui
|
||||||
|
description: qui Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [qui](https://github.com/autobrr/qui).
|
||||||
|
|
||||||
|
Generate an API key in qui under **Settings → API Keys**.
|
||||||
|
|
||||||
|
The widget has two modes:
|
||||||
|
|
||||||
|
- **Aggregated (default):** omit `instance` to show combined stats across all qBittorrent instances monitored by qui.
|
||||||
|
- **Per-instance:** set `instance` to the qui ID (visible in the qui UI) to show just that one.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: qui
|
||||||
|
url: http://qui.host.or.ip:7476
|
||||||
|
key: quiapikeyquiapikeyquiapikey
|
||||||
|
instance: 1 # optional; omit for aggregated stats across all instances
|
||||||
|
fields: ["leech", "download", "seed", "upload"] # optional
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
Allowed fields: `["leech", "download", "seed", "upload", "total", "errored", "ratio", "freeSpace"]` (maximum of 4).
|
||||||
|
|
||||||
|
Default fields: `["leech", "download", "seed", "upload"]`.
|
||||||
|
|
||||||
|
Note: `ratio` and `freeSpace` are only available with the 'single instance' version of the widget.
|
||||||
@@ -44,6 +44,7 @@ nav:
|
|||||||
- widgets/services/backrest.md
|
- widgets/services/backrest.md
|
||||||
- widgets/services/bazarr.md
|
- widgets/services/bazarr.md
|
||||||
- widgets/services/booklore.md
|
- widgets/services/booklore.md
|
||||||
|
- widgets/services/bookorbit.md
|
||||||
- widgets/services/beszel.md
|
- widgets/services/beszel.md
|
||||||
- widgets/services/caddy.md
|
- widgets/services/caddy.md
|
||||||
- widgets/services/calendar.md
|
- widgets/services/calendar.md
|
||||||
@@ -65,6 +66,7 @@ nav:
|
|||||||
- widgets/services/emby.md
|
- widgets/services/emby.md
|
||||||
- widgets/services/esphome.md
|
- widgets/services/esphome.md
|
||||||
- widgets/services/evcc.md
|
- widgets/services/evcc.md
|
||||||
|
- widgets/services/feed.md
|
||||||
- widgets/services/filebrowser.md
|
- widgets/services/filebrowser.md
|
||||||
- widgets/services/fileflows.md
|
- widgets/services/fileflows.md
|
||||||
- widgets/services/firefly.md
|
- widgets/services/firefly.md
|
||||||
@@ -148,6 +150,7 @@ nav:
|
|||||||
- widgets/services/pyload.md
|
- widgets/services/pyload.md
|
||||||
- widgets/services/qbittorrent.md
|
- widgets/services/qbittorrent.md
|
||||||
- widgets/services/qnap.md
|
- widgets/services/qnap.md
|
||||||
|
- widgets/services/qui.md
|
||||||
- widgets/services/radarr.md
|
- widgets/services/radarr.md
|
||||||
- widgets/services/readarr.md
|
- widgets/services/readarr.md
|
||||||
- widgets/services/romm.md
|
- widgets/services/romm.md
|
||||||
@@ -194,6 +197,7 @@ nav:
|
|||||||
- widgets/services/zabbix.md
|
- widgets/services/zabbix.md
|
||||||
- "Information Widgets":
|
- "Information Widgets":
|
||||||
- widgets/info/index.md
|
- widgets/info/index.md
|
||||||
|
- widgets/info/customapi.md
|
||||||
- widgets/info/datetime.md
|
- widgets/info/datetime.md
|
||||||
- widgets/info/glances.md
|
- widgets/info/glances.md
|
||||||
- widgets/info/greeting.md
|
- widgets/info/greeting.md
|
||||||
|
|||||||
@@ -106,6 +106,12 @@ function relativeDate(date, formatter) {
|
|||||||
const unitIndex = cutoffs.findIndex((cutoff) => cutoff > Math.abs(delta));
|
const unitIndex = cutoffs.findIndex((cutoff) => cutoff > Math.abs(delta));
|
||||||
const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
|
const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
|
||||||
|
|
||||||
|
if (units[unitIndex] === "day") {
|
||||||
|
// compare calendar days, not elapsed 24h blocks
|
||||||
|
const startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
||||||
|
return formatter.format(Math.round((startOfDay(date) - startOfDay(new Date())) / 86400000), "day");
|
||||||
|
}
|
||||||
|
|
||||||
return formatter.format(Math.floor(delta / divisor), units[unitIndex]);
|
return formatter.format(Math.floor(delta / divisor), units[unitIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +121,8 @@ module.exports = {
|
|||||||
locales: ["en"],
|
locales: ["en"],
|
||||||
},
|
},
|
||||||
serializeConfig: false,
|
serializeConfig: false,
|
||||||
|
// see https://github.com/i18next/i18next/issues/2227
|
||||||
|
cacheInBuiltFormats: false,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
init: (i18next) => {
|
init: (i18next) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homepage",
|
"name": "homepage",
|
||||||
"version": "2.4.0",
|
"version": "2.6.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
@@ -21,26 +21,27 @@
|
|||||||
"dockerode": "^5.0.0",
|
"dockerode": "^5.0.0",
|
||||||
"follow-redirects": "^1.16.0",
|
"follow-redirects": "^1.16.0",
|
||||||
"gamedig": "^5.3.3",
|
"gamedig": "^5.3.3",
|
||||||
"i18next": "^26.3.6",
|
"i18next": "^26.4.2",
|
||||||
"ical.js": "^2.2.1",
|
"ical.js": "^2.2.1",
|
||||||
"js-yaml": "^5.4.2",
|
"js-yaml": "^5.4.3",
|
||||||
"json-rpc-2.0": "^1.7.1",
|
"json-rpc-2.0": "^1.7.1",
|
||||||
"luxon": "^3.7.2",
|
"luxon": "^3.7.2",
|
||||||
"memory-cache": "^0.2.0",
|
"memory-cache": "^0.2.0",
|
||||||
"minecraftstatuspinger": "^1.2.2",
|
"minecraftstatuspinger": "^1.2.2",
|
||||||
"next": "^16.3.3",
|
"next": "^16.3.8",
|
||||||
"next-auth": "^4.24.15",
|
"next-auth": "^4.24.15",
|
||||||
"next-i18next": "^16.0.8",
|
"next-i18next": "^16.0.8",
|
||||||
"ping": "^1.0.0",
|
"ping": "^1.0.0",
|
||||||
"pretty-bytes": "^7.1.1",
|
"pretty-bytes": "^7.1.1",
|
||||||
"raw-body": "^4.0.0",
|
"raw-body": "^4.0.0",
|
||||||
"react": "^19.2.8",
|
"react": "^19.3.0",
|
||||||
"react-dom": "^19.2.8",
|
"react-dom": "^19.3.0",
|
||||||
"react-i18next": "^17.0.12",
|
"react-i18next": "^17.0.15",
|
||||||
"react-icons": "^5.6.0",
|
"react-icons": "^5.6.0",
|
||||||
"recharts": "^3.1.2",
|
"recharts": "^3.1.2",
|
||||||
|
"sax": "^1.6.1",
|
||||||
"swr": "^2.5.1",
|
"swr": "^2.5.1",
|
||||||
"systeminformation": "^5.33.1",
|
"systeminformation": "^5.33.13",
|
||||||
"tough-cookie": "^6.0.2",
|
"tough-cookie": "^6.0.2",
|
||||||
"urbackup-server-api": "^0.92.2",
|
"urbackup-server-api": "^0.92.2",
|
||||||
"winston": "^3.19.0",
|
"winston": "^3.19.0",
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"jsdom": "^30.0.1",
|
"jsdom": "^30.0.1",
|
||||||
"postcss": "^8.5.26",
|
"postcss": "^8.5.26",
|
||||||
"prettier": "^3.8.4",
|
"prettier": "^3.9.9",
|
||||||
"prettier-plugin-organize-imports": "^4.3.0",
|
"prettier-plugin-organize-imports": "^4.3.0",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.2",
|
||||||
"tailwindcss": "^4.3.3",
|
"tailwindcss": "^4.3.3",
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Seier",
|
"leech": "Seier",
|
||||||
"seed": "Vul"
|
"seed": "Vul"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "SVE Gebruik",
|
"cpuUsage": "SVE Gebruik",
|
||||||
"memUsage": "MEM Gebruik",
|
"memUsage": "MEM Gebruik",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Tou",
|
"queue": "Tou",
|
||||||
"processing": "Verwerking",
|
"processing": "Verwerking",
|
||||||
"processed": "Verwerk",
|
"processed": "Verwerk",
|
||||||
"time": "Tyd"
|
"time": "Tyd",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Netto Waarde",
|
"networth": "Netto Waarde",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Lees",
|
"reading": "Lees",
|
||||||
"finished": "Klaar"
|
"finished": "Klaar"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Tou",
|
"downloadCount": "Tou",
|
||||||
"downloadBytesRemaining": "Oorblywende",
|
"downloadBytesRemaining": "Oorblywende",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Gesoek",
|
"wanted": "Gesoek",
|
||||||
"queued": "In ry",
|
"queued": "In ry",
|
||||||
"leagues": "Ligas"
|
"leagues": "Ligas"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "المُستهلكون",
|
"leech": "المُستهلكون",
|
||||||
"seed": "المُزوِّدين"
|
"seed": "المُزوِّدين"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "استهلاك المعالج",
|
"cpuUsage": "استهلاك المعالج",
|
||||||
"memUsage": "استخدام الذاكرة العشوائية",
|
"memUsage": "استخدام الذاكرة العشوائية",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "الطابور",
|
"queue": "الطابور",
|
||||||
"processing": "قيد المعالجة",
|
"processing": "قيد المعالجة",
|
||||||
"processed": "مُعَالَج",
|
"processed": "مُعَالَج",
|
||||||
"time": "الوقت"
|
"time": "الوقت",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "صافي القيمة",
|
"networth": "صافي القيمة",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "أقرأُه",
|
"reading": "أقرأُه",
|
||||||
"finished": "منتهي"
|
"finished": "منتهي"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "الطابور",
|
"downloadCount": "الطابور",
|
||||||
"downloadBytesRemaining": "متبقِ",
|
"downloadBytesRemaining": "متبقِ",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU употреба",
|
"cpuUsage": "CPU употреба",
|
||||||
"memUsage": "Упортеба памет",
|
"memUsage": "Упортеба памет",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Време"
|
"time": "Време",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Sangonera",
|
"leech": "Sangonera",
|
||||||
"seed": "Sembrat"
|
"seed": "Sembrat"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Sangonera",
|
||||||
|
"download": "Baixada",
|
||||||
|
"seed": "Sembrat",
|
||||||
|
"upload": "Pujada",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errors",
|
||||||
|
"ratio": "Ràtio",
|
||||||
|
"freeSpace": "Lliure"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Ús de CPU",
|
"cpuUsage": "Ús de CPU",
|
||||||
"memUsage": "Ús de Memòria",
|
"memUsage": "Ús de Memòria",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Cua",
|
"queue": "Cua",
|
||||||
"processing": "Processant",
|
"processing": "Processant",
|
||||||
"processed": "Processat",
|
"processed": "Processat",
|
||||||
"time": "Temps"
|
"time": "Temps",
|
||||||
|
"failed": "Error"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valor Net",
|
"networth": "Valor Net",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Llegint",
|
"reading": "Llegint",
|
||||||
"finished": "Acabats"
|
"finished": "Acabats"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Llibres",
|
||||||
|
"authors": "Autors",
|
||||||
|
"series": "Sèries",
|
||||||
|
"storage": "Emmagatzematge",
|
||||||
|
"reading": "Llegint",
|
||||||
|
"finished": "Acabats"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Cua",
|
"downloadCount": "Cua",
|
||||||
"downloadBytesRemaining": "Restant",
|
"downloadBytesRemaining": "Restant",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Pendents",
|
"wanted": "Pendents",
|
||||||
"queued": "En cua",
|
"queued": "En cua",
|
||||||
"leagues": "Lligues"
|
"leagues": "Lligues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Sense elements"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Hledat…",
|
"placeholder": "Hledat…",
|
||||||
"provider": "Search engine: {{name}}",
|
"provider": "Vyhledávač: {{name}}",
|
||||||
"select_provider": "Select search engine"
|
"select_provider": "Vyberte vyhledávač"
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"cpu": "Využití procesoru",
|
"cpu": "Využití procesoru",
|
||||||
@@ -100,11 +100,11 @@
|
|||||||
"not_found": "Nenalezen",
|
"not_found": "Nenalezen",
|
||||||
"exited": "Ukončen",
|
"exited": "Ukončen",
|
||||||
"partial": "Částečný",
|
"partial": "Částečný",
|
||||||
"created": "Created",
|
"created": "Vytvořeno",
|
||||||
"paused": "Paused",
|
"paused": "Pozastaveno",
|
||||||
"restarting": "Restarting",
|
"restarting": "Restartuji",
|
||||||
"removing": "Removing",
|
"removing": "Odebírání",
|
||||||
"dead": "Dead"
|
"dead": "Mrtvý"
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"error": "Chyba",
|
"error": "Chyba",
|
||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leechované",
|
"leech": "Leechované",
|
||||||
"seed": "Seedované"
|
"seed": "Seedované"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leechované",
|
||||||
|
"download": "Stahování",
|
||||||
|
"seed": "Seedované",
|
||||||
|
"upload": "Nahravání",
|
||||||
|
"total": "Celkem",
|
||||||
|
"errored": "Chybné",
|
||||||
|
"ratio": "Poměr",
|
||||||
|
"freeSpace": "Volné"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Využití procesoru",
|
"cpuUsage": "Využití procesoru",
|
||||||
"memUsage": "Využití paměti",
|
"memUsage": "Využití paměti",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Fronta",
|
"queue": "Fronta",
|
||||||
"processing": "Zpracovává se",
|
"processing": "Zpracovává se",
|
||||||
"processed": "Zpracováno",
|
"processed": "Zpracováno",
|
||||||
"time": "Čas"
|
"time": "Čas",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Čisté jmění",
|
"networth": "Čisté jmění",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Čtené",
|
"reading": "Čtené",
|
||||||
"finished": "Přečtené"
|
"finished": "Přečtené"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Fronta",
|
"downloadCount": "Fronta",
|
||||||
"downloadBytesRemaining": "Zbývá",
|
"downloadBytesRemaining": "Zbývá",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Požadované",
|
"wanted": "Požadované",
|
||||||
"queued": "Ve frontě",
|
"queued": "Ve frontě",
|
||||||
"leagues": "Ligy"
|
"leagues": "Ligy"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Žádné položky"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU-Nutzung",
|
"cpuUsage": "CPU-Nutzung",
|
||||||
"memUsage": "Speichernutzung",
|
"memUsage": "Speichernutzung",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Warteschlange",
|
"queue": "Warteschlange",
|
||||||
"processing": "Wird verarbeitet",
|
"processing": "Wird verarbeitet",
|
||||||
"processed": "Wird verarbeitet",
|
"processed": "Wird verarbeitet",
|
||||||
"time": "Zeit"
|
"time": "Zeit",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Reinvermögen",
|
"networth": "Reinvermögen",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Am Lesen",
|
"reading": "Am Lesen",
|
||||||
"finished": "Fertig"
|
"finished": "Fertig"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Bücher",
|
||||||
|
"authors": "Autoren",
|
||||||
|
"series": "Serien",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Beendet"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Warteschlange",
|
"downloadCount": "Warteschlange",
|
||||||
"downloadBytesRemaining": "Verbleibend",
|
"downloadBytesRemaining": "Verbleibend",
|
||||||
@@ -980,11 +999,11 @@
|
|||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
"tags": "Schlagwörter",
|
"tags": "Schlagwörter",
|
||||||
"none": "Keine",
|
"none": "Keine",
|
||||||
"min": "Min",
|
"min": "Minimal",
|
||||||
"low": "Low",
|
"low": "Niedrig",
|
||||||
"default": "Default",
|
"default": "Standard",
|
||||||
"high": "High",
|
"high": "Hoch",
|
||||||
"urgent": "Urgent"
|
"urgent": "Dringend"
|
||||||
},
|
},
|
||||||
"plantit": {
|
"plantit": {
|
||||||
"events": "Ereignisse",
|
"events": "Ereignisse",
|
||||||
@@ -1098,8 +1117,8 @@
|
|||||||
"beszel": {
|
"beszel": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"systems": "Systeme",
|
"systems": "Systeme",
|
||||||
"up": "Up",
|
"up": "Online",
|
||||||
"down": "Down",
|
"down": "Offline",
|
||||||
"paused": "Pausiert",
|
"paused": "Pausiert",
|
||||||
"pending": "Wartend",
|
"pending": "Wartend",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
@@ -1249,14 +1268,17 @@
|
|||||||
"steps": "Schritte"
|
"steps": "Schritte"
|
||||||
},
|
},
|
||||||
"syncthing": {
|
"syncthing": {
|
||||||
"connected": "Connected",
|
"connected": "Verbunden",
|
||||||
"synced": "Synced",
|
"synced": "Synchronisiert",
|
||||||
"errors": "Errors",
|
"errors": "Fehler",
|
||||||
"storage": "Storage"
|
"storage": "Speicher"
|
||||||
},
|
},
|
||||||
"sportarr": {
|
"sportarr": {
|
||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Χρήση επεξεργαστή",
|
"cpuUsage": "Χρήση επεξεργαστή",
|
||||||
"memUsage": "Χρήση μνήμης",
|
"memUsage": "Χρήση μνήμης",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Αναμονή",
|
"queue": "Αναμονή",
|
||||||
"processing": "Σε επεξεργασία",
|
"processing": "Σε επεξεργασία",
|
||||||
"processed": "Επεξεργασμένα",
|
"processed": "Επεξεργασμένα",
|
||||||
"time": "Ώρα"
|
"time": "Ώρα",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Καθαρή αξία",
|
"networth": "Καθαρή αξία",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Ανάγνωση",
|
"reading": "Ανάγνωση",
|
||||||
"finished": "Ολοκληρώθηκε"
|
"finished": "Ολοκληρώθηκε"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Αναμονή",
|
"downloadCount": "Αναμονή",
|
||||||
"downloadBytesRemaining": "Απομένουν",
|
"downloadBytesRemaining": "Απομένουν",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Descargando",
|
"leech": "Descargando",
|
||||||
"seed": "Semillas"
|
"seed": "Semillas"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Sanguijuela",
|
||||||
|
"download": "Descargar",
|
||||||
|
"seed": "Semilla",
|
||||||
|
"upload": "Subir",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Con error",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Libre"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Uso de la CPU",
|
"cpuUsage": "Uso de la CPU",
|
||||||
"memUsage": "Uso de la memoria",
|
"memUsage": "Uso de la memoria",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Cola",
|
"queue": "Cola",
|
||||||
"processing": "Procesando",
|
"processing": "Procesando",
|
||||||
"processed": "Procesado",
|
"processed": "Procesado",
|
||||||
"time": "Tiempo"
|
"time": "Tiempo",
|
||||||
|
"failed": "Fallido"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Patrimonio neto",
|
"networth": "Patrimonio neto",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Lectura",
|
"reading": "Lectura",
|
||||||
"finished": "Finalizado"
|
"finished": "Finalizado"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Libros",
|
||||||
|
"authors": "Autores",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Almacenamiento",
|
||||||
|
"reading": "Lectura",
|
||||||
|
"finished": "Finalizado"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "En cola",
|
"downloadCount": "En cola",
|
||||||
"downloadBytesRemaining": "Restante",
|
"downloadBytesRemaining": "Restante",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Buscado",
|
"wanted": "Buscado",
|
||||||
"queued": "En cola",
|
"queued": "En cola",
|
||||||
"leagues": "Ligas"
|
"leagues": "Ligas"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No hay elementos"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "En téléchargement",
|
"leech": "En téléchargement",
|
||||||
"seed": "En partage"
|
"seed": "En partage"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Utilisation CPU",
|
"cpuUsage": "Utilisation CPU",
|
||||||
"memUsage": "RAM utilisée",
|
"memUsage": "RAM utilisée",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "File d'attente",
|
"queue": "File d'attente",
|
||||||
"processing": "En traitement",
|
"processing": "En traitement",
|
||||||
"processed": "Traité",
|
"processed": "Traité",
|
||||||
"time": "Temps"
|
"time": "Temps",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valeur Nette",
|
"networth": "Valeur Nette",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "En cours de lecture",
|
"reading": "En cours de lecture",
|
||||||
"finished": "Terminés"
|
"finished": "Terminés"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "File d'attente",
|
"downloadCount": "File d'attente",
|
||||||
"downloadBytesRemaining": "Restant",
|
"downloadBytesRemaining": "Restant",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Recherché",
|
"wanted": "Recherché",
|
||||||
"queued": "En file d'attente",
|
"queued": "En file d'attente",
|
||||||
"leagues": "Ligues"
|
"leagues": "Ligues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "עלוקה",
|
"leech": "עלוקה",
|
||||||
"seed": "זורע"
|
"seed": "זורע"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "שימוש במעבד",
|
"cpuUsage": "שימוש במעבד",
|
||||||
"memUsage": "שימוש בזיכרון",
|
"memUsage": "שימוש בזיכרון",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "תור",
|
"queue": "תור",
|
||||||
"processing": "בעיבוד",
|
"processing": "בעיבוד",
|
||||||
"processed": "עובדו",
|
"processed": "עובדו",
|
||||||
"time": "זמן"
|
"time": "זמן",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "שווי נקי",
|
"networth": "שווי נקי",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "תור",
|
"downloadCount": "תור",
|
||||||
"downloadBytesRemaining": "נותר",
|
"downloadBytesRemaining": "נותר",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Korištenje tuđeg sadržaja",
|
"leech": "Korištenje tuđeg sadržaja",
|
||||||
"seed": "Prenošenje preuzetog sadržaja"
|
"seed": "Prenošenje preuzetog sadržaja"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Korištenje procesora",
|
"cpuUsage": "Korištenje procesora",
|
||||||
"memUsage": "Korištenje memorije",
|
"memUsage": "Korištenje memorije",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Red čekanja",
|
"queue": "Red čekanja",
|
||||||
"processing": "Obrada",
|
"processing": "Obrada",
|
||||||
"processed": "Obrađeno",
|
"processed": "Obrađeno",
|
||||||
"time": "Vrijeme"
|
"time": "Vrijeme",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Neto vrijednost",
|
"networth": "Neto vrijednost",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Čitanje",
|
"reading": "Čitanje",
|
||||||
"finished": "Završeno"
|
"finished": "Završeno"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Red čekanja",
|
"downloadCount": "Red čekanja",
|
||||||
"downloadBytesRemaining": "Preostalo",
|
"downloadBytesRemaining": "Preostalo",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Željeno",
|
"wanted": "Željeno",
|
||||||
"queued": "U redu čekanja",
|
"queued": "U redu čekanja",
|
||||||
"leagues": "Lige"
|
"leagues": "Lige"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Processzor Használat",
|
"cpuUsage": "Processzor Használat",
|
||||||
"memUsage": "Memória Használat",
|
"memUsage": "Memória Használat",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Sorban",
|
"queue": "Sorban",
|
||||||
"processing": "Feldolgozás alatt",
|
"processing": "Feldolgozás alatt",
|
||||||
"processed": "Feldolgozott",
|
"processed": "Feldolgozott",
|
||||||
"time": "Idő"
|
"time": "Idő",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Nettó érték",
|
"networth": "Nettó érték",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Penggunaan CPU",
|
"cpuUsage": "Penggunaan CPU",
|
||||||
"memUsage": "Penggunaan MEM",
|
"memUsage": "Penggunaan MEM",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Waktu"
|
"time": "Waktu",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Kekayaan Bersih",
|
"networth": "Kekayaan Bersih",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "In download",
|
"leech": "In download",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Utilizzo CPU",
|
"cpuUsage": "Utilizzo CPU",
|
||||||
"memUsage": "Utilizzo MEM",
|
"memUsage": "Utilizzo MEM",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Tempo"
|
"time": "Tempo",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valore Netto",
|
"networth": "Valore Netto",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU使用量",
|
"cpuUsage": "CPU使用量",
|
||||||
"memUsage": "MEM使用量",
|
"memUsage": "MEM使用量",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "時間"
|
"time": "時間",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "募集中",
|
"wanted": "募集中",
|
||||||
"queued": "処理待ち",
|
"queued": "処理待ち",
|
||||||
"leagues": "リーグ"
|
"leagues": "リーグ"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "리치",
|
"leech": "리치",
|
||||||
"seed": "시드"
|
"seed": "시드"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU 사용량",
|
"cpuUsage": "CPU 사용량",
|
||||||
"memUsage": "메모리 사용량",
|
"memUsage": "메모리 사용량",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "대기열",
|
"queue": "대기열",
|
||||||
"processing": "처리 중",
|
"processing": "처리 중",
|
||||||
"processed": "처리됨",
|
"processed": "처리됨",
|
||||||
"time": "시간"
|
"time": "시간",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "순자산",
|
"networth": "순자산",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "읽는 중",
|
"reading": "읽는 중",
|
||||||
"finished": "완료"
|
"finished": "완료"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "대기열",
|
"downloadCount": "대기열",
|
||||||
"downloadBytesRemaining": "남음",
|
"downloadBytesRemaining": "남음",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Delen"
|
"seed": "Delen"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Verbruik",
|
"cpuUsage": "CPU Verbruik",
|
||||||
"memUsage": "MEM Gebruik",
|
"memUsage": "MEM Gebruik",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Wachtrij",
|
"queue": "Wachtrij",
|
||||||
"processing": "Verwerken",
|
"processing": "Verwerken",
|
||||||
"processed": "Verwerkt",
|
"processed": "Verwerkt",
|
||||||
"time": "Tijd"
|
"time": "Tijd",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Totaal eigen vermogen",
|
"networth": "Totaal eigen vermogen",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Lezen",
|
"reading": "Lezen",
|
||||||
"finished": "Voltooid"
|
"finished": "Voltooid"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Wachtrij",
|
"downloadCount": "Wachtrij",
|
||||||
"downloadBytesRemaining": "Resterend",
|
"downloadBytesRemaining": "Resterend",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Gewenst",
|
"wanted": "Gewenst",
|
||||||
"queued": "In de wachtrij",
|
"queued": "In de wachtrij",
|
||||||
"leagues": "Competities"
|
"leagues": "Competities"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Bruk",
|
"cpuUsage": "CPU Bruk",
|
||||||
"memUsage": "Minnebruk",
|
"memUsage": "Minnebruk",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,11 +100,11 @@
|
|||||||
"not_found": "Nie znaleziono",
|
"not_found": "Nie znaleziono",
|
||||||
"exited": "Zakończony",
|
"exited": "Zakończony",
|
||||||
"partial": "Częściowy",
|
"partial": "Częściowy",
|
||||||
"created": "Created",
|
"created": "Utworzony",
|
||||||
"paused": "Paused",
|
"paused": "Wstrzymany",
|
||||||
"restarting": "Restarting",
|
"restarting": "Ponowne uruchamianie",
|
||||||
"removing": "Removing",
|
"removing": "Usuwanie",
|
||||||
"dead": "Dead"
|
"dead": "Martwy"
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"error": "Błąd",
|
"error": "Błąd",
|
||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Pobieranie",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Wysyłanie",
|
||||||
|
"total": "Razem",
|
||||||
|
"errored": "Z błędami",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Wolne"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Użycie CPU",
|
"cpuUsage": "Użycie CPU",
|
||||||
"memUsage": "Użycie pamięci",
|
"memUsage": "Użycie pamięci",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "W kolejce",
|
"queue": "W kolejce",
|
||||||
"processing": "Przetwarzane",
|
"processing": "Przetwarzane",
|
||||||
"processed": "Przetworzone",
|
"processed": "Przetworzone",
|
||||||
"time": "Czas"
|
"time": "Czas",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Wartość netto",
|
"networth": "Wartość netto",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Czytane",
|
"reading": "Czytane",
|
||||||
"finished": "Skończone"
|
"finished": "Skończone"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Książki",
|
||||||
|
"authors": "Autorzy",
|
||||||
|
"series": "Serie",
|
||||||
|
"storage": "Pamięć",
|
||||||
|
"reading": "Czytane",
|
||||||
|
"finished": "Skończone"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "W kolejce",
|
"downloadCount": "W kolejce",
|
||||||
"downloadBytesRemaining": "Pozostało",
|
"downloadBytesRemaining": "Pozostało",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Poszukiwane",
|
"wanted": "Poszukiwane",
|
||||||
"queued": "W kolejce",
|
"queued": "W kolejce",
|
||||||
"leagues": "Ligi"
|
"leagues": "Ligi"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Brak elementów"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Pesquisar…",
|
"placeholder": "Pesquisar…",
|
||||||
"provider": "Search engine: {{name}}",
|
"provider": "Motor de Pesquisa: {{name}}",
|
||||||
"select_provider": "Select search engine"
|
"select_provider": "Seleciona o motor de pesquisa"
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
@@ -100,11 +100,11 @@
|
|||||||
"not_found": "Não Encontrado",
|
"not_found": "Não Encontrado",
|
||||||
"exited": "Saiu",
|
"exited": "Saiu",
|
||||||
"partial": "Parcial",
|
"partial": "Parcial",
|
||||||
"created": "Created",
|
"created": "Criado",
|
||||||
"paused": "Paused",
|
"paused": "Pausado",
|
||||||
"restarting": "Restarting",
|
"restarting": "A reiniciar",
|
||||||
"removing": "Removing",
|
"removing": "A remover",
|
||||||
"dead": "Dead"
|
"dead": "Morto"
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"error": "Erro",
|
"error": "Erro",
|
||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Fuga",
|
"leech": "Fuga",
|
||||||
"seed": "Semear"
|
"seed": "Semear"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Fuga",
|
||||||
|
"download": "Transferir",
|
||||||
|
"seed": "Semear",
|
||||||
|
"upload": "Enviar",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Erro",
|
||||||
|
"ratio": "Rácio",
|
||||||
|
"freeSpace": "Livre"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Utilização do CPU",
|
"cpuUsage": "Utilização do CPU",
|
||||||
"memUsage": "Utilização de Memória",
|
"memUsage": "Utilização de Memória",
|
||||||
@@ -479,7 +489,7 @@
|
|||||||
"users": "Utilizadores",
|
"users": "Utilizadores",
|
||||||
"loginsLast24H": "Inícios de Sessão (24h)",
|
"loginsLast24H": "Inícios de Sessão (24h)",
|
||||||
"failedLoginsLast24H": "Inícios de Sessão Falhados (24h)",
|
"failedLoginsLast24H": "Inícios de Sessão Falhados (24h)",
|
||||||
"authorizationsLast24H": "Auths (24h)"
|
"authorizationsLast24H": "Autenticações (24h)"
|
||||||
},
|
},
|
||||||
"proxmox": {
|
"proxmox": {
|
||||||
"mem": "MEM",
|
"mem": "MEM",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Fila de espera",
|
"queue": "Fila de espera",
|
||||||
"processing": "A Processar",
|
"processing": "A Processar",
|
||||||
"processed": "Processado",
|
"processed": "Processado",
|
||||||
"time": "Hora"
|
"time": "Hora",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valor Líquido",
|
"networth": "Valor Líquido",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "A ler",
|
"reading": "A ler",
|
||||||
"finished": "Concluído"
|
"finished": "Concluído"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Fila de espera",
|
"downloadCount": "Fila de espera",
|
||||||
"downloadBytesRemaining": "Restante",
|
"downloadBytesRemaining": "Restante",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Procurado",
|
"wanted": "Procurado",
|
||||||
"queued": "Em fila de espera",
|
"queued": "Em fila de espera",
|
||||||
"leagues": "Ligas"
|
"leagues": "Ligas"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Sem itens"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Uso de CPU",
|
"cpuUsage": "Uso de CPU",
|
||||||
"memUsage": "Uso de Memória",
|
"memUsage": "Uso de Memória",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Fila de espera",
|
"queue": "Fila de espera",
|
||||||
"processing": "Processando",
|
"processing": "Processando",
|
||||||
"processed": "Processado",
|
"processed": "Processado",
|
||||||
"time": "Hora"
|
"time": "Hora",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valor Líquido",
|
"networth": "Valor Líquido",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Lendo",
|
"reading": "Lendo",
|
||||||
"finished": "Finalizado"
|
"finished": "Finalizado"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Fila de espera",
|
"downloadCount": "Fila de espera",
|
||||||
"downloadBytesRemaining": "Restante",
|
"downloadBytesRemaining": "Restante",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Desejado",
|
"wanted": "Desejado",
|
||||||
"queued": "Na fila",
|
"queued": "Na fila",
|
||||||
"leagues": "Ligas"
|
"leagues": "Ligas"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Timp"
|
"time": "Timp",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Лич",
|
"leech": "Лич",
|
||||||
"seed": "Сид"
|
"seed": "Сид"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Лич",
|
||||||
|
"download": "Скачивание",
|
||||||
|
"seed": "Сид",
|
||||||
|
"upload": "Загрузка",
|
||||||
|
"total": "Всего",
|
||||||
|
"errored": "Ошибок",
|
||||||
|
"ratio": "Соотношение",
|
||||||
|
"freeSpace": "Свободно"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Использование ЦП",
|
"cpuUsage": "Использование ЦП",
|
||||||
"memUsage": "Использование ОЗУ",
|
"memUsage": "Использование ОЗУ",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Очередь",
|
"queue": "Очередь",
|
||||||
"processing": "Обрабатывается",
|
"processing": "Обрабатывается",
|
||||||
"processed": "Обработано",
|
"processed": "Обработано",
|
||||||
"time": "Время"
|
"time": "Время",
|
||||||
|
"failed": "Неудачно"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Общая средства",
|
"networth": "Общая средства",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Читаю",
|
"reading": "Читаю",
|
||||||
"finished": "Завершено"
|
"finished": "Завершено"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Книги",
|
||||||
|
"authors": "Авторы",
|
||||||
|
"series": "Серии",
|
||||||
|
"storage": "Память",
|
||||||
|
"reading": "Чтение",
|
||||||
|
"finished": "Завершено"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Очередь",
|
"downloadCount": "Очередь",
|
||||||
"downloadBytesRemaining": "Осталось",
|
"downloadBytesRemaining": "Осталось",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Требуется",
|
"wanted": "Требуется",
|
||||||
"queued": "В очереди",
|
"queued": "В очереди",
|
||||||
"leagues": "Лиги"
|
"leagues": "Лиги"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Ничего нет"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"empty_data": "Stav podsystému neznámy"
|
"empty_data": "Stav podsystému neznámy"
|
||||||
},
|
},
|
||||||
"unifi_drive": {
|
"unifi_drive": {
|
||||||
"healthy": "Healthy",
|
"healthy": "Zdravý",
|
||||||
"degraded": "Degraded",
|
"degraded": "Degraded",
|
||||||
"no_data": "No storage data available"
|
"no_data": "No storage data available"
|
||||||
},
|
},
|
||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Využitie CPU",
|
"cpuUsage": "Využitie CPU",
|
||||||
"memUsage": "Využitie pamäte",
|
"memUsage": "Využitie pamäte",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Poradie",
|
"queue": "Poradie",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Spracované",
|
"processed": "Spracované",
|
||||||
"time": "Čas"
|
"time": "Čas",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Úložisko",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Poradie",
|
"downloadCount": "Poradie",
|
||||||
"downloadBytesRemaining": "Zostávajúce",
|
"downloadBytesRemaining": "Zostávajúce",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "V poradí",
|
"queued": "V poradí",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Žiadne položky"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU",
|
"cpuUsage": "CPU",
|
||||||
"memUsage": "MEM",
|
"memUsage": "MEM",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Čas"
|
"time": "Čas",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Neto vrednost",
|
"networth": "Neto vrednost",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Искоришћеност процесора",
|
"cpuUsage": "Искоришћеност процесора",
|
||||||
"memUsage": "Заузеће меморије",
|
"memUsage": "Заузеће меморије",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Ред",
|
"queue": "Ред",
|
||||||
"processing": "Обрада",
|
"processing": "Обрада",
|
||||||
"processed": "Обрада",
|
"processed": "Обрада",
|
||||||
"time": "Време"
|
"time": "Време",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Нето вредност",
|
"networth": "Нето вредност",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Читање",
|
"reading": "Читање",
|
||||||
"finished": "Завршено"
|
"finished": "Завршено"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Ред",
|
"downloadCount": "Ред",
|
||||||
"downloadBytesRemaining": "Преостало",
|
"downloadBytesRemaining": "Преостало",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leech",
|
"leech": "Leech",
|
||||||
"seed": "Seed"
|
"seed": "Seed"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU Usage",
|
"cpuUsage": "CPU Usage",
|
||||||
"memUsage": "MEM Usage",
|
"memUsage": "MEM Usage",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "İndirilen",
|
"leech": "İndirilen",
|
||||||
"seed": "Gönderilen"
|
"seed": "Gönderilen"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "İşlemci Kullanımı",
|
"cpuUsage": "İşlemci Kullanımı",
|
||||||
"memUsage": "Bellek Kullanımı",
|
"memUsage": "Bellek Kullanımı",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Kuyruk",
|
"queue": "Kuyruk",
|
||||||
"processing": "İşleniyor",
|
"processing": "İşleniyor",
|
||||||
"processed": "İşlendi",
|
"processed": "İşlendi",
|
||||||
"time": "Zaman"
|
"time": "Zaman",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net değer",
|
"networth": "Net değer",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Okunuyor",
|
"reading": "Okunuyor",
|
||||||
"finished": "Bitti"
|
"finished": "Bitti"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Kuyruk",
|
"downloadCount": "Kuyruk",
|
||||||
"downloadBytesRemaining": "Kalan",
|
"downloadBytesRemaining": "Kalan",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"seconds": "с"
|
"seconds": "с"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"signout": "Sign out"
|
"signout": "Вихід"
|
||||||
},
|
},
|
||||||
"widget": {
|
"widget": {
|
||||||
"missing_type": "Відсутній тип віджета: {{type}}",
|
"missing_type": "Відсутній тип віджета: {{type}}",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"search": {
|
"search": {
|
||||||
"placeholder": "Пошук…",
|
"placeholder": "Пошук…",
|
||||||
"provider": "Search engine: {{name}}",
|
"provider": "Search engine: {{name}}",
|
||||||
"select_provider": "Select search engine"
|
"select_provider": "Вибрати пошукову систему"
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"cpu": "ЦП",
|
"cpu": "ЦП",
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
"nextRun": "Next Run",
|
"nextRun": "Next Run",
|
||||||
"running": "Running",
|
"running": "Running",
|
||||||
"warnings": "Warnings",
|
"warnings": "Warnings",
|
||||||
"errors": "Errors"
|
"errors": "Помилки"
|
||||||
},
|
},
|
||||||
"docker": {
|
"docker": {
|
||||||
"rx": "RX",
|
"rx": "RX",
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
"series": "Серіали",
|
"series": "Серіали",
|
||||||
"episodes": "Серії",
|
"episodes": "Серії",
|
||||||
"songs": "Пiснi",
|
"songs": "Пiснi",
|
||||||
"albums": "Albums"
|
"albums": "Альбоми"
|
||||||
},
|
},
|
||||||
"esphome": {
|
"esphome": {
|
||||||
"offline": "Офлайн",
|
"offline": "Офлайн",
|
||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Ліч",
|
"leech": "Ліч",
|
||||||
"seed": "Сід"
|
"seed": "Сід"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Використання CPU",
|
"cpuUsage": "Використання CPU",
|
||||||
"memUsage": "Використання пам'яті",
|
"memUsage": "Використання пам'яті",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Черга",
|
"queue": "Черга",
|
||||||
"processing": "Обробка",
|
"processing": "Обробка",
|
||||||
"processed": "Оброблено",
|
"processed": "Оброблено",
|
||||||
"time": "Час"
|
"time": "Час",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Чисті Активи",
|
"networth": "Чисті Активи",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Читаю",
|
"reading": "Читаю",
|
||||||
"finished": "Завершено"
|
"finished": "Завершено"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Книжки",
|
||||||
|
"authors": "Автори",
|
||||||
|
"series": "Серії",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Черга",
|
"downloadCount": "Черга",
|
||||||
"downloadBytesRemaining": "Залишилось",
|
"downloadBytesRemaining": "Залишилось",
|
||||||
@@ -1257,6 +1276,9 @@
|
|||||||
"sportarr": {
|
"sportarr": {
|
||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Ліги"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "Немає елементів"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "Leecher",
|
"leech": "Leecher",
|
||||||
"seed": "Seeder"
|
"seed": "Seeder"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Mức sử dụng CPU",
|
"cpuUsage": "Mức sử dụng CPU",
|
||||||
"memUsage": "Mức sử dụng bộ nhớ",
|
"memUsage": "Mức sử dụng bộ nhớ",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "Time"
|
"time": "Time",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Net Worth",
|
"networth": "Net Worth",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Queue",
|
"downloadCount": "Queue",
|
||||||
"downloadBytesRemaining": "Remaining",
|
"downloadBytesRemaining": "Remaining",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Cần tải",
|
"wanted": "Cần tải",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "未完成下載",
|
"leech": "未完成下載",
|
||||||
"seed": "已完成下載"
|
"seed": "已完成下載"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU 使用率",
|
"cpuUsage": "CPU 使用率",
|
||||||
"memUsage": "記憶體使用率",
|
"memUsage": "記憶體使用率",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "時間"
|
"time": "時間",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "淨值",
|
"networth": "淨值",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "佇列",
|
"downloadCount": "佇列",
|
||||||
"downloadBytesRemaining": "剩餘大小",
|
"downloadBytesRemaining": "剩餘大小",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "下载中",
|
"leech": "下载中",
|
||||||
"seed": "做种"
|
"seed": "做种"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "处理器",
|
"cpuUsage": "处理器",
|
||||||
"memUsage": "内存使用",
|
"memUsage": "内存使用",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "队列",
|
"queue": "队列",
|
||||||
"processing": "处理中",
|
"processing": "处理中",
|
||||||
"processed": "已处理",
|
"processed": "已处理",
|
||||||
"time": "时间"
|
"time": "时间",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "净值",
|
"networth": "净值",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "阅读中",
|
"reading": "阅读中",
|
||||||
"finished": "已读完"
|
"finished": "已读完"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "队列",
|
"downloadCount": "队列",
|
||||||
"downloadBytesRemaining": "剩余",
|
"downloadBytesRemaining": "剩余",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,6 +256,16 @@
|
|||||||
"leech": "未完成下載",
|
"leech": "未完成下載",
|
||||||
"seed": "已完成下載"
|
"seed": "已完成下載"
|
||||||
},
|
},
|
||||||
|
"qui": {
|
||||||
|
"leech": "Leech",
|
||||||
|
"download": "Download",
|
||||||
|
"seed": "Seed",
|
||||||
|
"upload": "Upload",
|
||||||
|
"total": "Total",
|
||||||
|
"errored": "Errored",
|
||||||
|
"ratio": "Ratio",
|
||||||
|
"freeSpace": "Free"
|
||||||
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "CPU 使用率",
|
"cpuUsage": "CPU 使用率",
|
||||||
"memUsage": "記憶體使用率",
|
"memUsage": "記憶體使用率",
|
||||||
@@ -780,7 +790,8 @@
|
|||||||
"queue": "Queue",
|
"queue": "Queue",
|
||||||
"processing": "Processing",
|
"processing": "Processing",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"time": "時間"
|
"time": "時間",
|
||||||
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "淨值",
|
"networth": "淨值",
|
||||||
@@ -859,6 +870,14 @@
|
|||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Finished"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
|
"bookorbit": {
|
||||||
|
"books": "Books",
|
||||||
|
"authors": "Authors",
|
||||||
|
"series": "Series",
|
||||||
|
"storage": "Storage",
|
||||||
|
"reading": "Reading",
|
||||||
|
"finished": "Finished"
|
||||||
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "佇列",
|
"downloadCount": "佇列",
|
||||||
"downloadBytesRemaining": "剩餘大小",
|
"downloadBytesRemaining": "剩餘大小",
|
||||||
@@ -1258,5 +1277,8 @@
|
|||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
"queued": "Queued",
|
"queued": "Queued",
|
||||||
"leagues": "Leagues"
|
"leagues": "Leagues"
|
||||||
|
},
|
||||||
|
"feed": {
|
||||||
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import createMockRes from "test-utils/create-mock-res";
|
||||||
|
|
||||||
|
vi.mock("next-auth/jwt", () => ({ getToken: vi.fn(async () => null) }));
|
||||||
|
vi.mock("utils/logger", () => ({ default: () => ({ error: vi.fn(), warn: vi.fn(), debug: vi.fn(), info: vi.fn() }) }));
|
||||||
|
|
||||||
|
const allRoutes = Object.entries(import.meta.glob("/src/pages/api/**/*.js"));
|
||||||
|
const routes = allRoutes.filter(([file]) => !/\/(auth|mcp)\//.test(file) && !file.endsWith("/healthcheck.js"));
|
||||||
|
|
||||||
|
describe("API authentication without middleware", () => {
|
||||||
|
beforeEach(() => vi.stubEnv("HOMEPAGE_AUTH_ENABLED", "true"));
|
||||||
|
afterEach(() => vi.unstubAllEnvs());
|
||||||
|
|
||||||
|
it.each(routes)("rejects anonymous access to %s at its exported handler", async (_file, load) => {
|
||||||
|
const { default: handler } = await load();
|
||||||
|
const req = { query: {}, headers: { "x-prerender-revalidate": "public-image-key" }, cookies: {} };
|
||||||
|
const res = createMockRes();
|
||||||
|
await handler(req, res);
|
||||||
|
expect(res.statusCode).toBe(401);
|
||||||
|
expect(res.body).toEqual({ error: "Unauthorized" });
|
||||||
|
expect(res.headers["Cache-Control"]).toBe("private, no-store");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps sign-in CSS public while protecting custom JavaScript", async () => {
|
||||||
|
const { default: handler } = await import("pages/api/config/[path]");
|
||||||
|
const css = createMockRes();
|
||||||
|
await handler({ query: { path: "custom.css" } }, css);
|
||||||
|
expect(css.statusCode).toBe(200);
|
||||||
|
const js = createMockRes();
|
||||||
|
await handler({ query: { path: "custom.js" }, headers: {}, cookies: {} }, js);
|
||||||
|
expect(js.statusCode).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("API host validation without middleware", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.stubEnv("HOMEPAGE_ALLOWED_HOSTS", "");
|
||||||
|
vi.stubEnv("PORT", "3000");
|
||||||
|
});
|
||||||
|
afterEach(() => vi.unstubAllEnvs());
|
||||||
|
|
||||||
|
it.each(allRoutes)("rejects disallowed hosts at %s, including public routes", async (_file, load) => {
|
||||||
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
||||||
|
const { default: handler } = await load();
|
||||||
|
const req = {
|
||||||
|
query: { path: "custom.css", nextauth: ["session"] },
|
||||||
|
method: "POST",
|
||||||
|
headers: { host: "evil.example", "x-prerender-revalidate": "public-image-key" },
|
||||||
|
cookies: {},
|
||||||
|
};
|
||||||
|
const res = createMockRes();
|
||||||
|
await handler(req, res);
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
expect(res.body).toEqual({ error: "Host validation failed. See logs for more details." });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -34,7 +34,7 @@ function mockResponse() {
|
|||||||
|
|
||||||
async function loadHandler() {
|
async function loadHandler() {
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
return (await import("./index")).default;
|
return (await import("pages/api/mcp/index")).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("pages/api/mcp", () => {
|
describe("pages/api/mcp", () => {
|
||||||
@@ -3,27 +3,20 @@ import { describe, expect, it, vi } from "vitest";
|
|||||||
import createMockRes from "test-utils/create-mock-res";
|
import createMockRes from "test-utils/create-mock-res";
|
||||||
|
|
||||||
import handler from "pages/api/revalidate";
|
import handler from "pages/api/revalidate";
|
||||||
|
import { invalidateDashboardData } from "utils/config/dashboard";
|
||||||
|
|
||||||
|
vi.mock("utils/config/dashboard", () => ({ invalidateDashboardData: vi.fn() }));
|
||||||
|
|
||||||
describe("pages/api/revalidate", () => {
|
describe("pages/api/revalidate", () => {
|
||||||
it("revalidates and returns {revalidated:true}", async () => {
|
it("invalidates the dashboard snapshot without regenerating a static page", async () => {
|
||||||
const req = {};
|
const req = {};
|
||||||
const res = createMockRes();
|
const res = createMockRes();
|
||||||
res.revalidate = vi.fn().mockResolvedValueOnce(undefined);
|
res.revalidate = vi.fn().mockResolvedValueOnce(undefined);
|
||||||
|
|
||||||
await handler(req, res);
|
await handler(req, res);
|
||||||
|
|
||||||
expect(res.revalidate).toHaveBeenCalledWith("/");
|
expect(invalidateDashboardData).toHaveBeenCalledOnce();
|
||||||
|
expect(res.revalidate).not.toHaveBeenCalled();
|
||||||
expect(res.body).toEqual({ revalidated: true });
|
expect(res.body).toEqual({ revalidated: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 500 when revalidate throws", async () => {
|
|
||||||
const req = {};
|
|
||||||
const res = createMockRes();
|
|
||||||
res.revalidate = vi.fn().mockRejectedValueOnce(new Error("nope"));
|
|
||||||
|
|
||||||
await handler(req, res);
|
|
||||||
|
|
||||||
expect(res.statusCode).toBe(500);
|
|
||||||
expect(res.body).toBe("Error revalidating");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ vi.mock("widgets/widgets", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import handler from "./proxy";
|
import handler from "pages/api/services/proxy";
|
||||||
|
|
||||||
function createReq({ method = "GET", body, query = {} } = {}) {
|
function createReq({ method = "GET", body, query = {} } = {}) {
|
||||||
return { method, body, query };
|
return { method, body, query };
|
||||||
@@ -19,22 +19,22 @@ describe("pages/api/theme", () => {
|
|||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns defaults when settings are missing", () => {
|
it("returns defaults when settings are missing", async () => {
|
||||||
getSettings.mockReturnValueOnce({});
|
getSettings.mockReturnValueOnce({});
|
||||||
|
|
||||||
const res = createMockRes();
|
const res = createMockRes();
|
||||||
handler({ res });
|
await handler({}, res);
|
||||||
|
|
||||||
expect(checkAndCopyConfig).toHaveBeenCalledWith("settings.yaml");
|
expect(checkAndCopyConfig).toHaveBeenCalledWith("settings.yaml");
|
||||||
expect(res.statusCode).toBe(200);
|
expect(res.statusCode).toBe(200);
|
||||||
expect(res.body).toEqual({ color: "slate", theme: "dark" });
|
expect(res.body).toEqual({ color: "slate", theme: "dark" });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns configured color + theme when present", () => {
|
it("returns configured color + theme when present", async () => {
|
||||||
getSettings.mockReturnValueOnce({ color: "red", theme: "light" });
|
getSettings.mockReturnValueOnce({ color: "red", theme: "light" });
|
||||||
|
|
||||||
const res = createMockRes();
|
const res = createMockRes();
|
||||||
handler({ res });
|
await handler({}, res);
|
||||||
|
|
||||||
expect(res.body).toEqual({ color: "red", theme: "light" });
|
expect(res.body).toEqual({ color: "red", theme: "light" });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import createMockRes from "test-utils/create-mock-res";
|
||||||
|
|
||||||
|
const { getPrivateWidgetOptions, httpProxy, logger } = vi.hoisted(() => ({
|
||||||
|
getPrivateWidgetOptions: vi.fn(),
|
||||||
|
httpProxy: vi.fn(),
|
||||||
|
logger: { debug: vi.fn() },
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/config/widget-helpers", () => ({
|
||||||
|
getPrivateWidgetOptions,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/proxy/http", () => ({
|
||||||
|
httpProxy,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("utils/logger", () => ({
|
||||||
|
default: () => logger,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import handler from "pages/api/widgets/customapi";
|
||||||
|
|
||||||
|
const json = (body) => Buffer.from(JSON.stringify(body));
|
||||||
|
|
||||||
|
async function callRoute(options, index = "0") {
|
||||||
|
getPrivateWidgetOptions.mockResolvedValueOnce(options);
|
||||||
|
const res = createMockRes();
|
||||||
|
await handler({ query: { index } }, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("pages/api/widgets/customapi", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["no widget at that index", undefined],
|
||||||
|
["a widget without a url", { method: "GET" }],
|
||||||
|
["an invalid url", { url: "api.local/data" }],
|
||||||
|
])("returns 400 without calling upstream for %s", async (_, options) => {
|
||||||
|
const res = await callRoute(options, "3");
|
||||||
|
|
||||||
|
expect(getPrivateWidgetOptions).toHaveBeenCalledWith("customapi", "3");
|
||||||
|
expect(res.statusCode).toBe(400);
|
||||||
|
expect(httpProxy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("proxies an authenticated POST with custom headers and a JSON body", async () => {
|
||||||
|
httpProxy.mockResolvedValueOnce([200, "application/json", json({ json: { hello: "world" } })]);
|
||||||
|
|
||||||
|
const res = await callRoute({
|
||||||
|
url: "https://httpbin.org/post",
|
||||||
|
username: "admin",
|
||||||
|
password: "hunter2",
|
||||||
|
method: "POST",
|
||||||
|
headers: { "X-Secret-Token": "super-secret", "Content-Type": "application/json" },
|
||||||
|
requestBody: { hello: "world" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(httpProxy).toHaveBeenCalledWith(new URL("https://httpbin.org/post"), {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"User-Agent": "homepage",
|
||||||
|
Accept: "application/json",
|
||||||
|
"X-Secret-Token": "super-secret",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Basic ${Buffer.from("admin:hunter2").toString("base64")}`,
|
||||||
|
},
|
||||||
|
body: '{"hello":"world"}',
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
expect(res.body).toEqual({ json: { hello: "world" } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sends a string body as-is and lets config override default headers", async () => {
|
||||||
|
httpProxy.mockResolvedValueOnce([200, "application/json", json({ data: { viewer: { login: "shamoon" } } })]);
|
||||||
|
const query = '{"query":"{ viewer { login } }"}';
|
||||||
|
|
||||||
|
const res = await callRoute({
|
||||||
|
url: "https://api.github.com/graphql",
|
||||||
|
method: "POST",
|
||||||
|
headers: { Authorization: "Bearer ghp_token", "User-Agent": "my-dashboard" },
|
||||||
|
requestBody: query,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(httpProxy).toHaveBeenCalledWith(expect.any(URL), {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "User-Agent": "my-dashboard", Accept: "application/json", Authorization: "Bearer ghp_token" },
|
||||||
|
body: query,
|
||||||
|
});
|
||||||
|
expect(res.body).toEqual({ data: { viewer: { login: "shamoon" } } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["an HTTP error", [403, "application/json", json({ message: "API rate limit exceeded for 1.2.3.4" })]],
|
||||||
|
[
|
||||||
|
"a network failure",
|
||||||
|
[500, "application/json", { error: { message: "connect ECONNREFUSED", rawError: { address: "10.0.0.5" } } }],
|
||||||
|
],
|
||||||
|
["a non-JSON response", [200, "text/html", Buffer.from("<html><body>Login</body></html>")]],
|
||||||
|
])("returns only a sanitized error for %s", async (_, upstream) => {
|
||||||
|
httpProxy.mockResolvedValueOnce(upstream);
|
||||||
|
|
||||||
|
const res = await callRoute({ url: "https://api.github.com/repos/gethomepage/homepage?token=abc" });
|
||||||
|
|
||||||
|
expect(httpProxy).toHaveBeenCalledWith(expect.any(URL), {
|
||||||
|
method: "GET",
|
||||||
|
headers: { "User-Agent": "homepage", Accept: "application/json" },
|
||||||
|
});
|
||||||
|
expect(res.statusCode).toBe(upstream[0] === 200 ? 500 : upstream[0]);
|
||||||
|
expect(res.body.error.url).toBe("api.github.com (see logs for details)");
|
||||||
|
expect(JSON.stringify(res.body)).not.toMatch(/rate limit|ECONNREFUSED|10\.0\.0\.5|<html>|token=abc/);
|
||||||
|
expect(res.setHeader).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import { invalidateDashboardData } from "utils/config/dashboard";
|
||||||
import { ColorContext } from "utils/contexts/color";
|
import { ColorContext } from "utils/contexts/color";
|
||||||
import { SettingsContext } from "utils/contexts/settings";
|
import { SettingsContext } from "utils/contexts/settings";
|
||||||
import { TabContext } from "utils/contexts/tab";
|
import { TabContext } from "utils/contexts/tab";
|
||||||
@@ -170,8 +171,9 @@ vi.mock("components/toggles/revalidate", () => ({
|
|||||||
default: () => null,
|
default: () => null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("pages/index getStaticProps", () => {
|
describe("pages/index getServerSideProps", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
invalidateDashboardData();
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
state.throwIn = null;
|
state.throwIn = null;
|
||||||
state.validateData = [];
|
state.validateData = [];
|
||||||
@@ -190,8 +192,8 @@ describe("pages/index getStaticProps", () => {
|
|||||||
it("returns initial settings and api fallbacks for swr", async () => {
|
it("returns initial settings and api fallbacks for swr", async () => {
|
||||||
getSettings.mockReturnValueOnce({ providers: { x: 1 }, language: "en", title: "Homepage" });
|
getSettings.mockReturnValueOnce({ providers: { x: 1 }, language: "en", title: "Homepage" });
|
||||||
|
|
||||||
const { getStaticProps } = await import("pages/index.jsx");
|
const { getServerSideProps } = await import("pages/index.jsx");
|
||||||
const result = await getStaticProps();
|
const result = await getServerSideProps({});
|
||||||
|
|
||||||
expect(result.props.initialSettings).toEqual({ language: "en", title: "Homepage" });
|
expect(result.props.initialSettings).toEqual({ language: "en", title: "Homepage" });
|
||||||
expect(result.props.fallback["/api/services"]).toEqual([{ name: "svc" }]);
|
expect(result.props.fallback["/api/services"]).toEqual([{ name: "svc" }]);
|
||||||
@@ -204,8 +206,8 @@ describe("pages/index getStaticProps", () => {
|
|||||||
it("normalizes legacy language codes before requesting translations", async () => {
|
it("normalizes legacy language codes before requesting translations", async () => {
|
||||||
getSettings.mockReturnValueOnce({ providers: {}, language: "zh-CN" });
|
getSettings.mockReturnValueOnce({ providers: {}, language: "zh-CN" });
|
||||||
|
|
||||||
const { getStaticProps } = await import("pages/index.jsx");
|
const { getServerSideProps } = await import("pages/index.jsx");
|
||||||
await getStaticProps();
|
await getServerSideProps({});
|
||||||
|
|
||||||
expect(serverSideTranslations).toHaveBeenCalledWith("zh-Hans");
|
expect(serverSideTranslations).toHaveBeenCalledWith("zh-Hans");
|
||||||
});
|
});
|
||||||
@@ -214,8 +216,8 @@ describe("pages/index getStaticProps", () => {
|
|||||||
getSettings.mockReturnValueOnce({ providers: {}, language: "de" });
|
getSettings.mockReturnValueOnce({ providers: {}, language: "de" });
|
||||||
state.throwIn = "services";
|
state.throwIn = "services";
|
||||||
|
|
||||||
const { getStaticProps } = await import("pages/index.jsx");
|
const { getServerSideProps } = await import("pages/index.jsx");
|
||||||
const result = await getStaticProps();
|
const result = await getServerSideProps({});
|
||||||
|
|
||||||
expect(result.props.initialSettings).toEqual({});
|
expect(result.props.initialSettings).toEqual({});
|
||||||
expect(result.props.fallback["/api/services"]).toEqual([]);
|
expect(result.props.fallback["/api/services"]).toEqual([]);
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { readdirSync } from "fs";
|
||||||
|
|
||||||
|
import { expect, it } from "vitest";
|
||||||
|
|
||||||
|
// Next compiles everything under src/pages into routes, so a colocated test ships
|
||||||
|
// to users and drags its dev dependencies into the runtime image.
|
||||||
|
function filesIn(dir, found = []) {
|
||||||
|
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||||
|
const path = `${dir}/${entry.name}`;
|
||||||
|
if (entry.isDirectory()) filesIn(path, found);
|
||||||
|
else found.push(path);
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
it("keeps test files out of src/pages", () => {
|
||||||
|
const tests = filesIn("src/pages").filter((path) => /\.(test|spec)\.[jt]sx?$/.test(path));
|
||||||
|
expect(tests).toEqual([]);
|
||||||
|
});
|
||||||
@@ -7,6 +7,10 @@ import { SettingsContext } from "utils/contexts/settings";
|
|||||||
export default function Item({ bookmark, iconOnly = false }) {
|
export default function Item({ bookmark, iconOnly = false }) {
|
||||||
const description = bookmark.description ?? new URL(bookmark.href).hostname;
|
const description = bookmark.description ?? new URL(bookmark.href).hostname;
|
||||||
const { settings } = useContext(SettingsContext);
|
const { settings } = useContext(SettingsContext);
|
||||||
|
const cardStyle =
|
||||||
|
settings.cardStyle === "hairline"
|
||||||
|
? "shadow-xs inset-ring inset-ring-black/5 dark:inset-ring-white/5 hover:inset-ring-black/10 dark:hover:inset-ring-white/10"
|
||||||
|
: "shadow-md shadow-theme-900/10 dark:shadow-theme-900/20";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
@@ -22,7 +26,8 @@ export default function Item({ bookmark, iconOnly = false }) {
|
|||||||
target={bookmark.target ?? settings.target ?? "_blank"}
|
target={bookmark.target ?? settings.target ?? "_blank"}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
|
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
|
||||||
"text-left cursor-pointer transition-all rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10",
|
cardStyle,
|
||||||
|
"text-left cursor-pointer transition-all rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10",
|
||||||
iconOnly ? "h-[60px] w-[60px] grid" : "block w-full mb-3",
|
iconOnly ? "h-[60px] w-[60px] grid" : "block w-full mb-3",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -21,6 +21,16 @@ describe("components/bookmarks/item", () => {
|
|||||||
expect(screen.getByRole("link").getAttribute("target")).toBe("_self");
|
expect(screen.getByRole("link").getAttribute("target")).toBe("_self");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("applies hairline card styles when cardStyle is set", () => {
|
||||||
|
renderWithProviders(<Item bookmark={{ name: "A", href: "http://example.com/x", abbr: "A" }} iconOnly={false} />, {
|
||||||
|
settings: { cardStyle: "hairline" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const className = screen.getByRole("link").className;
|
||||||
|
expect(className).toContain("inset-ring");
|
||||||
|
expect(className).not.toContain("shadow-md");
|
||||||
|
});
|
||||||
|
|
||||||
it("renders icon-only layout with icon when provided", () => {
|
it("renders icon-only layout with icon when provided", () => {
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
<Item bookmark={{ name: "A", href: "http://example.com/x", abbr: "A", icon: "mdi-home" }} iconOnly />,
|
<Item bookmark={{ name: "A", href: "http://example.com/x", abbr: "A", icon: "mdi-home" }} iconOnly />,
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ export default function Item({ service, groupName, useEqualHeights }) {
|
|||||||
const { settings } = useContext(SettingsContext);
|
const { settings } = useContext(SettingsContext);
|
||||||
const showStats = service.showStats === false ? false : settings.showStats;
|
const showStats = service.showStats === false ? false : settings.showStats;
|
||||||
const statusStyle = service.statusStyle !== undefined ? service.statusStyle : settings.statusStyle;
|
const statusStyle = service.statusStyle !== undefined ? service.statusStyle : settings.statusStyle;
|
||||||
|
const cardStyle =
|
||||||
|
settings.cardStyle === "hairline"
|
||||||
|
? "shadow-xs inset-ring inset-ring-black/5 dark:inset-ring-white/5 hover:inset-ring-black/10 dark:hover:inset-ring-white/10"
|
||||||
|
: "shadow-md shadow-theme-900/10 dark:shadow-theme-900/20";
|
||||||
const [statsOpen, setStatsOpen] = useState(service.showStats);
|
const [statsOpen, setStatsOpen] = useState(service.showStats);
|
||||||
const [statsClosing, setStatsClosing] = useState(false);
|
const [statsClosing, setStatsClosing] = useState(false);
|
||||||
|
|
||||||
@@ -39,7 +43,8 @@ export default function Item({ service, groupName, useEqualHeights }) {
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
|
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
|
||||||
useEqualHeights && "h-[calc(100%-0.5rem)]",
|
useEqualHeights && "h-[calc(100%-0.5rem)]",
|
||||||
"transition-all mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip service-card",
|
cardStyle,
|
||||||
|
"transition-all mb-2 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative overflow-clip service-card",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex select-none z-0 service-title">
|
<div className="flex select-none z-0 service-title">
|
||||||
|
|||||||
@@ -4,11 +4,14 @@ import { useContext, useMemo } from "react";
|
|||||||
|
|
||||||
import { BlockHighlightContext } from "./highlight-context";
|
import { BlockHighlightContext } from "./highlight-context";
|
||||||
|
|
||||||
|
import { SettingsContext } from "utils/contexts/settings";
|
||||||
import { evaluateHighlight, getHighlightClass } from "utils/highlights";
|
import { evaluateHighlight, getHighlightClass } from "utils/highlights";
|
||||||
|
|
||||||
export default function Block({ value, highlightValue, label, field }) {
|
export default function Block({ value, highlightValue, label, field }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const highlightConfig = useContext(BlockHighlightContext);
|
const highlightConfig = useContext(BlockHighlightContext);
|
||||||
|
const { settings } = useContext(SettingsContext);
|
||||||
|
const refined = settings?.blockStyle === "refined";
|
||||||
|
|
||||||
const highlight = useMemo(() => {
|
const highlight = useMemo(() => {
|
||||||
if (!highlightConfig) return null;
|
if (!highlightConfig) return null;
|
||||||
@@ -45,9 +48,20 @@ export default function Block({ value, highlightValue, label, field }) {
|
|||||||
data-highlight-level={highlight?.level}
|
data-highlight-level={highlight?.level}
|
||||||
data-highlight-source={highlight?.source}
|
data-highlight-source={highlight?.source}
|
||||||
>
|
>
|
||||||
<div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>
|
|
||||||
<div
|
<div
|
||||||
className={classNames("font-bold text-xs uppercase", applyToValueOnly && "text-theme-700 dark:text-theme-200")}
|
className={classNames(
|
||||||
|
refined ? "text-[13px] font-medium tabular-nums" : "font-thin text-sm",
|
||||||
|
"service-block-value",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{value === undefined || value === null ? "-" : value}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
refined ? "text-[10px] font-semibold uppercase tracking-wider opacity-60" : "font-bold text-xs uppercase",
|
||||||
|
applyToValueOnly && "text-theme-700 dark:text-theme-200",
|
||||||
|
"service-block-label",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{t(label)}
|
{t(label)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,6 +39,24 @@ describe("components/services/widget/block", () => {
|
|||||||
expect(el.className).toContain("danger-class");
|
expect(el.className).toContain("danger-class");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the standard block styles by default", () => {
|
||||||
|
const { container } = renderWithProviders(<Block label="some.label" value="1" />, { settings: {} });
|
||||||
|
|
||||||
|
expect(container.querySelector(".service-block-value").className).toContain("font-thin");
|
||||||
|
expect(container.querySelector(".service-block-label").className).toContain("font-bold");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies refined block styles when blockStyle is set", () => {
|
||||||
|
const { container } = renderWithProviders(<Block label="some.label" value="1" />, {
|
||||||
|
settings: { blockStyle: "refined" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const value = container.querySelector(".service-block-value");
|
||||||
|
expect(value.className).toContain("tabular-nums");
|
||||||
|
expect(value.className).not.toContain("font-thin");
|
||||||
|
expect(container.querySelector(".service-block-label").className).toContain("tracking-wider");
|
||||||
|
});
|
||||||
|
|
||||||
it("prefers highlightValue over the rendered value for numeric highlighting", () => {
|
it("prefers highlightValue over the rendered value for numeric highlighting", () => {
|
||||||
const highlightConfig = {
|
const highlightConfig = {
|
||||||
levels: { warn: "warn-class" },
|
levels: { warn: "warn-class" },
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import { useTranslation } from "next-i18next/pages";
|
||||||
|
import { TbApi } from "react-icons/tb";
|
||||||
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
import Container from "../widget/container";
|
||||||
|
import Error from "../widget/error";
|
||||||
|
import Raw from "../widget/raw";
|
||||||
|
import WidgetLabel from "../widget/widget_label";
|
||||||
|
|
||||||
|
import ResolvedIcon from "components/resolvedicon";
|
||||||
|
import { formatValue, getValue } from "widgets/customapi/utils";
|
||||||
|
|
||||||
|
export default function CustomApi({ options }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { index, icon, label, mappings = [], refreshInterval = 10000 } = options;
|
||||||
|
|
||||||
|
const { data, error } = useSWR(`/api/widgets/customapi?${new URLSearchParams({ index }).toString()}`, {
|
||||||
|
refreshInterval: Math.max(1000, refreshInterval),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error || (data?.error && !mappings.some((mapping) => mapping.field === "error"))) {
|
||||||
|
return <Error options={options} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container options={options} additionalClassNames="information-widget-customapi">
|
||||||
|
<Raw>
|
||||||
|
<div className="flex flex-row items-center">
|
||||||
|
<div className="flex-none mr-2">
|
||||||
|
{icon ? (
|
||||||
|
<ResolvedIcon icon={icon} width={24} height={24} />
|
||||||
|
) : (
|
||||||
|
<TbApi className="w-6 h-6 text-theme-800 dark:text-theme-200" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={classNames("flex flex-wrap items-center gap-0.5", !data && "animate-pulse")}>
|
||||||
|
{mappings.map((mapping) => (
|
||||||
|
<div key={mapping.label} className="flex flex-col items-center justify-center px-1 text-xs">
|
||||||
|
<span className="text-theme-800 dark:text-theme-200">{mapping.label}</span>
|
||||||
|
<span className="text-theme-800/70 dark:text-theme-200/50">
|
||||||
|
{data ? formatValue(t, mapping, getValue(mapping.field, data)) : "-"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{label && <WidgetLabel label={label} />}
|
||||||
|
</Raw>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import { screen } from "@testing-library/react";
|
||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
import { renderWithProviders } from "test-utils/render-with-providers";
|
||||||
|
|
||||||
|
const { useSWR } = vi.hoisted(() => ({ useSWR: vi.fn() }));
|
||||||
|
vi.mock("swr", () => ({ default: useSWR }));
|
||||||
|
|
||||||
|
vi.mock("components/resolvedicon", () => ({
|
||||||
|
default: ({ icon }) => <div data-testid="resolved-icon" data-icon={icon} />,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import CustomApi from "./customapi";
|
||||||
|
|
||||||
|
const settings = { settings: { target: "_self" } };
|
||||||
|
|
||||||
|
describe("components/widgets/customapi", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows GitHub repo stats once loaded, with the fallback icon and a label", () => {
|
||||||
|
const options = {
|
||||||
|
index: 6,
|
||||||
|
label: "Homepage",
|
||||||
|
refreshInterval: 300000,
|
||||||
|
mappings: [
|
||||||
|
{ field: "stargazers_count", label: "Stars", format: "number" },
|
||||||
|
{ field: "open_issues_count", label: "Open", format: "number" },
|
||||||
|
{ field: "forks_count", label: "Forks", format: "number" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
useSWR.mockReturnValue({ data: undefined, error: undefined });
|
||||||
|
const { container, rerender } = renderWithProviders(<CustomApi options={options} />, settings);
|
||||||
|
|
||||||
|
expect(useSWR).toHaveBeenCalledWith("/api/widgets/customapi?index=6", { refreshInterval: 300000 });
|
||||||
|
expect(screen.getAllByText("-")).toHaveLength(3);
|
||||||
|
expect(screen.queryByTestId("resolved-icon")).toBeNull();
|
||||||
|
expect(container.querySelector("svg")).not.toBeNull();
|
||||||
|
|
||||||
|
useSWR.mockReturnValue({
|
||||||
|
data: { stargazers_count: 32809, open_issues_count: 1, forks_count: 2127, owner: { login: "gethomepage" } },
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
rerender(<CustomApi options={options} />);
|
||||||
|
|
||||||
|
expect(screen.queryByText("-")).toBeNull();
|
||||||
|
expect(screen.getByText("Stars").nextSibling).toHaveTextContent("32809");
|
||||||
|
expect(screen.getByText("Open").nextSibling).toHaveTextContent("1");
|
||||||
|
expect(screen.getByText("Forks").nextSibling).toHaveTextContent("2127");
|
||||||
|
expect(screen.getByText("Homepage")).toHaveClass("information-widget-label");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows a nested weather value with a configured icon and suffix", () => {
|
||||||
|
useSWR.mockReturnValue({
|
||||||
|
data: { current: { time: "2026-09-22T20:15", temperature_2m: 7.8, wind_speed_10m: 12.4 } },
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<CustomApi
|
||||||
|
options={{
|
||||||
|
index: 7,
|
||||||
|
icon: "mdi-thermometer",
|
||||||
|
mappings: [{ field: "current.temperature_2m", label: "Temp", format: "float", suffix: "°C" }],
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(useSWR).toHaveBeenCalledWith("/api/widgets/customapi?index=7", { refreshInterval: 10000 });
|
||||||
|
expect(screen.getByTestId("resolved-icon")).toHaveAttribute("data-icon", "mdi-thermometer");
|
||||||
|
expect(screen.getByText("7.8 °C")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows a status API's error field as data when it is mapped", () => {
|
||||||
|
useSWR.mockReturnValue({ data: { error: "E_NONE", pending: 3 }, error: undefined });
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<CustomApi
|
||||||
|
options={{
|
||||||
|
index: 0,
|
||||||
|
mappings: [
|
||||||
|
{ field: "error", label: "Status", remap: [{ value: "E_NONE", to: "OK" }] },
|
||||||
|
{ field: "pending", label: "Queue", format: "number" },
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText("widget.api_error")).toBeNull();
|
||||||
|
expect(screen.getByText("OK")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("3")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shows the error state when the upstream API fails, clamping a too-fast refresh", () => {
|
||||||
|
useSWR.mockReturnValue({
|
||||||
|
data: { error: { message: "HTTP Error", url: "api.github.com (see logs for details)" } },
|
||||||
|
error: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithProviders(
|
||||||
|
<CustomApi
|
||||||
|
options={{ index: 6, refreshInterval: 500, mappings: [{ field: "stargazers_count", label: "Stars" }] }}
|
||||||
|
/>,
|
||||||
|
settings,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(useSWR).toHaveBeenCalledWith("/api/widgets/customapi?index=6", { refreshInterval: 1000 });
|
||||||
|
expect(screen.getByText("widget.api_error")).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText("Stars")).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,6 +16,7 @@ const widgetMappings = {
|
|||||||
longhorn: dynamic(() => import("components/widgets/longhorn/longhorn")),
|
longhorn: dynamic(() => import("components/widgets/longhorn/longhorn")),
|
||||||
kubernetes: dynamic(() => import("components/widgets/kubernetes/kubernetes")),
|
kubernetes: dynamic(() => import("components/widgets/kubernetes/kubernetes")),
|
||||||
stocks: dynamic(() => import("components/widgets/stocks/stocks")),
|
stocks: dynamic(() => import("components/widgets/stocks/stocks")),
|
||||||
|
customapi: dynamic(() => import("components/widgets/customapi/customapi")),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Widget({ widget, style }) {
|
export default function Widget({ widget, style }) {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ export default function Resource({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<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 gap-2">
|
||||||
<div className="pl-0.5">{value}</div>
|
<div className="pl-0.5 resource-value">{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 gap-2">
|
||||||
<div className="pl-0.5">{expandedValue}</div>
|
<div className="pl-0.5 resource-value">{expandedValue}</div>
|
||||||
<div className="pr-1">{expandedLabel}</div>
|
<div className="pr-1">{expandedLabel}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { getToken } from "next-auth/jwt";
|
import { getToken } from "next-auth/jwt";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
import { isAllowedHost, secureCookie } from "utils/auth";
|
||||||
import { isAuthEnabled } from "utils/env";
|
import { isAuthEnabled } from "utils/env";
|
||||||
|
|
||||||
const authEnabled = isAuthEnabled();
|
const authEnabled = isAuthEnabled();
|
||||||
@@ -17,18 +18,7 @@ function withPrivateCache(res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function middleware(req) {
|
export async function middleware(req) {
|
||||||
// Check the Host header, if HOMEPAGE_ALLOWED_HOSTS is set
|
if (!isAllowedHost(req.headers.get("host"))) {
|
||||||
const host = req.headers.get("host");
|
|
||||||
const port = process.env.PORT || 3000;
|
|
||||||
let allowedHosts = [`localhost:${port}`, `127.0.0.1:${port}`, `[::1]:${port}`];
|
|
||||||
const allowAll = process.env.HOMEPAGE_ALLOWED_HOSTS === "*";
|
|
||||||
if (process.env.HOMEPAGE_ALLOWED_HOSTS) {
|
|
||||||
allowedHosts = allowedHosts.concat(process.env.HOMEPAGE_ALLOWED_HOSTS.split(","));
|
|
||||||
}
|
|
||||||
if (!allowAll && (!host || !allowedHosts.includes(host))) {
|
|
||||||
console.error(
|
|
||||||
`Host validation failed for: ${host}. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port.`,
|
|
||||||
);
|
|
||||||
return NextResponse.json({ error: "Host validation failed. See logs for more details." }, { status: 400 });
|
return NextResponse.json({ error: "Host validation failed. See logs for more details." }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +30,7 @@ export async function middleware(req) {
|
|||||||
return withPrivateCache(NextResponse.next());
|
return withPrivateCache(NextResponse.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = await getToken({ req, secret: authSecret });
|
const token = await getToken({ req, secret: authSecret, secureCookie: secureCookie() });
|
||||||
if (!token) {
|
if (!token) {
|
||||||
const signInUrl = new URL("/auth/signin", req.url);
|
const signInUrl = new URL("/auth/signin", req.url);
|
||||||
// Same-origin by construction, so this cannot be used as an open redirect
|
// Same-origin by construction, so this cannot be used as an open redirect
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ describe("middleware", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
process.env = { ...originalEnv };
|
process.env = { ...originalEnv };
|
||||||
|
delete process.env.HOMEPAGE_ALLOWED_HOSTS;
|
||||||
console.error = originalConsoleError;
|
console.error = originalConsoleError;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -135,6 +136,29 @@ describe("middleware", () => {
|
|||||||
expect(res.type).toBe("next");
|
expect(res.type).toBe("next");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["NEXTAUTH_URL", "https://homepage.example", true],
|
||||||
|
["NEXTAUTH_URL", "HTTPS://homepage.example", true],
|
||||||
|
["NEXTAUTH_URL", " https://homepage.example ", true],
|
||||||
|
["NEXTAUTH_URL", "HTTP://homepage.example", false],
|
||||||
|
["HOMEPAGE_EXTERNAL_URL", "HTTPS://homepage.example", true],
|
||||||
|
["HOMEPAGE_EXTERNAL_URL", " https://homepage.example ", true],
|
||||||
|
["HOMEPAGE_EXTERNAL_URL", "homepage.example", false],
|
||||||
|
])("reads the session cookie NextAuth sets when %s is %j", async (variable, url, secure) => {
|
||||||
|
process.env.HOMEPAGE_AUTH_ENABLED = "true";
|
||||||
|
process.env.HOMEPAGE_AUTH_SECRET = "secret";
|
||||||
|
delete process.env.NEXTAUTH_URL;
|
||||||
|
process.env[variable] = url;
|
||||||
|
|
||||||
|
getToken.mockResolvedValueOnce({ sub: "user" });
|
||||||
|
|
||||||
|
const middleware = await loadMiddleware();
|
||||||
|
const res = await middleware(createReq("localhost:3000", "http://localhost:3000/"));
|
||||||
|
|
||||||
|
expect(getToken).toHaveBeenCalledWith(expect.objectContaining({ secureCookie: secure }));
|
||||||
|
expect(res.type).toBe("next");
|
||||||
|
});
|
||||||
|
|
||||||
it("redirects to signin when auth is enabled and no token is present", async () => {
|
it("redirects to signin when auth is enabled and no token is present", async () => {
|
||||||
process.env.HOMEPAGE_AUTH_ENABLED = "true";
|
process.env.HOMEPAGE_AUTH_ENABLED = "true";
|
||||||
process.env.HOMEPAGE_AUTH_SECRET = "secret";
|
process.env.HOMEPAGE_AUTH_SECRET = "secret";
|
||||||
@@ -147,6 +171,7 @@ describe("middleware", () => {
|
|||||||
expect(getToken).toHaveBeenCalledWith({
|
expect(getToken).toHaveBeenCalledWith({
|
||||||
req: expect.objectContaining({ url: "http://localhost:3000/some" }),
|
req: expect.objectContaining({ url: "http://localhost:3000/some" }),
|
||||||
secret: "secret",
|
secret: "secret",
|
||||||
|
secureCookie: false,
|
||||||
});
|
});
|
||||||
expect(NextResponse.redirect).toHaveBeenCalled();
|
expect(NextResponse.redirect).toHaveBeenCalled();
|
||||||
expect(res.type).toBe("redirect");
|
expect(res.type).toBe("redirect");
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { appWithTranslation } from "next-i18next/pages";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import "styles/globals.css";
|
import "styles/globals.css";
|
||||||
import "styles/manrope.css";
|
import "styles/manrope.css";
|
||||||
|
import "styles/plex-mono.css";
|
||||||
import "styles/theme.css";
|
import "styles/theme.css";
|
||||||
import { SWRConfig } from "swr";
|
import { SWRConfig } from "swr";
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { createHash, timingSafeEqual } from "node:crypto";
|
|||||||
import NextAuth from "next-auth";
|
import NextAuth from "next-auth";
|
||||||
import CredentialsProvider from "next-auth/providers/credentials";
|
import CredentialsProvider from "next-auth/providers/credentials";
|
||||||
|
|
||||||
|
import { withAllowedHost } from "utils/auth";
|
||||||
import { applyNextAuthEnv, isAuthEnabled } from "utils/env";
|
import { applyNextAuthEnv, isAuthEnabled } from "utils/env";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
@@ -163,7 +164,7 @@ export const authOptions = {
|
|||||||
|
|
||||||
const nextAuthHandler = NextAuth(authOptions);
|
const nextAuthHandler = NextAuth(authOptions);
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
// Just pass empty session if auth not enabled
|
// Just pass empty session if auth not enabled
|
||||||
if (!authEnabled) {
|
if (!authEnabled) {
|
||||||
return res.status(200).json({});
|
return res.status(200).json({});
|
||||||
@@ -171,3 +172,5 @@ export default async function handler(req, res) {
|
|||||||
|
|
||||||
return nextAuthHandler(req, res);
|
return nextAuthHandler(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAllowedHost(handler);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { withAuth } from "utils/auth";
|
||||||
import { bookmarksResponse } from "utils/config/api-response";
|
import { bookmarksResponse } from "utils/config/api-response";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
res.send(await bookmarksResponse());
|
res.send(await bookmarksResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAuth(handler);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
|
import { withAuth } from "utils/auth";
|
||||||
import { CONF_DIR } from "utils/config/config";
|
import { CONF_DIR } from "utils/config/config";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ const logger = createLogger("configFileService");
|
|||||||
* @param {import("next").NextApiRequest} req
|
* @param {import("next").NextApiRequest} req
|
||||||
* @param {import("next").NextApiResponse} res
|
* @param {import("next").NextApiResponse} res
|
||||||
*/
|
*/
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
const { path: relativePath } = req.query;
|
const { path: relativePath } = req.query;
|
||||||
|
|
||||||
// only two supported files, for now
|
// only two supported files, for now
|
||||||
@@ -32,3 +33,5 @@ export default async function handler(req, res) {
|
|||||||
return res.status(500).end("Internal Server Error");
|
return res.status(500).end("Internal Server Error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAuth(handler, { public: (req) => req.query?.path === "custom.css" });
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { withAuth } from "utils/auth";
|
||||||
import { getDockerStats } from "utils/docker/stats";
|
import { getDockerStats } from "utils/docker/stats";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
const logger = createLogger("dockerStats");
|
const logger = createLogger("dockerStats");
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
try {
|
try {
|
||||||
const result = await getDockerStats(req.query.server);
|
const result = await getDockerStats(req.query.server);
|
||||||
|
|
||||||
@@ -19,3 +20,5 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAuth(handler);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { withAuth } from "utils/auth";
|
||||||
import { getDockerStatuses } from "utils/docker/status";
|
import { getDockerStatuses } from "utils/docker/status";
|
||||||
import createLogger from "utils/logger";
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
const logger = createLogger("dockerStatuses");
|
const logger = createLogger("dockerStatuses");
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
try {
|
try {
|
||||||
const result = await getDockerStatuses(req.query.server);
|
const result = await getDockerStatuses(req.query.server);
|
||||||
|
|
||||||
@@ -19,3 +20,5 @@ export default async function handler(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAuth(handler);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { createHash } from "crypto";
|
|||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
|
import { withAuth } from "utils/auth";
|
||||||
import checkAndCopyConfig, { CONF_DIR } from "utils/config/config";
|
import checkAndCopyConfig, { CONF_DIR } from "utils/config/config";
|
||||||
|
|
||||||
const configs = [
|
const configs = [
|
||||||
@@ -20,7 +21,7 @@ function hash(buffer) {
|
|||||||
return hashSum.digest("hex");
|
return hashSum.digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
async function handler(req, res) {
|
||||||
const hashes = configs.map((config) => {
|
const hashes = configs.map((config) => {
|
||||||
checkAndCopyConfig(config);
|
checkAndCopyConfig(config);
|
||||||
const configYaml = join(CONF_DIR, config);
|
const configYaml = join(CONF_DIR, config);
|
||||||
@@ -36,3 +37,5 @@ export default async function handler(req, res) {
|
|||||||
hash: combinedHash,
|
hash: combinedHash,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withAuth(handler);
|
||||||
|
|||||||