Compare commits

..
161 changed files with 1051 additions and 20464 deletions

No files matched your search

-1
View File
@@ -33,7 +33,6 @@ body:
options: options:
# The below comment is used to insert a new version with on-release.yml # The below comment is used to insert a new version with on-release.yml
#NEXT_VERSION# #NEXT_VERSION#
- 1.71.0
- 1.70.0 - 1.70.0
- 1.69.2 - 1.69.2
- 1.69.0 - 1.69.0
+90 -7
View File
@@ -60,7 +60,7 @@ jobs:
TURBO_PLATFORM: linux/amd64 TURBO_PLATFORM: linux/amd64
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
if: "!env.ACT" if: '!env.ACT'
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@@ -81,6 +81,9 @@ jobs:
- name: Copy environment defaults - name: Copy environment defaults
run: cp .env.example .env run: cp .env.example .env
- name: Check formatting in affected workspaces
run: pnpm turbo run format --affected --continue -- --check
- name: Lint, typecheck, and build affected workspaces - name: Lint, typecheck, and build affected workspaces
run: pnpm turbo run lint typecheck build --affected --continue=dependencies-successful run: pnpm turbo run lint typecheck build --affected --continue=dependencies-successful
@@ -90,8 +93,12 @@ jobs:
- name: Run unit tests - name: Run unit tests
run: pnpm test run: pnpm test
- name: Report coverage
if: always() && !env.ACT
uses: davelosert/vitest-coverage-report-action@v2
container: container:
name: Container and E2E name: Container, E2E, and memory
needs: fast-gate needs: fast-gate
if: | if: |
github.event_name == 'merge_group' || github.event_name == 'merge_group' ||
@@ -104,7 +111,7 @@ jobs:
packages: write packages: write
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
if: "!env.ACT" if: '!env.ACT'
with: with:
persist-credentials: false persist-credentials: false
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }} ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }}
@@ -113,11 +120,11 @@ jobs:
uses: ./tooling/github/setup uses: ./tooling/github/setup
- name: Set up Docker Buildx - name: Set up Docker Buildx
if: "!env.ACT" if: '!env.ACT'
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v4
- name: Build container once - name: Build container once
if: "!env.ACT" if: '!env.ACT'
uses: docker/build-push-action@v7 uses: docker/build-push-action@v7
with: with:
context: . context: .
@@ -158,7 +165,7 @@ jobs:
--tag homarr-ci --tag homarr-e2e "${secret_args[@]}" . --tag homarr-ci --tag homarr-e2e "${secret_args[@]}" .
- name: Cache Playwright browsers - name: Cache Playwright browsers
if: "!env.ACT" if: '!env.ACT'
id: playwright-cache id: playwright-cache
uses: actions/cache@v6 uses: actions/cache@v6
with: with:
@@ -184,6 +191,82 @@ jobs:
path: e2e/test-results/ path: e2e/test-results/
retention-days: 7 retention-days: 7
- name: Run memory regression test
env:
CONTAINER_NAME: homarr-mem-${{ github.run_id }}-${{ github.run_attempt }}
SECRET_ENCRYPTION_KEY: 0000000000000000000000000000000000000000000000000000000000000000
run: |
docker run -d --name "$CONTAINER_NAME" -p 127.0.0.1::7575 \
-e NO_EXTERNAL_CONNECTION=true \
-e SECRET_ENCRYPTION_KEY="$SECRET_ENCRYPTION_KEY" \
homarr-ci
PORT=$(docker port "$CONTAINER_NAME" 7575/tcp | sed 's/.*://')
[[ "$PORT" =~ ^[0-9]+$ ]] || { echo "ERROR: invalid port mapping: '$PORT'"; exit 1; }
URL="http://127.0.0.1:${PORT}"
healthy=false
for i in $(seq 1 30); do
if curl -sf "$URL/api/health/ready" >/dev/null 2>&1; then
echo "Container healthy after $((i * 2))s"
healthy=true
break
fi
sleep 2
done
if [ "$healthy" != "true" ]; then
echo "ERROR: Container never became healthy"
docker logs "$CONTAINER_NAME" --tail 100
exit 1
fi
warmup_ok=0
for _ in $(seq 1 5); do
curl -sf "$URL/" >/dev/null 2>&1 && warmup_ok=$((warmup_ok + 1))
sleep 2
done
if [ "$warmup_ok" -eq 0 ]; then
echo "ERROR: All warmup requests failed"
docker logs "$CONTAINER_NAME" --tail 50
exit 1
fi
docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" | grep -qx true || {
echo "ERROR: Container died before memory measurement"
docker logs "$CONTAINER_NAME" --tail 100
exit 1
}
RAW_MEMORY=$(docker stats --no-stream --format '{{.MemUsage}}' "$CONTAINER_NAME" | sed 's| /.*||')
MEMORY_MB=$(echo "$RAW_MEMORY" | awk '
/GiB/ { gsub(/GiB/, ""); print $1 * 1024; next }
/MiB/ { gsub(/MiB/, ""); print $1; next }
/KiB/ { gsub(/KiB/, ""); print $1 / 1024; next }
{ print $1 / 1048576 }
')
echo "Memory usage: ${MEMORY_MB} MB (${RAW_MEMORY})"
[[ "$MEMORY_MB" =~ ^[0-9]+(\.[0-9]+)?$ ]] || {
echo "ERROR: non-numeric memory value: '$MEMORY_MB' (raw: '$RAW_MEMORY')"
docker logs "$CONTAINER_NAME" --tail 100
exit 1
}
if awk "BEGIN { exit !($MEMORY_MB < 50) }"; then
echo "ERROR: Memory suspiciously low (${MEMORY_MB} MB) — container may have crashed"
docker logs "$CONTAINER_NAME" --tail 100
exit 1
elif awk "BEGIN { exit !($MEMORY_MB > 700) }"; then
echo "ERROR: Memory usage ${MEMORY_MB} MB exceeds 700 MB"
docker logs "$CONTAINER_NAME" --tail 100
exit 1
fi
- name: Clean up memory test container
if: always()
env:
CONTAINER_NAME: homarr-mem-${{ github.run_id }}-${{ github.run_attempt }}
run: docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
- name: Determine preview tag - name: Determine preview tag
id: preview id: preview
if: | if: |
@@ -233,7 +316,7 @@ jobs:
run: test -n "$PR_NUMBER" || { echo "pr_number is required for cleanup"; exit 1; } run: test -n "$PR_NUMBER" || { echo "pr_number is required for cleanup"; exit 1; }
- name: Delete GHCR package version - name: Delete GHCR package version
if: "!env.ACT" if: '!env.ACT'
uses: actions/github-script@v8 uses: actions/github-script@v8
with: with:
script: | script: |
-4
View File
@@ -1,7 +1,3 @@
## [1.72.0](https://github.com/homarr-labs/homarr/compare/v1.71.0...v1.72.0) (2026-07-24)
## [1.71.0](https://github.com/homarr-labs/homarr/compare/v1.70.0...v1.71.0) (2026-07-17)
## [1.70.0](https://github.com/homarr-labs/homarr/compare/v1.69.2...v1.70.0) (2026-07-10) ## [1.70.0](https://github.com/homarr-labs/homarr/compare/v1.69.2...v1.70.0) (2026-07-10)
## [1.69.2](https://github.com/homarr-labs/homarr/compare/v1.69.1...v1.69.2) (2026-07-06) ## [1.69.2](https://github.com/homarr-labs/homarr/compare/v1.69.1...v1.69.2) (2026-07-06)
+3
View File
@@ -23,6 +23,9 @@
"react-hooks/exhaustive-deps": "warn", "react-hooks/exhaustive-deps": "warn",
"eslint/no-unused-expressions": "warn" "eslint/no-unused-expressions": "warn"
}, },
"options": {
"reportUnusedDisableDirectives": "off"
},
"ignorePatterns": ["**/*.config.js", "**/*.config.mjs", "**/*.cjs", ".docusaurus/**", "build/**"], "ignorePatterns": ["**/*.config.js", "**/*.config.mjs", "**/*.cjs", ".docusaurus/**", "build/**"],
"settings": { "settings": {
"react": { "version": "19" } "react": { "version": "19" }
@@ -2,9 +2,9 @@
<img src="https://raw.githubusercontent.com/homarr-labs/charts/refs/heads/main/charts/homarr/icon.svg" align="right" width="92" alt="homarr logo"> <img src="https://raw.githubusercontent.com/homarr-labs/charts/refs/heads/main/charts/homarr/icon.svg" align="right" width="92" alt="homarr logo">
![Version: 8.23.0](https://img.shields.io/badge/Version-8.23.0-informational?style=flat) ![Version: 8.22.0](https://img.shields.io/badge/Version-8.22.0-informational?style=flat)
![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat)
![AppVersion: v1.71.0](https://img.shields.io/badge/AppVersion-v1.71.0-informational?style=flat) ![AppVersion: v1.70.0](https://img.shields.io/badge/AppVersion-v1.70.0-informational?style=flat)
A Helm chart to deploy homarr for Kubernetes A Helm chart to deploy homarr for Kubernetes
@@ -259,7 +259,7 @@ httproute:
value: / value: /
backendRefs: backendRefs:
- name: homarr - name: homarr
port: 7575 port: 8080
```` ````
</details> </details>
@@ -419,17 +419,17 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack
| envSecrets.dbEncryption.key | string | `"db-encryption-key"` | Secret key for SECRET_ENCRYPTION_KEY can be generated with `openssl rand -hex 32` | | envSecrets.dbEncryption.key | string | `"db-encryption-key"` | Secret key for SECRET_ENCRYPTION_KEY can be generated with `openssl rand -hex 32` |
| fullnameOverride | string | `""` | Overrides chart's fullname | | fullnameOverride | string | `""` | Overrides chart's fullname |
| hostAliases | list | `[]` | Add static entries to /etc/hosts in the Pod. This is useful in the following cases: - You are running in a dual-stack cluster (IPv4 + IPv6) and want to force usage of IPv4 for specific hostnames - Your application is having DNS resolution issues or IPv6 preference issues - You need to override or simulate DNS entries without changing global DNS - You are running in an air-gapped or isolated environment without external DNS Example: hostAliases: - ip: "192.168.1.10" hostnames: - "example.com" - "example.internal" | | hostAliases | list | `[]` | Add static entries to /etc/hosts in the Pod. This is useful in the following cases: - You are running in a dual-stack cluster (IPv4 + IPv6) and want to force usage of IPv4 for specific hostnames - Your application is having DNS resolution issues or IPv6 preference issues - You need to override or simulate DNS entries without changing global DNS - You are running in an air-gapped or isolated environment without external DNS Example: hostAliases: - ip: "192.168.1.10" hostnames: - "example.com" - "example.internal" |
| httproute | object | `{"enabled":false,"hostnames":["chart-example.local"],"parentRefs":[{"name":"my-gateway","namespace":"default"}],"rules":[{"backendRefs":[{"name":"homarr","port":7575}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}` | Gateway API HTTPRoute configuration | | httproute | object | `{"enabled":false,"hostnames":["chart-example.local"],"parentRefs":[{"name":"my-gateway","namespace":"default"}],"rules":[{"backendRefs":[{"name":"homarr","port":8080}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}` | Gateway API HTTPRoute configuration |
| httproute.enabled | bool | `false` | Enable HTTPRoute | | httproute.enabled | bool | `false` | Enable HTTPRoute |
| httproute.hostnames | list | `["chart-example.local"]` | Hostnames this route matches (similar to ingress.hosts.host) | | httproute.hostnames | list | `["chart-example.local"]` | Hostnames this route matches (similar to ingress.hosts.host) |
| httproute.parentRefs | list | `[{"name":"my-gateway","namespace":"default"}]` | References to the parent Gateway(s) this route attaches to. Each item must include at least a `name`, and optionally a `namespace`. | | httproute.parentRefs | list | `[{"name":"my-gateway","namespace":"default"}]` | References to the parent Gateway(s) this route attaches to. Each item must include at least a `name`, and optionally a `namespace`. |
| httproute.rules | list | `[{"backendRefs":[{"name":"homarr","port":7575}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | List of routing rules. Each rule can include: - matches: path/header/query matching - filters: optional transformations (redirects, header modifications, etc.) - backendRefs: one or more Kubernetes Services to forward traffic to | | httproute.rules | list | `[{"backendRefs":[{"name":"homarr","port":8080}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | List of routing rules. Each rule can include: - matches: path/header/query matching - filters: optional transformations (redirects, header modifications, etc.) - backendRefs: one or more Kubernetes Services to forward traffic to |
| httproute.rules[0].filters | list | `[]` | Optional filters for this rule (default: empty) | | httproute.rules[0].filters | list | `[]` | Optional filters for this rule (default: empty) |
| httproute.rules[0].matches[0].path.type | string | `"PathPrefix"` | Path match type. One of: Exact, PathPrefix, RegularExpression | | httproute.rules[0].matches[0].path.type | string | `"PathPrefix"` | Path match type. One of: Exact, PathPrefix, RegularExpression |
| httproute.rules[0].matches[0].path.value | string | `"/"` | Path value to match | | httproute.rules[0].matches[0].path.value | string | `"/"` | Path value to match |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"ghcr.io/homarr-labs/homarr"` | Image repository | | image.repository | string | `"ghcr.io/homarr-labs/homarr"` | Image repository |
| image.tag | string | `"v1.71.0"` | Overrides the image tag whose default is the chart appVersion | | image.tag | string | `"v1.70.0"` | Overrides the image tag whose default is the chart appVersion |
| imagePullSecrets | list | `[]` | Secrets for Docker registry | | imagePullSecrets | list | `[]` | Secrets for Docker registry |
| ingress.annotations | object | `{}` | Ingress annotations | | ingress.annotations | object | `{}` | Ingress annotations |
| ingress.enabled | bool | `false` | Enable ingress | | ingress.enabled | bool | `false` | Enable ingress |
+2 -1
View File
@@ -50,11 +50,12 @@ import { immichServerStatsWidget } from '../../widgets/immich-server-stats';
<code>user.read</code>,{" "} <code>user.read</code>,{" "}
<code>user.update</code>,{" "} <code>user.update</code>,{" "}
<code>asset.read</code>,{" "} <code>asset.read</code>,{" "}
<code>asset.view</code>,{" "}
<code>asset.download</code>,{" "} <code>asset.download</code>,{" "}
<code>asset.statistics</code>,{" "} <code>asset.statistics</code>,{" "}
<code>server.statistics</code>,{" "} <code>server.statistics</code>,{" "}
<code>server.about</code>. <code>server.about</code>.
<br />
Additional permissions may be required depending on your Immich version. If you encounter authorization errors, grant any missing permissions requested by the server.
</span> </span>
), ),
@@ -15,7 +15,7 @@ import beszelSystemStats from "./img/beszel-system-stats.png";
<WidgetHeader widget={beszelSystemStatsWidget} categories={["System Monitoring", "Charts"]} /> <WidgetHeader widget={beszelSystemStatsWidget} categories={["System Monitoring", "Charts"]} />
This widget displays time-series charts for a selected Beszel system, including CPU, memory, disk, network, and Docker container metrics. The Disk Usage chart combines the root disk and every extra filesystem reported by Beszel. You can use the realtime Live view or select a historical period ranging from 1 hour to 30 days. Live view keeps a one-minute window and pauses while the browser tab is hidden. If the live stream drops, the widget now shows the connection failure state immediately and can switch back to historical data. This widget displays time-series charts for a selected Beszel system, including CPU, memory, disk, network, and Docker container metrics. The Disk Usage chart combines the root disk and every extra filesystem reported by Beszel. You can use the realtime Live view or select a historical period ranging from 1 hour to 30 days. If the live stream drops, the widget now shows the connection failure state immediately and can switch back to historical data.
### Screenshots ### Screenshots
@@ -1,6 +1,6 @@
--- ---
title: 'Immich Album Carousel' title: 'Immich Album Carousel'
description: 'Shows a slideshow of pictures from an Immich album or your full library' description: 'Shows a slideshow of your album pictures from Immich'
hide_title: true hide_title: true
--- ---
@@ -37,3 +37,4 @@ import screen from './img/screen.png';
### Configuration ### Configuration
<WidgetConfig configuration={immichAlbumCarouselWidget.configuration} /> <WidgetConfig configuration={immichAlbumCarouselWidget.configuration} />
@@ -4,16 +4,15 @@ import { IconPhoto } from "@tabler/icons-react";
export const immichAlbumCarouselWidget: WidgetDefinition = { export const immichAlbumCarouselWidget: WidgetDefinition = {
icon: IconPhoto, icon: IconPhoto,
name: "Immich Album", name: "Immich Album",
description: "Shows a slideshow of pictures from an Immich album or your full library", description: "Shows a slideshow of your album pictures from Immich",
path: "../../widgets/immich-album-carousel", path: "../../widgets/immich-album-carousel",
configuration: { configuration: {
items: [ items: [
{ {
name: "Album", name: "Album",
description: description: "Select the Immich album to show in the slideshow.",
"Select an Immich album or All photos. An empty selection also shows random photos from your full library.",
values: { type: "string" }, values: { type: "string" },
defaultValue: "All photos", defaultValue: "",
}, },
{ {
name: "Interval in seconds", name: "Interval in seconds",
@@ -1,44 +1,41 @@
--- ---
title: "Media Request List" title: 'Media Request List'
description: "See a list of all media requests from your integration" description: 'See a list of all media requests from your integration'
hide_title: true hide_title: true
--- ---
import { WidgetHeader } from "@site/src/components/widgets/header"; import { WidgetHeader } from '@site/src/components/widgets/header';
import { AddingWidget } from "@site/src/components/widgets/adding"; import { AddingWidget } from '@site/src/components/widgets/adding';
import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetConfig } from '@site/src/components/widgets/configuration';
import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; import { WidgetIntegrations } from '@site/src/components/widgets/integrations';
import { IconAd } from "@tabler/icons-react"; import { IconAd } from "@tabler/icons-react";
import Tabs from "@theme/Tabs"; import Tabs from '@theme/Tabs';
import TabItem from "@theme/TabItem"; import TabItem from '@theme/TabItem';
import { mediaRequestListWidget } from "."; import { mediaRequestListWidget } from '.';
import { jellyseerrIntegration } from "@site/docs/integrations/jellyseerr"; import { jellyseerrIntegration } from '@site/docs/integrations/jellyseerr';
import { overseerrIntegration } from "@site/docs/integrations/overseerr"; import { overseerrIntegration } from '@site/docs/integrations/overseerr';
<WidgetHeader widget={mediaRequestListWidget} categories={["Media requests"]} />
<WidgetHeader
widget={mediaRequestListWidget}
categories={['Media requests']}
/>
Provides a list of all open and recently closed requests. It also provides the functionality to approve or reject requests. Provides a list of all open and recently closed requests. It also provides the functionality to approve or reject requests.
You can limit the list to specific request statuses (for example, only show `pending`) and restrict it to requests created within the last N days.
### Screenshots ### Screenshots
import mediaRequestList from "./img/list.png"; import mediaRequestList from './img/list.png';
<img src={mediaRequestList} alt="media-request-list" width={256} height={256} /> <img src={mediaRequestList} alt="media-request-list" width={256} height={256} />
### Supported Integrations ### Supported Integrations
<WidgetIntegrations <WidgetIntegrations items={[{
items={[ integration: jellyseerrIntegration,
{ }, {
integration: jellyseerrIntegration, integration: overseerrIntegration,
}, }]} />
{
integration: overseerrIntegration,
},
]}
/>
### Interactions ### Interactions
@@ -50,5 +47,4 @@ import mediaRequestList from "./img/list.png";
<AddingWidget /> <AddingWidget />
### Configuration ### Configuration
<WidgetConfig configuration={mediaRequestListWidget.configuration} /> <WidgetConfig configuration={mediaRequestListWidget.configuration} />
@@ -14,18 +14,6 @@ export const mediaRequestListWidget: WidgetDefinition = {
values: { type: "boolean" }, values: { type: "boolean" },
defaultValue: "yes", defaultValue: "yes",
}, },
{
name: "Statuses to show",
description: "Only requests with these statuses will be shown. Defaults to all statuses.",
values: "List of: 'pending', 'approved', 'declined', 'failed', 'completed'",
defaultValue: "All statuses",
},
{
name: "Show only recent requests",
description: "Limit to requests created within this many days. Set to 0 to disable the time filter.",
values: "0-365",
defaultValue: "0",
},
], ],
}, },
}; };
@@ -2,7 +2,6 @@
import type { PropsWithChildren } from "react"; import type { PropsWithChildren } from "react";
import { useState } from "react"; import { useState } from "react";
import type { QueryKey } from "@tanstack/react-query";
import { QueryClient } from "@tanstack/react-query"; import { QueryClient } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental"; import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental";
@@ -34,7 +33,6 @@ import {
import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared"; import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared";
import { env } from "@homarr/common/env"; import { env } from "@homarr/common/env";
import { showWarningNotification } from "@homarr/notifications"; import { showWarningNotification } from "@homarr/notifications";
import { widgetImports } from "@homarr/widgets";
import { createWidgetQueryPersister } from "./query-cache-persister"; import { createWidgetQueryPersister } from "./query-cache-persister";
@@ -92,13 +90,6 @@ export function TRPCReactProvider(props: PropsWithChildren) {
}, },
}); });
client.setQueryDefaults([["widget"]], { refetchInterval: queryCacheDefaultRefetchIntervalMs }); client.setQueryDefaults([["widget"]], { refetchInterval: queryCacheDefaultRefetchIntervalMs });
for (const { definition } of Object.values(widgetImports)) {
const def = definition as { refetchInterval?: number | null; queryKey?: QueryKey; kind: string };
if (def.refetchInterval === undefined) continue;
const key = def.queryKey ?? [["widget", def.kind]];
const interval = def.refetchInterval === null ? false : def.refetchInterval * 1000;
client.setQueryDefaults(key, { refetchInterval: interval });
}
return client; return client;
}); });
@@ -16,10 +16,7 @@ export default async function AppEditPage(props: AppEditPageProps) {
const params = await props.params; const params = await props.params;
const session = await auth(); const session = await auth();
if ( if (!session?.user.permissions.includes("app-modify-all")) {
!session?.user.permissions.includes("board-modify-all") ||
!session?.user.permissions.includes("app-modify-all")
) {
notFound(); notFound();
} }
const app = await api.app.byId({ id: params.id }); const app = await api.app.byId({ id: params.id });
@@ -10,7 +10,7 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
export default async function AppNewPage() { export default async function AppNewPage() {
const session = await auth(); const session = await auth();
if (!session?.user.permissions.includes("board-modify-all") || !session?.user.permissions.includes("app-create")) { if (!session?.user.permissions.includes("app-create")) {
notFound(); notFound();
} }
@@ -1,5 +1,5 @@
import { Fragment } from "react"; import { Fragment } from "react";
import { notFound, redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text } from "@mantine/core"; import { ActionIcon, ActionIconGroup, Anchor, Avatar, Card, Group, Stack, Text } from "@mantine/core";
import { IconBox, IconPencil } from "@tabler/icons-react"; import { IconBox, IconPencil } from "@tabler/icons-react";
import { z } from "zod/v4"; import { z } from "zod/v4";
@@ -33,9 +33,6 @@ export default async function AppsPage(props: AppsPageProps) {
if (!session) { if (!session) {
redirect("/auth/login"); redirect("/auth/login");
} }
if (!session.user.permissions.includes("board-modify-all")) {
notFound();
}
const searchParams = searchParamsSchema.parse(await props.searchParams); const searchParams = searchParamsSchema.parse(await props.searchParams);
@@ -61,7 +61,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) {
icon: IconBox, icon: IconBox,
href: "/manage/apps", href: "/manage/apps",
label: t("items.apps"), label: t("items.apps"),
hidden: !session?.user.permissions.includes("app-create"), hidden: !session,
iconProps: { iconProps: {
strokeWidth: 2.5, strokeWidth: 2.5,
}, },
@@ -71,20 +71,20 @@ export default async function ManageLayout({ children }: PropsWithChildren) {
icon: IconAffiliateFilled, icon: IconAffiliateFilled,
href: "/manage/integrations", href: "/manage/integrations",
label: t("items.integrations"), label: t("items.integrations"),
hidden: !session?.user.permissions.includes("integration-create"), hidden: !session,
"data-onboarding-tour-id": "manage-integrations", "data-onboarding-tour-id": "manage-integrations",
}, },
{ {
icon: IconApi, icon: IconApi,
href: "/manage/custom-widgets", href: "/manage/custom-widgets",
label: t("items.customWidgets"), label: t("items.customWidgets"),
hidden: !session?.user.permissions.includes("admin"), hidden: !session,
}, },
{ {
icon: IconSearch, icon: IconSearch,
href: "/manage/search-engines", href: "/manage/search-engines",
label: t("items.searchEngies"), label: t("items.searchEngies"),
hidden: !session?.user.permissions.includes("search-engine-create"), hidden: !session,
iconProps: { iconProps: {
strokeWidth: 2.5, strokeWidth: 2.5,
}, },
@@ -94,7 +94,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) {
icon: IconPhotoFilled, icon: IconPhotoFilled,
href: "/manage/medias", href: "/manage/medias",
label: t("items.medias"), label: t("items.medias"),
hidden: !session?.user.permissions.includes("media-upload"), hidden: !session,
"data-onboarding-tour-id": "manage-medias", "data-onboarding-tour-id": "manage-medias",
}, },
{ {
@@ -193,10 +193,6 @@ export function DockerTable({ initialData }: DockerTableProps) {
positionToolbarAlertBanner: "top", positionToolbarAlertBanner: "top",
enableTableFooter: false, enableTableFooter: false,
enableBottomToolbar: false, enableBottomToolbar: false,
// MRT's built-in full-screen mode does not stretch the table to fill the
// viewport, so with few containers it renders as a thin strip (#6230). Disable
// it, matching the other management tables (users, invites).
enableFullScreenToggle: false,
positionGlobalFilter: "right", positionGlobalFilter: "right",
mantineSearchTextInputProps: { mantineSearchTextInputProps: {
placeholder: tDocker("table.search", { count: String(containers.length) }), placeholder: tDocker("table.search", { count: String(containers.length) }),
@@ -31,7 +31,6 @@ import {
userChangeHomeBoardsSchema, userChangeHomeBoardsSchema,
userChangeSearchPreferencesSchema, userChangeSearchPreferencesSchema,
userEditProfileSchema, userEditProfileSchema,
userEnableRightClickOnWidgetsSchema,
userFirstDayOfWeekSchema, userFirstDayOfWeekSchema,
userPingIconsEnabledSchema, userPingIconsEnabledSchema,
} from "@homarr/validation/user"; } from "@homarr/validation/user";
@@ -52,7 +51,6 @@ const userGeneralSettingsSchema = z.object({
ddgBangsEnabled: userChangeSearchPreferencesSchema.shape.ddgBangsEnabled, ddgBangsEnabled: userChangeSearchPreferencesSchema.shape.ddgBangsEnabled,
firstDayOfWeek: userFirstDayOfWeekSchema.shape.firstDayOfWeek, firstDayOfWeek: userFirstDayOfWeekSchema.shape.firstDayOfWeek,
pingIconsEnabled: userPingIconsEnabledSchema.shape.pingIconsEnabled, pingIconsEnabled: userPingIconsEnabledSchema.shape.pingIconsEnabled,
enableRightClickOnWidgets: userEnableRightClickOnWidgetsSchema.shape.enableRightClickOnWidgets,
}); });
type FormValues = z.infer<typeof userGeneralSettingsSchema>; type FormValues = z.infer<typeof userGeneralSettingsSchema>;
@@ -80,7 +78,6 @@ const buildInitialValues = (user: RouterOutputs["user"]["getById"]): FormValues
ddgBangsEnabled: user.ddgBangs, ddgBangsEnabled: user.ddgBangs,
firstDayOfWeek: user.firstDayOfWeek as DayOfWeek, firstDayOfWeek: user.firstDayOfWeek as DayOfWeek,
pingIconsEnabled: user.pingIconsEnabled, pingIconsEnabled: user.pingIconsEnabled,
enableRightClickOnWidgets: user.enableRightClickOnWidgets,
}); });
export const UserGeneralSettingsForm = ({ export const UserGeneralSettingsForm = ({
@@ -98,7 +95,6 @@ export const UserGeneralSettingsForm = ({
const changeSearchPreferencesMutation = clientApi.user.changeSearchPreferences.useMutation(); const changeSearchPreferencesMutation = clientApi.user.changeSearchPreferences.useMutation();
const changeFirstDayOfWeekMutation = clientApi.user.changeFirstDayOfWeek.useMutation(); const changeFirstDayOfWeekMutation = clientApi.user.changeFirstDayOfWeek.useMutation();
const changePingIconsEnabledMutation = clientApi.user.changePingIconsEnabled.useMutation(); const changePingIconsEnabledMutation = clientApi.user.changePingIconsEnabled.useMutation();
const changeEnableRightClickOnWidgetsMutation = clientApi.user.changeEnableRightClickOnWidgets.useMutation();
const initialValues = buildInitialValues(user); const initialValues = buildInitialValues(user);
const initialValuesRef = useRef(initialValues); const initialValuesRef = useRef(initialValues);
@@ -118,7 +114,6 @@ export const UserGeneralSettingsForm = ({
changeSearchPreferencesMutation, changeSearchPreferencesMutation,
changeFirstDayOfWeekMutation, changeFirstDayOfWeekMutation,
changePingIconsEnabledMutation, changePingIconsEnabledMutation,
changeEnableRightClickOnWidgetsMutation,
]; ];
const isPending = mutations.some((m) => m.isPending); const isPending = mutations.some((m) => m.isPending);
@@ -174,14 +169,6 @@ export const UserGeneralSettingsForm = ({
action: () => action: () =>
changePingIconsEnabledMutation.mutateAsync({ id: user.id, pingIconsEnabled: parsed.data.pingIconsEnabled }), changePingIconsEnabledMutation.mutateAsync({ id: user.id, pingIconsEnabled: parsed.data.pingIconsEnabled }),
}, },
{
when: changed("enableRightClickOnWidgets"),
action: () =>
changeEnableRightClickOnWidgetsMutation.mutateAsync({
id: user.id,
enableRightClickOnWidgets: parsed.data.enableRightClickOnWidgets,
}),
},
]; ];
const promises = saveActions.filter((s) => s.when).map((s) => s.action()); const promises = saveActions.filter((s) => s.when).map((s) => s.action());
@@ -318,11 +305,6 @@ export const UserGeneralSettingsForm = ({
label={t("user.field.pingIconsEnabled.label")} label={t("user.field.pingIconsEnabled.label")}
{...form.getInputProps("pingIconsEnabled", { type: "checkbox" })} {...form.getInputProps("pingIconsEnabled", { type: "checkbox" })}
/> />
<Switch
label={t("user.field.enableRightClickOnWidgets.label")}
description={t("user.field.enableRightClickOnWidgets.description")}
{...form.getInputProps("enableRightClickOnWidgets", { type: "checkbox" })}
/>
</Stack> </Stack>
</Card> </Card>
</SimpleGrid> </SimpleGrid>
@@ -1,25 +1,19 @@
import { notFound } from "next/navigation";
import { ImageProxy } from "@homarr/image-proxy"; import { ImageProxy } from "@homarr/image-proxy";
export const GET = async (_request: Request, props: { params: Promise<{ id: string }> }) => { export const GET = async (_request: Request, props: { params: Promise<{ id: string }> }) => {
const { id } = await props.params; const { id } = await props.params;
const imageProxy = new ImageProxy(); const imageProxy = new ImageProxy();
const result = await imageProxy.forwardImageAsync(id); const image = await imageProxy.forwardImageAsync(id);
if (!image) {
if ("error" in result) { notFound();
const status = result.error === "upstream-error" ? result.statusCode : result.error === "fetch-error" ? 502 : 404;
return new Response(null, {
status,
headers: {
"X-Homarr-Image-Proxy-Error": result.error,
},
});
} }
return new Response(result.image, { return new Response(image, {
headers: { headers: {
"Cache-Control": "public, max-age=3600, immutable", // Cache for 1 hour "Cache-Control": "public, max-age=3600, immutable", // Cache for 1 hour
...(result.contentType ? { "Content-Type": result.contentType } : {}),
}, },
}); });
}; };
@@ -1,17 +1,9 @@
"use client"; "use client";
import type { MutableRefObject, ReactNode } from "react"; import type { MutableRefObject, ReactNode } from "react";
import { useCallback, useMemo } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { Group, Loader, Menu, Switch, Text, Tooltip } from "@mantine/core"; import { Group, Loader, Menu, Switch, Text } from "@mantine/core";
import { import { IconCopy, IconLayoutKanban, IconRefresh, IconSettings, IconTrash } from "@tabler/icons-react";
IconAlertTriangle,
IconCircleCheck,
IconCopy,
IconLayoutKanban,
IconRefresh,
IconSettings,
IconTrash,
} from "@tabler/icons-react";
import type { QueryClient, QueryKey } from "@tanstack/react-query"; import type { QueryClient, QueryKey } from "@tanstack/react-query";
import { useIsFetching, useQueryClient } from "@tanstack/react-query"; import { useIsFetching, useQueryClient } from "@tanstack/react-query";
@@ -19,12 +11,10 @@ import { clientApi } from "@homarr/api/client";
import { useSession } from "@homarr/auth/client"; import { useSession } from "@homarr/auth/client";
import { useRequiredBoard } from "@homarr/boards/context"; import { useRequiredBoard } from "@homarr/boards/context";
import { useEditMode } from "@homarr/boards/edit-mode"; import { useEditMode } from "@homarr/boards/edit-mode";
import { useTimeAgo } from "@homarr/common";
import { useConfirmModal, useModalAction } from "@homarr/modals"; import { useConfirmModal, useModalAction } from "@homarr/modals";
import { useSettings } from "@homarr/settings"; import { useSettings } from "@homarr/settings";
import { translateIfNecessary } from "@homarr/translation"; import { translateIfNecessary } from "@homarr/translation";
import { useI18n, useScopedI18n } from "@homarr/translation/client"; import { useI18n, useScopedI18n } from "@homarr/translation/client";
import type { TranslationFunction } from "@homarr/translation";
import type { WidgetContextMenuAction } from "@homarr/widgets"; import type { WidgetContextMenuAction } from "@homarr/widgets";
import { reduceWidgetOptionsWithDefaultValues, widgetImports } from "@homarr/widgets"; import { reduceWidgetOptionsWithDefaultValues, widgetImports } from "@homarr/widgets";
import { WidgetEditModal } from "@homarr/widgets/modals"; import { WidgetEditModal } from "@homarr/widgets/modals";
@@ -48,7 +38,6 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont
const tMenu = useScopedI18n("item.menu.label"); const tMenu = useScopedI18n("item.menu.label");
const t = useI18n(); const t = useI18n();
const settings = useSettings(); const settings = useSettings();
const isRightClickEnabled = settings.enableRightClickOnWidgets;
const { openModal } = useModalAction(WidgetEditModal); const { openModal } = useModalAction(WidgetEditModal);
const { openModal: openMoveModal } = useModalAction(ItemMoveModal); const { openModal: openMoveModal } = useModalAction(ItemMoveModal);
const { openConfirmModal } = useConfirmModal(); const { openConfirmModal } = useConfirmModal();
@@ -169,7 +158,6 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont
); );
if (!session) return <>{children}</>; if (!session) return <>{children}</>;
if (!isRightClickEnabled) return <>{children}</>;
const visibleWidgetActions = widgetContextActions.filter((a) => !a.hidden); const visibleWidgetActions = widgetContextActions.filter((a) => !a.hidden);
@@ -244,14 +232,11 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont
onClick={handleRefetch} onClick={handleRefetch}
disabled={isWidgetFetching} disabled={isWidgetFetching}
> >
<Group justify="space-between" wrap="nowrap" gap="sm"> <Group justify="space-between" wrap="nowrap">
{tMenu("refresh")} {tMenu("refresh")}
<WidgetQueryStatus <Text size="xs" c="dimmed">
queryClient={queryClient} <WidgetCacheAge queryClient={queryClient} queryKey={widgetQueryKey} isFetching={isWidgetFetching} />
queryKey={widgetQueryKey} </Text>
isFetching={isWidgetFetching}
t={t}
/>
</Group> </Group>
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
@@ -288,65 +273,34 @@ export const WidgetContextMenu = ({ item, widgetStateRef, children }: WidgetCont
); );
}; };
interface WidgetQueryStatusProps { const WidgetCacheAge = ({
queryClient,
queryKey,
isFetching,
}: {
queryClient: QueryClient; queryClient: QueryClient;
queryKey: QueryKey; queryKey: QueryKey;
isFetching: boolean; isFetching: boolean;
t: TranslationFunction; }) => {
} // 1s tick for "just now" → "1s ago" label transition; isFetching prop handles refetch reactivity
const [, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick((n) => n + 1), 1000);
return () => clearInterval(id);
}, []);
const WidgetQueryStatus = ({ queryClient, queryKey, isFetching, t }: WidgetQueryStatusProps) => { if (isFetching) return <Loader size={12} />;
const queries = queryClient.getQueryCache().findAll({ queryKey });
const timestamps = queries.map((query) => query.state.dataUpdatedAt).filter(Boolean);
const latest = timestamps.length > 0 ? Math.max(...timestamps) : 0;
const ageLabel = useTimeAgo(new Date(latest));
if (isFetching) { const timestamps = queryClient
return ( .getQueryCache()
<Group gap={4} wrap="nowrap"> .findAll({ queryKey })
<Loader size={12} /> .map((q) => q.state.dataUpdatedAt)
<Text size="xs" c="dimmed"> .filter(Boolean);
{t("item.menu.status.loading")} if (timestamps.length === 0) return null;
</Text>
</Group>
);
}
if (queries.length === 0) { const latest = Math.max(...timestamps);
return ( const seconds = Math.floor((Date.now() - latest) / 1000);
<Text size="xs" c="dimmed"> if (seconds < 5) return "just now";
{t("item.menu.status.idle")} if (seconds < 60) return `${seconds}s ago`;
</Text> return `${Math.floor(seconds / 60)}m ago`;
);
}
const hasError = queries.some((q) => q.state.status === "error");
if (hasError) {
const errorQuery = queries.find((q) => q.state.status === "error");
const errorMessage =
errorQuery?.state.error instanceof Error
? errorQuery.state.error.message
: String(errorQuery?.state.error ?? "Unknown error");
return (
<Tooltip label={errorMessage} multiline position="left" w={250}>
<Group gap={4} wrap="nowrap">
<IconAlertTriangle size={12} color="var(--mantine-color-red-6)" />
<Text size="xs" c="red.6">
{t("item.menu.status.error")} · {ageLabel}
</Text>
</Group>
</Tooltip>
);
}
return (
<Group gap={4} wrap="nowrap">
<IconCircleCheck size={12} color="var(--mantine-color-green-6)" />
<Text size="xs" c="dimmed">
{t("item.menu.status.success")} · {ageLabel}
</Text>
</Group>
);
}; };
+2 -2
View File
@@ -6,7 +6,7 @@
}, },
"engines": { "engines": {
"node": ">=24.18.0", "node": ">=24.18.0",
"pnpm": ">=11.15.0" "pnpm": ">=11.11.0"
}, },
"packageManager": "pnpm@11.15.0" "packageManager": "pnpm@11.11.0"
} }
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "homarr", "name": "homarr",
"version": "1.72.0", "version": "1.70.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "cross-env CI=true turbo build", "build": "cross-env CI=true turbo build",
@@ -69,7 +69,7 @@
}, },
"engines": { "engines": {
"node": ">=24.18.0", "node": ">=24.18.0",
"pnpm": ">=11.15.0" "pnpm": ">=11.11.0"
}, },
"packageManager": "pnpm@11.15.0" "packageManager": "pnpm@11.11.0"
} }
+1 -2
View File
@@ -18,8 +18,7 @@ import { AppAccessControl } from "./app/app-access-control";
const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/homarr.svg"; const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/homarr.svg";
export const appRouter = createTRPCRouter({ export const appRouter = createTRPCRouter({
getPaginated: permissionRequiredProcedure getPaginated: protectedProcedure
.requiresPermission("board-modify-all")
.input(paginatedSchema) .input(paginatedSchema)
.output(z.object({ items: z.array(selectAppSchema), totalCount: z.number() })) .output(z.object({ items: z.array(selectAppSchema), totalCount: z.number() }))
.meta({ .meta({
+1 -1
View File
@@ -101,7 +101,7 @@ export const homeRouter = createTRPCRouter({
}); });
} }
if (ctx.session?.user.permissions.includes("board-modify-all")) { if (ctx.session?.user) {
statistics.push({ statistics.push({
titleKey: "app", titleKey: "app",
subtitleKey: "resources", subtitleKey: "resources",
@@ -3,7 +3,7 @@ import { z } from "zod/v4";
import { createId } from "@homarr/common"; import { createId } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs"; import { createLogger } from "@homarr/core/infrastructure/logs";
import { and, asc, eq, like } from "@homarr/db"; import { asc, eq, like } from "@homarr/db";
import { getServerSettingByKeyAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries"; import { getServerSettingByKeyAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries";
import { searchEngines, users } from "@homarr/db/schema"; import { searchEngines, users } from "@homarr/db/schema";
import { byIdSchema, paginatedSchema, searchSchema } from "@homarr/validation/common"; import { byIdSchema, paginatedSchema, searchSchema } from "@homarr/validation/common";
@@ -130,15 +130,9 @@ export const searchEngineRouter = createTRPCRouter({
return null; return null;
}), }),
search: publicProcedure.input(searchSchema).query(async ({ ctx, input }) => { search: protectedProcedure.input(searchSchema).query(async ({ ctx, input }) => {
return await ctx.db.query.searchEngines.findMany({ return await ctx.db.query.searchEngines.findMany({
// Public dashboards have no session: restrict anonymous users to generic where: like(searchEngines.short, `${input.query.toLowerCase().trim()}%`),
// (non-integration) engines so custom search engines work there too (#4132),
// while integration-backed engines stay available only when signed in.
where: and(
like(searchEngines.short, `${input.query.toLowerCase().trim()}%`),
ctx.session?.user ? undefined : eq(searchEngines.type, "generic"),
),
with: { with: {
integration: { integration: {
columns: { columns: {
-27
View File
@@ -76,33 +76,6 @@ describe("all should return all apps", () => {
}); });
}); });
describe("getPaginated should require board modification access", () => {
test("should throw FORBIDDEN without board-modify-all", async () => {
const caller = appRouter.createCaller({
db: createDb(),
deviceType: undefined,
session: createDefaultSession(),
});
await expect(caller.getPaginated({ page: 1, pageSize: 10 })).rejects.toThrow("Permission denied");
});
test("should return apps with board-modify-all", async () => {
const db = createDb();
const caller = appRouter.createCaller({
db,
deviceType: undefined,
session: createDefaultSession(["board-modify-all"]),
});
await db.insert(apps).values({ id: "1", name: "Homarr", iconUrl: "https://homarr.dev/icon.svg" });
await expect(caller.getPaginated({ page: 1, pageSize: 10 })).resolves.toMatchObject({
totalCount: 1,
items: [{ id: "1" }],
});
});
});
describe("byId should return an app by id", () => { describe("byId should return an app by id", () => {
test("should return an app by id when canUserSeeAppAsync returns true", async () => { test("should return an app by id when canUserSeeAppAsync returns true", async () => {
// Arrange // Arrange
-77
View File
@@ -357,83 +357,6 @@ describe("delete should delete user", () => {
}); });
}); });
describe("changeEnableRightClickOnWidgets should toggle the right-click preference", () => {
test("non-admin can toggle their own preference", async () => {
const db = createDb();
const caller = userRouter.createCaller({
db,
deviceType: undefined,
session: defaultSession,
});
await db.insert(users).values({
id: defaultOwnerId,
name: "owner",
});
await caller.changeEnableRightClickOnWidgets({ id: defaultOwnerId, enableRightClickOnWidgets: false });
const updated = await db.query.users.findFirst({
where: eq(users.id, defaultOwnerId),
columns: { enableRightClickOnWidgets: true },
});
expect(updated?.enableRightClickOnWidgets).toBe(false);
await caller.changeEnableRightClickOnWidgets({ id: defaultOwnerId, enableRightClickOnWidgets: true });
const restored = await db.query.users.findFirst({
where: eq(users.id, defaultOwnerId),
columns: { enableRightClickOnWidgets: true },
});
expect(restored?.enableRightClickOnWidgets).toBe(true);
});
test("non-admin cannot toggle another user's preference", async () => {
const db = createDb();
const caller = userRouter.createCaller({
db,
deviceType: undefined,
session: defaultSession,
});
const otherUserId = createId();
await db.insert(users).values({ id: defaultOwnerId });
await db.insert(users).values({ id: otherUserId, name: "other" });
await expect(
caller.changeEnableRightClickOnWidgets({ id: otherUserId, enableRightClickOnWidgets: false }),
).rejects.toThrow("User not found");
const other = await db.query.users.findFirst({
where: eq(users.id, otherUserId),
columns: { enableRightClickOnWidgets: true },
});
expect(other?.enableRightClickOnWidgets).toBe(true);
});
test("admin can toggle another user's preference", async () => {
const db = createDb();
const adminSession = createSession(["admin"]);
const caller = userRouter.createCaller({
db,
deviceType: undefined,
session: adminSession,
});
const targetUserId = createId();
await db.insert(users).values({ id: defaultOwnerId });
await db.insert(users).values({ id: targetUserId, name: "target" });
await caller.changeEnableRightClickOnWidgets({ id: targetUserId, enableRightClickOnWidgets: false });
const target = await db.query.users.findFirst({
where: eq(users.id, targetUserId),
columns: { enableRightClickOnWidgets: true },
});
expect(target?.enableRightClickOnWidgets).toBe(false);
});
});
const createOnboardingStepAsync = async (db: Database, step: OnboardingStep) => { const createOnboardingStepAsync = async (db: Database, step: OnboardingStep) => {
await db.insert(onboarding).values({ await db.insert(onboarding).values({
id: createId(), id: createId(),
-29
View File
@@ -23,7 +23,6 @@ import {
userCreateSchema, userCreateSchema,
userDdgBangsSchema, userDdgBangsSchema,
userEditProfileSchema, userEditProfileSchema,
userEnableRightClickOnWidgetsSchema,
userFirstDayOfWeekSchema, userFirstDayOfWeekSchema,
userInitSchema, userInitSchema,
userPingIconsEnabledSchema, userPingIconsEnabledSchema,
@@ -346,7 +345,6 @@ export const userRouter = createTRPCRouter({
mobileHomeBoardId: true, mobileHomeBoardId: true,
firstDayOfWeek: true, firstDayOfWeek: true,
pingIconsEnabled: true, pingIconsEnabled: true,
enableRightClickOnWidgets: true,
defaultSearchEngineId: true, defaultSearchEngineId: true,
openSearchInNewTab: true, openSearchInNewTab: true,
ddgBangs: true, ddgBangs: true,
@@ -383,7 +381,6 @@ export const userRouter = createTRPCRouter({
mobileHomeBoardId: true, mobileHomeBoardId: true,
firstDayOfWeek: true, firstDayOfWeek: true,
pingIconsEnabled: true, pingIconsEnabled: true,
enableRightClickOnWidgets: true,
defaultSearchEngineId: true, defaultSearchEngineId: true,
openSearchInNewTab: true, openSearchInNewTab: true,
ddgBangs: true, ddgBangs: true,
@@ -654,32 +651,6 @@ export const userRouter = createTRPCRouter({
}) })
.where(eq(users.id, ctx.session.user.id)); .where(eq(users.id, ctx.session.user.id));
}), }),
changeEnableRightClickOnWidgets: protectedProcedure
.meta({
openapi: {
method: "PATCH",
path: "/api/users/right-click-widgets",
tags: ["users"],
protect: true,
},
})
.input(convertIntersectionToZodObject(userEnableRightClickOnWidgetsSchema.and(byIdSchema)))
.output(z.void())
.mutation(async ({ input, ctx }) => {
if (!ctx.session.user.permissions.includes("admin") && ctx.session.user.id !== input.id) {
throw new TRPCError({
code: "NOT_FOUND",
message: "User not found",
});
}
await ctx.db
.update(users)
.set({
enableRightClickOnWidgets: input.enableRightClickOnWidgets,
})
.where(eq(users.id, input.id));
}),
changePingIconsEnabled: protectedProcedure changePingIconsEnabled: protectedProcedure
.input(userPingIconsEnabledSchema.and(byIdSchema)) .input(userPingIconsEnabledSchema.and(byIdSchema))
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
@@ -1,45 +0,0 @@
import { describe, expect, test } from "vitest";
import { BoundedAsyncQueue } from "../bounded-async-queue";
describe("BoundedAsyncQueue", () => {
test("keeps only the newest values when the queue is full", async () => {
const queue = new BoundedAsyncQueue<number>(2);
queue.push(1);
queue.push(2);
queue.push(3);
queue.close();
await expect(queue.next()).resolves.toEqual({ value: 2, done: false });
await expect(queue.next()).resolves.toEqual({ value: 3, done: false });
await expect(queue.next()).resolves.toEqual({ value: undefined, done: true });
});
test("resolves a pending read as soon as a value arrives", async () => {
const queue = new BoundedAsyncQueue<string>(1);
const next = queue.next();
queue.push("latest");
await expect(next).resolves.toEqual({ value: "latest", done: false });
});
test("resolves a pending read when the producer closes", async () => {
const queue = new BoundedAsyncQueue<number>(1);
const next = queue.next();
queue.close();
await expect(next).resolves.toEqual({ value: undefined, done: true });
});
test("rejects a pending read when the producer fails", async () => {
const queue = new BoundedAsyncQueue<number>(1);
const next = queue.next();
const error = new Error("upstream failed");
queue.fail(error);
await expect(next).rejects.toBe(error);
});
});
+81 -78
View File
@@ -1,4 +1,5 @@
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { createLogger } from "@homarr/core/infrastructure/logs"; import { createLogger } from "@homarr/core/infrastructure/logs";
@@ -13,10 +14,8 @@ import {
import { settleIntegrationQueries } from "../../settle-integrations"; import { settleIntegrationQueries } from "../../settle-integrations";
import { createManyIntegrationMiddleware } from "../../middlewares/integration"; import { createManyIntegrationMiddleware } from "../../middlewares/integration";
import { createTRPCRouter, publicProcedure } from "../../trpc"; import { createTRPCRouter, publicProcedure } from "../../trpc";
import { BoundedAsyncQueue } from "./bounded-async-queue";
const logger = createLogger({ module: "beszelRouter" }); const logger = createLogger({ module: "beszelRouter" });
const MAX_PENDING_LIVE_EVENTS = 4;
const errorMessage = (error: unknown) => (error instanceof Error ? error.message : String(error)); const errorMessage = (error: unknown) => (error instanceof Error ? error.message : String(error));
@@ -204,94 +203,98 @@ export const beszelRouter = createTRPCRouter({
systemId: z.string(), systemId: z.string(),
}), }),
) )
.subscription(async function* ({ ctx, input, signal }) { .subscription(({ ctx, input }) => {
const integration = ctx.integrations[0]; return observable<LiveStatsEvent>((emit) => {
if (!integration) { const controller = new AbortController();
throw new TRPCError({ code: "BAD_REQUEST", message: "At least one Beszel integrationId is required" }); let isActive = true;
} let emittedEventCount = 0;
const queue = new BoundedAsyncQueue<LiveStatsEvent>(MAX_PENDING_LIVE_EVENTS); logger.debug("Beszel realtime subscription started", {
const controller = new AbortController(); userId: ctx.session?.user?.id,
let emittedEventCount = 0; integrationIds: ctx.integrations.map((integration) => integration.id),
systemId: input.systemId,
});
const stop = () => {
controller.abort();
void queue.return();
};
if (signal?.aborted) return;
signal?.addEventListener("abort", stop, { once: true });
logger.debug("Beszel realtime subscription started", {
userId: ctx.session?.user?.id,
integrationIds: ctx.integrations.map((candidate) => candidate.id),
systemId: input.systemId,
});
try {
const instance = await createIntegrationAsync(integration);
if (controller.signal.aborted) return;
void (async () => { void (async () => {
try { const integration = ctx.integrations[0];
if (typeof instance.subscribeRealtimeMetrics !== "function") { if (!integration) {
throw new TRPCError({ emit.error(
code: "METHOD_NOT_SUPPORTED", new TRPCError({ code: "BAD_REQUEST", message: "At least one Beszel integrationId is required" }),
message: `Integration ${integration.kind} does not support realtime metrics`,
});
}
await instance.subscribeRealtimeMetrics(
input.systemId,
(event) => {
emittedEventCount += 1;
if (emittedEventCount <= 2 || emittedEventCount % 60 === 0) {
logger.debug("Forwarding Beszel realtime events", {
userId: ctx.session?.user?.id,
integrationId: integration.id,
systemId: input.systemId,
eventType: event.type,
emittedEventCount,
statsCount: Array.isArray(event.record.stats) ? event.record.stats.length : undefined,
});
}
queue.push(event);
},
controller.signal,
); );
queue.close(); return;
} catch (error) { }
if (controller.signal.aborted) {
queue.close();
return;
}
logger.warn("Beszel realtime subscription failed", { try {
const instance = await createIntegrationAsync(integration);
if (typeof instance.subscribeRealtimeMetrics === "function") {
await instance.subscribeRealtimeMetrics(
input.systemId,
(event) => {
if (!isActive) return;
emittedEventCount += 1;
if (emittedEventCount <= 2 || emittedEventCount % 60 === 0) {
logger.debug("Forwarding Beszel realtime events", {
userId: ctx.session?.user?.id,
integrationId: integration.id,
systemId: input.systemId,
eventType: event.type,
emittedEventCount,
statsCount: Array.isArray(event.record.stats) ? event.record.stats.length : undefined,
});
}
emit.next(event);
},
controller.signal,
);
} else {
emit.error(
new TRPCError({
code: "METHOD_NOT_SUPPORTED",
message: `Integration ${integration.kind} does not support realtime metrics`,
}),
);
}
} catch (error) {
if (isActive) {
logger.warn("Beszel realtime subscription failed", {
userId: ctx.session?.user?.id,
integrationId: integration.id,
systemId: input.systemId,
emittedEventCount,
error: errorMessage(error),
});
emit.error(
error instanceof TRPCError
? error
: new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: error instanceof Error ? error.message : String(error),
}),
);
}
}
if (isActive) {
logger.debug("Beszel realtime subscription completed", {
userId: ctx.session?.user?.id, userId: ctx.session?.user?.id,
integrationId: integration.id, integrationId: integration.id,
systemId: input.systemId, systemId: input.systemId,
emittedEventCount, emittedEventCount,
error: errorMessage(error),
}); });
queue.fail( emit.complete();
error instanceof TRPCError
? error
: new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: error instanceof Error ? error.message : String(error),
}),
);
} }
})(); })();
for await (const event of queue) yield event; return () => {
} finally { isActive = false;
stop(); logger.debug("Beszel realtime subscription cancelled", {
signal?.removeEventListener("abort", stop); userId: ctx.session?.user?.id,
logger.debug("Beszel realtime subscription stopped", { integrationIds: ctx.integrations.map((integration) => integration.id),
userId: ctx.session?.user?.id, systemId: input.systemId,
integrationId: integration.id, emittedEventCount,
systemId: input.systemId, });
emittedEventCount, controller.abort();
}); };
} });
}), }),
}); });
@@ -1,88 +0,0 @@
type QueueResult<T> = IteratorResult<T, undefined>;
type PendingRead<T> = {
resolve: (result: QueueResult<T>) => void;
reject: (reason?: unknown) => void;
};
/**
* A small async queue for live streams.
*
* Live metrics are snapshots, so retaining every snapshot while a client is
* slow is both unnecessary and dangerous. When the queue is full, discard
* the oldest pending snapshot and keep the newest one.
*/
export class BoundedAsyncQueue<T> implements AsyncIterableIterator<T> {
private readonly values: T[] = [];
private pendingRead: PendingRead<T> | undefined;
private closed = false;
private failed = false;
private failure: unknown;
public constructor(private readonly maxSize: number) {
if (!Number.isInteger(maxSize) || maxSize < 1) {
throw new Error("A bounded async queue requires a positive integer max size");
}
}
public push(value: T): void {
if (this.closed) return;
if (this.pendingRead) {
const pendingRead = this.pendingRead;
this.pendingRead = undefined;
pendingRead.resolve({ value, done: false });
return;
}
if (this.values.length >= this.maxSize) this.values.shift();
this.values.push(value);
}
public close(): void {
if (this.closed) return;
this.closed = true;
if (this.pendingRead) {
const pendingRead = this.pendingRead;
this.pendingRead = undefined;
pendingRead.resolve({ value: undefined, done: true });
}
}
public fail(error: unknown): void {
if (this.closed) return;
this.closed = true;
this.failed = true;
this.failure = error;
this.values.length = 0;
if (this.pendingRead) {
const pendingRead = this.pendingRead;
this.pendingRead = undefined;
pendingRead.reject(error);
}
}
public next(): Promise<QueueResult<T>> {
if (this.values.length > 0) {
return Promise.resolve({ value: this.values.shift() as T, done: false });
}
if (this.failed) return Promise.reject(this.failure);
if (this.closed) return Promise.resolve({ value: undefined, done: true });
return new Promise<QueueResult<T>>((resolve, reject) => {
this.pendingRead = { resolve, reject };
});
}
public return(): Promise<QueueResult<T>> {
this.values.length = 0;
this.close();
return Promise.resolve({ value: undefined, done: true });
}
public [Symbol.asyncIterator](): AsyncIterableIterator<T> {
return this;
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ export const immichRouter = createTRPCRouter({
.concat(createImmichIntegrationMiddleware("query")) .concat(createImmichIntegrationMiddleware("query"))
.input( .input(
z.object({ z.object({
albumId: z.string().optional(), albumId: z.string(),
}), }),
) )
.query(async ({ ctx, input }) => { .query(async ({ ctx, input }) => {
@@ -3,10 +3,7 @@ import { z } from "zod/v4";
import { getIntegrationKindsByCategory } from "@homarr/definitions"; import { getIntegrationKindsByCategory } from "@homarr/definitions";
import { createIntegrationAsync } from "@homarr/integrations"; import { createIntegrationAsync } from "@homarr/integrations";
import { mediaRequestStatusConfiguration } from "@homarr/integrations/types"; import { mediaRequestStatusConfiguration } from "@homarr/integrations/types";
import { import { mediaRequestListRequestHandler } from "@homarr/request-handler/media-request-list";
mediaRequestListInputSchema,
mediaRequestListRequestHandler,
} from "@homarr/request-handler/media-request-list";
import { mediaRequestStatsRequestHandler } from "@homarr/request-handler/media-request-stats"; import { mediaRequestStatsRequestHandler } from "@homarr/request-handler/media-request-stats";
import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration";
@@ -19,14 +16,13 @@ export const mediaRequestsRouter = createTRPCRouter({
mcp: { mcp: {
enabled: true, enabled: true,
description: description:
"Get latest media requests from Overseerr/Jellyseerr with their status (pending, approved, declined, failed, completed). REQUIRED: integrationIds (array of Overseerr/Jellyseerr integration IDs from integration_all). OPTIONAL: statuses (array of statuses to include, must be non-empty) and recentDays (number 0-365; 0 disables the time filter).", "Get latest media requests from Overseerr/Jellyseerr with their status (pending, approved, declined, available). REQUIRED: integrationIds (array of Overseerr/Jellyseerr integration IDs from integration_all)",
}, },
}) })
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRequest"))) .concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRequest")))
.input(mediaRequestListInputSchema) .query(async ({ ctx }) => {
.query(async ({ ctx, input }) => {
const results = await settleIntegrationQueries(ctx.integrations, async (integration) => { const results = await settleIntegrationQueries(ctx.integrations, async (integration) => {
const { data } = await mediaRequestListRequestHandler.handler(integration, input).getDataAsync(); const { data } = await mediaRequestListRequestHandler.handler(integration, {}).getDataAsync();
return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data }; return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data };
}); });
return results return results
+4 -7
View File
@@ -3,7 +3,6 @@ import { escapeForRegEx } from "@tiptap/react";
import { z } from "zod/v4"; import { z } from "zod/v4";
import { decryptSecret } from "@homarr/common/server"; import { decryptSecret } from "@homarr/common/server";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { eq } from "@homarr/db"; import { eq } from "@homarr/db";
import { boards, items, widgetSecrets } from "@homarr/db/schema"; import { boards, items, widgetSecrets } from "@homarr/db/schema";
import { releaseProviderKinds } from "@homarr/definitions"; import { releaseProviderKinds } from "@homarr/definitions";
@@ -12,8 +11,6 @@ import { releasesRequestHandler } from "@homarr/request-handler/releases";
import { createTRPCRouter, publicProcedure } from "../../trpc"; import { createTRPCRouter, publicProcedure } from "../../trpc";
import { throwIfActionForbiddenAsync } from "../board/board-access"; import { throwIfActionForbiddenAsync } from "../board/board-access";
const logger = createLogger({ module: "releasesRouter" });
const formatVersionFilterRegex = (versionFilter: z.infer<typeof releaseVersionFilterSchema> | undefined) => { const formatVersionFilterRegex = (versionFilter: z.infer<typeof releaseVersionFilterSchema> | undefined) => {
if (!versionFilter) return undefined; if (!versionFilter) return undefined;
@@ -74,13 +71,13 @@ export const releasesRouter = createTRPCRouter({
for (const secret of secrets) { for (const secret of secrets) {
try { try {
tokensByProvider.set(secret.kind, decryptSecret(secret.value)); tokensByProvider.set(secret.kind, decryptSecret(secret.value));
} catch (error) { } catch {
logger.warn("Failed to decrypt widget secret", { itemId: input.itemId, kind: secret.kind, error }); // Skip corrupt secrets
} }
} }
} }
} catch (error) { } catch {
logger.warn("Failed to load release widget tokens", { itemId: input.itemId, error }); // Access denied or table not yet migrated -- proceed without tokens
} }
} }
@@ -67,14 +67,12 @@ export const fetchWithTrustedCertificatesAsync = async (
url: RequestInfo, url: RequestInfo,
options?: RequestInit & { timeout?: number; bodyTimeout?: number }, options?: RequestInit & { timeout?: number; bodyTimeout?: number },
): Promise<Response> => { ): Promise<Response> => {
const agent = const agent = await createCertificateAgentAsync(
options?.dispatcher ?? undefined,
(await createCertificateAgentAsync( options?.bodyTimeout !== undefined ? { bodyTimeout: options.bodyTimeout } : undefined,
undefined, );
options?.bodyTimeout !== undefined ? { bodyTimeout: options.bodyTimeout } : undefined,
));
if (options?.timeout) { if (options?.timeout) {
const { bodyTimeout: _bodyTimeout, dispatcher: _dispatcher, ...fetchOptions } = options; const { bodyTimeout: _bodyTimeout, ...fetchOptions } = options;
return await withTimeoutAsync( return await withTimeoutAsync(
async (signal) => async (signal) =>
fetch(url, { fetch(url, {
@@ -86,7 +84,7 @@ export const fetchWithTrustedCertificatesAsync = async (
); );
} }
const { bodyTimeout: _bodyTimeout, dispatcher: _dispatcher, ...fetchOptions } = options ?? {}; const { bodyTimeout: _bodyTimeout, ...fetchOptions } = options ?? {};
return fetch(url, { return fetch(url, {
...fetchOptions, ...fetchOptions,
dispatcher: agent, dispatcher: agent,
@@ -1 +0,0 @@
ALTER TABLE `user` ADD `enable_right_click_on_widgets` boolean DEFAULT true NOT NULL;
File diff suppressed because it is too large. Load diff
@@ -302,13 +302,6 @@
"when": 1783176100870, "when": 1783176100870,
"tag": "0042_add_widget_secret", "tag": "0042_add_widget_secret",
"breakpoints": true "breakpoints": true
},
{
"idx": 43,
"version": "5",
"when": 1783852800000,
"tag": "0043_add_right_click_preference",
"breakpoints": true
} }
] ]
} }
@@ -1 +0,0 @@
ALTER TABLE "user" ADD COLUMN "enable_right_click_on_widgets" boolean DEFAULT true NOT NULL;
File diff suppressed because it is too large. Load diff
@@ -64,13 +64,6 @@
"when": 1783176100870, "when": 1783176100870,
"tag": "0008_add_widget_secret", "tag": "0008_add_widget_secret",
"breakpoints": true "breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1783786677702,
"tag": "0009_add_right_click_preference",
"breakpoints": true
} }
] ]
} }
@@ -1 +0,0 @@
ALTER TABLE `user` ADD `enable_right_click_on_widgets` integer DEFAULT true NOT NULL;
File diff suppressed because it is too large. Load diff
@@ -288,13 +288,6 @@
"when": 1783176100870, "when": 1783176100870,
"tag": "0040_add_widget_secret", "tag": "0040_add_widget_secret",
"breakpoints": true "breakpoints": true
},
{
"idx": 41,
"version": "6",
"when": 1783786658943,
"tag": "0041_add_right_click_preference",
"breakpoints": true
} }
] ]
} }
-1
View File
@@ -86,7 +86,6 @@ export const users = mysqlTable("user", {
colorScheme: varchar({ length: 5 }).$type<ColorScheme>().default("dark").notNull(), colorScheme: varchar({ length: 5 }).$type<ColorScheme>().default("dark").notNull(),
firstDayOfWeek: tinyint().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday firstDayOfWeek: tinyint().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday
pingIconsEnabled: boolean().default(false).notNull(), pingIconsEnabled: boolean().default(false).notNull(),
enableRightClickOnWidgets: boolean().default(true).notNull(),
completedManageTour: boolean().default(false).notNull(), completedManageTour: boolean().default(false).notNull(),
completedBoardTour: boolean().default(false).notNull(), completedBoardTour: boolean().default(false).notNull(),
}); });
-1
View File
@@ -85,7 +85,6 @@ export const users = pgTable("user", {
colorScheme: varchar({ length: 5 }).$type<ColorScheme>().default("dark").notNull(), colorScheme: varchar({ length: 5 }).$type<ColorScheme>().default("dark").notNull(),
firstDayOfWeek: smallint().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday firstDayOfWeek: smallint().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday
pingIconsEnabled: boolean().default(false).notNull(), pingIconsEnabled: boolean().default(false).notNull(),
enableRightClickOnWidgets: boolean().default(true).notNull(),
completedManageTour: boolean().default(false).notNull(), completedManageTour: boolean().default(false).notNull(),
completedBoardTour: boolean().default(false).notNull(), completedBoardTour: boolean().default(false).notNull(),
}); });
-1
View File
@@ -68,7 +68,6 @@ export const users = sqliteTable("user", {
colorScheme: text().$type<ColorScheme>().default("dark").notNull(), colorScheme: text().$type<ColorScheme>().default("dark").notNull(),
firstDayOfWeek: int().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday firstDayOfWeek: int().$type<DayOfWeek>().default(1).notNull(), // Defaults to Monday
pingIconsEnabled: int({ mode: "boolean" }).default(false).notNull(), pingIconsEnabled: int({ mode: "boolean" }).default(false).notNull(),
enableRightClickOnWidgets: int({ mode: "boolean" }).default(true).notNull(),
completedManageTour: int({ mode: "boolean" }).default(false).notNull(), completedManageTour: int({ mode: "boolean" }).default(false).notNull(),
completedBoardTour: int({ mode: "boolean" }).default(false).notNull(), completedBoardTour: int({ mode: "boolean" }).default(false).notNull(),
}); });
+1 -1
View File
@@ -37,5 +37,5 @@ describe("Mysql Migration", () => {
connection.end(); connection.end();
await mysqlContainer.stop(); await mysqlContainer.stop();
}, 120_000); }, 40_000);
}); });
+1
View File
@@ -467,6 +467,7 @@ export const integrationDefs = {
iconUrl: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/archiveteam-warrior.png", iconUrl: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/archiveteam-warrior.png",
category: ["archiving"], category: ["archiving"],
documentationUrl: null, documentationUrl: null,
defaultUrl: "http://localhost:8001",
}, },
// This integration only returns mock data, it is used during development (but can also be used in production by directly going to the create page) // This integration only returns mock data, it is used during development (but can also be used in production by directly going to the create page)
mock: { mock: {
+8 -31
View File
@@ -19,12 +19,6 @@ const createUrlByIdChannel = (id: string) =>
headers: `${string}.${string}`; headers: `${string}.${string}`;
}>(`image-proxy:url:${id}`); }>(`image-proxy:url:${id}`);
export type ForwardImageResult =
| { image: ArrayBuffer; contentType: string | null }
| { error: "not-found" }
| { error: "upstream-error"; statusCode: number }
| { error: "fetch-error" };
export class ImageProxy { export class ImageProxy {
private static hmacKey: Buffer<ArrayBuffer> | null = null; private static hmacKey: Buffer<ArrayBuffer> | null = null;
@@ -53,34 +47,17 @@ export class ImageProxy {
return this.createImageUrl(id); return this.createImageUrl(id);
} }
public async forwardImageAsync(id: string): Promise<ForwardImageResult> { public async forwardImageAsync(id: string): Promise<ArrayBuffer | null> {
const urlAndHeaders = await this.getImageUrlAndHeadersAsync(id); const urlAndHeaders = await this.getImageUrlAndHeadersAsync(id);
if (!urlAndHeaders) { if (!urlAndHeaders) {
return { error: "not-found" }; return null;
} }
const response = await fetchWithTrustedCertificatesAsync(urlAndHeaders.url, {
headers: urlAndHeaders.headers ?? {},
});
const proxyUrl = this.createImageUrl(id); const proxyUrl = this.createImageUrl(id);
let response: Awaited<ReturnType<typeof fetchWithTrustedCertificatesAsync>>;
try {
response = await fetchWithTrustedCertificatesAsync(urlAndHeaders.url, {
headers: urlAndHeaders.headers ?? {},
});
} catch (error) {
logger.error(
new ErrorWithMetadata(
"Failed to connect to image source",
{
id,
url: this.redactUrl(urlAndHeaders.url),
headers: this.redactHeaders(urlAndHeaders.headers),
proxyUrl,
},
{ cause: error },
),
);
return { error: "fetch-error" };
}
if (!response.ok) { if (!response.ok) {
logger.error( logger.error(
new ErrorWithMetadata("Failed to fetch image", { new ErrorWithMetadata("Failed to fetch image", {
@@ -91,7 +68,7 @@ export class ImageProxy {
statusCode: response.status, statusCode: response.status,
}), }),
); );
return { error: "upstream-error", statusCode: response.status }; return null;
} }
const arrayBuffer = await response.arrayBuffer(); const arrayBuffer = await response.arrayBuffer();
@@ -103,7 +80,7 @@ export class ImageProxy {
size: `${(arrayBuffer.byteLength / 1024).toFixed(1)}KB`, size: `${(arrayBuffer.byteLength / 1024).toFixed(1)}KB`,
}); });
return { image: arrayBuffer, contentType: response.headers.get("content-type") }; return arrayBuffer;
} }
private createImageUrl(id: string): string { private createImageUrl(id: string): string {
@@ -1,7 +1,6 @@
import { ResponseError } from "@homarr/common/server"; import { ResponseError } from "@homarr/common/server";
import { createLogger } from "@homarr/core/infrastructure/logs"; import { createLogger } from "@homarr/core/infrastructure/logs";
import { createCertificateAgentAsync, fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http"; import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
import type { Response as UndiciResponse } from "undici";
import type { IntegrationInput, IntegrationTestingInput } from "../base/integration"; import type { IntegrationInput, IntegrationTestingInput } from "../base/integration";
import { Integration } from "../base/integration"; import { Integration } from "../base/integration";
@@ -358,41 +357,19 @@ export class BeszelIntegration extends Integration {
let emittedSnapshotCount = 0; let emittedSnapshotCount = 0;
while (!signal.aborted) { while (!signal.aborted) {
let streamResponse: UndiciResponse | undefined;
let streamAgent: Awaited<ReturnType<typeof createCertificateAgentAsync>> | undefined;
const closeStreamAsync = async () => {
const response = streamResponse;
streamResponse = undefined;
const agent = streamAgent;
streamAgent = undefined;
if (response?.body) await response.body.cancel().catch(() => {});
if (agent) await agent.close().catch(() => {});
};
try { try {
let session = await this.authenticateAsync(); let session = await this.authenticateAsync();
const openStream = async () => { const openStream = async () =>
streamAgent = await createCertificateAgentAsync(undefined, { bodyTimeout: 0 }); await fetchWithTrustedCertificatesAsync(realtimeUrl, {
try { headers: {
const response = await fetchWithTrustedCertificatesAsync(realtimeUrl, { Accept: "text/event-stream",
headers: { Authorization: session.token,
Accept: "text/event-stream", "Cache-Control": "no-cache",
Authorization: session.token, Pragma: "no-cache",
"Cache-Control": "no-cache", },
Pragma: "no-cache", signal,
}, bodyTimeout: 0,
signal, });
bodyTimeout: 0,
dispatcher: streamAgent,
});
streamResponse = response;
return response;
} catch (error) {
await closeStreamAsync();
throw error;
}
};
logger.debug("Opening Beszel rt_metrics SSE connection", { logger.debug("Opening Beszel rt_metrics SSE connection", {
integrationId: this.integration.id, integrationId: this.integration.id,
@@ -401,7 +378,6 @@ export class BeszelIntegration extends Integration {
}); });
let response = await openStream(); let response = await openStream();
if (response.status === 401) { if (response.status === 401) {
await closeStreamAsync();
await this.sessionStore.clearAsync(); await this.sessionStore.clearAsync();
session = await this.authenticateAsync(); session = await this.authenticateAsync();
response = await openStream(); response = await openStream();
@@ -426,21 +402,14 @@ export class BeszelIntegration extends Integration {
clientId = frame.id || fallbackClientId; clientId = frame.id || fallbackClientId;
if (!clientId) throw new Error("PocketBase PB_CONNECT event did not include a client ID"); if (!clientId) throw new Error("PocketBase PB_CONNECT event did not include a client ID");
if (!streamAgent) throw new Error("Beszel realtime stream agent is not available");
const subscribeResponse = await fetchWithTrustedCertificatesAsync(realtimeUrl, { const subscribeResponse = await fetchWithTrustedCertificatesAsync(realtimeUrl, {
method: "POST", method: "POST",
headers: { Authorization: session.token, "Content-Type": "application/json" }, headers: { Authorization: session.token, "Content-Type": "application/json" },
body: JSON.stringify({ clientId, subscriptions: [topic] }), body: JSON.stringify({ clientId, subscriptions: [topic] }),
signal, signal,
dispatcher: streamAgent,
}); });
try { if (subscribeResponse.status === 401) await this.sessionStore.clearAsync();
if (subscribeResponse.status === 401) await this.sessionStore.clearAsync(); if (!subscribeResponse.ok) throw new ResponseError(subscribeResponse);
if (!subscribeResponse.ok) throw new ResponseError(subscribeResponse);
await subscribeResponse.arrayBuffer();
} finally {
if (subscribeResponse.body) await subscribeResponse.body.cancel().catch(() => {});
}
logger.debug("Subscribed to Beszel rt_metrics topic", { logger.debug("Subscribed to Beszel rt_metrics topic", {
integrationId: this.integration.id, integrationId: this.integration.id,
systemId, systemId,
@@ -492,12 +461,10 @@ export class BeszelIntegration extends Integration {
} finally { } finally {
await reader.cancel().catch(() => {}); await reader.cancel().catch(() => {});
reader.releaseLock(); reader.releaseLock();
await closeStreamAsync();
} }
if (!signal.aborted) throw new Error("Beszel rt_metrics SSE stream ended unexpectedly"); if (!signal.aborted) throw new Error("Beszel rt_metrics SSE stream ended unexpectedly");
} catch (error) { } catch (error) {
await closeStreamAsync();
if (signal.aborted) break; if (signal.aborted) break;
if (error instanceof ResponseError && error.statusCode === 401 && retryAttempt === 0) { if (error instanceof ResponseError && error.statusCode === 401 && retryAttempt === 0) {
retryAttempt += 1; retryAttempt += 1;
@@ -10,7 +10,6 @@ vi.hoisted(() => {
const BESZEL_URL = process.env.BESZEL_TEST_URL ?? "http://localhost:8090"; const BESZEL_URL = process.env.BESZEL_TEST_URL ?? "http://localhost:8090";
const BESZEL_EMAIL = process.env.BESZEL_TEST_EMAIL ?? ""; const BESZEL_EMAIL = process.env.BESZEL_TEST_EMAIL ?? "";
const BESZEL_PASSWORD = process.env.BESZEL_TEST_PASSWORD ?? ""; const BESZEL_PASSWORD = process.env.BESZEL_TEST_PASSWORD ?? "";
const closeAgent = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
vi.mock("@homarr/redis", () => ({ vi.mock("@homarr/redis", () => ({
createGetSetChannel: () => ({ createGetSetChannel: () => ({
@@ -33,7 +32,7 @@ vi.mock("@homarr/core/infrastructure/logs", () => ({
vi.mock("@homarr/core/infrastructure/http", () => ({ vi.mock("@homarr/core/infrastructure/http", () => ({
fetchWithTrustedCertificatesAsync: (url: URL | string, init?: RequestInit) => fetch(url, init), fetchWithTrustedCertificatesAsync: (url: URL | string, init?: RequestInit) => fetch(url, init),
createAxiosCertificateInstanceAsync: vi.fn().mockResolvedValue({}), createAxiosCertificateInstanceAsync: vi.fn().mockResolvedValue({}),
createCertificateAgentAsync: vi.fn().mockResolvedValue({ close: closeAgent }), createCertificateAgentAsync: vi.fn().mockResolvedValue(undefined),
})); }));
vi.mock("@homarr/core/infrastructure/certificates", () => ({ vi.mock("@homarr/core/infrastructure/certificates", () => ({
@@ -154,7 +153,6 @@ describe("subscribeRealtimeMetrics", () => {
expect(subscriptionBodies).toEqual([{ clientId: "client-1", subscriptions: [topic] }]); expect(subscriptionBodies).toEqual([{ clientId: "client-1", subscriptions: [topic] }]);
expect(events.map((event) => event.type)).toEqual(["system_stats", "container_stats"]); expect(events.map((event) => event.type)).toEqual(["system_stats", "container_stats"]);
expect(closeAgent).toHaveBeenCalled();
} finally { } finally {
globalThis.fetch = originalFetch; globalThis.fetch = originalFetch;
} }
@@ -117,12 +117,6 @@ export class EmbyIntegration extends Integration implements IMediaServerIntegrat
episodeName: sessionInfo.NowPlayingItem.EpisodeTitle, episodeName: sessionInfo.NowPlayingItem.EpisodeTitle,
albumName: sessionInfo.NowPlayingItem.Album ?? "", albumName: sessionInfo.NowPlayingItem.Album ?? "",
episodeCount: sessionInfo.NowPlayingItem.EpisodeCount, episodeCount: sessionInfo.NowPlayingItem.EpisodeCount,
playback: {
state: null,
positionMs: null,
durationMs: null,
},
location: null,
metadata: null, metadata: null,
}; };
} }
@@ -1,14 +1,10 @@
import { import {
AssetMediaSize,
AssetTypeEnum,
AssetVisibility,
getAlbumInfo, getAlbumInfo,
getAllAlbums, getAllAlbums,
getMyUser, getMyUser,
getServerStatistics, getServerStatistics,
init, init,
searchAssets, searchAssets,
searchRandom,
searchUsers, searchUsers,
} from "@immich/sdk"; } from "@immich/sdk";
import type { AssetResponseDto, MetadataSearchDto } from "@immich/sdk"; import type { AssetResponseDto, MetadataSearchDto } from "@immich/sdk";
@@ -46,7 +42,6 @@ export interface ImmichAsset {
} }
const logger = createLogger({ module: "immich-integration" }); const logger = createLogger({ module: "immich-integration" });
const randomPhotoCount = 50;
export class ImmichIntegration extends Integration { export class ImmichIntegration extends Integration {
constructor(integration: IntegrationInput) { constructor(integration: IntegrationInput) {
@@ -67,36 +62,36 @@ export class ImmichIntegration extends Integration {
}; };
} }
public async getAlbumAsync(albumId?: string): Promise<ImmichAlbum> { public async getAlbumAsync(albumId: string): Promise<ImmichAlbum> {
this.initClient(); this.initClient();
const requestOptions = this.getRequestOptions(); const requestOptions = this.getRequestOptions();
if (!albumId) {
const assets = await searchRandom(
{
randomSearchDto: {
size: randomPhotoCount,
type: AssetTypeEnum.Image,
visibility: AssetVisibility.Timeline,
},
},
requestOptions,
);
return {
id: "",
albumName: "",
assets: await this.createAssetsAsync(assets),
};
}
const [album, albumAssets] = await Promise.all([ const [album, albumAssets] = await Promise.all([
getAlbumInfo({ id: albumId }, requestOptions), getAlbumInfo({ id: albumId }, requestOptions),
this.searchAlbumAssetsAsync(albumId), this.searchAlbumAssetsAsync(albumId),
]); ]);
const imageProxy = new ImageProxy();
return { return {
albumName: album.albumName, albumName: album.albumName,
assets: await this.createAssetsAsync(albumAssets), assets: await Promise.all(
albumAssets.map(async (asset) => {
const publicLink = await imageProxy.createImageAsync(
this.url(`/api/assets/${asset.id}/original`).toString(),
{
"x-api-key": this.getSecretValue("apiKey"),
},
);
return {
id: asset.id,
type: asset.type,
thumbhash: asset.thumbhash,
fileCreatedAt: asset.fileCreatedAt,
fileModifiedAt: asset.fileModifiedAt,
originalPath: asset.originalPath,
updatedAt: asset.updatedAt,
publicLink,
};
}),
),
id: album.id, id: album.id,
}; };
} }
@@ -138,32 +133,6 @@ export class ImmichIntegration extends Integration {
return assets; return assets;
} }
private async createAssetsAsync(assets: AssetResponseDto[]): Promise<ImmichAsset[]> {
const imageProxy = new ImageProxy();
return await Promise.all(
assets.map(async (asset) => {
const publicLink = await imageProxy.createImageAsync(
// This is the URL generated by the SDK's viewAsset call. Preview images are
// browser-compatible while avoiding the large original asset download.
this.url(`/api/assets/${asset.id}/thumbnail`, { size: AssetMediaSize.Preview }).toString(),
{
"x-api-key": this.getSecretValue("apiKey"),
},
);
return {
id: asset.id,
type: asset.type,
thumbhash: asset.thumbhash,
fileCreatedAt: asset.fileCreatedAt,
fileModifiedAt: asset.fileModifiedAt,
originalPath: asset.originalPath,
updatedAt: asset.updatedAt,
publicLink,
};
}),
);
}
private getRequestOptions(fetchAsync = fetchWithTrustedCertificatesAsync) { private getRequestOptions(fetchAsync = fetchWithTrustedCertificatesAsync) {
return { return {
// Undici and node types are not the same // Undici and node types are not the same
@@ -13,12 +13,6 @@ export interface StreamSession {
episodeName?: string | null; episodeName?: string | null;
albumName?: string | null; albumName?: string | null;
episodeCount?: number | null; episodeCount?: number | null;
playback: {
state: "playing" | "paused" | "buffering" | null;
positionMs: number | null;
durationMs: number | null;
};
location: "lan" | "wan" | null;
metadata: { metadata: {
video: { video: {
resolution: { resolution: {
@@ -17,10 +17,6 @@ import type { IMediaServerIntegration } from "../interfaces/media-server/media-s
import type { CurrentSessionsInput, StreamSession } from "../interfaces/media-server/media-server-types"; import type { CurrentSessionsInput, StreamSession } from "../interfaces/media-server/media-server-types";
import type { IMediaReleasesIntegration, MediaRelease, MediaType } from "../types"; import type { IMediaReleasesIntegration, MediaRelease, MediaType } from "../types";
function ticksToMs(ticks: number | null | undefined): number | null {
return ticks ? Math.round(ticks / 10_000) : null;
}
@HandleIntegrationErrors([integrationAxiosHttpErrorHandler]) @HandleIntegrationErrors([integrationAxiosHttpErrorHandler])
export class JellyfinIntegration extends Integration implements IMediaServerIntegration, IMediaReleasesIntegration { export class JellyfinIntegration extends Integration implements IMediaServerIntegration, IMediaReleasesIntegration {
private readonly jellyfin: Jellyfin = new Jellyfin({ private readonly jellyfin: Jellyfin = new Jellyfin({
@@ -54,9 +50,6 @@ export class JellyfinIntegration extends Integration implements IMediaServerInte
let currentlyPlaying: StreamSession["currentlyPlaying"] | null = null; let currentlyPlaying: StreamSession["currentlyPlaying"] | null = null;
if (sessionInfo.NowPlayingItem) { if (sessionInfo.NowPlayingItem) {
const positionMs = ticksToMs(sessionInfo.PlayState?.PositionTicks);
const durationMs = ticksToMs(sessionInfo.NowPlayingItem.RunTimeTicks);
currentlyPlaying = { currentlyPlaying = {
type: convertJellyfinType(sessionInfo.NowPlayingItem.Type), type: convertJellyfinType(sessionInfo.NowPlayingItem.Type),
name: sessionInfo.NowPlayingItem.SeriesName ?? sessionInfo.NowPlayingItem.Name ?? "", name: sessionInfo.NowPlayingItem.SeriesName ?? sessionInfo.NowPlayingItem.Name ?? "",
@@ -64,12 +57,6 @@ export class JellyfinIntegration extends Integration implements IMediaServerInte
episodeName: sessionInfo.NowPlayingItem.EpisodeTitle, episodeName: sessionInfo.NowPlayingItem.EpisodeTitle,
albumName: sessionInfo.NowPlayingItem.Album ?? "", albumName: sessionInfo.NowPlayingItem.Album ?? "",
episodeCount: sessionInfo.NowPlayingItem.EpisodeCount, episodeCount: sessionInfo.NowPlayingItem.EpisodeCount,
playback: {
state: sessionInfo.PlayState?.IsPaused ? "paused" : "playing",
positionMs,
durationMs,
},
location: null,
metadata: { metadata: {
video: { video: {
resolution: resolution:
@@ -13,8 +13,6 @@ const sessions: StreamSession[] = [
episodeName: null, episodeName: null,
albumName: null, albumName: null,
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -29,8 +27,6 @@ const sessions: StreamSession[] = [
episodeName: "Ozymandias", episodeName: "Ozymandias",
albumName: null, albumName: null,
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -45,8 +41,6 @@ const sessions: StreamSession[] = [
episodeName: null, episodeName: null,
albumName: null, albumName: null,
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -61,8 +55,6 @@ const sessions: StreamSession[] = [
episodeName: "The We We Are", episodeName: "The We We Are",
albumName: null, albumName: null,
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -77,8 +69,6 @@ const sessions: StreamSession[] = [
episodeName: null, episodeName: null,
albumName: "Random Access Memories", albumName: "Random Access Memories",
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -93,8 +83,6 @@ const sessions: StreamSession[] = [
episodeName: null, episodeName: null,
albumName: null, albumName: null,
episodeCount: null, episodeCount: null,
playback: { state: null, positionMs: null, durationMs: null },
location: null,
metadata: null, metadata: null,
}, },
}, },
@@ -153,9 +153,9 @@ export class OverseerrIntegration
); );
} else if (pendingResults.length > 0) requests = pendingResults; } else if (pendingResults.length > 0) requests = pendingResults;
else if (allResults.length > 0) requests = allResults; else if (allResults.length > 0) requests = allResults;
else return []; else return Promise.all([]);
const settled = await Promise.allSettled( return await Promise.all(
requests.map(async (request): Promise<MediaRequest> => { requests.map(async (request): Promise<MediaRequest> => {
const information = await this.getItemInformationAsync(request.media.tmdbId, request.type); const information = await this.getItemInformationAsync(request.media.tmdbId, request.type);
@@ -184,10 +184,6 @@ export class OverseerrIntegration
}; };
}), }),
); );
return settled
.filter((result): result is PromiseFulfilledResult<MediaRequest> => result.status === "fulfilled")
.map((result) => result.value);
} }
protected mapRequestStatus(status: UpstreamMediaRequestStatus): MediaRequestStatus { protected mapRequestStatus(status: UpstreamMediaRequestStatus): MediaRequestStatus {
@@ -305,10 +301,6 @@ export class OverseerrIntegration
}, },
}); });
if (!response.ok) {
throw new Error(`Failed to fetch ${type} information for id ${id}: ${response.status} ${response.statusText}`);
}
if (type === "tv") { if (type === "tv") {
const series = (await response.json()) as TvInformation; const series = (await response.json()) as TvInformation;
return { return {
@@ -3,54 +3,6 @@ interface MediaContainer {
Track?: Session[]; Track?: Session[];
} }
interface Stream {
$: {
streamType: string;
codec?: string;
language?: string;
selected?: string;
width?: string;
height?: string;
frameRate?: string;
channels?: string;
};
}
interface Part {
Stream?: Stream[];
$: {
container?: string;
};
}
interface Media {
Part?: Part[];
$: {
videoResolution?: string;
videoCodec?: string;
audioCodec?: string;
bitrate?: string;
container?: string;
};
}
interface TranscodeSession {
$: {
throttled?: string;
progress?: string;
speed?: string;
videoDecision?: string;
audioDecision?: string;
sourceVideoCodec?: string;
sourceAudioCodec?: string;
videoCodec?: string;
audioCodec?: string;
container?: string;
width?: string;
height?: string;
};
}
interface Session { interface Session {
User?: { User?: {
$: { $: {
@@ -63,20 +15,13 @@ interface Session {
$: { $: {
product: string; product: string;
title: string; title: string;
address?: string;
state?: string;
local?: string;
}; };
}[]; }[];
Session?: { Session?: {
$: { $: {
id: string; id: string;
bandwidth?: string;
location?: string;
}; };
}[]; }[];
TranscodeSession?: TranscodeSession[];
Media?: Media[];
$: { $: {
grandparentTitle?: string; grandparentTitle?: string;
parentTitle?: string; parentTitle?: string;
@@ -84,8 +29,6 @@ interface Session {
index?: number; index?: number;
type: string; type: string;
live?: string; live?: string;
viewOffset?: string;
duration?: string;
}; };
} }
@@ -17,32 +17,6 @@ import type { PlexResponse } from "./interface";
const logger = createLogger({ module: "plexIntegration" }); const logger = createLogger({ module: "plexIntegration" });
function parseOptionalNumber(value: string | undefined): number | null {
if (!value) {
return null;
}
const parsed = Number(value);
return Number.isNaN(parsed) ? null : parsed;
}
function parseLocation(value: string | undefined): "lan" | "wan" | null {
return value === "lan" || value === "wan" ? value : null;
}
function parsePlaybackState(value: string | undefined): "playing" | "paused" | "buffering" | null {
return value === "playing" || value === "paused" || value === "buffering" ? value : null;
}
function parseResolution(
width: string | undefined,
height: string | undefined,
): { width: number; height: number } | null {
const parsedWidth = parseOptionalNumber(width);
const parsedHeight = parseOptionalNumber(height);
return parsedWidth !== null && parsedHeight !== null ? { width: parsedWidth, height: parsedHeight } : null;
}
export class PlexIntegration extends Integration implements IMediaServerIntegration, IMediaReleasesIntegration { export class PlexIntegration extends Integration implements IMediaServerIntegration, IMediaReleasesIntegration {
public async getCurrentSessionsAsync(_options: CurrentSessionsInput): Promise<StreamSession[]> { public async getCurrentSessionsAsync(_options: CurrentSessionsInput): Promise<StreamSession[]> {
const token = super.getSecretValue("apiKey"); const token = super.getSecretValue("apiKey");
@@ -69,24 +43,11 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat
const userElement = mediaElement.User ? mediaElement.User[0] : undefined; const userElement = mediaElement.User ? mediaElement.User[0] : undefined;
const playerElement = mediaElement.Player ? mediaElement.Player[0] : undefined; const playerElement = mediaElement.Player ? mediaElement.Player[0] : undefined;
const sessionElement = mediaElement.Session ? mediaElement.Session[0] : undefined; const sessionElement = mediaElement.Session ? mediaElement.Session[0] : undefined;
const transcodeElement = mediaElement.TranscodeSession ? mediaElement.TranscodeSession[0] : undefined;
const mediaInfoElement = mediaElement.Media ? mediaElement.Media[0] : undefined;
if (!playerElement) { if (!playerElement) {
return undefined; return undefined;
} }
const positionMs = parseOptionalNumber(mediaElement.$.viewOffset);
const durationMs = parseOptionalNumber(mediaElement.$.duration);
const playbackState = parsePlaybackState(playerElement.$.state);
const location = parseLocation(sessionElement?.$.location);
const streams = mediaInfoElement?.Part?.[0]?.Stream ?? [];
const videoStream = streams.find((stream) => stream.$.streamType === "1");
const audioStream = streams.find((stream) => stream.$.streamType === "2");
return { return {
sessionId: sessionElement?.$.id ?? "unknown", sessionId: sessionElement?.$.id ?? "unknown",
sessionName: `${playerElement.$.product} (${playerElement.$.title})`, sessionName: `${playerElement.$.product} (${playerElement.$.title})`,
@@ -102,30 +63,7 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat
episodeName: mediaElement.$.title ?? null, episodeName: mediaElement.$.title ?? null,
albumName: mediaElement.$.type === "track" ? (mediaElement.$.parentTitle ?? null) : null, albumName: mediaElement.$.type === "track" ? (mediaElement.$.parentTitle ?? null) : null,
episodeCount: mediaElement.$.index ?? null, episodeCount: mediaElement.$.index ?? null,
playback: { metadata: null,
state: playbackState,
positionMs,
durationMs,
},
location,
metadata: {
video: {
resolution: parseResolution(videoStream?.$.width, videoStream?.$.height),
frameRate: parseOptionalNumber(videoStream?.$.frameRate),
},
audio: {
channelCount: parseOptionalNumber(audioStream?.$.channels),
codec: audioStream?.$.codec ?? mediaInfoElement?.$.audioCodec ?? null,
},
transcoding: {
container: transcodeElement?.$.container ?? null,
resolution: parseResolution(transcodeElement?.$.width, transcodeElement?.$.height),
target: {
audioCodec: transcodeElement?.$.audioCodec ?? null,
videoCodec: transcodeElement?.$.videoCodec ?? null,
},
},
},
}, },
}; };
}) })
@@ -23,8 +23,6 @@ type OptionMapping = {
const optionMapping: OptionMapping = { const optionMapping: OptionMapping = {
"mediaRequests-requestList": { "mediaRequests-requestList": {
linksTargetNewTab: (oldOptions) => oldOptions.openInNewTab, linksTargetNewTab: (oldOptions) => oldOptions.openInNewTab,
statusFilter: () => undefined,
recentDays: () => undefined,
}, },
"mediaRequests-requestStats": {}, "mediaRequests-requestStats": {},
bookmarks: { bookmarks: {
@@ -65,9 +63,6 @@ const optionMapping: OptionMapping = {
useCustomTimezone: () => true, useCustomTimezone: () => true,
customTimeFormat: () => undefined, customTimeFormat: () => undefined,
customDateFormat: () => undefined, customDateFormat: () => undefined,
showWeather: () => undefined,
weatherLocation: () => undefined,
isWeatherFormatFahrenheit: () => undefined,
}, },
downloads: { downloads: {
activeTorrentThreshold: (oldOptions) => activeTorrentThreshold: (oldOptions) =>
+17 -4
View File
@@ -300,7 +300,10 @@ async function getContainersWithStatsAsync() {
const stats = await instance const stats = await instance
.getContainer(container.Id) .getContainer(container.Id)
.stats({ stream: false, "one-shot": true }) // Not in one-shot mode: the daemon then includes precpu_stats (the
// previous reading), which is required to compute the current CPU usage
// as a delta. One-shot omits it and would only expose lifetime totals.
.stats({ stream: false })
.catch( .catch(
() => () =>
({ ({
@@ -336,12 +339,22 @@ export function calculateCpuUsage(stats: ContainerStats): number {
} }
const numberOfCpus = stats.cpu_stats.online_cpus; const numberOfCpus = stats.cpu_stats.online_cpus;
const usage = stats.cpu_stats.system_cpu_usage;
if (!usage || usage === 0) { // Docker's own formula for the current (instantaneous) CPU usage: it compares
// the latest reading against the previous one (precpu_stats). Dividing the
// cumulative total_usage by the cumulative system_cpu_usage instead would
// report the container's lifetime average, which stays high long after a load
// spike has ended. precpu_stats is only present when the stats are NOT fetched
// in one-shot mode; when it is absent (e.g. Podman) the deltas fall back to the
// cumulative totals, matching the previous behaviour.
const cpuDelta = stats.cpu_stats.cpu_usage.total_usage - (stats.precpu_stats?.cpu_usage?.total_usage ?? 0);
const systemDelta = (stats.cpu_stats.system_cpu_usage ?? 0) - (stats.precpu_stats?.system_cpu_usage ?? 0);
if (systemDelta <= 0 || cpuDelta < 0) {
return 0; return 0;
} }
return (stats.cpu_stats.cpu_usage.total_usage / usage) * numberOfCpus * 100; return (cpuDelta / systemDelta) * numberOfCpus * 100;
} }
export function calculateMemoryUsage(stats: ContainerStats): number { export function calculateMemoryUsage(stats: ContainerStats): number {
+1 -1
View File
@@ -33,7 +33,7 @@ export const immichAlbumsRequestHandler = createIntegrationRequestHandler<
export const immichAlbumRequestHandler = createIntegrationRequestHandler< export const immichAlbumRequestHandler = createIntegrationRequestHandler<
ImmichAlbum, ImmichAlbum,
IntegrationKindByCategory<"photoService">, IntegrationKindByCategory<"photoService">,
{ albumId?: string } { albumId: string }
>({ >({
async requestAsync(integration, input) { async requestAsync(integration, input) {
const integrationInstance = await createIntegrationAsync(integration); const integrationInstance = await createIntegrationAsync(integration);
@@ -13,7 +13,6 @@ type IntegrationOfKind<TKind extends IntegrationKind> = Omit<Integration, "kind"
interface Options<TData, TKind extends IntegrationKind, TInput extends Record<string, unknown>> { interface Options<TData, TKind extends IntegrationKind, TInput extends Record<string, unknown>> {
requestAsync: (integration: IntegrationOfKind<TKind>, input: TInput) => Promise<TData>; requestAsync: (integration: IntegrationOfKind<TKind>, input: TInput) => Promise<TData>;
cacheTtlMs?: number; cacheTtlMs?: number;
fallbackToStaleOnError?: boolean;
} }
export const createIntegrationRequestHandler = < export const createIntegrationRequestHandler = <
@@ -33,7 +32,6 @@ export const createIntegrationRequestHandler = <
return options.requestAsync(integration, input.options); return options.requestAsync(integration, input.options);
}, },
cacheTtlMs: options.cacheTtlMs, cacheTtlMs: options.cacheTtlMs,
fallbackToStaleOnError: options.fallbackToStaleOnError,
}); });
return { return {
@@ -1,7 +1,6 @@
interface Options<TData, TInput extends Record<string, unknown>> { interface Options<TData, TInput extends Record<string, unknown>> {
requestAsync: (input: TInput) => Promise<TData>; requestAsync: (input: TInput) => Promise<TData>;
cacheTtlMs?: number; cacheTtlMs?: number;
fallbackToStaleOnError?: boolean;
} }
type CacheEntry<TData> = { data: TData; timestamp: Date; expiresAt: number }; type CacheEntry<TData> = { data: TData; timestamp: Date; expiresAt: number };
@@ -36,6 +35,7 @@ export const createRequestHandler = <TData, TInput extends Record<string, unknow
if (cached && Date.now() < cached.expiresAt) { if (cached && Date.now() < cached.expiresAt) {
return { data: cached.data, timestamp: cached.timestamp }; return { data: cached.data, timestamp: cached.timestamp };
} }
if (cached) cache.delete(key);
const existing = inflight.get(key); const existing = inflight.get(key);
if (existing) return existing; if (existing) return existing;
@@ -55,9 +55,6 @@ export const createRequestHandler = <TData, TInput extends Record<string, unknow
}) })
.catch((err) => { .catch((err) => {
inflight.delete(key); inflight.delete(key);
if (options.fallbackToStaleOnError && cached) {
return cached;
}
throw err; throw err;
}); });
@@ -1,44 +1,16 @@
import { z } from "zod/v4";
import type { IntegrationKindByCategory } from "@homarr/definitions"; import type { IntegrationKindByCategory } from "@homarr/definitions";
import { createIntegrationAsync } from "@homarr/integrations"; import { createIntegrationAsync } from "@homarr/integrations";
import type { MediaRequest, MediaRequestStatus } from "@homarr/integrations/types"; import type { MediaRequest } from "@homarr/integrations/types";
import { createIntegrationRequestHandler } from "./lib/integration-request-handler"; import { createIntegrationRequestHandler } from "./lib/integration-request-handler";
const mediaRequestStatusValues = [
"pending",
"approved",
"declined",
"failed",
"completed",
] as const satisfies readonly MediaRequestStatus[];
const MS_PER_DAY = 24 * 60 * 60 * 1000;
export const mediaRequestListInputSchema = z.object({
statuses: z.array(z.enum(mediaRequestStatusValues)).nonempty(),
recentDays: z.number().min(0).max(365),
});
export type MediaRequestListInput = z.infer<typeof mediaRequestListInputSchema>;
export const mediaRequestListRequestHandler = createIntegrationRequestHandler< export const mediaRequestListRequestHandler = createIntegrationRequestHandler<
MediaRequest[], MediaRequest[],
IntegrationKindByCategory<"mediaRequest">, IntegrationKindByCategory<"mediaRequest">,
MediaRequestListInput Record<string, never>
>({ >({
async requestAsync(integration, input) { async requestAsync(integration, _input) {
const integrationInstance = await createIntegrationAsync(integration); const integrationInstance = await createIntegrationAsync(integration);
const requests = await integrationInstance.getRequestsAsync(); return await integrationInstance.getRequestsAsync();
const cutoff = input.recentDays > 0 ? Date.now() - input.recentDays * MS_PER_DAY : null;
const statusSet = new Set<MediaRequestStatus>(input.statuses);
return requests.filter((request) => {
if (!statusSet.has(request.status)) return false;
if (cutoff !== null && request.createdAt.getTime() < cutoff) return false;
return true;
});
}, },
cacheTtlMs: 60_000,
fallbackToStaleOnError: true,
}); });
@@ -16,6 +16,4 @@ export const mediaRequestStatsRequestHandler = createIntegrationRequestHandler<
users: await integrationInstance.getUsersAsync(), users: await integrationInstance.getUsersAsync(),
}; };
}, },
cacheTtlMs: 60_000,
fallbackToStaleOnError: true,
}); });
@@ -134,33 +134,7 @@ const getGithubApi = (baseUrl: string, userAgent: string, token?: string) =>
baseUrl, baseUrl,
auth: token, auth: token,
request: { fetch: fetchWithTrustedCertificatesAsync }, request: { fetch: fetchWithTrustedCertificatesAsync },
throttle: { throttle: { enabled: true },
enabled: true,
onRateLimit: (
retryAfter: number,
options: { url?: string; method?: string },
_octokit: unknown,
retryCount: number,
) => {
logger.warn(`GitHub rate limit exceeded, retrying after ${retryAfter}s (attempt ${retryCount + 1})`, {
url: options.url,
method: options.method,
});
return retryCount < 1;
},
onSecondaryRateLimit: (
retryAfter: number,
options: { url?: string; method?: string },
_octokit: unknown,
retryCount: number,
) => {
logger.warn(`GitHub secondary rate limit exceeded, retrying after ${retryAfter}s (attempt ${retryCount + 1})`, {
url: options.url,
method: options.method,
});
return retryCount < 1;
},
},
userAgent, userAgent,
}); });
@@ -745,19 +719,6 @@ const linuxServerIOReleasesSchema = z.object({
}), }),
}); });
// Parse a github.com project URL (as returned by the LSIO registry) into an
// "owner/repo" identifier, or null if it is not a github.com repository URL.
const parseGithubRepo = (url: string): string | null => {
try {
const parsed = new URL(url);
if (parsed.hostname !== "github.com") return null;
const [owner, repo] = parsed.pathname.replace(/^\/+/, "").split("/");
return owner && repo ? `${owner}/${repo}` : null;
} catch {
return null;
}
};
const getLinuxServerIOReleaseAsync = async ( const getLinuxServerIOReleaseAsync = async (
baseUrl: string, baseUrl: string,
identifier: string, identifier: string,
@@ -795,50 +756,27 @@ const getLinuxServerIOReleaseAsync = async (
}; };
} }
if (!regex || regex.test(release.version)) { if (regex && !regex.test(release.version)) {
return { return {
success: true, success: false,
data: { error: {
latestRelease: release.version, code: "noMatchingVersion",
latestReleaseAt: release.version_timestamp, message: `Regex /${versionRegex}/ does not match LSIO version "${release.version}"`,
releaseDescription: release.changelog?.shift()?.desc,
projectUrl: release.github_url,
projectDescription: release.description,
isArchived: release.deprecated,
createdAt: release.initial_date,
starsCount: release.stars,
}, },
}; };
} }
// LSIO's /api/v1/images only exposes the single latest version, so a filter
// that does not match it cannot surface an older release (#4351). Delegate to
// the image's GitHub repository to fetch the real release history while
// keeping LSIO's own image metadata.
const githubRepo = parseGithubRepo(release.github_url);
if (githubRepo) {
const githubResult = await getGithubReleaseAsync(getReleaseProviderDefaultUrl("github"), githubRepo, versionRegex);
if (githubResult.success) {
return {
success: true,
data: {
...githubResult.data,
projectUrl: release.github_url,
projectDescription: release.description,
isArchived: release.deprecated,
starsCount: release.stars,
createdAt: release.initial_date ?? githubResult.data.createdAt,
},
};
}
return githubResult;
}
return { return {
success: false, success: true,
error: { data: {
code: "noMatchingVersion", latestRelease: release.version,
message: `Regex /${versionRegex}/ does not match LSIO version "${release.version}"`, latestReleaseAt: release.version_timestamp,
releaseDescription: release.changelog?.shift()?.desc,
projectUrl: release.github_url,
projectDescription: release.description,
isArchived: release.deprecated,
createdAt: release.initial_date,
starsCount: release.stars,
}, },
}; };
}; };
@@ -75,6 +75,26 @@ describe("calculateCpuUsage", () => {
// (500 / 100000) * 2 * 100 = 1 // (500 / 100000) * 2 * 100 = 1
expect(calculateCpuUsage(stats)).toBe(1); expect(calculateCpuUsage(stats)).toBe(1);
}); });
test("should use the delta against precpu_stats for the current usage", () => {
const stats = createStats({
cpu_stats: { online_cpus: 4, cpu_usage: { total_usage: 1_002_000 }, system_cpu_usage: 20_000 },
precpu_stats: { cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 10_000 },
});
// Despite a large lifetime total_usage, only the recent delta counts:
// (2000 / 10000) * 4 * 100 = 80
expect(calculateCpuUsage(stats)).toBe(80);
});
test("should report 0 for a container that was busy over its lifetime but is idle now", () => {
const stats = createStats({
cpu_stats: { online_cpus: 4, cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 20_000 },
precpu_stats: { cpu_usage: { total_usage: 1_000_000 }, system_cpu_usage: 10_000 },
});
// No CPU delta since the last reading -> current usage is 0, even though the
// lifetime average would be high. This is the regression the fix addresses.
expect(calculateCpuUsage(stats)).toBe(0);
});
}); });
describe("calculateMemoryUsage", () => { describe("calculateMemoryUsage", () => {
@@ -126,128 +126,6 @@ describe("getLatestMatchingReleaseAsync for GitHub Container Registry", () => {
}); });
}); });
describe("getLatestMatchingReleaseAsync for LinuxServer.io", () => {
beforeEach(() => {
mockedFetch.mockReset();
});
test("uses the LinuxServer.io latest release without fetching GitHub history", async () => {
mockedFetch.mockResolvedValueOnce(createLinuxServerResponse());
const result = await getLatestMatchingReleaseAsync({
id: "tautulli",
provider: "linuxServerIO",
identifier: "lscr.io/linuxserver/tautulli:latest",
});
expect(result).toEqual({
success: true,
data: {
latestRelease: "v2.17.2-ls237",
latestReleaseAt: new Date("2026-07-17T00:25:42.000Z"),
releaseDescription: "Rebase to Alpine 3.24.",
projectUrl: "https://github.com/linuxserver/docker-tautulli",
projectDescription: "Tautulli image",
isArchived: false,
createdAt: new Date("2015-08-10T00:00:00.000Z"),
starsCount: 934,
},
});
expect(mockedFetch).toHaveBeenCalledOnce();
expectUrl(0, "https://api.linuxserver.io/api/v1/images");
});
test("fetches GitHub history when a version filter requires it", async () => {
mockedFetch.mockImplementation(async (input) => {
const url = new URL(input.toString());
if (url.origin === "https://api.linuxserver.io") return createLinuxServerResponse();
if (url.pathname === "/repos/linuxserver/docker-tautulli/releases") {
return createJsonResponse([
{
tag_name: "v2.16.0-ls200",
published_at: "2026-01-10T12:00:00.000Z",
html_url: "https://github.com/linuxserver/docker-tautulli/releases/tag/v2.16.0-ls200",
body: "Older supported image",
prerelease: false,
},
]);
}
if (url.pathname === "/repos/linuxserver/docker-tautulli") {
return createJsonResponse({
html_url: "https://github.com/linuxserver/docker-tautulli",
description: "GitHub description",
fork: false,
archived: false,
created_at: "2015-08-10T00:00:00.000Z",
stargazers_count: 934,
open_issues_count: 2,
forks_count: 80,
});
}
return createJsonResponse({ message: "Not Found" }, { status: 404, statusText: "Not Found" });
});
const result = await getLatestMatchingReleaseAsync({
id: "tautulli",
provider: "linuxServerIO",
identifier: "linuxserver/tautulli",
versionRegex: "^v2\\.16\\..+-ls[0-9]+$",
});
expect(result).toEqual({
success: true,
data: expect.objectContaining({
latestRelease: "v2.16.0-ls200",
projectUrl: "https://github.com/linuxserver/docker-tautulli",
projectDescription: "Tautulli image",
}),
});
expect(mockedFetch).toHaveBeenCalledTimes(3);
});
test("uses the LinuxServer.io latest release when it matches the version filter", async () => {
mockedFetch.mockResolvedValueOnce(createLinuxServerResponse());
const result = await getLatestMatchingReleaseAsync({
id: "tautulli",
provider: "linuxServerIO",
identifier: "linuxserver/tautulli",
versionRegex: "^v2\\.17\\..+-ls[0-9]+$",
});
expect(result).toEqual({
success: true,
data: expect.objectContaining({ latestRelease: "v2.17.2-ls237" }),
});
expect(mockedFetch).toHaveBeenCalledOnce();
expectUrl(0, "https://api.linuxserver.io/api/v1/images");
});
test("returns the GitHub error when filtered release history cannot be fetched", async () => {
mockedFetch.mockImplementation(async (input) => {
const url = new URL(input.toString());
if (url.origin === "https://api.linuxserver.io") return createLinuxServerResponse();
return createJsonResponse({ message: "GitHub unavailable" }, { status: 404, statusText: "Not Found" });
});
const result = await getLatestMatchingReleaseAsync({
id: "tautulli",
provider: "linuxServerIO",
identifier: "linuxserver/tautulli",
versionRegex: "^v2\\.16\\..+-ls[0-9]+$",
});
expect(result).toEqual({
success: false,
error: expect.objectContaining({ code: "unexpected", message: expect.stringContaining("GitHub unavailable") }),
});
expect(mockedFetch.mock.calls.length).toBeGreaterThan(1);
});
});
interface MockGhcrResponsesInput { interface MockGhcrResponsesInput {
registryOrigin?: string; registryOrigin?: string;
repositoryName: string; repositoryName: string;
@@ -307,27 +185,6 @@ const createJsonResponse = (body: unknown, init: JsonResponseInit = {}) =>
}, },
}); });
const createLinuxServerResponse = () =>
createJsonResponse({
data: {
repositories: {
linuxserver: [
{
name: "tautulli",
initial_date: "2015-08-10",
github_url: "https://github.com/linuxserver/docker-tautulli",
description: "Tautulli image",
version: "v2.17.2-ls237",
version_timestamp: "2026-07-17 00:25:42+00:00",
stars: 934,
deprecated: false,
changelog: [{ date: "2026-07-05", desc: "Rebase to Alpine 3.24." }],
},
],
},
},
});
const expectUrl = (callIndex: number, expectedUrl: string) => { const expectUrl = (callIndex: number, expectedUrl: string) => {
expect(mockedFetch.mock.calls[callIndex]?.[0].toString().split("?")[0]).toBe(expectedUrl); expect(mockedFetch.mock.calls[callIndex]?.[0].toString().split("?")[0]).toBe(expectedUrl);
}; };
+1 -4
View File
@@ -9,7 +9,7 @@ export const weatherRequestHandler = createWidgetRequestHandler({
async requestAsync(input: { latitude: number; longitude: number }) { async requestAsync(input: { latitude: number; longitude: number }) {
const res = await withTimeoutAsync(async (signal) => { const res = await withTimeoutAsync(async (signal) => {
return await fetchWithTrustedCertificatesAsync( return await fetchWithTrustedCertificatesAsync(
`https://api.open-meteo.com/v1/forecast?latitude=${input.latitude}&longitude=${input.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset,wind_speed_10m_max,wind_gusts_10m_max,relative_humidity_2m_mean&current_weather=true&timezone=auto`, `https://api.open-meteo.com/v1/forecast?latitude=${input.latitude}&longitude=${input.longitude}&daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset,wind_speed_10m_max,wind_gusts_10m_max&current_weather=true&timezone=auto`,
{ signal }, { signal },
); );
}); });
@@ -27,7 +27,6 @@ export const weatherRequestHandler = createWidgetRequestHandler({
sunset: weather.daily.sunset[index], sunset: weather.daily.sunset[index],
maxWindSpeed: weather.daily.wind_speed_10m_max[index], maxWindSpeed: weather.daily.wind_speed_10m_max[index],
maxWindGusts: weather.daily.wind_gusts_10m_max[index], maxWindGusts: weather.daily.wind_gusts_10m_max[index],
humidity: weather.daily.relative_humidity_2m_mean[index],
}; };
}), }),
} satisfies Weather; } satisfies Weather;
@@ -49,7 +48,6 @@ const atLocationOutput = z.object({
sunset: z.array(z.string()), sunset: z.array(z.string()),
wind_speed_10m_max: z.array(z.number()), wind_speed_10m_max: z.array(z.number()),
wind_gusts_10m_max: z.array(z.number()), wind_gusts_10m_max: z.array(z.number()),
relative_humidity_2m_mean: z.array(z.number()),
}), }),
}); });
@@ -68,6 +66,5 @@ export interface Weather {
sunset: string | undefined; sunset: string | undefined;
maxWindSpeed: number | undefined; maxWindSpeed: number | undefined;
maxWindGusts: number | undefined; maxWindGusts: number | undefined;
humidity: number | undefined;
}[]; }[];
} }
-3
View File
@@ -10,7 +10,6 @@ export type SettingsContextProps = Pick<
| "openSearchInNewTab" | "openSearchInNewTab"
| "ddgBangs" | "ddgBangs"
| "pingIconsEnabled" | "pingIconsEnabled"
| "enableRightClickOnWidgets"
> & > &
Pick<ServerSettings["board"], "enableStatusByDefault" | "forceDisableStatus"> & Pick<ServerSettings["board"], "enableStatusByDefault" | "forceDisableStatus"> &
Pick<ServerSettings["user"], "enableGravatar">; Pick<ServerSettings["user"], "enableGravatar">;
@@ -33,7 +32,6 @@ export type UserSettings = Pick<
| "openSearchInNewTab" | "openSearchInNewTab"
| "ddgBangs" | "ddgBangs"
| "pingIconsEnabled" | "pingIconsEnabled"
| "enableRightClickOnWidgets"
>; >;
export const createSettings = ({ export const createSettings = ({
@@ -50,7 +48,6 @@ export const createSettings = ({
homeBoardId: user?.homeBoardId ?? serverSettings.board.homeBoardId, homeBoardId: user?.homeBoardId ?? serverSettings.board.homeBoardId,
mobileHomeBoardId: user?.mobileHomeBoardId ?? serverSettings.board.mobileHomeBoardId, mobileHomeBoardId: user?.mobileHomeBoardId ?? serverSettings.board.mobileHomeBoardId,
pingIconsEnabled: user?.pingIconsEnabled ?? false, pingIconsEnabled: user?.pingIconsEnabled ?? false,
enableRightClickOnWidgets: user?.enableRightClickOnWidgets ?? true,
enableStatusByDefault: serverSettings.board.enableStatusByDefault, enableStatusByDefault: serverSettings.board.enableStatusByDefault,
forceDisableStatus: serverSettings.board.forceDisableStatus, forceDisableStatus: serverSettings.board.forceDisableStatus,
enableGravatar: serverSettings.user.enableGravatar, enableGravatar: serverSettings.user.enableGravatar,
@@ -56,13 +56,6 @@ export const userPreferenceDefinitions = [
mutationGroup: "pingIconsEnabled", mutationGroup: "pingIconsEnabled",
aliases: ["ping", "icon", "status"], aliases: ["ping", "icon", "status"],
}, },
{
key: "enableRightClickOnWidgets",
kind: "boolean",
guest: false,
mutationGroup: "enableRightClickOnWidgets",
aliases: ["right click", "context menu", "tile", "widget menu"],
},
{ {
key: "fullPreferencesPage", key: "fullPreferencesPage",
kind: "link", kind: "link",
@@ -17,10 +17,6 @@ export const appIntegrationBoardMode = {
return groups; return groups;
} }
return groups.concat( return groups.concat([appsSearchGroup, integrationsSearchGroup]);
session.user.permissions.includes("board-modify-all")
? [appsSearchGroup, integrationsSearchGroup]
: [integrationsSearchGroup],
);
}, },
} satisfies SearchMode; } satisfies SearchMode;
@@ -87,8 +87,7 @@ export const globalCommandGroup = createGroup<Command>({
icon: IconBox, icon: IconBox,
name: tOption("newApp.label"), name: tOption("newApp.label"),
useInteraction: interaction.link(() => ({ href: "/manage/apps/new" })), useInteraction: interaction.link(() => ({ href: "/manage/apps/new" })),
hidden: hidden: !session?.user.permissions.includes("app-create"),
!session?.user.permissions.includes("board-modify-all") || !session?.user.permissions.includes("app-create"),
}, },
{ {
commandKey: "newIntegration", commandKey: "newIntegration",
@@ -76,7 +76,7 @@ export const pagesSearchGroup = createGroup<{
icon: IconBox, icon: IconBox,
path: "/manage/apps", path: "/manage/apps",
name: t("manageApp.label"), name: t("manageApp.label"),
hidden: !session?.user.permissions.includes("board-modify-all"), hidden: !session,
}, },
{ {
icon: IconPlug, icon: IconPlug,
@@ -3,7 +3,6 @@
import { import {
IconActivity, IconActivity,
IconCalendarWeek, IconCalendarWeek,
IconClick,
IconDeviceDesktop, IconDeviceDesktop,
IconExternalLink, IconExternalLink,
IconHome, IconHome,
@@ -47,7 +46,6 @@ export const preferenceIcons: Record<UserPreferenceKey, TablerIcon> = {
homeBoardId: IconHome, homeBoardId: IconHome,
mobileHomeBoardId: IconLayoutBoard, mobileHomeBoardId: IconLayoutBoard,
pingIconsEnabled: IconActivity, pingIconsEnabled: IconActivity,
enableRightClickOnWidgets: IconClick,
fullPreferencesPage: IconSettings, fullPreferencesPage: IconSettings,
}; };
@@ -93,7 +93,6 @@ export const useUserPreferences = () => {
const homeBoardsMutation = clientApi.user.changeHomeBoards.useMutation({ onSuccess: refresh }); const homeBoardsMutation = clientApi.user.changeHomeBoards.useMutation({ onSuccess: refresh });
const firstDayMutation = clientApi.user.changeFirstDayOfWeek.useMutation({ onSuccess: refresh }); const firstDayMutation = clientApi.user.changeFirstDayOfWeek.useMutation({ onSuccess: refresh });
const pingMutation = clientApi.user.changePingIconsEnabled.useMutation({ onSuccess: refresh }); const pingMutation = clientApi.user.changePingIconsEnabled.useMutation({ onSuccess: refresh });
const rightClickMutation = clientApi.user.changeEnableRightClickOnWidgets.useMutation({ onSuccess: refresh });
const getEffective = (key: UserPreferenceKey): unknown => const getEffective = (key: UserPreferenceKey): unknown =>
key in optimisticRef.current ? optimisticRef.current[key] : settingsRef.current[key as keyof SettingsContextProps]; key in optimisticRef.current ? optimisticRef.current[key] : settingsRef.current[key as keyof SettingsContextProps];
@@ -117,8 +116,6 @@ export const useUserPreferences = () => {
}), }),
firstDayOfWeek: (uid, _key, value) => firstDayMutation.mutateAsync({ id: uid, firstDayOfWeek: value as DayOfWeek }), firstDayOfWeek: (uid, _key, value) => firstDayMutation.mutateAsync({ id: uid, firstDayOfWeek: value as DayOfWeek }),
pingIconsEnabled: (uid, _key, value) => pingMutation.mutateAsync({ id: uid, pingIconsEnabled: value as boolean }), pingIconsEnabled: (uid, _key, value) => pingMutation.mutateAsync({ id: uid, pingIconsEnabled: value as boolean }),
enableRightClickOnWidgets: (uid, _key, value) =>
rightClickMutation.mutateAsync({ id: uid, enableRightClickOnWidgets: value as boolean }),
}; };
const groupPending: Record<string, boolean> = { const groupPending: Record<string, boolean> = {
@@ -126,7 +123,6 @@ export const useUserPreferences = () => {
homeBoards: homeBoardsMutation.isPending, homeBoards: homeBoardsMutation.isPending,
firstDayOfWeek: firstDayMutation.isPending, firstDayOfWeek: firstDayMutation.isPending,
pingIconsEnabled: pingMutation.isPending, pingIconsEnabled: pingMutation.isPending,
enableRightClickOnWidgets: rightClickMutation.isPending,
}; };
const persistedValues = useMemo<Record<UserPreferenceKey, unknown>>(() => { const persistedValues = useMemo<Record<UserPreferenceKey, unknown>>(() => {
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Utilitza icones pels pings" "label": "Utilitza icones pels pings"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Motor de cerca principal" "label": "Motor de cerca principal"
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "", "clear": "",
"heading": "", "heading": "",
"align": "", "align": "",
"directionLtr": "",
"directionRtl": "",
"blockquote": "", "blockquote": "",
"horizontalLine": "", "horizontalLine": "",
"bulletList": "", "bulletList": "",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "", "clear": "",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "" "label": ""
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "为 ping 使用图标" "label": "为 ping 使用图标"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "默认搜索引擎" "label": "默认搜索引擎"
}, },
@@ -1289,14 +1285,6 @@
"label": "API 密钥 (机密)", "label": "API 密钥 (机密)",
"newLabel": "新建API密钥(机密)" "newLabel": "新建API密钥(机密)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "应用 ID", "label": "应用 ID",
"newLabel": "新应用 ID" "newLabel": "新应用 ID"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "自定义日期格式", "label": "自定义日期格式",
"description": "使用 ISO 8601 格式化日期(这将覆盖其他选项)" "description": "使用 ISO 8601 格式化日期(这将覆盖其他选项)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "清除格式", "clear": "清除格式",
"heading": "标题 {level}", "heading": "标题 {level}",
"align": "对齐文本: {position}", "align": "对齐文本: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "引用", "blockquote": "引用",
"horizontalLine": "横线", "horizontalLine": "横线",
"bulletList": "符号列表", "bulletList": "符号列表",
@@ -2267,8 +2225,7 @@
"sunrise": "日出", "sunrise": "日出",
"sunset": "日落", "sunset": "日落",
"maxWindSpeed": "最大风速:{maxWindSpeed} {unit}", "maxWindSpeed": "最大风速:{maxWindSpeed} {unit}",
"maxWindGusts": "最大阵风:{maxWindGusts} {unit}", "maxWindGusts": "最大阵风:{maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "晴朗", "clear": "晴朗",
@@ -2732,11 +2689,6 @@
"user": "用户", "user": "用户",
"name": "名称", "name": "名称",
"id": "ID", "id": "ID",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "技术统计", "title": "技术统计",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich 服务器统计", "name": "Immich 服务器统计",
"description": "有关您的 Immich 实例的信息", "description": "有关您的 Immich 实例的信息",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich 相册", "name": "Immich 相册",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "相册ID", "label": "相册ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Immich 相册图片幻灯片", "description": "Immich 相册图片幻灯片",
"noAlbumSelected": "未选择相册,请编辑组件并选择一个相册",
"noPhotos": "此相册中没有照片" "noPhotos": "此相册中没有照片"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "在新标签页中打开链接" "label": "在新标签页中打开链接"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS 订阅", "name": "RSS 订阅",
"description": "监视和显示一个或多个通用 RSS、ATOM 或 JSON 源", "description": "监视和显示一个或多个通用 RSS、ATOM 或 JSON 源",
@@ -3606,11 +3336,7 @@
"name": "通知", "name": "通知",
"description": "在集成中显示通知历史", "description": "在集成中显示通知历史",
"noItems": "没有可显示的通知。", "noItems": "没有可显示的通知。",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "网速测试追踪器", "name": "网速测试追踪器",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "容器", "title": "容器",
"table": { "table": {
"updated": "已更新 {when}", "updated": "已更新 {when}",
"refresh": {
"lastUpdated": ""
},
"search": "搜索 {count} 容器", "search": "搜索 {count} 容器",
"selected": "{totalCount} 容器的 {selectCount}", "selected": "{totalCount} 容器的 {selectCount}",
"footer": "总计 {count} 容器", "footer": "总计 {count} 容器",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+9 -333
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "crwdns44:0crwdne44:0" "label": "crwdns44:0crwdne44:0"
}, },
"enableRightClickOnWidgets": {
"label": "crwdns6095:0crwdne6095:0",
"description": "crwdns6097:0crwdne6097:0"
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "crwdns2694:0crwdne2694:0" "label": "crwdns2694:0crwdne2694:0"
}, },
@@ -866,7 +862,7 @@
"created": "crwdns5553:0{name}crwdne5553:0", "created": "crwdns5553:0{name}crwdne5553:0",
"updated": "crwdns5555:0{name}crwdne5555:0", "updated": "crwdns5555:0{name}crwdne5555:0",
"deleted": "crwdns5557:0{name}crwdne5557:0", "deleted": "crwdns5557:0{name}crwdne5557:0",
"imported": "crwdns6079:0crwdne6079:0", "imported": "crwdns5559:0crwdne5559:0",
"aiPromptCopied": "crwdns5561:0crwdne5561:0", "aiPromptCopied": "crwdns5561:0crwdne5561:0",
"aiPromptDescription": "crwdns5563:0crwdne5563:0", "aiPromptDescription": "crwdns5563:0crwdne5563:0",
"aiPromptCopy": "crwdns5565:0crwdne5565:0", "aiPromptCopy": "crwdns5565:0crwdne5565:0",
@@ -1289,14 +1285,6 @@
"label": "crwdns3618:0crwdne3618:0", "label": "crwdns3618:0crwdne3618:0",
"newLabel": "crwdns3620:0crwdne3620:0" "newLabel": "crwdns3620:0crwdne3620:0"
}, },
"patchmonApiKey": {
"label": "crwdns5859:0crwdne5859:0",
"newLabel": "crwdns5861:0crwdne5861:0"
},
"patchmonApiSecret": {
"label": "crwdns5863:0crwdne5863:0",
"newLabel": "crwdns5865:0crwdne5865:0"
},
"githubAppId": { "githubAppId": {
"label": "crwdns3676:0crwdne3676:0", "label": "crwdns3676:0crwdne3676:0",
"newLabel": "crwdns3678:0crwdne3678:0" "newLabel": "crwdns3678:0crwdne3678:0"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "crwdns5753:0crwdne5753:0",
"description": "crwdns5755:0crwdne5755:0"
},
"paperlessNgx": { "paperlessNgx": {
"name": "crwdns5003:0crwdne5003:0", "name": "crwdns5003:0crwdne5003:0",
"description": "crwdns5005:0crwdne5005:0" "description": "crwdns5005:0crwdne5005:0"
},
"patchmon": {
"name": "crwdns5867:0crwdne5867:0",
"description": "crwdns5869:0crwdne5869:0"
},
"bazarr": {
"name": "crwdns5799:0crwdne5799:0",
"description": "crwdns5801:0crwdne5801:0"
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "crwdns5739:0crwdne5739:0", "refresh": "crwdns5739:0crwdne5739:0",
"options": "crwdns5709:0crwdne5709:0", "options": "crwdns5709:0crwdne5709:0",
"actions": "crwdns5711:0crwdne5711:0" "actions": "crwdns5711:0crwdne5711:0"
},
"status": {
"success": "crwdns6049:0crwdne6049:0",
"error": "crwdns6051:0crwdne6051:0",
"loading": "crwdns6053:0crwdne6053:0",
"idle": "crwdns6055:0crwdne6055:0"
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "crwdns2726:0crwdne2726:0", "label": "crwdns2726:0crwdne2726:0",
"description": "crwdns2728:0crwdne2728:0" "description": "crwdns2728:0crwdne2728:0"
},
"showWeather": {
"label": "crwdns6113:0crwdne6113:0",
"description": "crwdns6115:0crwdne6115:0"
},
"weatherLocation": {
"label": "crwdns6117:0crwdne6117:0"
},
"isWeatherFormatFahrenheit": {
"label": "crwdns6119:0crwdne6119:0"
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "crwdns884:0crwdne884:0", "clear": "crwdns884:0crwdne884:0",
"heading": "crwdns886:0{level}crwdne886:0", "heading": "crwdns886:0{level}crwdne886:0",
"align": "crwdns888:0{position}crwdne888:0", "align": "crwdns888:0{position}crwdne888:0",
"directionLtr": "crwdns6043:0crwdne6043:0",
"directionRtl": "crwdns6045:0crwdne6045:0",
"blockquote": "crwdns890:0crwdne890:0", "blockquote": "crwdns890:0crwdne890:0",
"horizontalLine": "crwdns892:0crwdne892:0", "horizontalLine": "crwdns892:0crwdne892:0",
"bulletList": "crwdns894:0crwdne894:0", "bulletList": "crwdns894:0crwdne894:0",
@@ -2267,8 +2225,7 @@
"sunrise": "crwdns2712:0crwdne2712:0", "sunrise": "crwdns2712:0crwdne2712:0",
"sunset": "crwdns2714:0crwdne2714:0", "sunset": "crwdns2714:0crwdne2714:0",
"maxWindSpeed": "crwdns3772:0{maxWindSpeed}crwdnd3772:0{unit}crwdne3772:0", "maxWindSpeed": "crwdns3772:0{maxWindSpeed}crwdnd3772:0{unit}crwdne3772:0",
"maxWindGusts": "crwdns3774:0{maxWindGusts}crwdnd3774:0{unit}crwdne3774:0", "maxWindGusts": "crwdns3774:0{maxWindGusts}crwdnd3774:0{unit}crwdne3774:0"
"humidity": "crwdns6111:0{humidity}crwdne6111:0"
}, },
"kind": { "kind": {
"clear": "crwdns1032:0crwdne1032:0", "clear": "crwdns1032:0crwdne1032:0",
@@ -2732,11 +2689,6 @@
"user": "crwdns2476:0crwdne2476:0", "user": "crwdns2476:0crwdne2476:0",
"name": "crwdns2478:0crwdne2478:0", "name": "crwdns2478:0crwdne2478:0",
"id": "crwdns2480:0crwdne2480:0", "id": "crwdns2480:0crwdne2480:0",
"status": "crwdns6085:0crwdne6085:0",
"directPlay": "crwdns6087:0crwdne6087:0",
"transcoding": "crwdns6089:0crwdne6089:0",
"paused": "crwdns6091:0crwdne6091:0",
"remaining": "crwdns6093:0{minutes}crwdne6093:0",
"metadata": { "metadata": {
"title": "crwdns3744:0crwdne3744:0", "title": "crwdns3744:0crwdne3744:0",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "crwdns5055:0crwdne5055:0" "internalServerError": "crwdns5055:0crwdne5055:0"
} }
}, },
"patchmon": {
"name": "crwdns5871:0crwdne5871:0",
"description": "crwdns5873:0crwdne5873:0",
"title": "crwdns5875:0crwdne5875:0",
"totalHosts": "crwdns5877:0crwdne5877:0",
"hostsNeedingUpdates": "crwdns5879:0crwdne5879:0",
"securityUpdates": "crwdns5881:0crwdne5881:0",
"upToDateHosts": "crwdns5883:0crwdne5883:0",
"hostsWithSecurityUpdates": "crwdns5885:0crwdne5885:0",
"recentUpdates24h": "crwdns5887:0crwdne5887:0",
"totalOutdatedPackages": "crwdns5889:0crwdne5889:0",
"totalRepos": "crwdns5891:0crwdne5891:0",
"osDistribution": "crwdns5893:0crwdne5893:0",
"compliance": "crwdns5895:0crwdne5895:0",
"complianceRatio": "crwdns5897:0{upToDate}crwdnd5897:0{total}crwdne5897:0",
"lastUpdated": "crwdns5899:0{time}crwdne5899:0",
"option": {
"showTotalHosts": {
"label": "crwdns5901:0crwdne5901:0",
"description": "crwdns5903:0crwdne5903:0"
},
"showHostsNeedingUpdates": {
"label": "crwdns5905:0crwdne5905:0",
"description": "crwdns5907:0crwdne5907:0"
},
"showSecurityUpdates": {
"label": "crwdns5909:0crwdne5909:0",
"description": "crwdns5911:0crwdne5911:0"
},
"showUpToDateHosts": {
"label": "crwdns5913:0crwdne5913:0",
"description": "crwdns5915:0crwdne5915:0"
},
"showHostsWithSecurityUpdates": {
"label": "crwdns5917:0crwdne5917:0",
"description": "crwdns5919:0crwdne5919:0"
},
"showRecentUpdates24h": {
"label": "crwdns5921:0crwdne5921:0",
"description": "crwdns5923:0crwdne5923:0"
},
"showTotalOutdatedPackages": {
"label": "crwdns5925:0crwdne5925:0",
"description": "crwdns5927:0crwdne5927:0"
},
"showTotalRepos": {
"label": "crwdns5929:0crwdne5929:0",
"description": "crwdns5931:0crwdne5931:0"
},
"enableThresholdColors": {
"label": "crwdns5933:0crwdne5933:0",
"description": "crwdns5935:0crwdne5935:0"
},
"useCustomThresholds": {
"label": "crwdns5937:0crwdne5937:0",
"description": "crwdns5939:0crwdne5939:0"
},
"thresholdMode": {
"option": {
"absolute": "crwdns5941:0crwdne5941:0",
"percent": "crwdns5943:0crwdne5943:0"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "crwdns5945:0crwdne5945:0",
"description": "crwdns5947:0crwdne5947:0"
},
"hostsNeedingUpdatesWarningAt": {
"label": "crwdns5949:0crwdne5949:0",
"description": "crwdns5951:0crwdne5951:0"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "crwdns5953:0crwdne5953:0",
"description": "crwdns5955:0crwdne5955:0"
},
"securityUpdatesThresholdMode": {
"label": "crwdns5957:0crwdne5957:0",
"description": "crwdns5959:0crwdne5959:0"
},
"securityUpdatesWarningAt": {
"label": "crwdns5961:0crwdne5961:0",
"description": "crwdns5963:0crwdne5963:0"
},
"securityUpdatesCriticalAt": {
"label": "crwdns5965:0crwdne5965:0",
"description": "crwdns5967:0crwdne5967:0"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "crwdns5969:0crwdne5969:0",
"description": "crwdns5971:0crwdne5971:0"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "crwdns5973:0crwdne5973:0",
"description": "crwdns5975:0crwdne5975:0"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "crwdns5977:0crwdne5977:0",
"description": "crwdns5979:0crwdne5979:0"
},
"upToDateHostsThresholdMode": {
"label": "crwdns5981:0crwdne5981:0",
"description": "crwdns5983:0crwdne5983:0"
},
"upToDateHostsWarningAt": {
"label": "crwdns5985:0crwdne5985:0",
"description": "crwdns5987:0crwdne5987:0"
},
"upToDateHostsCriticalAt": {
"label": "crwdns5989:0crwdne5989:0",
"description": "crwdns5991:0crwdne5991:0"
},
"totalOutdatedPackagesThresholdMode": {
"label": "crwdns5993:0crwdne5993:0",
"description": "crwdns5995:0crwdne5995:0"
},
"totalOutdatedPackagesWarningAt": {
"label": "crwdns5997:0crwdne5997:0",
"description": "crwdns5999:0crwdne5999:0"
},
"totalOutdatedPackagesCriticalAt": {
"label": "crwdns6001:0crwdne6001:0",
"description": "crwdns6003:0crwdne6003:0"
},
"showOsDistribution": {
"label": "crwdns6005:0crwdne6005:0",
"description": "crwdns6007:0crwdne6007:0"
},
"osDistributionLimit": {
"label": "crwdns6009:0crwdne6009:0",
"description": "crwdns6011:0crwdne6011:0",
"option": {
"3": "crwdns6013:0crwdne6013:0",
"5": "crwdns6015:0crwdne6015:0",
"10": "crwdns6017:0crwdne6017:0",
"all": "crwdns6019:0crwdne6019:0"
}
},
"showOsVersion": {
"label": "crwdns6021:0crwdne6021:0",
"description": "crwdns6023:0crwdne6023:0"
},
"showComplianceHero": {
"label": "crwdns6025:0crwdne6025:0",
"description": "crwdns6027:0crwdne6027:0"
},
"osDisplayMode": {
"label": "crwdns6029:0crwdne6029:0",
"description": "crwdns6031:0crwdne6031:0",
"option": {
"bars": "crwdns6033:0crwdne6033:0",
"donut": "crwdns6035:0crwdne6035:0"
}
}
},
"error": {
"internalServerError": "crwdns6037:0crwdne6037:0"
}
},
"bazarr": {
"name": "crwdns5803:0crwdne5803:0",
"description": "crwdns5805:0crwdne5805:0",
"episodes": "crwdns5807:0crwdne5807:0",
"movies": "crwdns5809:0crwdne5809:0",
"providers": "crwdns5811:0crwdne5811:0",
"status": "crwdns5813:0crwdne5813:0",
"option": {
"showMissingEpisodes": {
"label": "crwdns5815:0crwdne5815:0",
"description": "crwdns5817:0crwdne5817:0"
},
"showMissingMovies": {
"label": "crwdns5819:0crwdne5819:0",
"description": "crwdns5821:0crwdne5821:0"
},
"showProviderIssues": {
"label": "crwdns5823:0crwdne5823:0",
"description": "crwdns5825:0crwdne5825:0"
},
"showHealthIssues": {
"label": "crwdns5827:0crwdne5827:0",
"description": "crwdns5829:0crwdne5829:0"
}
},
"error": {
"internalServerError": "crwdns5831:0crwdne5831:0"
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "crwdns3880:0crwdne3880:0", "name": "crwdns3880:0crwdne3880:0",
"description": "crwdns3882:0crwdne3882:0", "description": "crwdns3882:0crwdne3882:0",
@@ -3017,11 +2782,10 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "crwdns3908:0crwdne3908:0", "name": "crwdns3908:0crwdne3908:0",
"allPhotos": "crwdns6103:0crwdne6103:0",
"option": { "option": {
"albumId": { "albumId": {
"label": "crwdns5715:0crwdne5715:0", "label": "crwdns5715:0crwdne5715:0",
"description": "crwdns6105:0crwdne6105:0" "description": "crwdns5717:0crwdne5717:0"
}, },
"rotationIntervalSeconds": { "rotationIntervalSeconds": {
"label": "crwdns3914:0crwdne3914:0", "label": "crwdns3914:0crwdne3914:0",
@@ -3036,8 +2800,9 @@
"description": "crwdns5721:0crwdne5721:0" "description": "crwdns5721:0crwdne5721:0"
} }
}, },
"description": "crwdns6107:0crwdne6107:0", "description": "crwdns3922:0crwdne3922:0",
"noPhotos": "crwdns6109:0crwdne6109:0" "noAlbumSelected": "crwdns3924:0crwdne3924:0",
"noPhotos": "crwdns3926:0crwdne3926:0"
}, },
"downloads": { "downloads": {
"name": "crwdns1170:0crwdne1170:0", "name": "crwdns1170:0crwdne1170:0",
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "crwdns1306:0crwdne1306:0" "label": "crwdns1306:0crwdne1306:0"
},
"statusFilter": {
"label": "crwdns6081:0crwdne6081:0"
},
"recentDays": {
"label": "crwdns6083:0crwdne6083:0"
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "crwdns5833:0crwdne5833:0",
"description": "crwdns5835:0crwdne5835:0",
"option": {
"showMissing": {
"label": "crwdns5837:0crwdne5837:0"
},
"showQueued": {
"label": "crwdns5839:0crwdne5839:0"
},
"pageSize": {
"label": "crwdns5841:0crwdne5841:0"
}
},
"tab": {
"missing": "crwdns5843:0crwdne5843:0",
"queued": "crwdns5845:0crwdne5845:0"
},
"type": {
"movie": "crwdns5847:0crwdne5847:0",
"episode": "crwdns5849:0crwdne5849:0"
},
"empty": {
"missing": "crwdns5851:0crwdne5851:0",
"queued": "crwdns5853:0crwdne5853:0",
"noTabsEnabled": "crwdns5855:0crwdne5855:0"
},
"timeLeft": "crwdns5857:0crwdne5857:0"
},
"rssFeed": { "rssFeed": {
"name": "crwdns1352:0crwdne1352:0", "name": "crwdns1352:0crwdne1352:0",
"description": "crwdns1354:0crwdne1354:0", "description": "crwdns1354:0crwdne1354:0",
@@ -3606,11 +3336,7 @@
"name": "crwdns3476:0crwdne3476:0", "name": "crwdns3476:0crwdne3476:0",
"description": "crwdns3478:0crwdne3478:0", "description": "crwdns3478:0crwdne3478:0",
"noItems": "crwdns3480:0crwdne3480:0", "noItems": "crwdns3480:0crwdne3480:0",
"option": { "option": {}
"hideLogos": {
"label": "crwdns5757:0crwdne5757:0"
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "crwdns4014:0crwdne4014:0", "name": "crwdns4014:0crwdne4014:0",
@@ -3691,40 +3417,6 @@
"internalServerError": "crwdns5095:0crwdne5095:0" "internalServerError": "crwdns5095:0crwdne5095:0"
} }
}, },
"traefik": {
"name": "crwdns5759:0crwdne5759:0",
"description": "crwdns5761:0crwdne5761:0",
"option": {
"showTcp": {
"label": "crwdns5763:0crwdne5763:0"
},
"showUdp": {
"label": "crwdns5765:0crwdne5765:0"
},
"showEntryPoints": {
"label": "crwdns5767:0crwdne5767:0"
}
},
"instances": "crwdns5769:0crwdne5769:0",
"versionUnknown": "crwdns5771:0crwdne5771:0",
"summary": {
"routers": "crwdns5773:0crwdne5773:0",
"entryPoints": "crwdns5775:0crwdne5775:0"
},
"resource": {
"routers": "crwdns5777:0crwdne5777:0",
"services": "crwdns5779:0crwdne5779:0",
"middlewares": "crwdns5781:0crwdne5781:0"
},
"status": {
"healthy": "crwdns5783:0crwdne5783:0",
"errors": "crwdns5785:0{count}crwdne5785:0",
"warnings": "crwdns5787:0{count}crwdne5787:0"
},
"error": {
"internalServerError": "crwdns5789:0crwdne5789:0"
}
},
"audioStats": { "audioStats": {
"name": "crwdns5097:0crwdne5097:0", "name": "crwdns5097:0crwdne5097:0",
"description": "crwdns5099:0crwdne5099:0", "description": "crwdns5099:0crwdne5099:0",
@@ -4091,8 +3783,8 @@
}, },
"disk": { "disk": {
"title": "crwdns4943:0crwdne4943:0", "title": "crwdns4943:0crwdne4943:0",
"subtitle": "crwdns6039:0crwdne6039:0", "subtitle": "crwdns4945:0crwdne4945:0",
"series": "crwdns6041:0crwdne6041:0" "series": "crwdns4947:0crwdne4947:0"
}, },
"diskIO": { "diskIO": {
"title": "crwdns4949:0crwdne4949:0", "title": "crwdns4949:0crwdne4949:0",
@@ -4100,11 +3792,6 @@
"read": "crwdns4953:0crwdne4953:0", "read": "crwdns4953:0crwdne4953:0",
"write": "crwdns4955:0crwdne4955:0" "write": "crwdns4955:0crwdne4955:0"
}, },
"storage": {
"title": "crwdns5793:0crwdne5793:0",
"subtitle": "crwdns5795:0crwdne5795:0",
"series": "crwdns5797:0crwdne5797:0"
},
"network": { "network": {
"title": "crwdns4957:0crwdne4957:0", "title": "crwdns4957:0crwdne4957:0",
"subtitle": "crwdns4959:0crwdne4959:0", "subtitle": "crwdns4959:0crwdne4959:0",
@@ -5237,9 +4924,6 @@
"title": "crwdns1892:0crwdne1892:0", "title": "crwdns1892:0crwdne1892:0",
"table": { "table": {
"updated": "crwdns1894:0{when}crwdne1894:0", "updated": "crwdns1894:0{when}crwdne1894:0",
"refresh": {
"lastUpdated": "crwdns6047:0{when}crwdne6047:0"
},
"search": "crwdns3432:0{count}crwdne3432:0", "search": "crwdns3432:0{count}crwdne3432:0",
"selected": "crwdns1898:0{selectCount}crwdnd1898:0{totalCount}crwdne1898:0", "selected": "crwdns1898:0{selectCount}crwdnd1898:0{totalCount}crwdne1898:0",
"footer": "crwdns3434:0{count}crwdne3434:0", "footer": "crwdns3434:0{count}crwdne3434:0",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "crwdns6099:0crwdne6099:0",
"children": {
"detail": {
"title": "crwdns6101:0crwdne6101:0"
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "crwdns4367:0crwdne4367:0" "label": "crwdns4367:0crwdne4367:0"
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Používat ikony pro pingy" "label": "Používat ikony pro pingy"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "" "label": ""
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Vymazat formátování", "clear": "Vymazat formátování",
"heading": "Nadpis {level}", "heading": "Nadpis {level}",
"align": "Zarovnat text: {position}", "align": "Zarovnat text: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Citace", "blockquote": "Citace",
"horizontalLine": "Vodorovná čára", "horizontalLine": "Vodorovná čára",
"bulletList": "Odrážkový seznam", "bulletList": "Odrážkový seznam",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Jasno", "clear": "Jasno",
@@ -2732,11 +2689,6 @@
"user": "Uživatel", "user": "Uživatel",
"name": "Jméno", "name": "Jméno",
"id": "Id", "id": "Id",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Otevírat odkazy v nové kartě" "label": "Otevírat odkazy v nové kartě"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Kontejnery", "title": "Kontejnery",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+11 -335
View File
@@ -8,9 +8,9 @@
"action": { "action": {
"scratch": "Start fra bunden", "scratch": "Start fra bunden",
"importOldmarr": "Importer fra Homarr før 1.0", "importOldmarr": "Importer fra Homarr før 1.0",
"restoreSqlite": "Gendan fra SQLite backup", "restoreSqlite": "",
"restoreSqliteDescription": "Upload en fuld SQLite database backup fra en tidligere Homarr instans. Dette vil gendanne alle tavler, brugere, apps, integrationer og indstillinger.", "restoreSqliteDescription": "",
"backToOptions": "← Tilbage til opsætningsmuligheder" "backToOptions": ""
} }
}, },
"import": { "import": {
@@ -94,12 +94,12 @@
"subtitle": "Konfigurer serverindstillinger." "subtitle": "Konfigurer serverindstillinger."
}, },
"integrations": { "integrations": {
"title": "Integrationer", "title": "",
"subtitle": "Vælg de tjenester, du bruger.", "subtitle": "",
"description": "Vælg de integrationer, du gerne vil forbinde. Vi konfigurerer dit dashboard med matchende widgets automatisk.", "description": "",
"action": { "action": {
"continue": "Forsæt", "continue": "",
"skip": "Spring over for nu" "skip": ""
}, },
"configure": { "configure": {
"progress": "", "progress": "",
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Brug ikoner til pings" "label": "Brug ikoner til pings"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Standardsøgemaskine" "label": "Standardsøgemaskine"
}, },
@@ -1289,14 +1285,6 @@
"label": "API-nøgle (Secret)", "label": "API-nøgle (Secret)",
"newLabel": "Ny API-nøgle (Key)" "newLabel": "Ny API-nøgle (Key)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "App Id", "label": "App Id",
"newLabel": "Nyt App Id" "newLabel": "Nyt App Id"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Brugerdefineret datoformat", "label": "Brugerdefineret datoformat",
"description": "Brug ISO 8601 til at formatere dato (dette vil tilsidesætte andre valg)" "description": "Brug ISO 8601 til at formatere dato (dette vil tilsidesætte andre valg)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Ryd formatering", "clear": "Ryd formatering",
"heading": "Overskrift {level}", "heading": "Overskrift {level}",
"align": "Juster tekst: {position}", "align": "Juster tekst: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Citatblok", "blockquote": "Citatblok",
"horizontalLine": "Horisontal linje", "horizontalLine": "Horisontal linje",
"bulletList": "Punktopstillet liste", "bulletList": "Punktopstillet liste",
@@ -2267,8 +2225,7 @@
"sunrise": "Solopgang", "sunrise": "Solopgang",
"sunset": "Solnedgang", "sunset": "Solnedgang",
"maxWindSpeed": "Maks. vindhastighed: {maxWindSpeed} {unit}", "maxWindSpeed": "Maks. vindhastighed: {maxWindSpeed} {unit}",
"maxWindGusts": "Maks. vindstød {maxWindGusts} {unit}", "maxWindGusts": "Maks. vindstød {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Skyfrit", "clear": "Skyfrit",
@@ -2732,11 +2689,6 @@
"user": "Bruger", "user": "Bruger",
"name": "Navn", "name": "Navn",
"id": "Id", "id": "Id",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Statistik for nørder", "title": "Statistik for nørder",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich Server Statistik", "name": "Immich Server Statistik",
"description": "Information om din Immich instans", "description": "Information om din Immich instans",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich album", "name": "Immich album",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "Album ID", "label": "Album ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Diasshow af billeder i dit Immich album", "description": "Diasshow af billeder i dit Immich album",
"noAlbumSelected": "Intet album valgt, rediger widget og vælg et album",
"noPhotos": "Ingen fotos i dette album" "noPhotos": "Ingen fotos i dette album"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Åbn links i ny fane" "label": "Åbn links i ny fane"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS feeds", "name": "RSS feeds",
"description": "Overvåg og vis en eller flere generiske RSS, ATOM eller JSON feeds", "description": "Overvåg og vis en eller flere generiske RSS, ATOM eller JSON feeds",
@@ -3606,11 +3336,7 @@
"name": "Notifikationer", "name": "Notifikationer",
"description": "Vis notifikationshistorik fra en integration", "description": "Vis notifikationshistorik fra en integration",
"noItems": "Ingen notifikationer at vise.", "noItems": "Ingen notifikationer at vise.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "Speedtest Tracker", "name": "Speedtest Tracker",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Containere", "title": "Containere",
"table": { "table": {
"updated": "Opdateret {when}", "updated": "Opdateret {when}",
"refresh": {
"lastUpdated": ""
},
"search": "Søg {count} containere", "search": "Søg {count} containere",
"selected": "{selectCount} af {totalCount} containere valgt", "selected": "{selectCount} af {totalCount} containere valgt",
"footer": "Total {count} containere", "footer": "Total {count} containere",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Symbole für Pings verwenden" "label": "Symbole für Pings verwenden"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Standard Suchmaschine" "label": "Standard Suchmaschine"
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Benutzerdefiniertes Datumsformat", "label": "Benutzerdefiniertes Datumsformat",
"description": "ISO 8601 Standard benutzen um das Datum zu formatieren (dies wird andere Optionen überschreiben)" "description": "ISO 8601 Standard benutzen um das Datum zu formatieren (dies wird andere Optionen überschreiben)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Formatierung entfernen", "clear": "Formatierung entfernen",
"heading": "Überschrift {level}", "heading": "Überschrift {level}",
"align": "Text ausrichten: {position}", "align": "Text ausrichten: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Blockzitat", "blockquote": "Blockzitat",
"horizontalLine": "Horizontale Linie", "horizontalLine": "Horizontale Linie",
"bulletList": "Aufzählung", "bulletList": "Aufzählung",
@@ -2267,8 +2225,7 @@
"sunrise": "Sonnenaufgang", "sunrise": "Sonnenaufgang",
"sunset": "Sonnenuntergang", "sunset": "Sonnenuntergang",
"maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} km/h", "maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} km/h",
"maxWindGusts": "Maximale Windböen: {maxWindGusts} km/h", "maxWindGusts": "Maximale Windböen: {maxWindGusts} km/h"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Klar", "clear": "Klar",
@@ -2732,11 +2689,6 @@
"user": "Benutzer", "user": "Benutzer",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Links in neuem Tab öffnen" "label": "Links in neuem Tab öffnen"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS Feeds", "name": "RSS Feeds",
"description": "Einen oder mehrere generische RSS, ATOM oder JSON-Feeds überwachen und anzeigen", "description": "Einen oder mehrere generische RSS, ATOM oder JSON-Feeds überwachen und anzeigen",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Container", "title": "Container",
"table": { "table": {
"updated": "Aktualisiert {when}", "updated": "Aktualisiert {when}",
"refresh": {
"lastUpdated": ""
},
"search": "{count} Container durchsuchen", "search": "{count} Container durchsuchen",
"selected": "{selectCount} von {totalCount} ausgewählten Containern", "selected": "{selectCount} von {totalCount} ausgewählten Containern",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+10 -334
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Symbole für Pings verwenden" "label": "Symbole für Pings verwenden"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Standard Suchmaschine" "label": "Standard Suchmaschine"
}, },
@@ -1025,7 +1021,7 @@
"mediaMonitoring": "Überwachung", "mediaMonitoring": "Überwachung",
"speedtest": "Geschwindigkeitstest", "speedtest": "Geschwindigkeitstest",
"analytics": "Nutzungsdaten", "analytics": "Nutzungsdaten",
"vpn": "VPN", "vpn": "",
"mediaLibrary": "Medienbibliothek", "mediaLibrary": "Medienbibliothek",
"uptimeMonitoring": "Überwachung der Betriebszeit" "uptimeMonitoring": "Überwachung der Betriebszeit"
}, },
@@ -1289,14 +1285,6 @@
"label": "API-Schlüssel (Secret)", "label": "API-Schlüssel (Secret)",
"newLabel": "Neuer API-Schlüssel (Secret)" "newLabel": "Neuer API-Schlüssel (Secret)"
}, },
"patchmonApiKey": {
"label": "API Key",
"newLabel": "Neuer API Key"
},
"patchmonApiSecret": {
"label": "API Secret",
"newLabel": "Neues API Secret"
},
"githubAppId": { "githubAppId": {
"label": "App ID", "label": "App ID",
"newLabel": "Neue App ID" "newLabel": "Neue App ID"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "Traefik",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "Paperless-ngx", "name": "Paperless-ngx",
"description": "Dokumentenverwaltungssystem zum Archivieren und Organisieren gescannter Dokumente" "description": "Dokumentenverwaltungssystem zum Archivieren und Organisieren gescannter Dokumente"
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1623,15 +1599,9 @@
"menu": { "menu": {
"label": { "label": {
"settings": "Einstellungen", "settings": "Einstellungen",
"refresh": "Aktualisieren", "refresh": "",
"options": "Optionen", "options": "",
"actions": "Aktionen" "actions": ""
},
"status": {
"success": "",
"error": "Fehler",
"loading": "Wird geladen",
"idle": "Leerlauf"
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Benutzerdefiniertes Datumsformat", "label": "Benutzerdefiniertes Datumsformat",
"description": "ISO 8601 Standard benutzen um das Datum zu formatieren (dies wird andere Optionen überschreiben)" "description": "ISO 8601 Standard benutzen um das Datum zu formatieren (dies wird andere Optionen überschreiben)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Formatierung entfernen", "clear": "Formatierung entfernen",
"heading": "Überschrift {level}", "heading": "Überschrift {level}",
"align": "Text ausrichten: {position}", "align": "Text ausrichten: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Blockzitat", "blockquote": "Blockzitat",
"horizontalLine": "Horizontale Linie", "horizontalLine": "Horizontale Linie",
"bulletList": "Aufzählung", "bulletList": "Aufzählung",
@@ -2267,8 +2225,7 @@
"sunrise": "Sonnenaufgang", "sunrise": "Sonnenaufgang",
"sunset": "Sonnenuntergang", "sunset": "Sonnenuntergang",
"maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} {unit}", "maxWindSpeed": "Maximale Windgeschwindigkeit: {maxWindSpeed} {unit}",
"maxWindGusts": "Maximale Windböen: {maxWindGusts} {unit}", "maxWindGusts": "Maximale Windböen: {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Klar", "clear": "Klar",
@@ -2330,7 +2287,7 @@
"visibleStorageVolumes": { "visibleStorageVolumes": {
"label": "", "label": "",
"description": "", "description": "",
"placeholder": "Speichervolumen auswählen" "placeholder": ""
}, },
"defaultTab": { "defaultTab": {
"label": "Standard Tab" "label": "Standard Tab"
@@ -2469,8 +2426,8 @@
}, },
"vpn": { "vpn": {
"name": "", "name": "",
"description": "Übersicht deiner VPN-Verbindungen", "description": "",
"serviceUnavailable": "VPN nicht verfügbar", "serviceUnavailable": "",
"option": {} "option": {}
}, },
"ups": { "ups": {
@@ -2732,11 +2689,6 @@
"user": "Benutzer", "user": "Benutzer",
"name": "Name", "name": "Name",
"id": "Id", "id": "Id",
"status": "Status",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Statistiken für Nerds", "title": "Statistiken für Nerds",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "Fehler beim Abrufen der Paperless-ngx-Daten" "internalServerError": "Fehler beim Abrufen der Paperless-ngx-Daten"
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "Alle Hosts anzeigen",
"description": "Gesamtanzahl der überwachten Hosts anzeigen"
},
"showHostsNeedingUpdates": {
"label": "Hosts die Updates benötigen anzeigen",
"description": "Hosts mit mindestens einem veralteten Paket anzeigen"
},
"showSecurityUpdates": {
"label": "Sicherheits-Updates anzeigen",
"description": "Gesamtzahl der verfügbaren Sicherheits-Updates anzeigen"
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich Serverstatistik einblenden", "name": "Immich Serverstatistik einblenden",
"description": "Informationen über Ihre Immich Instanz", "description": "Informationen über Ihre Immich Instanz",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich Album", "name": "Immich Album",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "Album ID", "label": "Album ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Diashow der Bilder in Ihrem Immich Album", "description": "Diashow der Bilder in Ihrem Immich Album",
"noAlbumSelected": "Kein Album ausgewählt, Widget bearbeiten und Album auswählen",
"noPhotos": "Keine Fotos in diesem Album" "noPhotos": "Keine Fotos in diesem Album"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Links in neuem Tab öffnen" "label": "Links in neuem Tab öffnen"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS Feeds", "name": "RSS Feeds",
"description": "Einen oder mehrere generische RSS, ATOM oder JSON-Feeds überwachen und anzeigen", "description": "Einen oder mehrere generische RSS, ATOM oder JSON-Feeds überwachen und anzeigen",
@@ -3606,11 +3336,7 @@
"name": "Benachrichtigungen", "name": "Benachrichtigungen",
"description": "Benachrichtigungshistorie von einer Integration anzeigen", "description": "Benachrichtigungshistorie von einer Integration anzeigen",
"noItems": "Keine Benachrichtigungen zum Anzeigen.", "noItems": "Keine Benachrichtigungen zum Anzeigen.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "Speedtest Tracker", "name": "Speedtest Tracker",
@@ -3691,40 +3417,6 @@
"internalServerError": "Fehler beim Abrufen der Laufzeit Daten" "internalServerError": "Fehler beim Abrufen der Laufzeit Daten"
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "Audiostatistiken", "name": "Audiostatistiken",
"description": "Bibliotheks- und Wiedergabestatistiken von Navidrome oder Audiobookshelf", "description": "Bibliotheks- und Wiedergabestatistiken von Navidrome oder Audiobookshelf",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Container", "title": "Container",
"table": { "table": {
"updated": "Aktualisiert {when}", "updated": "Aktualisiert {when}",
"refresh": {
"lastUpdated": ""
},
"search": "{count} Container durchsuchen", "search": "{count} Container durchsuchen",
"selected": "{selectCount} von {totalCount} ausgewählten Containern", "selected": "{selectCount} von {totalCount} ausgewählten Containern",
"footer": "Insgesamt {count} Container", "footer": "Insgesamt {count} Container",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "Alle Einstellungen öffnen" "label": "Alle Einstellungen öffnen"
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "" "label": ""
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Προεπιλεγμένη μηχανή αναζήτησης" "label": "Προεπιλεγμένη μηχανή αναζήτησης"
}, },
@@ -1289,14 +1285,6 @@
"label": "Κλειδί API (Μυστικό)", "label": "Κλειδί API (Μυστικό)",
"newLabel": "Νέο Κλειδί API (Μυστικό)" "newLabel": "Νέο Κλειδί API (Μυστικό)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Εκκαθάριση μορφοποίησης", "clear": "Εκκαθάριση μορφοποίησης",
"heading": "Επικεφαλίδα {level}", "heading": "Επικεφαλίδα {level}",
"align": "Στοίχιση κειμένου: {position}", "align": "Στοίχιση κειμένου: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Μπλοκ κειμένου παράθεσης", "blockquote": "Μπλοκ κειμένου παράθεσης",
"horizontalLine": "Οριζόντια γραμμή", "horizontalLine": "Οριζόντια γραμμή",
"bulletList": "Λίστα με κουκκίδες", "bulletList": "Λίστα με κουκκίδες",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Καθαρός", "clear": "Καθαρός",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Άνοιγμα συνδέσμων σε νέα καρτέλα" "label": "Άνοιγμα συνδέσμων σε νέα καρτέλα"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+70 -394
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Use icons for pings" "label": "Use icons for pings"
}, },
"enableRightClickOnWidgets": {
"label": "Enable right-click on widgets",
"description": "Show Homarr's context menu when right-clicking a widget. Disable to use the browser's default menu (e.g. \"Open link in new tab\")."
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Default search engine" "label": "Default search engine"
}, },
@@ -713,76 +709,76 @@
"addMapping": "Add Mapping", "addMapping": "Add Mapping",
"addColumn": "Add Column", "addColumn": "Add Column",
"edit": "Edit", "edit": "Edit",
"removeMapping": "Remove mapping", "removeMapping": "",
"removeColumn": "Remove column", "removeColumn": "",
"addItem": "Add Item", "addItem": "",
"removeItem": "Remove item", "removeItem": "",
"addBar": "Add Bar", "addBar": "",
"duplicate": "Duplicate", "duplicate": "",
"copyAiPrompt": "Copy AI prompt", "copyAiPrompt": "",
"enable": "Enable", "enable": "",
"disable": "Disable", "disable": "",
"menu": "Actions" "menu": ""
}, },
"field": { "field": {
"name": "Name", "name": "",
"description": "Description", "description": "",
"iconUrl": "Icon URL", "iconUrl": "",
"url": "URL", "url": "",
"authType": "Auth Type", "authType": "",
"headerName": "Header/Query Parameter Name", "headerName": "",
"method": "Method", "method": "",
"requestBody": "Request Body", "requestBody": "",
"displayType": "Display Type", "displayType": "",
"jsonPath": "JSON Path", "jsonPath": "",
"jsonPathHint": "Use JSONPath syntax to extract values, e.g. $.data.temperature or $.items[0].name", "jsonPathHint": "",
"label": "Label", "label": "",
"unit": "Unit", "unit": "",
"mappings": "Mappings", "mappings": "",
"tablePath": "Array JSON Path", "tablePath": "",
"tablePathHint": "Path to the array in the response, e.g. $.data.items", "tablePathHint": "",
"columns": "Columns", "columns": "",
"header": "Header", "header": "",
"items": "Items", "items": "",
"gridColumns": "Grid Columns", "gridColumns": "",
"cardStyle": "Card Style", "cardStyle": "",
"bars": "Bars", "bars": "",
"valuePath": "Value JSON Path", "valuePath": "",
"maxPath": "Max Value JSON Path", "maxPath": "",
"showPercentage": "Show Percentage", "showPercentage": "",
"barSize": "Bar Size", "barSize": "",
"goodValues": "Good Values (comma-separated)", "goodValues": "",
"dotSize": "Dot Size", "dotSize": "",
"valueSize": "Value Size", "valueSize": "",
"labelPosition": "Label Position", "labelPosition": "",
"kvLayout": "Layout", "kvLayout": "",
"striped": "Striped Rows", "striped": "",
"compact": "Compact Mode", "compact": "",
"maxHeight": "Max Height (px)", "maxHeight": "",
"color": "Colour", "color": "",
"buttonLabel": "Button Label", "buttonLabel": "",
"buttonColor": "Button Colour", "buttonColor": "",
"confirmText": "Confirmation Text", "confirmText": "",
"confirmTextHint": "If set, a confirmation dialogue will appear before executing the request", "confirmTextHint": "",
"successMessage": "Success Message", "successMessage": "",
"successMessageHint": "Message shown after successful execution", "successMessageHint": "",
"enabled": "Enabled", "enabled": "",
"template": { "template": {
"label": "JSX Template", "label": "",
"description": "Mantine JSX template. Access API response fields via data bindings (e.g. data.name). Use whitelisted components only. Forbidden: constructor, __proto__, eval, Function, window, document." "description": ""
} }
}, },
"placeholder": { "placeholder": {
"exampleLabel": "CPU Temperature", "exampleLabel": "",
"exampleLabelShort": "CPU Temp", "exampleLabelShort": "",
"exampleHeader": "Name", "exampleHeader": "",
"exampleUnit": "°C", "exampleUnit": "",
"iconUrl": "https://...", "iconUrl": "",
"url": "https://api.example.com/api/v1/status", "url": "",
"headerName": "X-API-Key", "headerName": "",
"jsonPath": "$.data.value", "jsonPath": "",
"tablePath": "$.data.items", "tablePath": "",
"columnJsonPath": "$.name", "columnJsonPath": "",
"valuePath": "", "valuePath": "",
"maxPath": "", "maxPath": "",
"goodValues": "", "goodValues": "",
@@ -1289,14 +1285,6 @@
"label": "API Key (Secret)", "label": "API Key (Secret)",
"newLabel": "New API Key (Secret)" "newLabel": "New API Key (Secret)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "App Id", "label": "App Id",
"newLabel": "New App Id" "newLabel": "New App Id"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Custom date format", "label": "Custom date format",
"description": "Use ISO 8601 to format date (this will override other options)" "description": "Use ISO 8601 to format date (this will override other options)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Clear formatting", "clear": "Clear formatting",
"heading": "Heading {level}", "heading": "Heading {level}",
"align": "Align text: {position}", "align": "Align text: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Blockquote", "blockquote": "Blockquote",
"horizontalLine": "Horizontal line", "horizontalLine": "Horizontal line",
"bulletList": "Bullet list", "bulletList": "Bullet list",
@@ -2267,8 +2225,7 @@
"sunrise": "Sunrise", "sunrise": "Sunrise",
"sunset": "Sunset", "sunset": "Sunset",
"maxWindSpeed": "Max wind speed: {maxWindSpeed} {unit}", "maxWindSpeed": "Max wind speed: {maxWindSpeed} {unit}",
"maxWindGusts": "Max wind gusts: {maxWindGusts} {unit}", "maxWindGusts": "Max wind gusts: {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Clear", "clear": "Clear",
@@ -2732,11 +2689,6 @@
"user": "User", "user": "User",
"name": "Name", "name": "Name",
"id": "Id", "id": "Id",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Stats for nerds", "title": "Stats for nerds",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich Server Stats", "name": "Immich Server Stats",
"description": "Information about your Immich instance", "description": "Information about your Immich instance",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich Album", "name": "Immich Album",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "Album ID", "label": "Album ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "" "label": ""
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5894,10 +5578,10 @@
}, },
"searchEngine": { "searchEngine": {
"none": "", "none": "",
"unavailable": "Currently selected (unavailable)" "unavailable": ""
}, },
"colorScheme": { "colorScheme": {
"label": "Colour scheme", "label": "",
"children": { "children": {
"detail": { "detail": {
"title": "Select your colour scheme" "title": "Select your colour scheme"
@@ -5968,16 +5652,8 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "Enable right-click on widgets",
"children": {
"detail": {
"title": "Enable right-click on widgets"
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "Open full preferences page" "label": ""
} }
} }
} }
+5 -45
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Use icons for pings" "label": "Use icons for pings"
}, },
"enableRightClickOnWidgets": {
"label": "Enable right-click on widgets",
"description": "Show Homarr's context menu when right-clicking a widget. Disable to use the browser's default menu (e.g. \"Open link in new tab\")."
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Default search engine" "label": "Default search engine"
}, },
@@ -1626,12 +1622,6 @@
"refresh": "Refresh", "refresh": "Refresh",
"options": "Options", "options": "Options",
"actions": "Actions" "actions": "Actions"
},
"status": {
"success": "OK",
"error": "Error",
"loading": "Loading",
"idle": "Idle"
} }
}, },
"create": { "create": {
@@ -1905,16 +1895,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Custom date format", "label": "Custom date format",
"description": "Use ISO 8601 to format date (this will override other options)" "description": "Use ISO 8601 to format date (this will override other options)"
},
"showWeather": {
"label": "Show weather",
"description": "Display a small animated weather icon and temperature in the corner of the card"
},
"weatherLocation": {
"label": "Weather location"
},
"isWeatherFormatFahrenheit": {
"label": "Use Fahrenheit"
} }
} }
}, },
@@ -2267,8 +2247,7 @@
"sunrise": "Sunrise", "sunrise": "Sunrise",
"sunset": "Sunset", "sunset": "Sunset",
"maxWindSpeed": "Max wind speed: {maxWindSpeed} {unit}", "maxWindSpeed": "Max wind speed: {maxWindSpeed} {unit}",
"maxWindGusts": "Max wind gusts: {maxWindGusts} {unit}", "maxWindGusts": "Max wind gusts: {maxWindGusts} {unit}"
"humidity": "Humidity: {humidity}%"
}, },
"kind": { "kind": {
"clear": "Clear", "clear": "Clear",
@@ -2732,11 +2711,6 @@
"user": "User", "user": "User",
"name": "Name", "name": "Name",
"id": "Id", "id": "Id",
"status": "Status",
"directPlay": "Direct play",
"transcoding": "Transcoding",
"paused": "Paused",
"remaining": "{minutes} min left",
"metadata": { "metadata": {
"title": "Stats for nerds", "title": "Stats for nerds",
"video": { "video": {
@@ -3017,11 +2991,10 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich Album", "name": "Immich Album",
"allPhotos": "All photos",
"option": { "option": {
"albumId": { "albumId": {
"label": "Album", "label": "Album",
"description": "Select an Immich album or All photos. An empty selection also shows random photos from your full library." "description": "Select the Immich album to show in the slideshow."
}, },
"rotationIntervalSeconds": { "rotationIntervalSeconds": {
"label": "Interval in seconds", "label": "Interval in seconds",
@@ -3036,8 +3009,9 @@
"description": "Show photos in a random order instead of always starting with the same album order." "description": "Show photos in a random order instead of always starting with the same album order."
} }
}, },
"description": "Slideshow of pictures from an Immich album or your full library", "description": "Slideshow of pictures in your Immich album",
"noPhotos": "No photos found" "noAlbumSelected": "No album selected, edit widget and choose an album",
"noPhotos": "No photos in this album"
}, },
"downloads": { "downloads": {
"name": "Download Client", "name": "Download Client",
@@ -3221,12 +3195,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Open links in new tab" "label": "Open links in new tab"
},
"statusFilter": {
"label": "Statuses to show"
},
"recentDays": {
"label": "Show only recent requests"
} }
}, },
"pending": { "pending": {
@@ -5968,14 +5936,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "Enable right-click on widgets",
"children": {
"detail": {
"title": "Enable right-click on widgets"
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "Open full preferences page" "label": "Open full preferences page"
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Usar iconos para pings" "label": "Usar iconos para pings"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Motor de búsqueda predeterminado" "label": "Motor de búsqueda predeterminado"
}, },
@@ -1289,14 +1285,6 @@
"label": "Clave API (Credencial)", "label": "Clave API (Credencial)",
"newLabel": "Nueva clave API (Credencial)" "newLabel": "Nueva clave API (Credencial)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "ID de aplicación", "label": "ID de aplicación",
"newLabel": "Nuevo ID de aplicación" "newLabel": "Nuevo ID de aplicación"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Formato de fecha personalizado", "label": "Formato de fecha personalizado",
"description": "Usar ISO 8601 para dar formato a la hora (esto anulará otras opciones)" "description": "Usar ISO 8601 para dar formato a la hora (esto anulará otras opciones)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Borrar formato", "clear": "Borrar formato",
"heading": "Encabezado {level}", "heading": "Encabezado {level}",
"align": "Alinear texto: {position}", "align": "Alinear texto: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Cita", "blockquote": "Cita",
"horizontalLine": "Línea horizontal", "horizontalLine": "Línea horizontal",
"bulletList": "Lista sin ordenar", "bulletList": "Lista sin ordenar",
@@ -2267,8 +2225,7 @@
"sunrise": "Amanecer", "sunrise": "Amanecer",
"sunset": "Atardecer", "sunset": "Atardecer",
"maxWindSpeed": "Velocidad máxima del viento: {maxWindSpeed} {unit}", "maxWindSpeed": "Velocidad máxima del viento: {maxWindSpeed} {unit}",
"maxWindGusts": "Máximas ráfagas de viento: {maxWindGusts} {unit}", "maxWindGusts": "Máximas ráfagas de viento: {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Despejado", "clear": "Despejado",
@@ -2732,11 +2689,6 @@
"user": "Usuario", "user": "Usuario",
"name": "Nombre", "name": "Nombre",
"id": "ID", "id": "ID",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Estadísticas", "title": "Estadísticas",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Estadísticas del servidor Immich", "name": "Estadísticas del servidor Immich",
"description": "Información del servidor Immich", "description": "Información del servidor Immich",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Álbum de Immich", "name": "Álbum de Immich",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "ID de álbum", "label": "ID de álbum",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Presentación de fotos de un álbum de Immich", "description": "Presentación de fotos de un álbum de Immich",
"noAlbumSelected": "No se ha seleccionado ningún álbum. Edita el widget y selecciona uno.",
"noPhotos": "No hay fotos en este álbum" "noPhotos": "No hay fotos en este álbum"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Abrir enlaces en una pestaña nueva" "label": "Abrir enlaces en una pestaña nueva"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "Fuentes RSS", "name": "Fuentes RSS",
"description": "Monitorear y mostrar una o más RSS genéricas, ATOM o JSON", "description": "Monitorear y mostrar una o más RSS genéricas, ATOM o JSON",
@@ -3606,11 +3336,7 @@
"name": "Notificaciones", "name": "Notificaciones",
"description": "Mostrar el historial de notificaciones desde una integración", "description": "Mostrar el historial de notificaciones desde una integración",
"noItems": "Ninguna notificación para mostrar.", "noItems": "Ninguna notificación para mostrar.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "Speedtest Tracker", "name": "Speedtest Tracker",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Contenedores", "title": "Contenedores",
"table": { "table": {
"updated": "Actualizado {when}", "updated": "Actualizado {when}",
"refresh": {
"lastUpdated": ""
},
"search": "Buscar {count} contenedores", "search": "Buscar {count} contenedores",
"selected": "{selectCount} de {totalCount} contenedores seleccionados", "selected": "{selectCount} de {totalCount} contenedores seleccionados",
"footer": "{count} contenedores en total", "footer": "{count} contenedores en total",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "" "label": ""
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "" "label": ""
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "", "clear": "",
"heading": "", "heading": "",
"align": "", "align": "",
"directionLtr": "",
"directionRtl": "",
"blockquote": "", "blockquote": "",
"horizontalLine": "", "horizontalLine": "",
"bulletList": "", "bulletList": "",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "", "clear": "",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "" "label": ""
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Käytä ping-kuvakkeita" "label": "Käytä ping-kuvakkeita"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Oletushakukone" "label": "Oletushakukone"
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "Sovellustunniste", "label": "Sovellustunniste",
"newLabel": "Uusi sovellustunniste" "newLabel": "Uusi sovellustunniste"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Oma päiväyksen esitystapa", "label": "Oma päiväyksen esitystapa",
"description": "Määritä ISO 8601 -standardin mukainen päiväyksen muoto (korvaa muut valinnat)." "description": "Määritä ISO 8601 -standardin mukainen päiväyksen muoto (korvaa muut valinnat)."
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "", "clear": "",
"heading": "", "heading": "",
"align": "", "align": "",
"directionLtr": "",
"directionRtl": "",
"blockquote": "", "blockquote": "",
"horizontalLine": "", "horizontalLine": "",
"bulletList": "", "bulletList": "",
@@ -2267,8 +2225,7 @@
"sunrise": "Auringonnousu", "sunrise": "Auringonnousu",
"sunset": "Auringonlasku", "sunset": "Auringonlasku",
"maxWindSpeed": "Tuulen nopeus: {maxWindSpeed} {unit}", "maxWindSpeed": "Tuulen nopeus: {maxWindSpeed} {unit}",
"maxWindGusts": "Puuskien nopeus: {maxWindSpeed} {unit}", "maxWindGusts": "Puuskien nopeus: {maxWindSpeed} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "", "clear": "",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Avaa linkit uudessa välilehdessä" "label": "Avaa linkit uudessa välilehdessä"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "Näytä integraation ilmoitushistoria", "description": "Näytä integraation ilmoitushistoria",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Kontit", "title": "Kontit",
"table": { "table": {
"updated": "Päivitetty {when}", "updated": "Päivitetty {when}",
"refresh": {
"lastUpdated": ""
},
"search": "Suodata {count} konttia...", "search": "Suodata {count} konttia...",
"selected": "{selectCount}/{totalCount} kontista valittu", "selected": "{selectCount}/{totalCount} kontista valittu",
"footer": "Yhteensä {count} konttia", "footer": "Yhteensä {count} konttia",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "Avaa täysi asetussivu" "label": "Avaa täysi asetussivu"
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Utiliser les icônes pour les pings" "label": "Utiliser les icônes pour les pings"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Moteur de recherche par défaut" "label": "Moteur de recherche par défaut"
}, },
@@ -1289,14 +1285,6 @@
"label": "Clé API (secrète)", "label": "Clé API (secrète)",
"newLabel": "Nouvelle clé API (secrète)" "newLabel": "Nouvelle clé API (secrète)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "Identifiant de l'application", "label": "Identifiant de l'application",
"newLabel": "Nouvel Id de l'Application" "newLabel": "Nouvel Id de l'Application"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "Actualiser", "refresh": "Actualiser",
"options": "Options", "options": "Options",
"actions": "Actions" "actions": "Actions"
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Format de date personnalisé", "label": "Format de date personnalisé",
"description": "Utiliser ISO 8601 pour formater la date (cela remplacera les autres options)" "description": "Utiliser ISO 8601 pour formater la date (cela remplacera les autres options)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Effacer la mise en forme", "clear": "Effacer la mise en forme",
"heading": "Titre {level}", "heading": "Titre {level}",
"align": "Aligner le texte : {position}", "align": "Aligner le texte : {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Citation", "blockquote": "Citation",
"horizontalLine": "Ligne horizontale", "horizontalLine": "Ligne horizontale",
"bulletList": "Liste à puces", "bulletList": "Liste à puces",
@@ -2267,8 +2225,7 @@
"sunrise": "Lever du Soleil", "sunrise": "Lever du Soleil",
"sunset": "Coucher du soleil", "sunset": "Coucher du soleil",
"maxWindSpeed": "Vitesse maximale du vent : {maxWindSpeed} km/h", "maxWindSpeed": "Vitesse maximale du vent : {maxWindSpeed} km/h",
"maxWindGusts": "Rafales de vent maximales : {maxWindGusts} km/h", "maxWindGusts": "Rafales de vent maximales : {maxWindGusts} km/h"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Clair", "clear": "Clair",
@@ -2732,11 +2689,6 @@
"user": "Utilisateur", "user": "Utilisateur",
"name": "Nom", "name": "Nom",
"id": "Id", "id": "Id",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Statistiques détaillées", "title": "Statistiques détaillées",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Statistiques du serveur Immich", "name": "Statistiques du serveur Immich",
"description": "Informations sur votre instance Immich", "description": "Informations sur votre instance Immich",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Album Immich", "name": "Album Immich",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "Identifiant de l'album", "label": "Identifiant de l'album",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Diaporama de photos dans votre album Immich", "description": "Diaporama de photos dans votre album Immich",
"noAlbumSelected": "Aucun album sélectionné, modifier le widget et choisissez un album",
"noPhotos": "Aucune photo dans cet album" "noPhotos": "Aucune photo dans cet album"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Ouvrir les liens dans un nouvel onglet" "label": "Ouvrir les liens dans un nouvel onglet"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "Flux RSS", "name": "Flux RSS",
"description": "Surveiller et afficher un ou plusieurs flux RSS, ATOM ou JSON génériques", "description": "Surveiller et afficher un ou plusieurs flux RSS, ATOM ou JSON génériques",
@@ -3606,11 +3336,7 @@
"name": "Notifications", "name": "Notifications",
"description": "Afficher l'historique des notifications à partir d'une intégration", "description": "Afficher l'historique des notifications à partir d'une intégration",
"noItems": "Aucune notification à afficher.", "noItems": "Aucune notification à afficher.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "Suivi de test de vitesse", "name": "Suivi de test de vitesse",
@@ -3691,40 +3417,6 @@
"internalServerError": "Impossible de récupérer les données de disponibilité" "internalServerError": "Impossible de récupérer les données de disponibilité"
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "Statistiques audio", "name": "Statistiques audio",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Conteneurs", "title": "Conteneurs",
"table": { "table": {
"updated": "Mis à jour {when}", "updated": "Mis à jour {when}",
"refresh": {
"lastUpdated": ""
},
"search": "Rechercher dans {count} conteneurs", "search": "Rechercher dans {count} conteneurs",
"selected": "{selectCount} sur {totalCount} conteneurs sélectionnés", "selected": "{selectCount} sur {totalCount} conteneurs sélectionnés",
"footer": "Total des conteneurs {count}", "footer": "Total des conteneurs {count}",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "השתמש בסמלים עבור פינגים" "label": "השתמש בסמלים עבור פינגים"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "מנוע חיפוש ברירת מחדל" "label": "מנוע חיפוש ברירת מחדל"
}, },
@@ -1289,14 +1285,6 @@
"label": "מפתח API (סודי)", "label": "מפתח API (סודי)",
"newLabel": "מפתח API חדש (סודי)" "newLabel": "מפתח API חדש (סודי)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "מזהה אפליקציה", "label": "מזהה אפליקציה",
"newLabel": "מזהה אפליקציה חדש" "newLabel": "מזהה אפליקציה חדש"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "פורמט זמן מותאם אישית", "label": "פורמט זמן מותאם אישית",
"description": "השתמש ב-ISO 8601 כדי לעצב תצוגת זמן (זה ידרוס אפשרויות אחרות)" "description": "השתמש ב-ISO 8601 כדי לעצב תצוגת זמן (זה ידרוס אפשרויות אחרות)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "נקה עיצוב", "clear": "נקה עיצוב",
"heading": "כותרת {level}", "heading": "כותרת {level}",
"align": "יישור טקסט: {position}", "align": "יישור טקסט: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "ציטוט", "blockquote": "ציטוט",
"horizontalLine": "קו אופקי", "horizontalLine": "קו אופקי",
"bulletList": "רשימת תבליט", "bulletList": "רשימת תבליט",
@@ -2267,8 +2225,7 @@
"sunrise": "זריחה", "sunrise": "זריחה",
"sunset": "שקיעה", "sunset": "שקיעה",
"maxWindSpeed": "מהירות רוח מקסימלית: {maxWindSpeed} קמ״ש", "maxWindSpeed": "מהירות רוח מקסימלית: {maxWindSpeed} קמ״ש",
"maxWindGusts": "משבי רוח מקסימלים: {maxWindGusts} קמ״ש", "maxWindGusts": "משבי רוח מקסימלים: {maxWindGusts} קמ״ש"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "בהיר", "clear": "בהיר",
@@ -2732,11 +2689,6 @@
"user": "משתמש", "user": "משתמש",
"name": "שם", "name": "שם",
"id": "מזהה", "id": "מזהה",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "סטטיסטיקות לחנונים", "title": "סטטיסטיקות לחנונים",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "פתח לינק בלשונית חדשה" "label": "פתח לינק בלשונית חדשה"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "הזנות RSS", "name": "הזנות RSS",
"description": "מעקב והצג עדכוני RSS, ATOM או JSON גנרי אחד או יותר", "description": "מעקב והצג עדכוני RSS, ATOM או JSON גנרי אחד או יותר",
@@ -3606,11 +3336,7 @@
"name": "התראות", "name": "התראות",
"description": "הצגת היסטוריית התראות מאינטגרציה", "description": "הצגת היסטוריית התראות מאינטגרציה",
"noItems": "אין התראות להצגה.", "noItems": "אין התראות להצגה.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "מיכלים", "title": "מיכלים",
"table": { "table": {
"updated": "עודכן ב- {when}", "updated": "עודכן ב- {when}",
"refresh": {
"lastUpdated": ""
},
"search": "חפש {count} קונטיינרים", "search": "חפש {count} קונטיינרים",
"selected": "{selectCount} מ- {totalCount} קונטיינרים נבחרו", "selected": "{selectCount} מ- {totalCount} קונטיינרים נבחרו",
"footer": "סה״כ {count} קונטיינרים", "footer": "סה״כ {count} קונטיינרים",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "" "label": ""
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "" "label": ""
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "", "clear": "",
"heading": "", "heading": "",
"align": "", "align": "",
"directionLtr": "",
"directionRtl": "",
"blockquote": "", "blockquote": "",
"horizontalLine": "", "horizontalLine": "",
"bulletList": "", "bulletList": "",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Vedro", "clear": "Vedro",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Otvori veze u novoj kartici" "label": "Otvori veze u novoj kartici"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Ikonok használata a pingekhez" "label": "Ikonok használata a pingekhez"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Alapértelmezett kereső" "label": "Alapértelmezett kereső"
}, },
@@ -1289,14 +1285,6 @@
"label": "Api Kulcs (Titkos)", "label": "Api Kulcs (Titkos)",
"newLabel": "Új API Kulcs (Titkos)" "newLabel": "Új API Kulcs (Titkos)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "App Azonosító", "label": "App Azonosító",
"newLabel": "Új App Azonosító" "newLabel": "Új App Azonosító"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Egyedi dátumformátum", "label": "Egyedi dátumformátum",
"description": "A dátum formázásához használja az ISO 8601 szabványt (ez felülírja az egyéb beállításokat)" "description": "A dátum formázásához használja az ISO 8601 szabványt (ez felülírja az egyéb beállításokat)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Formázás törlése", "clear": "Formázás törlése",
"heading": "Címsor {level}", "heading": "Címsor {level}",
"align": "Szöveg igazítása: {position}", "align": "Szöveg igazítása: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Idézet", "blockquote": "Idézet",
"horizontalLine": "Vízszintes vonal", "horizontalLine": "Vízszintes vonal",
"bulletList": "Lista", "bulletList": "Lista",
@@ -2267,8 +2225,7 @@
"sunrise": "Napkelte", "sunrise": "Napkelte",
"sunset": "Naplemente", "sunset": "Naplemente",
"maxWindSpeed": "Legnagyobb szélsebesség: {maxWindSpeed} {unit}", "maxWindSpeed": "Legnagyobb szélsebesség: {maxWindSpeed} {unit}",
"maxWindGusts": "Legerősebb széllökés: {maxWindGusts} {unit}", "maxWindGusts": "Legerősebb széllökés: {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Tiszta", "clear": "Tiszta",
@@ -2732,11 +2689,6 @@
"user": "Felhasználó", "user": "Felhasználó",
"name": "Név", "name": "Név",
"id": "Azonosító", "id": "Azonosító",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "Statisztikák a rajongóknak", "title": "Statisztikák a rajongóknak",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich szerver statisztikák", "name": "Immich szerver statisztikák",
"description": "Információk az Immich-példányodról", "description": "Információk az Immich-példányodról",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich Album", "name": "Immich Album",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "Album ID", "label": "Album ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Képek diavetítése az Immich-albumodból", "description": "Képek diavetítése az Immich-albumodból",
"noAlbumSelected": "Nincs kiválasztott album; szerkeszd a widgetet, és válassz ki egy albumot",
"noPhotos": "Ebben az albumban nincs fénykép" "noPhotos": "Ebben az albumban nincs fénykép"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Linkek megnyitása új fülön" "label": "Linkek megnyitása új fülön"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS feedek", "name": "RSS feedek",
"description": "Egy vagy több általános RSS-, ATOM- vagy JSON-hírcsatorna figyelése és megjelenítése", "description": "Egy vagy több általános RSS-, ATOM- vagy JSON-hírcsatorna figyelése és megjelenítése",
@@ -3606,11 +3336,7 @@
"name": "Értesítések", "name": "Értesítések",
"description": "Egy integráció értesítési előzményeinek megjelenítése", "description": "Egy integráció értesítési előzményeinek megjelenítése",
"noItems": "Nincs megjelenítendő üzenet.", "noItems": "Nincs megjelenítendő üzenet.",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "Hálózatsebesség Monitorozó", "name": "Hálózatsebesség Monitorozó",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "Tartály", "title": "Tartály",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Usa le icone per i ping" "label": "Usa le icone per i ping"
}, },
"enableRightClickOnWidgets": {
"label": "Abilita clic destro sui widget",
"description": "Mostra il menu contestuale di Homarr quando si fa clic destro su un widget. Disabilita per usare il menu predefinito del browser (es. \"Apri collegamento in una nuova scheda\")."
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "Motore di ricerca predefinito" "label": "Motore di ricerca predefinito"
}, },
@@ -1289,14 +1285,6 @@
"label": "Chiave API (Secret)", "label": "Chiave API (Secret)",
"newLabel": "Nuova Chiave API (Secret)" "newLabel": "Nuova Chiave API (Secret)"
}, },
"patchmonApiKey": {
"label": "Chiave API",
"newLabel": "Nuova chiave API"
},
"patchmonApiSecret": {
"label": "Secret API",
"newLabel": "Nuova API Secret"
},
"githubAppId": { "githubAppId": {
"label": "Id App", "label": "Id App",
"newLabel": "Nuovo Id App" "newLabel": "Nuovo Id App"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "Traefik",
"description": "Cloud-native reverse proxy e bilanciatore del carico"
},
"paperlessNgx": { "paperlessNgx": {
"name": "Paperless-ngx", "name": "Paperless-ngx",
"description": "Sistema di gestione documentale per archiviare e organizzare documenti scansionati" "description": "Sistema di gestione documentale per archiviare e organizzare documenti scansionati"
},
"patchmon": {
"name": "PatchMon",
"description": "Gestione delle patch e monitoraggio per gli host Linux"
},
"bazarr": {
"name": "Bazarr",
"description": "Applicazione complementare a Sonarr e Radarr che gestisce e scarica i sottotitoli"
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "Aggiorna", "refresh": "Aggiorna",
"options": "Opzioni", "options": "Opzioni",
"actions": "Azioni" "actions": "Azioni"
},
"status": {
"success": "OK",
"error": "Errore",
"loading": "Caricamento",
"idle": "Inattivo"
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "Formato data personalizzato", "label": "Formato data personalizzato",
"description": "Usa ISO 8601 per formattare la data (questo sovrascriverà altre opzioni)" "description": "Usa ISO 8601 per formattare la data (questo sovrascriverà altre opzioni)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Rimuovi formattazione", "clear": "Rimuovi formattazione",
"heading": "Intestazione {level}", "heading": "Intestazione {level}",
"align": "Allinea testo: {position}", "align": "Allinea testo: {position}",
"directionLtr": "Imposta la direzione del testo da sinistra a sinistra",
"directionRtl": "Imposta la direzione del testo da destra a destra",
"blockquote": "Citazione", "blockquote": "Citazione",
"horizontalLine": "Linea orizzontale", "horizontalLine": "Linea orizzontale",
"bulletList": "Elenco puntato", "bulletList": "Elenco puntato",
@@ -2267,8 +2225,7 @@
"sunrise": "Alba", "sunrise": "Alba",
"sunset": "Tramonto", "sunset": "Tramonto",
"maxWindSpeed": "Max velocità vento: {maxWindSpeed} km/h", "maxWindSpeed": "Max velocità vento: {maxWindSpeed} km/h",
"maxWindGusts": "Max raffiche di vento: {maxWindGusts} km/h", "maxWindGusts": "Max raffiche di vento: {maxWindGusts} km/h"
"humidity": "Umidità: {humidity}%"
}, },
"kind": { "kind": {
"clear": "Sereno", "clear": "Sereno",
@@ -2732,11 +2689,6 @@
"user": "Utente", "user": "Utente",
"name": "Nome", "name": "Nome",
"id": "Id", "id": "Id",
"status": "Stato",
"directPlay": "Riproduzione diretta",
"transcoding": "Transcodifica",
"paused": "In pausa",
"remaining": "{minutes} min rimanenti",
"metadata": { "metadata": {
"title": "Statistiche per nerd", "title": "Statistiche per nerd",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "Impossibile recuperare i dati di Paperless-ngx" "internalServerError": "Impossibile recuperare i dati di Paperless-ngx"
} }
}, },
"patchmon": {
"name": "PatchMon",
"description": "Panoramica dello stato delle patch host da PatchMon",
"title": "Statistiche PatchMon",
"totalHosts": "Host Totali",
"hostsNeedingUpdates": "Necessita di aggiornamenti",
"securityUpdates": "Aggiornamenti di sicurezza",
"upToDateHosts": "Host aggiornati",
"hostsWithSecurityUpdates": "Host con aggiornamenti di sicurezza",
"recentUpdates24h": "Aggiornamenti (24h)",
"totalOutdatedPackages": "Pacchetti obsoleti",
"totalRepos": "Repository",
"osDistribution": "Distribuzione OS",
"compliance": "Conformità Patch",
"complianceRatio": "{upToDate} / {total}",
"lastUpdated": "Aggiornato {time}",
"option": {
"showTotalHosts": {
"label": "Mostra host totali",
"description": "Visualizzare il numero totale di host monitorati"
},
"showHostsNeedingUpdates": {
"label": "Mostra host che necessitano di aggiornamenti",
"description": "Visualizza gli host con almeno un pacchetto obsoleto"
},
"showSecurityUpdates": {
"label": "Mostra aggiornamenti di sicurezza",
"description": "Mostra il numero totale di aggiornamenti di sicurezza disponibili"
},
"showUpToDateHosts": {
"label": "Mostra host aggiornati",
"description": "Visualizza host con zero pacchetti obsoleti"
},
"showHostsWithSecurityUpdates": {
"label": "Mostra host con aggiornamenti di sicurezza",
"description": "Visualizza host che richiedono patch di sicurezza"
},
"showRecentUpdates24h": {
"label": "Mostra aggiornamenti recenti (24h)",
"description": "Mostra il numero di aggiornamenti applicati nelle ultime 24 ore"
},
"showTotalOutdatedPackages": {
"label": "Mostra pacchetti obsoleti",
"description": "Mostra il numero totale di pacchetti obsoleti su tutti gli host"
},
"showTotalRepos": {
"label": "Mostra repository",
"description": "Mostra il numero di repository attivi che vengono controllati"
},
"enableThresholdColors": {
"label": "Abilita colori di soglia",
"description": "Valori della statistica di colore verde, giallo, o rosso in base alle preimpostazioni di gravità"
},
"useCustomThresholds": {
"label": "Soglie avanzate",
"description": "Personalizza gli avvisi e le soglie critiche per stat utilizzando conteggi assoluti o percentuali del totale degli host"
},
"thresholdMode": {
"option": {
"absolute": "Conteggio assoluto",
"percent": "Percentuale degli host totali"
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "Modalità soglia aggiornamenti richiesti",
"description": "Confronta il numero di aggiornamenti richiesti come valore assoluto o percentuale su host totali"
},
"hostsNeedingUpdatesWarningAt": {
"label": "Soglia di avviso aggiornamenti richiesti",
"description": "Inserisci il giallo quando il valore raggiunge questa soglia"
},
"hostsNeedingUpdatesCriticalAt": {
"label": "Soglia critica aggiornamenti richiesti",
"description": "Inserisci il rosso quando il valore raggiunge questa soglia"
},
"securityUpdatesThresholdMode": {
"label": "Modalità soglia aggiornamenti di sicurezza",
"description": "Confronta il valore degli aggiornamenti di sicurezza come valore assoluto o percentuale del totale degli host"
},
"securityUpdatesWarningAt": {
"label": "Soglia di avviso aggiornamenti di sicurezza",
"description": "Inserisci il giallo quando il valore raggiunge questa soglia"
},
"securityUpdatesCriticalAt": {
"label": "Soglia critica aggiornamenti di sicurezza",
"description": "Inserisci il rosso quando il valore raggiunge questa soglia"
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "Modalità soglia host con aggiornamenti di sicurezza",
"description": "Confronta il numero di host come valore assoluto o percentuale su host totali"
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "Soglia di avviso host con aggiornamenti di sicurezza",
"description": "Inserisci il giallo quando il valore raggiunge questa soglia"
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "Soglia critica host con aggiornamenti di sicurezza",
"description": "Inserisci il rosso quando il valore raggiunge questa soglia"
},
"upToDateHostsThresholdMode": {
"label": "Modalità soglia host aggiornati",
"description": "Confronta il numero di host aggiornati come valore assoluto o percentuale su host totali"
},
"upToDateHostsWarningAt": {
"label": "Soglia di avviso host aggiornati",
"description": "Inserisci il giallo quando il valore è pari o superiore a questa soglia ma al di sotto della copertura completa"
},
"upToDateHostsCriticalAt": {
"label": "Soglia critica host aggiornati",
"description": "Inserisci rosso quando il valore scende al di sotto di questa soglia"
},
"totalOutdatedPackagesThresholdMode": {
"label": "Modalità soglia pacchetti obsoleti",
"description": "Confronta il numero di pacchetti obsoleti come valore assoluto o percentuale sui host totali"
},
"totalOutdatedPackagesWarningAt": {
"label": "Soglia di avviso pacchetti obsoleti",
"description": "Inserisci il giallo quando il valore raggiunge questa soglia"
},
"totalOutdatedPackagesCriticalAt": {
"label": "Soglia critica pacchetti obsoleti",
"description": "Inserisci il rosso quando il valore raggiunge questa soglia"
},
"showOsDistribution": {
"label": "Mostra distribuzione OS",
"description": "Mostra un dettaglio degli host monitorati per sistema operativo"
},
"osDistributionLimit": {
"label": "Limite distribuzione OS",
"description": "Numero massimo di sistemi operativi da visualizzare",
"option": {
"3": "Top 3",
"5": "Top 5",
"10": "Top 10",
"all": "Tutto"
}
},
"showOsVersion": {
"label": "Mostra versione OS",
"description": "Aggiungi la versione del sistema operativo a ogni etichetta di distribuzione quando disponibile"
},
"showComplianceHero": {
"label": "Mostra sezione principale conformità",
"description": "Mostra un anello di conformità con la percentuale di host aggiornati"
},
"osDisplayMode": {
"label": "Modalità di visualizzazione OS",
"description": "Scegli come visualizzare la distribuzione del sistema operativo",
"option": {
"bars": "Barre orizzontali",
"donut": "Grafico a ciambella"
}
}
},
"error": {
"internalServerError": "Impossibile recuperare i dati di PatchMon"
}
},
"bazarr": {
"name": "Bazarr",
"description": "Panoramica dei sottotitoli mancanti e dello stato di salute della tua istanza Bazarr",
"episodes": "Episodi Mancanti",
"movies": "Film Mancanti",
"providers": "Problemi del Provider",
"status": "Problemi di stato",
"option": {
"showMissingEpisodes": {
"label": "Mostra episodi mancanti",
"description": "Mostra il numero di episodi con sottotitoli mancanti"
},
"showMissingMovies": {
"label": "Mostra film mancanti",
"description": "Mostra il numero di film con sottotitoli mancanti"
},
"showProviderIssues": {
"label": "Mostra problemi del provider",
"description": "Mostra i provider di sottotitoli con problemi"
},
"showHealthIssues": {
"label": "Mostra problemi di stato",
"description": "Mostra il numero di problemi di stato di Bazarr"
}
},
"error": {
"internalServerError": "Impossibile recuperare i dati Bazarr"
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Statistiche Server Immich", "name": "Statistiche Server Immich",
"description": "Informazioni sulla tua istanza Immich", "description": "Informazioni sulla tua istanza Immich",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Album Immich", "name": "Album Immich",
"allPhotos": "Tutte le foto",
"option": { "option": {
"albumId": { "albumId": {
"label": "ID Album", "label": "ID Album",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Presentazione delle immagini nel tuo album Immich", "description": "Presentazione delle immagini nel tuo album Immich",
"noAlbumSelected": "Nessun album selezionato, modifica il widget e scegli un album",
"noPhotos": "Nessuna foto in questo album" "noPhotos": "Nessuna foto in questo album"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Apri i link in nuova scheda" "label": "Apri i link in nuova scheda"
},
"statusFilter": {
"label": "Stati da mostrare"
},
"recentDays": {
"label": "Mostra solo le richieste recenti"
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "Contenuti multimediali mancanti & in coda",
"description": "Mostra i film e gli episodi mancanti e in coda da Radarr e Sonarr",
"option": {
"showMissing": {
"label": "Mostra elementi mancanti"
},
"showQueued": {
"label": "Mostra elementi in coda"
},
"pageSize": {
"label": "Elementi per pagina"
}
},
"tab": {
"missing": "Mancanti",
"queued": "In coda"
},
"type": {
"movie": "Film",
"episode": "Episodio"
},
"empty": {
"missing": "Nessun elemento mancante",
"queued": "Nessun elemento in coda",
"noTabsEnabled": "Abilita almeno una scheda nelle impostazioni del widget"
},
"timeLeft": "Tempo residuo"
},
"rssFeed": { "rssFeed": {
"name": "Feed RSS", "name": "Feed RSS",
"description": "Monitora e visualizza uno o più feed generici RSS, ATOM o JSON", "description": "Monitora e visualizza uno o più feed generici RSS, ATOM o JSON",
@@ -3606,11 +3336,7 @@
"name": "Notifiche", "name": "Notifiche",
"description": "Visualizza la cronologia delle notifiche da un'integrazione", "description": "Visualizza la cronologia delle notifiche da un'integrazione",
"noItems": "Nessuna notifica da visualizzare.", "noItems": "Nessuna notifica da visualizzare.",
"option": { "option": {}
"hideLogos": {
"label": "Nascondi loghi"
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "SpeedTest Tracker", "name": "SpeedTest Tracker",
@@ -3691,40 +3417,6 @@
"internalServerError": "Impossibile recuperare i dati di uptime" "internalServerError": "Impossibile recuperare i dati di uptime"
} }
}, },
"traefik": {
"name": "Traefik",
"description": "Panoramica dei router, dei servizi, dei middleware e dei punti di ingresso di Traefik",
"option": {
"showTcp": {
"label": "Mostrare TCP"
},
"showUdp": {
"label": "Mostra UDP"
},
"showEntryPoints": {
"label": "Mostra punti di accesso"
}
},
"instances": "Istanze di Traefik",
"versionUnknown": "Versione sconosciuta",
"summary": {
"routers": "Routers",
"entryPoints": "Punti di accesso"
},
"resource": {
"routers": "Routers",
"services": "Servizi",
"middlewares": "Middleware"
},
"status": {
"healthy": "Normale funzionamento",
"errors": "{count} errori",
"warnings": "{count} avvisi"
},
"error": {
"internalServerError": "Recupero dei dati Traefik non riuscito"
}
},
"audioStats": { "audioStats": {
"name": "Statistiche audio", "name": "Statistiche audio",
"description": "Statistiche della libreria e di riproduzione da Navidrome o Audiobookshelf", "description": "Statistiche della libreria e di riproduzione da Navidrome o Audiobookshelf",
@@ -4100,11 +3792,6 @@
"read": "Lettura", "read": "Lettura",
"write": "Scrittura" "write": "Scrittura"
}, },
"storage": {
"title": "Spazio di archiviazione",
"subtitle": "Utilizzo del disco per filesystem",
"series": "Usato"
},
"network": { "network": {
"title": "Larghezza di Banda", "title": "Larghezza di Banda",
"subtitle": "Traffico di rete delle interfacce pubbliche", "subtitle": "Traffico di rete delle interfacce pubbliche",
@@ -5237,9 +4924,6 @@
"title": "Containers", "title": "Containers",
"table": { "table": {
"updated": "Aggiornato {when}", "updated": "Aggiornato {when}",
"refresh": {
"lastUpdated": "Ultimo aggiornamento {when}"
},
"search": "Cerca {count} container", "search": "Cerca {count} container",
"selected": "{selectCount} di {totalCount} containers selezionati", "selected": "{selectCount} di {totalCount} containers selezionati",
"footer": "Totale container {count}", "footer": "Totale container {count}",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "Abilita clic destro sui widget",
"children": {
"detail": {
"title": "Abilita clic destro sui widget"
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "Apri la pagina completa delle preferenze" "label": "Apri la pagina completa delle preferenze"
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "Pingにアイコンを使う" "label": "Pingにアイコンを使う"
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "既定の検索エンジン" "label": "既定の検索エンジン"
}, },
@@ -1289,14 +1285,6 @@
"label": "API キー (シークレット)", "label": "API キー (シークレット)",
"newLabel": "新しい API キー (シークレット)" "newLabel": "新しい API キー (シークレット)"
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "App Id", "label": "App Id",
"newLabel": "新規App Id" "newLabel": "新規App Id"
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "日付の書式をカスタマイズ", "label": "日付の書式をカスタマイズ",
"description": "日付の書式に ISO-8601を使用します(これは他のオプションを上書きします)" "description": "日付の書式に ISO-8601を使用します(これは他のオプションを上書きします)"
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "書式をクリア", "clear": "書式をクリア",
"heading": "見出し {level}", "heading": "見出し {level}",
"align": "テキストの整列: {position}", "align": "テキストの整列: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "引用", "blockquote": "引用",
"horizontalLine": "水平線", "horizontalLine": "水平線",
"bulletList": "箇条書きリスト", "bulletList": "箇条書きリスト",
@@ -2267,8 +2225,7 @@
"sunrise": "日出", "sunrise": "日出",
"sunset": "日没", "sunset": "日没",
"maxWindSpeed": "最大風速: {maxWindSpeed} {unit}", "maxWindSpeed": "最大風速: {maxWindSpeed} {unit}",
"maxWindGusts": "最大瞬間風速: {maxWindGusts} {unit}", "maxWindGusts": "最大瞬間風速: {maxWindGusts} {unit}"
"humidity": ""
}, },
"kind": { "kind": {
"clear": "晴れ", "clear": "晴れ",
@@ -2732,11 +2689,6 @@
"user": "ユーザー", "user": "ユーザー",
"name": "名称", "name": "名称",
"id": "Id", "id": "Id",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "詳細統計情報", "title": "詳細統計情報",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "Immich サーバーの統計", "name": "Immich サーバーの統計",
"description": "Immich インスタンスに関する情報", "description": "Immich インスタンスに関する情報",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "Immich アルバム", "name": "Immich アルバム",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "アルバム ID", "label": "アルバム ID",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "Immichアルバムの写真のスライド", "description": "Immichアルバムの写真のスライド",
"noAlbumSelected": "アルバムが選択されていない、ウィジェットを編集してアルバムを選択してください",
"noPhotos": "このアルバムには写真がありません" "noPhotos": "このアルバムには写真がありません"
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "リンクを新しいタブで開く" "label": "リンクを新しいタブで開く"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "RSS フィード", "name": "RSS フィード",
"description": "1つまたは複数の一般的な RSS、ATOM、または JSON フィードを監視して表示します", "description": "1つまたは複数の一般的な RSS、ATOM、または JSON フィードを監視して表示します",
@@ -3606,11 +3336,7 @@
"name": "通知", "name": "通知",
"description": "連携機能からの通知履歴を表示する", "description": "連携機能からの通知履歴を表示する",
"noItems": "表示する通知はありません。", "noItems": "表示する通知はありません。",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "スピードテストトラッカー", "name": "スピードテストトラッカー",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "コンテナ", "title": "コンテナ",
"table": { "table": {
"updated": "{when} に更新しました", "updated": "{when} に更新しました",
"refresh": {
"lastUpdated": ""
},
"search": "{count} 個のコンテナを検索", "search": "{count} 個のコンテナを検索",
"selected": "{totalCount} 個のうち、{selectCount} 個のコンテナが選択されています", "selected": "{totalCount} 個のうち、{selectCount} 個のコンテナが選択されています",
"footer": "合計 {count} 個のコンテナ", "footer": "合計 {count} 個のコンテナ",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
File diff suppressed because it is too large. Load diff
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "" "label": ""
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "" "label": ""
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Išvalyti formatavimą", "clear": "Išvalyti formatavimą",
"heading": "Antraštė {level}", "heading": "Antraštė {level}",
"align": "Teksto lygiavimas: {position}", "align": "Teksto lygiavimas: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Kabutės", "blockquote": "Kabutės",
"horizontalLine": "Horizontali linija", "horizontalLine": "Horizontali linija",
"bulletList": "Suženklintasis sąrašas", "bulletList": "Suženklintasis sąrašas",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "", "clear": "",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Atidaryti naujame skirtuke" "label": "Atidaryti naujame skirtuke"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
+3 -327
View File
@@ -198,10 +198,6 @@
"pingIconsEnabled": { "pingIconsEnabled": {
"label": "" "label": ""
}, },
"enableRightClickOnWidgets": {
"label": "",
"description": ""
},
"defaultSearchEngine": { "defaultSearchEngine": {
"label": "" "label": ""
}, },
@@ -1289,14 +1285,6 @@
"label": "", "label": "",
"newLabel": "" "newLabel": ""
}, },
"patchmonApiKey": {
"label": "",
"newLabel": ""
},
"patchmonApiSecret": {
"label": "",
"newLabel": ""
},
"githubAppId": { "githubAppId": {
"label": "", "label": "",
"newLabel": "" "newLabel": ""
@@ -1340,21 +1328,9 @@
} }
} }
}, },
"traefik": {
"name": "",
"description": ""
},
"paperlessNgx": { "paperlessNgx": {
"name": "", "name": "",
"description": "" "description": ""
},
"patchmon": {
"name": "",
"description": ""
},
"bazarr": {
"name": "",
"description": ""
} }
}, },
"media": { "media": {
@@ -1626,12 +1602,6 @@
"refresh": "", "refresh": "",
"options": "", "options": "",
"actions": "" "actions": ""
},
"status": {
"success": "",
"error": "",
"loading": "",
"idle": ""
} }
}, },
"create": { "create": {
@@ -1905,16 +1875,6 @@
"customDateFormat": { "customDateFormat": {
"label": "", "label": "",
"description": "" "description": ""
},
"showWeather": {
"label": "",
"description": ""
},
"weatherLocation": {
"label": ""
},
"isWeatherFormatFahrenheit": {
"label": ""
} }
} }
}, },
@@ -1976,8 +1936,6 @@
"clear": "Notīrīt formatējumu", "clear": "Notīrīt formatējumu",
"heading": "Virsraksts {level}", "heading": "Virsraksts {level}",
"align": "Teksta līdzināšana: {position}", "align": "Teksta līdzināšana: {position}",
"directionLtr": "",
"directionRtl": "",
"blockquote": "Citāts", "blockquote": "Citāts",
"horizontalLine": "Horizontāla līnija", "horizontalLine": "Horizontāla līnija",
"bulletList": "Aizzīmju saraksts", "bulletList": "Aizzīmju saraksts",
@@ -2267,8 +2225,7 @@
"sunrise": "", "sunrise": "",
"sunset": "", "sunset": "",
"maxWindSpeed": "", "maxWindSpeed": "",
"maxWindGusts": "", "maxWindGusts": ""
"humidity": ""
}, },
"kind": { "kind": {
"clear": "Skaidrs", "clear": "Skaidrs",
@@ -2732,11 +2689,6 @@
"user": "", "user": "",
"name": "", "name": "",
"id": "", "id": "",
"status": "",
"directPlay": "",
"transcoding": "",
"paused": "",
"remaining": "",
"metadata": { "metadata": {
"title": "", "title": "",
"video": { "video": {
@@ -2802,193 +2754,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"patchmon": {
"name": "",
"description": "",
"title": "",
"totalHosts": "",
"hostsNeedingUpdates": "",
"securityUpdates": "",
"upToDateHosts": "",
"hostsWithSecurityUpdates": "",
"recentUpdates24h": "",
"totalOutdatedPackages": "",
"totalRepos": "",
"osDistribution": "",
"compliance": "",
"complianceRatio": "",
"lastUpdated": "",
"option": {
"showTotalHosts": {
"label": "",
"description": ""
},
"showHostsNeedingUpdates": {
"label": "",
"description": ""
},
"showSecurityUpdates": {
"label": "",
"description": ""
},
"showUpToDateHosts": {
"label": "",
"description": ""
},
"showHostsWithSecurityUpdates": {
"label": "",
"description": ""
},
"showRecentUpdates24h": {
"label": "",
"description": ""
},
"showTotalOutdatedPackages": {
"label": "",
"description": ""
},
"showTotalRepos": {
"label": "",
"description": ""
},
"enableThresholdColors": {
"label": "",
"description": ""
},
"useCustomThresholds": {
"label": "",
"description": ""
},
"thresholdMode": {
"option": {
"absolute": "",
"percent": ""
}
},
"hostsNeedingUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsNeedingUpdatesCriticalAt": {
"label": "",
"description": ""
},
"securityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"securityUpdatesWarningAt": {
"label": "",
"description": ""
},
"securityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesThresholdMode": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesWarningAt": {
"label": "",
"description": ""
},
"hostsWithSecurityUpdatesCriticalAt": {
"label": "",
"description": ""
},
"upToDateHostsThresholdMode": {
"label": "",
"description": ""
},
"upToDateHostsWarningAt": {
"label": "",
"description": ""
},
"upToDateHostsCriticalAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesThresholdMode": {
"label": "",
"description": ""
},
"totalOutdatedPackagesWarningAt": {
"label": "",
"description": ""
},
"totalOutdatedPackagesCriticalAt": {
"label": "",
"description": ""
},
"showOsDistribution": {
"label": "",
"description": ""
},
"osDistributionLimit": {
"label": "",
"description": "",
"option": {
"3": "",
"5": "",
"10": "",
"all": ""
}
},
"showOsVersion": {
"label": "",
"description": ""
},
"showComplianceHero": {
"label": "",
"description": ""
},
"osDisplayMode": {
"label": "",
"description": "",
"option": {
"bars": "",
"donut": ""
}
}
},
"error": {
"internalServerError": ""
}
},
"bazarr": {
"name": "",
"description": "",
"episodes": "",
"movies": "",
"providers": "",
"status": "",
"option": {
"showMissingEpisodes": {
"label": "",
"description": ""
},
"showMissingMovies": {
"label": "",
"description": ""
},
"showProviderIssues": {
"label": "",
"description": ""
},
"showHealthIssues": {
"label": "",
"description": ""
}
},
"error": {
"internalServerError": ""
}
},
"immich-serverStats": { "immich-serverStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3017,7 +2782,6 @@
}, },
"immich-albumCarousel": { "immich-albumCarousel": {
"name": "", "name": "",
"allPhotos": "",
"option": { "option": {
"albumId": { "albumId": {
"label": "", "label": "",
@@ -3037,6 +2801,7 @@
} }
}, },
"description": "", "description": "",
"noAlbumSelected": "",
"noPhotos": "" "noPhotos": ""
}, },
"downloads": { "downloads": {
@@ -3221,12 +2986,6 @@
"option": { "option": {
"linksTargetNewTab": { "linksTargetNewTab": {
"label": "Atvērt saites jaunā cilnē" "label": "Atvērt saites jaunā cilnē"
},
"statusFilter": {
"label": ""
},
"recentDays": {
"label": ""
} }
}, },
"pending": { "pending": {
@@ -3334,35 +3093,6 @@
} }
} }
}, },
"mediaMissing": {
"name": "",
"description": "",
"option": {
"showMissing": {
"label": ""
},
"showQueued": {
"label": ""
},
"pageSize": {
"label": ""
}
},
"tab": {
"missing": "",
"queued": ""
},
"type": {
"movie": "",
"episode": ""
},
"empty": {
"missing": "",
"queued": "",
"noTabsEnabled": ""
},
"timeLeft": ""
},
"rssFeed": { "rssFeed": {
"name": "", "name": "",
"description": "", "description": "",
@@ -3606,11 +3336,7 @@
"name": "", "name": "",
"description": "", "description": "",
"noItems": "", "noItems": "",
"option": { "option": {}
"hideLogos": {
"label": ""
}
}
}, },
"speedtestTracker": { "speedtestTracker": {
"name": "", "name": "",
@@ -3691,40 +3417,6 @@
"internalServerError": "" "internalServerError": ""
} }
}, },
"traefik": {
"name": "",
"description": "",
"option": {
"showTcp": {
"label": ""
},
"showUdp": {
"label": ""
},
"showEntryPoints": {
"label": ""
}
},
"instances": "",
"versionUnknown": "",
"summary": {
"routers": "",
"entryPoints": ""
},
"resource": {
"routers": "",
"services": "",
"middlewares": ""
},
"status": {
"healthy": "",
"errors": "",
"warnings": ""
},
"error": {
"internalServerError": ""
}
},
"audioStats": { "audioStats": {
"name": "", "name": "",
"description": "", "description": "",
@@ -4100,11 +3792,6 @@
"read": "", "read": "",
"write": "" "write": ""
}, },
"storage": {
"title": "",
"subtitle": "",
"series": ""
},
"network": { "network": {
"title": "", "title": "",
"subtitle": "", "subtitle": "",
@@ -5237,9 +4924,6 @@
"title": "", "title": "",
"table": { "table": {
"updated": "", "updated": "",
"refresh": {
"lastUpdated": ""
},
"search": "", "search": "",
"selected": "", "selected": "",
"footer": "", "footer": "",
@@ -5968,14 +5652,6 @@
} }
} }
}, },
"enableRightClickOnWidgets": {
"label": "",
"children": {
"detail": {
"title": ""
}
}
},
"fullPreferencesPage": { "fullPreferencesPage": {
"label": "" "label": ""
} }
Loaded 100 of 161 files, more files were not shown because too many files have changed in this diff. Show more