Compare commits
62
Commits
No files matched your search
@@ -33,6 +33,8 @@ 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.57.1
|
||||||
|
- 1.57.0
|
||||||
- 1.56.1
|
- 1.56.1
|
||||||
- 1.56.0
|
- 1.56.0
|
||||||
- 1.55.0
|
- 1.55.0
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ runs:
|
|||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Build docker image for ${{ inputs.architecture }}
|
- name: Build docker image for ${{ inputs.architecture }}
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
push: false
|
push: false
|
||||||
load: true
|
load: true
|
||||||
|
|||||||
@@ -31,6 +31,12 @@
|
|||||||
automerge: false,
|
automerge: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
// Updates lockfile for prebuilt-debian after if package.json is updated, otherwise only root lockfile is updated
|
||||||
|
postUpgradeTasks: {
|
||||||
|
commands: ["cd deployments/prebuilt-debian && pnpm install --ignore-workspace --lockfile-only"],
|
||||||
|
fileFilters: ["deployments/prebuilt-debian/pnpm-lock.yaml"],
|
||||||
|
executionMode: "update",
|
||||||
|
},
|
||||||
updateInternalDeps: true,
|
updateInternalDeps: true,
|
||||||
rangeStrategy: "bump",
|
rangeStrategy: "bump",
|
||||||
automerge: false,
|
automerge: false,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
- name: Build docker image
|
- name: Build docker image
|
||||||
id: build-docker-image
|
id: build-docker-image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.CROWDIN_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.CROWDIN_APP_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.CROWDIN_APP_ID }}
|
app-id: ${{ secrets.CROWDIN_APP_ID }}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
||||||
@@ -60,12 +60,12 @@ jobs:
|
|||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
with:
|
with:
|
||||||
node-version: 24.14.0
|
node-version: 24.14.1
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- run: npm i -g pnpm
|
- run: npm i -g pnpm
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
@@ -123,7 +123,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: "${{ env.GHCR_REPO }}"
|
images: "${{ env.GHCR_REPO }}"
|
||||||
|
|
||||||
@@ -135,11 +135,11 @@ jobs:
|
|||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Build and push by digest
|
- name: Build and push by digest
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
network: host
|
network: host
|
||||||
@@ -162,7 +162,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: "${{ env.GHCR_REPO }}"
|
images: "${{ env.GHCR_REPO }}"
|
||||||
|
|
||||||
@@ -174,11 +174,11 @@ jobs:
|
|||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Build and push by digest
|
- name: Build and push by digest
|
||||||
id: build
|
id: build
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
network: host
|
network: host
|
||||||
@@ -231,7 +231,7 @@ jobs:
|
|||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
if: needs.release.outputs.skipped == 'false'
|
if: needs.release.outputs.skipped == 'false'
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
args: "Created a release PR ${{ steps.create-pull-request.outputs.url }} for version ${{ steps.semver.outputs.next }} (new behaviour: ${{ steps.semver.outputs.bump }})"
|
args: "Created a release PR ${{ steps.create-pull-request.outputs.url }} for version ${{ steps.semver.outputs.next }} (new behaviour: ${{ steps.semver.outputs.bump }})"
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainApprovalToken
|
id: obtainApprovalToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
gh pr review --approve --body "Automatically approved by GitHub Action"
|
gh pr review --approve --body "Automatically approved by GitHub Action"
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainMergeToken
|
id: obtainMergeToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.HOMARR_DOCS_RELEASE_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.HOMARR_DOCS_RELEASE_APP_PRIVATE_KEY }}
|
||||||
app-id: ${{ vars.HOMARR_DOCS_RELEASE_APP_ID }}
|
app-id: ${{ vars.HOMARR_DOCS_RELEASE_APP_ID }}
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
|
||||||
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.HOMARR_UPDATE_CONTRIBUTORS_PRIVATE_KEY }}
|
private-key: ${{ secrets.HOMARR_UPDATE_CONTRIBUTORS_PRIVATE_KEY }}
|
||||||
app-id: ${{ vars.HOMARR_UPDATE_CONTRIBUTORS_APP_ID }}
|
app-id: ${{ vars.HOMARR_UPDATE_CONTRIBUTORS_APP_ID }}
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v5
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
private-key: ${{ secrets.HOMARR_UPDATE_CONTRIBUTORS_PRIVATE_KEY }}
|
private-key: ${{ secrets.HOMARR_UPDATE_CONTRIBUTORS_PRIVATE_KEY }}
|
||||||
app-id: ${{ vars.HOMARR_UPDATE_CONTRIBUTORS_APP_ID }}
|
app-id: ${{ vars.HOMARR_UPDATE_CONTRIBUTORS_APP_ID }}
|
||||||
|
|||||||
@@ -1,3 +1,50 @@
|
|||||||
|
## [1.58.0](https://github.com/homarr-labs/homarr/compare/v1.57.1...v1.58.0) (2026-04-03)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **integrations:** add search.ch integration with timetable widget ([#5180](https://github.com/homarr-labs/homarr/issues/5180)) ([abb2dfc](https://github.com/homarr-labs/homarr/commit/abb2dfc92ab51b16e7172374cfee8b9c0c752454))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **boards:** unable to click on links at settings page ([#5230](https://github.com/homarr-labs/homarr/issues/5230)) ([6a200c3](https://github.com/homarr-labs/homarr/commit/6a200c39afaa1a9a1057643612065a40ad1cdd82))
|
||||||
|
* **deps:** update dependency @ctrl/deluge to ^7.5.3 ([#5365](https://github.com/homarr-labs/homarr/issues/5365)) ([9c134c5](https://github.com/homarr-labs/homarr/commit/9c134c5ceb742b21b021ef3b49de8cc0d526d460))
|
||||||
|
* **deps:** update dependency @ctrl/deluge to v8 ([#5367](https://github.com/homarr-labs/homarr/issues/5367)) ([e88e3d1](https://github.com/homarr-labs/homarr/commit/e88e3d17c01dab8836bec11d2ac01195f06cdc2e))
|
||||||
|
* **deps:** update dependency @immich/sdk to ^2.6.2 ([#5370](https://github.com/homarr-labs/homarr/issues/5370)) ([4a5bafa](https://github.com/homarr-labs/homarr/commit/4a5bafa79092b209e94a56f72362011f416bf115))
|
||||||
|
* **deps:** update dependency @immich/sdk to ^2.6.3 ([#5380](https://github.com/homarr-labs/homarr/issues/5380)) ([2dd3c90](https://github.com/homarr-labs/homarr/commit/2dd3c906c4215b55e23f4b15ba4b423e23be8376))
|
||||||
|
* **deps:** update dependency @tabler/icons-react to ^3.41.0 ([#5384](https://github.com/homarr-labs/homarr/issues/5384)) ([a9bcc9d](https://github.com/homarr-labs/homarr/commit/a9bcc9d04bdfcf28ea561cd590ca2a4bd775593c))
|
||||||
|
* **deps:** update dependency better-sqlite3 to ^12.8.0 ([#5266](https://github.com/homarr-labs/homarr/issues/5266)) ([46db8b6](https://github.com/homarr-labs/homarr/commit/46db8b6ab32406fb4ff7a7a9938692954778a070))
|
||||||
|
* **deps:** update dependency drizzle-orm to ^0.45.2 ([#5388](https://github.com/homarr-labs/homarr/issues/5388)) ([0a78e3f](https://github.com/homarr-labs/homarr/commit/0a78e3f12aa99509f42d7af647a478c5abaf5c96))
|
||||||
|
* **deps:** update dependency fast-xml-parser to ^5.5.9 ([#5359](https://github.com/homarr-labs/homarr/issues/5359)) ([189806b](https://github.com/homarr-labs/homarr/commit/189806b5a2b8e67f925cc8def6bc8ddefdc5bfc4))
|
||||||
|
* **deps:** update dependency fastify to ^5.8.4 ([#5351](https://github.com/homarr-labs/homarr/issues/5351)) ([728f7e4](https://github.com/homarr-labs/homarr/commit/728f7e489aa499bcd7e97c7ec8571e29e7e2cab3))
|
||||||
|
* **deps:** update dependency isomorphic-dompurify to ^3.7.0 ([#5366](https://github.com/homarr-labs/homarr/issues/5366)) ([c2b54dd](https://github.com/homarr-labs/homarr/commit/c2b54ddfaab93daa4e65c0c38bf5c27e4402a492))
|
||||||
|
* **deps:** update dependency isomorphic-dompurify to ^3.7.1 ([#5369](https://github.com/homarr-labs/homarr/issues/5369)) ([8d1ff40](https://github.com/homarr-labs/homarr/commit/8d1ff4065d669268f0e6a03f2b68c1ba728a756a))
|
||||||
|
* **deps:** update dependency jotai to ^2.19.0 ([#5368](https://github.com/homarr-labs/homarr/issues/5368)) ([14d8717](https://github.com/homarr-labs/homarr/commit/14d87178b5a93bdc6fb74793feed95d014814d0b))
|
||||||
|
* **deps:** update dependency node-ical to ^0.23.1 - abandoned ([#4856](https://github.com/homarr-labs/homarr/issues/4856)) ([b07c545](https://github.com/homarr-labs/homarr/commit/b07c545f17f4dafa62167047baa9eed4b7ee4395))
|
||||||
|
* **deps:** update dependency typescript-eslint to ^8.57.2 ([#5360](https://github.com/homarr-labs/homarr/issues/5360)) ([cefbf0e](https://github.com/homarr-labs/homarr/commit/cefbf0e2715e9adbc72cdb0b83d84c309e3257d6))
|
||||||
|
* **deps:** update dependency undici to v7.24.6 ([#5374](https://github.com/homarr-labs/homarr/issues/5374)) ([4f2cc9a](https://github.com/homarr-labs/homarr/commit/4f2cc9af2a42e19624def3bdea60fcb00334c483))
|
||||||
|
* **deps:** update dependency zod to ^4.3.5 - abandoned ([#4803](https://github.com/homarr-labs/homarr/issues/4803)) ([2b4c83d](https://github.com/homarr-labs/homarr/commit/2b4c83dccac168ffa6f9b6e184ed004659373cf7))
|
||||||
|
* **deps:** update dependency zod to ^4.3.6 ([#5376](https://github.com/homarr-labs/homarr/issues/5376)) ([a9582f0](https://github.com/homarr-labs/homarr/commit/a9582f04edb0e161d1fab6e64b13d0ce463ef341))
|
||||||
|
* **deps:** update tanstack-query monorepo to ^5.95.0 ([#5325](https://github.com/homarr-labs/homarr/issues/5325)) ([b11bf36](https://github.com/homarr-labs/homarr/commit/b11bf367d0567e4c8b9068804442ebd200dab01c))
|
||||||
|
* **deps:** update tanstack-query monorepo to ^5.95.1 ([#5355](https://github.com/homarr-labs/homarr/issues/5355)) ([332b6b4](https://github.com/homarr-labs/homarr/commit/332b6b4f42e7c90570cd4c25a6e6a331a76c660f))
|
||||||
|
* **deps:** update tanstack-query monorepo to ^5.95.2 ([#5357](https://github.com/homarr-labs/homarr/issues/5357)) ([6820991](https://github.com/homarr-labs/homarr/commit/682099189b689ea17e16af41fd280a72ed68016f))
|
||||||
|
* **deps:** update tiptap monorepo to v3.20.5 ([#5371](https://github.com/homarr-labs/homarr/issues/5371)) ([6820f8a](https://github.com/homarr-labs/homarr/commit/6820f8afea622587c1ee18b13d13a041ca0572ee))
|
||||||
|
* **deps:** update tiptap monorepo to v3.21.0 ([#5386](https://github.com/homarr-labs/homarr/issues/5386)) ([b30dbaf](https://github.com/homarr-labs/homarr/commit/b30dbafbbbad468ff37ff11237a64ec29df62345))
|
||||||
|
* **deps:** update trpc monorepo to ^11.15.0 ([#5354](https://github.com/homarr-labs/homarr/issues/5354)) ([2fb2981](https://github.com/homarr-labs/homarr/commit/2fb2981d2fb79ca2ca6a9bc5c08d91c8fa5710e7))
|
||||||
|
* **deps:** update trpc monorepo to ^11.15.1 ([#5381](https://github.com/homarr-labs/homarr/issues/5381)) ([451e68a](https://github.com/homarr-labs/homarr/commit/451e68ab57551e23dd7ae772b7483cc56d57ebbb))
|
||||||
|
* **deps:** update trpc monorepo to ^11.16.0 ([#5392](https://github.com/homarr-labs/homarr/issues/5392)) ([72a93e6](https://github.com/homarr-labs/homarr/commit/72a93e681f3701459176692857220730c279f80b))
|
||||||
|
* **deps:** update turbo monorepo to ^2.8.21 ([#5391](https://github.com/homarr-labs/homarr/issues/5391)) ([fa40b6b](https://github.com/homarr-labs/homarr/commit/fa40b6b647b884a7f10c268a22330e0e68b50d4d))
|
||||||
|
* honor trusted certificates in Immich integration requests ([#5275](https://github.com/homarr-labs/homarr/issues/5275)) ([7679553](https://github.com/homarr-labs/homarr/commit/7679553f16ff2945a3eb6cb668ca3a701d13d5ce)), closes [#5242](https://github.com/homarr-labs/homarr/issues/5242)
|
||||||
|
* node-ical prevents many trpc queries from loading ([#5395](https://github.com/homarr-labs/homarr/issues/5395)) ([c977b84](https://github.com/homarr-labs/homarr/commit/c977b84e2d84d5724219f5ff5f99bc550438e168))
|
||||||
|
|
||||||
|
## [1.57.1](https://github.com/homarr-labs/homarr/compare/v1.57.0...v1.57.1) (2026-03-27)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* dashdot gpu ([#5347](https://github.com/homarr-labs/homarr/issues/5347)) ([192a43a](https://github.com/homarr-labs/homarr/commit/192a43a031eb9431da2c11395eda69a6c7236b9b))
|
||||||
|
* **deps:** update dependency @t3-oss/env-nextjs to ^0.13.11 ([#5345](https://github.com/homarr-labs/homarr/issues/5345)) ([49d9394](https://github.com/homarr-labs/homarr/commit/49d9394cd78b2a1146c8dc00dd982215a2f9a580))
|
||||||
|
* **deps:** update dependency dockerode to ^4.0.10 ([#5327](https://github.com/homarr-labs/homarr/issues/5327)) ([42a3791](https://github.com/homarr-labs/homarr/commit/42a3791e6b5664a0f28d3ee4d29d5257ef3765f6))
|
||||||
|
* **deps:** update dependency fast-xml-parser to ^5.5.8 ([#5324](https://github.com/homarr-labs/homarr/issues/5324)) ([7982938](https://github.com/homarr-labs/homarr/commit/798293813cf82e38d7059069823f927b7cdfb3b8))
|
||||||
|
|
||||||
## [1.57.0](https://github.com/homarr-labs/homarr/compare/v1.56.1...v1.57.0) (2026-03-27)
|
## [1.57.0](https://github.com/homarr-labs/homarr/compare/v1.56.1...v1.57.0) (2026-03-27)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.14.0-alpine AS base
|
FROM node:24.14.1-alpine AS base
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|||||||
+11
-11
@@ -55,14 +55,14 @@
|
|||||||
"@mantine/modals": "^8.3.18",
|
"@mantine/modals": "^8.3.18",
|
||||||
"@mantine/tiptap": "^8.3.18",
|
"@mantine/tiptap": "^8.3.18",
|
||||||
"@million/lint": "1.0.14",
|
"@million/lint": "1.0.14",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.0",
|
||||||
"@tanstack/react-query": "^5.91.2",
|
"@tanstack/react-query": "^5.95.2",
|
||||||
"@tanstack/react-query-devtools": "^5.91.3",
|
"@tanstack/react-query-devtools": "^5.95.2",
|
||||||
"@tanstack/react-query-next-experimental": "^5.91.0",
|
"@tanstack/react-query-next-experimental": "^5.95.2",
|
||||||
"@trpc/client": "^11.14.1",
|
"@trpc/client": "^11.16.0",
|
||||||
"@trpc/next": "^11.14.1",
|
"@trpc/next": "^11.16.0",
|
||||||
"@trpc/react-query": "^11.14.1",
|
"@trpc/react-query": "^11.16.0",
|
||||||
"@trpc/server": "^11.14.1",
|
"@trpc/server": "^11.16.0",
|
||||||
"@xterm/addon-canvas": "^0.7.0",
|
"@xterm/addon-canvas": "^0.7.0",
|
||||||
"@xterm/addon-fit": "0.11.0",
|
"@xterm/addon-fit": "0.11.0",
|
||||||
"@xterm/xterm": "^6.0.0",
|
"@xterm/xterm": "^6.0.0",
|
||||||
@@ -73,8 +73,8 @@
|
|||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"flag-icons": "^7.5.0",
|
"flag-icons": "^7.5.0",
|
||||||
"glob": "^13.0.6",
|
"glob": "^13.0.6",
|
||||||
"isomorphic-dompurify": "^3.6.0",
|
"isomorphic-dompurify": "^3.7.1",
|
||||||
"jotai": "^2.18.1",
|
"jotai": "^2.19.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"swagger-ui-react": "^5.32.1",
|
"swagger-ui-react": "^5.32.1",
|
||||||
"use-deep-compare-effect": "^1.8.1",
|
"use-deep-compare-effect": "^1.8.1",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { Button, Grid, Group, Loader, Stack, TextInput } from "@mantine/core";
|
import { Button, Grid, Group, Loader, Stack, TextInput } from "@mantine/core";
|
||||||
import { useDebouncedValue, useDocumentTitle, useFavicon } from "@mantine/hooks";
|
import { useDebouncedValue, useDocumentTitle } from "@mantine/hooks";
|
||||||
|
|
||||||
import { useUpdateBoard } from "@homarr/boards/updater";
|
import { useUpdateBoard } from "@homarr/boards/updater";
|
||||||
import { useZodForm } from "@homarr/form";
|
import { useZodForm } from "@homarr/form";
|
||||||
@@ -10,6 +10,7 @@ import { IconPicker } from "@homarr/forms-collection";
|
|||||||
import { useI18n } from "@homarr/translation/client";
|
import { useI18n } from "@homarr/translation/client";
|
||||||
import { boardSavePartialSettingsSchema } from "@homarr/validation/board";
|
import { boardSavePartialSettingsSchema } from "@homarr/validation/board";
|
||||||
|
|
||||||
|
import { homarrLogoPath } from "~/components/layout/logo/homarr-logo";
|
||||||
import { createMetaTitle } from "~/metadata";
|
import { createMetaTitle } from "~/metadata";
|
||||||
import type { Board } from "../../_types";
|
import type { Board } from "../../_types";
|
||||||
import { useSavePartialSettingsMutation } from "./_shared";
|
import { useSavePartialSettingsMutation } from "./_shared";
|
||||||
@@ -53,7 +54,6 @@ export const GeneralSettingsContent = ({ board }: Props) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useLogoPreview(form.values.logoImageUrl);
|
useLogoPreview(form.values.logoImageUrl);
|
||||||
useFaviconPreview(form.values.faviconImageUrl);
|
|
||||||
const metaTitleStatus = useMetaTitlePreview(form.values.metaTitle);
|
const metaTitleStatus = useMetaTitlePreview(form.values.metaTitle);
|
||||||
|
|
||||||
// Cleanup for not applied changes of the page title and logo image URL
|
// Cleanup for not applied changes of the page title and logo image URL
|
||||||
@@ -75,6 +75,7 @@ export const GeneralSettingsContent = ({ board }: Props) => {
|
|||||||
pageTitle: values.pageTitle,
|
pageTitle: values.pageTitle,
|
||||||
logoImageUrl: values.logoImageUrl,
|
logoImageUrl: values.logoImageUrl,
|
||||||
};
|
};
|
||||||
|
updateFavicon(values.faviconImageUrl ?? homarrLogoPath);
|
||||||
savePartialSettings({
|
savePartialSettings({
|
||||||
id: board.id,
|
id: board.id,
|
||||||
...values,
|
...values,
|
||||||
@@ -146,7 +147,13 @@ const useMetaTitlePreview = (title: string | null) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const useFaviconPreview = (url: string | null) => {
|
// Previously we used the useFavicon hook from Mantine
|
||||||
const [faviconDebounced] = useDebouncedValue(url ?? "", 500);
|
// However if the user tried to click on a link to a different page
|
||||||
useFavicon(faviconDebounced);
|
// it caused an error "Cannot read properties of null (reading 'removeChild')"
|
||||||
|
// Probably because the head element was null (https://github.com/mantinedev/mantine/blob/b90d9b81031f45f5d15e75f25138ed6477f65bce/packages/%40mantine/hooks/src/use-favicon/use-favicon.ts#L21)
|
||||||
|
// See https://github.com/homarr-labs/homarr/issues/4905
|
||||||
|
const updateFavicon = (url: string) => {
|
||||||
|
const link: HTMLLinkElement | null = document.querySelector('link[rel="icon"]');
|
||||||
|
if (!link) return;
|
||||||
|
link.href = url;
|
||||||
};
|
};
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
"@homarr/widgets": "workspace:^0.1.0",
|
"@homarr/widgets": "workspace:^0.1.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"fastify": "^5.8.2",
|
"fastify": "^5.8.4",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"undici": "7.24.5"
|
"undici": "7.24.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:24.14.0-trixie AS base
|
FROM node:24.14.1-trixie AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json .
|
COPY package.json .
|
||||||
COPY pnpm-lock.yaml .
|
COPY pnpm-lock.yaml .
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
"name": "homarr-prebuilt-debian",
|
"name": "homarr-prebuilt-debian",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "^12.6.2"
|
"better-sqlite3": "^12.8.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.32.1",
|
"packageManager": "pnpm@10.33.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.14.0",
|
"node": ">=24.14.1",
|
||||||
"pnpm": ">=10.32.1"
|
"pnpm": ">=10.33.0"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
|
|||||||
+6
-5
@@ -9,16 +9,16 @@ importers:
|
|||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: ^12.6.2
|
specifier: ^12.8.0
|
||||||
version: 12.6.2
|
version: 12.8.0
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
better-sqlite3@12.6.2:
|
better-sqlite3@12.8.0:
|
||||||
resolution: {integrity: sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA==}
|
resolution: {integrity: sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ==}
|
||||||
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x}
|
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x}
|
||||||
|
|
||||||
bindings@1.5.0:
|
bindings@1.5.0:
|
||||||
@@ -93,6 +93,7 @@ packages:
|
|||||||
prebuild-install@7.1.3:
|
prebuild-install@7.1.3:
|
||||||
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
|
resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
pump@3.0.3:
|
pump@3.0.3:
|
||||||
@@ -147,7 +148,7 @@ snapshots:
|
|||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
better-sqlite3@12.6.2:
|
better-sqlite3@12.8.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bindings: 1.5.0
|
bindings: 1.5.0
|
||||||
prebuild-install: 7.1.3
|
prebuild-install: 7.1.3
|
||||||
|
|||||||
+11
-4
@@ -302,6 +302,13 @@
|
|||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr><td align="center">
|
<tr><td align="center">
|
||||||
|
<a href="https://homarr.dev/docs/integrations/search-ch" target="_blank" rel="noreferrer noopener">
|
||||||
|
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/search-ch.png" alt="Search.ch" width="90" height="90" />
|
||||||
|
<br/>
|
||||||
|
<p align="center">Search.ch</p>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
<a href="https://homarr.dev/docs/integrations/seerr" target="_blank" rel="noreferrer noopener">
|
<a href="https://homarr.dev/docs/integrations/seerr" target="_blank" rel="noreferrer noopener">
|
||||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/seerr.svg" alt="Seerr" width="90" height="90" />
|
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/seerr.svg" alt="Seerr" width="90" height="90" />
|
||||||
<br/>
|
<br/>
|
||||||
@@ -342,15 +349,15 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<p align="center">Transmission</p>
|
<p align="center">Transmission</p>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td></tr>
|
||||||
<td align="center">
|
<tr><td align="center">
|
||||||
<a href="https://homarr.dev/docs/integrations/truenas" target="_blank" rel="noreferrer noopener">
|
<a href="https://homarr.dev/docs/integrations/truenas" target="_blank" rel="noreferrer noopener">
|
||||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/truenas.svg" alt="TrueNAS" width="90" height="90" />
|
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/truenas.svg" alt="TrueNAS" width="90" height="90" />
|
||||||
<br/>
|
<br/>
|
||||||
<p align="center">TrueNAS</p>
|
<p align="center">TrueNAS</p>
|
||||||
</a>
|
</a>
|
||||||
</td></tr>
|
</td>
|
||||||
<tr><td align="center">
|
<td align="center">
|
||||||
<a href="https://homarr.dev/docs/integrations/unifi-controller" target="_blank" rel="noreferrer noopener">
|
<a href="https://homarr.dev/docs/integrations/unifi-controller" target="_blank" rel="noreferrer noopener">
|
||||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/unifi.png" alt="Unifi Controller" width="90" height="90" />
|
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/unifi.png" alt="Unifi Controller" width="90" height="90" />
|
||||||
<br/>
|
<br/>
|
||||||
|
|||||||
+17
-17
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homarr",
|
"name": "homarr",
|
||||||
"version": "1.57.0",
|
"version": "1.58.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env CI=true turbo build",
|
"build": "cross-env CI=true turbo build",
|
||||||
@@ -43,26 +43,26 @@
|
|||||||
"@semantic-release/npm": "^13.1.5",
|
"@semantic-release/npm": "^13.1.5",
|
||||||
"@semantic-release/release-notes-generator": "^14.1.0",
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
||||||
"@testcontainers/redis": "^11.13.0",
|
"@testcontainers/redis": "^11.13.0",
|
||||||
"@turbo/gen": "^2.8.20",
|
"@turbo/gen": "^2.8.21",
|
||||||
"@vitejs/plugin-react": "^5.2.0",
|
"@vitejs/plugin-react": "^5.2.0",
|
||||||
"@vitest/coverage-v8": "^4.1.0",
|
"@vitest/coverage-v8": "^4.1.2",
|
||||||
"@vitest/ui": "^4.1.0",
|
"@vitest/ui": "^4.1.2",
|
||||||
"conventional-changelog-conventionalcommits": "^9.3.0",
|
"conventional-changelog-conventionalcommits": "^9.3.1",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"jsdom": "^28.1.0",
|
"jsdom": "^29.0.1",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"semantic-release": "^25.0.3",
|
"semantic-release": "^25.0.3",
|
||||||
"testcontainers": "^11.13.0",
|
"testcontainers": "^11.13.0",
|
||||||
"turbo": "^2.8.20",
|
"turbo": "^2.8.21",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite-tsconfig-paths": "^6.1.1",
|
"vite-tsconfig-paths": "^6.1.1",
|
||||||
"vitest": "^4.1.0"
|
"vitest": "^4.1.2"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.32.1",
|
"packageManager": "pnpm@10.33.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.14.0",
|
"node": ">=24.14.1",
|
||||||
"pnpm": ">=10.32.1"
|
"pnpm": ">=10.33.0"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
@@ -79,23 +79,23 @@
|
|||||||
"overrides": {
|
"overrides": {
|
||||||
"@babel/helpers@<7.26.10": ">=7.29.2",
|
"@babel/helpers@<7.26.10": ">=7.29.2",
|
||||||
"@babel/runtime@<7.26.10": ">=7.29.2",
|
"@babel/runtime@<7.26.10": ">=7.29.2",
|
||||||
"axios@>=1.0.0 <1.8.2": ">=1.13.6",
|
"axios@>=1.0.0 <1.8.2": ">=1.14.0",
|
||||||
"brace-expansion@>=2.0.0 <=2.0.1": ">=5.0.4",
|
"brace-expansion@>=2.0.0 <=2.0.1": ">=5.0.5",
|
||||||
"brace-expansion@>=1.0.0 <=1.1.11": ">=5.0.4",
|
"brace-expansion@>=1.0.0 <=1.1.11": ">=5.0.5",
|
||||||
"esbuild@<=0.24.2": ">=0.27.4",
|
"esbuild@<=0.24.2": ">=0.27.4",
|
||||||
"form-data@>=4.0.0 <4.0.4": ">=4.0.5",
|
"form-data@>=4.0.0 <4.0.4": ">=4.0.5",
|
||||||
"hono@<4.6.5": ">=4.12.8",
|
"hono@<4.6.5": ">=4.12.9",
|
||||||
"linkifyjs@<4.3.2": ">=4.3.2",
|
"linkifyjs@<4.3.2": ">=4.3.2",
|
||||||
"nanoid@>=4.0.0 <5.0.9": ">=5.1.7",
|
"nanoid@>=4.0.0 <5.0.9": ">=5.1.7",
|
||||||
"prismjs@<1.30.0": ">=1.30.0",
|
"prismjs@<1.30.0": ">=1.30.0",
|
||||||
"proxmox-api>undici": "7.24.5",
|
"proxmox-api>undici": "7.24.6",
|
||||||
"react-is": "^19.2.4",
|
"react-is": "^19.2.4",
|
||||||
"rollup@>=4.0.0 <4.22.4": ">=4.60.0",
|
"rollup@>=4.0.0 <4.22.4": ">=4.60.0",
|
||||||
"sha.js@<=2.4.11": ">=2.4.12",
|
"sha.js@<=2.4.11": ">=2.4.12",
|
||||||
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.2",
|
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.2",
|
||||||
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.2",
|
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.2",
|
||||||
"tmp@<=0.2.3": ">=0.2.5",
|
"tmp@<=0.2.3": ">=0.2.5",
|
||||||
"vite@>=5.0.0 <=5.4.18": ">=8.0.1"
|
"vite@>=5.0.0 <=5.4.18": ">=8.0.3"
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"@types/node-unifi": "patches/@types__node-unifi.patch",
|
"@types/node-unifi": "patches/@types__node-unifi.patch",
|
||||||
|
|||||||
@@ -41,18 +41,18 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@kubernetes/client-node": "^1.4.0",
|
"@kubernetes/client-node": "^1.4.0",
|
||||||
"@tanstack/react-query": "^5.91.2",
|
"@tanstack/react-query": "^5.95.2",
|
||||||
"@trpc/client": "^11.14.1",
|
"@trpc/client": "^11.16.0",
|
||||||
"@trpc/react-query": "^11.14.1",
|
"@trpc/react-query": "^11.16.0",
|
||||||
"@trpc/server": "^11.14.1",
|
"@trpc/server": "^11.16.0",
|
||||||
"@trpc/tanstack-react-query": "^11.14.1",
|
"@trpc/tanstack-react-query": "^11.16.0",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"trpc-to-openapi": "^3.2.0",
|
"trpc-to-openapi": "^3.2.0",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export const userRouter = createTRPCRouter({
|
|||||||
create: permissionRequiredProcedure
|
create: permissionRequiredProcedure
|
||||||
.requiresPermission("admin")
|
.requiresPermission("admin")
|
||||||
.meta({ openapi: { method: "POST", path: "/api/users", tags: ["users"], protect: true } })
|
.meta({ openapi: { method: "POST", path: "/api/users", tags: ["users"], protect: true } })
|
||||||
.input(userCreateSchema)
|
.input(convertIntersectionToZodObject(userCreateSchema))
|
||||||
.output(z.void())
|
.output(z.void())
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
throwIfCredentialsDisabled();
|
throwIfCredentialsDisabled();
|
||||||
@@ -376,7 +376,7 @@ export const userRouter = createTRPCRouter({
|
|||||||
await ctx.db.delete(users).where(eq(users.id, input.userId));
|
await ctx.db.delete(users).where(eq(users.id, input.userId));
|
||||||
}),
|
}),
|
||||||
changePassword: protectedProcedure
|
changePassword: protectedProcedure
|
||||||
.input(userChangePasswordApiSchema)
|
.input(convertIntersectionToZodObject(userChangePasswordApiSchema))
|
||||||
.output(z.void())
|
.output(z.void())
|
||||||
.meta({ openapi: { method: "PATCH", path: "/api/users/{userId}/changePassword", tags: ["users"], protect: true } })
|
.meta({ openapi: { method: "PATCH", path: "/api/users/{userId}/changePassword", tags: ["users"], protect: true } })
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
|||||||
@@ -26,5 +26,6 @@ export const widgetRouter = createTRPCRouter({
|
|||||||
networkController: lazy(() => import("./network-controller").then((mod) => mod.networkControllerRouter)),
|
networkController: lazy(() => import("./network-controller").then((mod) => mod.networkControllerRouter)),
|
||||||
firewall: lazy(() => import("./firewall").then((mod) => mod.firewallRouter)),
|
firewall: lazy(() => import("./firewall").then((mod) => mod.firewallRouter)),
|
||||||
notifications: lazy(() => import("./notifications").then((mod) => mod.notificationsRouter)),
|
notifications: lazy(() => import("./notifications").then((mod) => mod.notificationsRouter)),
|
||||||
|
timetable: lazy(() => import("./timetable").then((mod) => mod.timetableRouter)),
|
||||||
tracearr: lazy(() => import("./tracearr").then((mod) => mod.tracearrRouter)),
|
tracearr: lazy(() => import("./tracearr").then((mod) => mod.tracearrRouter)),
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||||
|
import { timetableOptionsSchema } from "@homarr/integrations/types";
|
||||||
|
import {
|
||||||
|
timetableGetTimetableRequestHandler,
|
||||||
|
timetableSearchStationsRequestHandler,
|
||||||
|
} from "@homarr/request-handler/timetable";
|
||||||
|
|
||||||
|
import { createOneIntegrationMiddleware } from "../../middlewares/integration";
|
||||||
|
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||||
|
|
||||||
|
export const timetableRouter = createTRPCRouter({
|
||||||
|
getTimetable: publicProcedure
|
||||||
|
.concat(createOneIntegrationMiddleware("query", ...getIntegrationKindsByCategory("timetable")))
|
||||||
|
.input(timetableOptionsSchema)
|
||||||
|
.query(async ({ input, ctx }) => {
|
||||||
|
const innerHandler = timetableGetTimetableRequestHandler.handler(ctx.integration, {
|
||||||
|
stationId: input.stationId,
|
||||||
|
limit: input.limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}),
|
||||||
|
searchStations: publicProcedure
|
||||||
|
.concat(createOneIntegrationMiddleware("query", ...getIntegrationKindsByCategory("timetable")))
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
query: z.string(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.query(async ({ input, ctx }) => {
|
||||||
|
const innerHandler = timetableSearchStationsRequestHandler.handler(ctx.integration, {
|
||||||
|
query: input.query,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}),
|
||||||
|
});
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"next-auth": "5.0.0-beta.30",
|
"next-auth": "5.0.0-beta.30",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"undici": "7.24.5",
|
"undici": "7.24.6",
|
||||||
"zod": "^4.2.1",
|
"zod": "^4.3.6",
|
||||||
"zod-validation-error": "^5.0.0"
|
"zod-validation-error": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -38,15 +38,15 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@t3-oss/env-nextjs": "^0.13.11",
|
"@t3-oss/env-nextjs": "^0.13.11",
|
||||||
"better-sqlite3": "^12.6.2",
|
"better-sqlite3": "^12.8.0",
|
||||||
"dns-caching": "^0.2.9",
|
"dns-caching": "^0.2.9",
|
||||||
"drizzle-orm": "^0.45.1",
|
"drizzle-orm": "^0.45.2",
|
||||||
"ioredis": "5.10.1",
|
"ioredis": "5.10.1",
|
||||||
"mysql2": "3.20.0",
|
"mysql2": "3.20.0",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.20.0",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"winston": "3.19.0",
|
"winston": "3.19.0",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"@homarr/core": "workspace:^0.1.0",
|
"@homarr/core": "workspace:^0.1.0",
|
||||||
"@homarr/cron-jobs": "workspace:^0.1.0",
|
"@homarr/cron-jobs": "workspace:^0.1.0",
|
||||||
"@tanstack/react-query": "^5.91.2",
|
"@tanstack/react-query": "^5.95.2",
|
||||||
"@trpc/client": "^11.14.1",
|
"@trpc/client": "^11.16.0",
|
||||||
"@trpc/server": "^11.14.1",
|
"@trpc/server": "^11.16.0",
|
||||||
"@trpc/tanstack-react-query": "^11.14.1",
|
"@trpc/tanstack-react-query": "^11.16.0",
|
||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { mediaServerJob } from "./jobs/integrations/media-server";
|
|||||||
import { mediaTranscodingJob } from "./jobs/integrations/media-transcoding";
|
import { mediaTranscodingJob } from "./jobs/integrations/media-transcoding";
|
||||||
import { networkControllerJob } from "./jobs/integrations/network-controller";
|
import { networkControllerJob } from "./jobs/integrations/network-controller";
|
||||||
import { refreshNotificationsJob } from "./jobs/integrations/notifications";
|
import { refreshNotificationsJob } from "./jobs/integrations/notifications";
|
||||||
|
import { timetableJob } from "./jobs/integrations/timetable";
|
||||||
import { tracearrJob } from "./jobs/integrations/tracearr";
|
import { tracearrJob } from "./jobs/integrations/tracearr";
|
||||||
import { minecraftServerStatusJob } from "./jobs/minecraft-server-status";
|
import { minecraftServerStatusJob } from "./jobs/minecraft-server-status";
|
||||||
import { pingJob } from "./jobs/ping";
|
import { pingJob } from "./jobs/ping";
|
||||||
@@ -51,6 +52,7 @@ export const jobGroup = createCronJobGroup({
|
|||||||
firewallInterfaces: firewallInterfacesJob,
|
firewallInterfaces: firewallInterfacesJob,
|
||||||
refreshNotifications: refreshNotificationsJob,
|
refreshNotifications: refreshNotificationsJob,
|
||||||
weather: weatherJob,
|
weather: weatherJob,
|
||||||
|
timetable: timetableJob,
|
||||||
tracearr: tracearrJob,
|
tracearr: tracearrJob,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { EVERY_5_MINUTES } from "@homarr/cron-jobs-core/expressions";
|
||||||
|
import { createRequestIntegrationJobHandler } from "@homarr/request-handler/lib/cached-request-integration-job-handler";
|
||||||
|
import { timetableGetTimetableRequestHandler } from "@homarr/request-handler/timetable";
|
||||||
|
|
||||||
|
import { createCronJob } from "../../lib";
|
||||||
|
|
||||||
|
export const timetableJob = createCronJob("timetable", EVERY_5_MINUTES).withCallback(
|
||||||
|
createRequestIntegrationJobHandler(timetableGetTimetableRequestHandler.handler, {
|
||||||
|
widgetKinds: ["timetable"],
|
||||||
|
getInput: {
|
||||||
|
timetable: (options) =>
|
||||||
|
options.station
|
||||||
|
? {
|
||||||
|
stationId: options.station.value,
|
||||||
|
limit: 10,
|
||||||
|
}
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
@@ -51,10 +51,10 @@
|
|||||||
"@paralleldrive/cuid2": "^3.3.0",
|
"@paralleldrive/cuid2": "^3.3.0",
|
||||||
"@testcontainers/mysql": "^11.13.0",
|
"@testcontainers/mysql": "^11.13.0",
|
||||||
"@testcontainers/postgresql": "^11.13.0",
|
"@testcontainers/postgresql": "^11.13.0",
|
||||||
"better-sqlite3": "^12.6.2",
|
"better-sqlite3": "^12.8.0",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"drizzle-kit": "^0.31.10",
|
"drizzle-kit": "^0.31.10",
|
||||||
"drizzle-orm": "^0.45.1",
|
"drizzle-orm": "^0.45.2",
|
||||||
"drizzle-zod": "^0.8.3",
|
"drizzle-zod": "^0.8.3",
|
||||||
"mysql2": "3.20.0",
|
"mysql2": "3.20.0",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.20.0",
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"fast-xml-parser": "^5.5.8",
|
"fast-xml-parser": "^5.5.9",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -334,6 +334,15 @@ export const integrationDefs = {
|
|||||||
// @ts-expect-error - docs page will be created when integration is merged
|
// @ts-expect-error - docs page will be created when integration is merged
|
||||||
documentationUrl: createDocumentationLink("/docs/integrations/coolify"),
|
documentationUrl: createDocumentationLink("/docs/integrations/coolify"),
|
||||||
},
|
},
|
||||||
|
searchCh: {
|
||||||
|
name: "Search.ch",
|
||||||
|
secretKinds: [[]],
|
||||||
|
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/search-ch.png",
|
||||||
|
defaultUrl: "https://search.ch",
|
||||||
|
category: ["timetable"],
|
||||||
|
// @ts-expect-error - docs page will be created when integration is merged
|
||||||
|
documentationUrl: createDocumentationLink("/docs/integrations/search-ch"),
|
||||||
|
},
|
||||||
immich: {
|
immich: {
|
||||||
name: "Immich",
|
name: "Immich",
|
||||||
secretKinds: [["apiKey"]],
|
secretKinds: [["apiKey"]],
|
||||||
@@ -434,6 +443,7 @@ export const integrationCategories = [
|
|||||||
"releasesProvider",
|
"releasesProvider",
|
||||||
"notifications",
|
"notifications",
|
||||||
"firewall",
|
"firewall",
|
||||||
|
"timetable",
|
||||||
"photoService",
|
"photoService",
|
||||||
"mediaMonitoring",
|
"mediaMonitoring",
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const widgetKinds = [
|
|||||||
"systemResources",
|
"systemResources",
|
||||||
"coolify",
|
"coolify",
|
||||||
"systemDisks",
|
"systemDisks",
|
||||||
|
"timetable",
|
||||||
"immich-serverStats",
|
"immich-serverStats",
|
||||||
"immich-albumCarousel",
|
"immich-albumCarousel",
|
||||||
"tracearr",
|
"tracearr",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@mantine/form": "^8.3.18",
|
"@mantine/form": "^8.3.18",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ctrl/deluge": "^7.5.2",
|
"@ctrl/deluge": "^8.0.0",
|
||||||
"@ctrl/qbittorrent": "^9.11.2",
|
"@ctrl/qbittorrent": "^9.11.2",
|
||||||
"@ctrl/transmission": "^7.4.0",
|
"@ctrl/transmission": "^7.4.0",
|
||||||
"@gitbeaker/rest": "^43.8.0",
|
"@gitbeaker/rest": "^43.8.0",
|
||||||
@@ -38,18 +38,18 @@
|
|||||||
"@homarr/redis": "workspace:^0.1.0",
|
"@homarr/redis": "workspace:^0.1.0",
|
||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@immich/sdk": "^2.6.1",
|
"@immich/sdk": "^2.6.3",
|
||||||
"@jellyfin/sdk": "^0.13.0",
|
"@jellyfin/sdk": "^0.13.0",
|
||||||
"@octokit/auth-app": "^8.2.0",
|
"@octokit/auth-app": "^8.2.0",
|
||||||
"ical.js": "^2.2.1",
|
"ical.js": "^2.2.1",
|
||||||
"maria2": "^0.4.1",
|
"maria2": "^0.4.1",
|
||||||
"node-ical": "^0.22.1",
|
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"proxmox-api": "1.1.1",
|
"proxmox-api": "1.1.1",
|
||||||
|
"timezones-ical-library": "^2.1.3",
|
||||||
"tsdav": "^2.1.8",
|
"tsdav": "^2.1.8",
|
||||||
"undici": "7.24.5",
|
"undici": "7.24.6",
|
||||||
"xml2js": "^0.6.2",
|
"xml2js": "^0.6.2",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import { PlexIntegration } from "../plex/plex-integration";
|
|||||||
import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration";
|
import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration";
|
||||||
import { ProxmoxIntegration } from "../proxmox/proxmox-integration";
|
import { ProxmoxIntegration } from "../proxmox/proxmox-integration";
|
||||||
import { QuayIntegration } from "../quay/quay-integration";
|
import { QuayIntegration } from "../quay/quay-integration";
|
||||||
|
import { SearchChIntegration } from "../search-ch/search-ch-integration";
|
||||||
import { SeerrIntegration } from "../seerr/seerr-integration";
|
import { SeerrIntegration } from "../seerr/seerr-integration";
|
||||||
import { TracearrIntegration } from "../tracearr/tracearr-integration";
|
import { TracearrIntegration } from "../tracearr/tracearr-integration";
|
||||||
import { TrueNasIntegration } from "../truenas/truenas-integration";
|
import { TrueNasIntegration } from "../truenas/truenas-integration";
|
||||||
@@ -114,6 +115,7 @@ export const integrationCreators = {
|
|||||||
coolify: CoolifyIntegration,
|
coolify: CoolifyIntegration,
|
||||||
tracearr: TracearrIntegration,
|
tracearr: TracearrIntegration,
|
||||||
glances: GlancesIntegration,
|
glances: GlancesIntegration,
|
||||||
|
searchCh: SearchChIntegration,
|
||||||
immich: ImmichIntegration,
|
immich: ImmichIntegration,
|
||||||
} satisfies Record<IntegrationKind, IntegrationInstance | [(input: IntegrationInput) => Promise<Integration>]>;
|
} satisfies Record<IntegrationKind, IntegrationInstance | [(input: IntegrationInput) => Promise<Integration>]>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { getAlbumInfo, getAllAlbums, getMyUser, getServerStatistics, init, searchUsers } from "@immich/sdk";
|
import { getAlbumInfo, getAllAlbums, getMyUser, getServerStatistics, init, searchUsers } from "@immich/sdk";
|
||||||
|
|
||||||
|
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||||
import { ImageProxy } from "@homarr/image-proxy";
|
import { ImageProxy } from "@homarr/image-proxy";
|
||||||
|
|
||||||
@@ -41,7 +42,10 @@ export class ImmichIntegration extends Integration {
|
|||||||
|
|
||||||
public async getServerStatsAsync(): Promise<ImmichServerStats> {
|
public async getServerStatsAsync(): Promise<ImmichServerStats> {
|
||||||
this.initClient();
|
this.initClient();
|
||||||
const [statistics, users] = await Promise.all([getServerStatistics(), searchUsers()]);
|
const [statistics, users] = await Promise.all([
|
||||||
|
getServerStatistics(this.getRequestOptions()),
|
||||||
|
searchUsers(this.getRequestOptions()),
|
||||||
|
]);
|
||||||
return {
|
return {
|
||||||
photoCount: statistics.photos,
|
photoCount: statistics.photos,
|
||||||
userCount: users.length,
|
userCount: users.length,
|
||||||
@@ -52,7 +56,7 @@ export class ImmichIntegration extends Integration {
|
|||||||
|
|
||||||
public async getAlbumAsync(albumId: string): Promise<ImmichAlbum> {
|
public async getAlbumAsync(albumId: string): Promise<ImmichAlbum> {
|
||||||
this.initClient();
|
this.initClient();
|
||||||
const album = await getAlbumInfo({ id: albumId });
|
const album = await getAlbumInfo({ id: albumId }, this.getRequestOptions());
|
||||||
const imageProxy = new ImageProxy();
|
const imageProxy = new ImageProxy();
|
||||||
return {
|
return {
|
||||||
albumName: album.albumName,
|
albumName: album.albumName,
|
||||||
@@ -89,17 +93,24 @@ export class ImmichIntegration extends Integration {
|
|||||||
}[]
|
}[]
|
||||||
> {
|
> {
|
||||||
this.initClient();
|
this.initClient();
|
||||||
const albums = await getAllAlbums({});
|
const albums = await getAllAlbums({}, this.getRequestOptions());
|
||||||
return albums.map((album) => ({ id: album.id, albumName: album.albumName, assetCount: album.assetCount }));
|
return albums.map((album) => ({ id: album.id, albumName: album.albumName, assetCount: album.assetCount }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async testingAsync(_: IntegrationTestingInput): Promise<TestingResult> {
|
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||||
this.initClient();
|
this.initClient();
|
||||||
const user = await getMyUser();
|
const user = await getMyUser(this.getRequestOptions(input.fetchAsync));
|
||||||
logger.debug(`Logged in as ${user.name} (${user.id})`);
|
logger.debug(`Logged in as ${user.name} (${user.id})`);
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getRequestOptions(fetchAsync = fetchWithTrustedCertificatesAsync) {
|
||||||
|
return {
|
||||||
|
// Undici and node types are not the same
|
||||||
|
fetch: fetchAsync as unknown as typeof fetch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the credentials and prepares the client for calls.
|
* Sets the credentials and prepares the client for calls.
|
||||||
* Must be called before any other functions.
|
* Must be called before any other functions.
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import type { Station, Timetable, TimetableOptions } from "./timetable-types";
|
||||||
|
|
||||||
|
export interface TimetableIntegration {
|
||||||
|
searchStationsAsync(query: string): Promise<Station[]>;
|
||||||
|
getTimetableAsync(options: TimetableOptions): Promise<Timetable>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export interface Station {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const timetableOptionsSchema = z.object({
|
||||||
|
stationId: z.string(),
|
||||||
|
limit: z.number().default(10),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TimetableOptions = z.infer<typeof timetableOptionsSchema>;
|
||||||
|
|
||||||
|
export interface TimetableEntry {
|
||||||
|
timestamp: Date;
|
||||||
|
delay: number;
|
||||||
|
line: {
|
||||||
|
name: string;
|
||||||
|
color: string | null;
|
||||||
|
} | null;
|
||||||
|
location: string;
|
||||||
|
platform: {
|
||||||
|
name: string;
|
||||||
|
hasChanged: boolean;
|
||||||
|
} | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Timetable {
|
||||||
|
stationId: string;
|
||||||
|
timestamp: Date;
|
||||||
|
entries: TimetableEntry[];
|
||||||
|
}
|
||||||
@@ -2,8 +2,9 @@ import type { Agent } from "https";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import timezone from "dayjs/plugin/timezone";
|
import timezone from "dayjs/plugin/timezone";
|
||||||
import utc from "dayjs/plugin/utc";
|
import utc from "dayjs/plugin/utc";
|
||||||
|
import ICAL from "ical.js";
|
||||||
import type { RequestInit as NodeFetchRequestInit } from "node-fetch";
|
import type { RequestInit as NodeFetchRequestInit } from "node-fetch";
|
||||||
import * as ical from "node-ical";
|
import { tzlib_get_ical_block, tzlib_get_timezones } from "timezones-ical-library";
|
||||||
import { DAVClient } from "tsdav";
|
import { DAVClient } from "tsdav";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
@@ -21,6 +22,20 @@ import type { CalendarEvent } from "../interfaces/calendar/calendar-types";
|
|||||||
import type { Notification } from "../interfaces/notifications/notification-types";
|
import type { Notification } from "../interfaces/notifications/notification-types";
|
||||||
import type { INotificationsIntegration } from "../interfaces/notifications/notifications-integration";
|
import type { INotificationsIntegration } from "../interfaces/notifications/notifications-integration";
|
||||||
|
|
||||||
|
// Register all existing timezones
|
||||||
|
if (ICAL.TimezoneService.count === 0) {
|
||||||
|
const timezones = tzlib_get_timezones() as string[];
|
||||||
|
for (const tzid of timezones) {
|
||||||
|
ICAL.TimezoneService.register(
|
||||||
|
new ICAL.Timezone({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-non-null-assertion
|
||||||
|
component: new ICAL.Component(ICAL.parse((tzlib_get_ical_block(tzid) as string[])[0]!)),
|
||||||
|
tzid,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const notificationSchema = z.object({
|
const notificationSchema = z.object({
|
||||||
ocs: z.object({
|
ocs: z.object({
|
||||||
data: z.array(
|
data: z.array(
|
||||||
@@ -68,42 +83,64 @@ export class NextcloudIntegration extends Integration implements ICalendarIntegr
|
|||||||
|
|
||||||
return calendarEvents
|
return calendarEvents
|
||||||
.map((event) => {
|
.map((event) => {
|
||||||
// @ts-expect-error the typescript definitions for this package are wrong
|
if (typeof event.data !== "string") {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
|
return [];
|
||||||
const icalData = ical.default.parseICS(event.data) as ical.CalendarResponse;
|
|
||||||
const veventObject = Object.values(icalData).find((data) => data.type === "VEVENT");
|
|
||||||
|
|
||||||
if (!veventObject) {
|
|
||||||
throw new Error(`Invalid event data object: ${JSON.stringify(event.data)}. Unable to process the calendar.`);
|
|
||||||
}
|
}
|
||||||
|
const comp = ICAL.Component.fromString(event.data);
|
||||||
|
const veventComponent = comp.getFirstSubcomponent("vevent");
|
||||||
|
|
||||||
|
if (!veventComponent) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const veventObject = new ICAL.Event(veventComponent);
|
||||||
|
|
||||||
logger.debug(`Converting VEVENT event to ${event.etag} from Nextcloud: ${JSON.stringify(veventObject)}`);
|
logger.debug(`Converting VEVENT event to ${event.etag} from Nextcloud: ${JSON.stringify(veventObject)}`);
|
||||||
|
|
||||||
const eventUrlWithoutHost = new URL(event.url).pathname;
|
const eventUrlWithoutHost = new URL(event.url).pathname;
|
||||||
const eventSlug = Buffer.from(eventUrlWithoutHost).toString("base64url");
|
const eventSlug = Buffer.from(eventUrlWithoutHost).toString("base64url");
|
||||||
|
|
||||||
const startDates = veventObject.rrule ? veventObject.rrule.between(start, end) : [veventObject.start];
|
const durationMs = veventObject.duration.toSeconds() * 1000;
|
||||||
|
|
||||||
const durationMs = veventObject.end.getTime() - veventObject.start.getTime();
|
// Handle recurring events
|
||||||
|
let startDates: Date[];
|
||||||
|
if (veventObject.isRecurring()) {
|
||||||
|
const iterator = veventObject.iterator();
|
||||||
|
startDates = [];
|
||||||
|
|
||||||
|
// Iterate through occurrences within the time range
|
||||||
|
let next: ICAL.Time | undefined;
|
||||||
|
// next actually returns undefined when there are no more occurrences
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
while ((next = iterator.next())) {
|
||||||
|
const nextStartDate = next.convertToZone(ICAL.Timezone.utcTimezone).toJSDate();
|
||||||
|
if (nextStartDate > end) break;
|
||||||
|
const nextEndDate = new Date(nextStartDate.getTime() + durationMs);
|
||||||
|
if (nextEndDate < start) continue;
|
||||||
|
|
||||||
|
startDates.push(nextStartDate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startDates = [veventObject.startDate.convertToZone(ICAL.Timezone.utcTimezone).toJSDate()];
|
||||||
|
}
|
||||||
|
|
||||||
return startDates.map((startDate) => {
|
return startDates.map((startDate) => {
|
||||||
const timezoneOffsetMinutes = veventObject.rrule?.origOptions.tzid
|
const endDate = new Date(startDate.getTime() + durationMs);
|
||||||
? dayjs(startDate).tz(veventObject.rrule.origOptions.tzid).utcOffset()
|
const dateInMillis = startDate.valueOf();
|
||||||
: 0;
|
|
||||||
const utcStartDate = new Date(startDate.getTime() - timezoneOffsetMinutes * 60 * 1000);
|
// Get color property from the component
|
||||||
const endDate = new Date(utcStartDate.getTime() + durationMs);
|
const colorProperty = veventComponent.getFirstProperty("color");
|
||||||
const dateInMillis = utcStartDate.valueOf();
|
const color = colorProperty?.getFirstValue() as string | undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: veventObject.summary,
|
title: veventObject.summary,
|
||||||
subTitle: null,
|
subTitle: null,
|
||||||
description: veventObject.description,
|
description: veventObject.description || null,
|
||||||
startDate: utcStartDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
image: null,
|
image: null,
|
||||||
location: veventObject.location || null,
|
location: veventObject.location || null,
|
||||||
indicatorColor:
|
indicatorColor: color ?? "#ff8600",
|
||||||
"color" in veventObject && typeof veventObject.color === "string" ? veventObject.color : "#ff8600",
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
href: this.externalUrl(
|
href: this.externalUrl(
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { ResponseError } from "@homarr/common/server";
|
||||||
|
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
|
||||||
|
|
||||||
|
import type { IntegrationTestingInput } from "../base/integration";
|
||||||
|
import { Integration } from "../base/integration";
|
||||||
|
import { TestConnectionError } from "../base/test-connection/test-connection-error";
|
||||||
|
import type { TestingResult } from "../base/test-connection/test-connection-service";
|
||||||
|
import type { TimetableIntegration } from "../interfaces/timetable/timetable-integration";
|
||||||
|
import type { Station, Timetable, TimetableOptions } from "../interfaces/timetable/timetable-types";
|
||||||
|
|
||||||
|
const supportedStationTypes = ["bus", "tram", "train", "ship", "cablecar", "funicular", "chairlift"];
|
||||||
|
|
||||||
|
export class SearchChIntegration extends Integration implements TimetableIntegration {
|
||||||
|
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||||
|
const response = await input.fetchAsync(this.url("/timetable/api/completion.json", { term: "Zürich" }));
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return TestConnectionError.StatusResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for stations matching the given query.
|
||||||
|
* @param query The search query for station names.
|
||||||
|
* @returns A list of stations matching the search query.
|
||||||
|
* @docs https://search.ch/fahrplan/api/help
|
||||||
|
*/
|
||||||
|
public async searchStationsAsync(query: string): Promise<Station[]> {
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(
|
||||||
|
this.url("/timetable/api/completion.json", {
|
||||||
|
term: query,
|
||||||
|
show_ids: 1,
|
||||||
|
nofavorites: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new ResponseError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await searchSchema.parseAsync(await response.json());
|
||||||
|
|
||||||
|
return (
|
||||||
|
data
|
||||||
|
// Remove completions like addresses, we only want stations.
|
||||||
|
.filter((item) => supportedStationTypes.some((type) => item.iconclass.endsWith(type)))
|
||||||
|
.map((item) => (item.id !== undefined ? { id: item.id, name: item.label } : null))
|
||||||
|
.filter((item) => item !== null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the departure timetable for a given station.
|
||||||
|
* @param options Timetable options including station ID and limit.
|
||||||
|
* @returns timetable for the given station.
|
||||||
|
* @docs https://search.ch/fahrplan/api/help
|
||||||
|
*/
|
||||||
|
public async getTimetableAsync(options: TimetableOptions): Promise<Timetable> {
|
||||||
|
const now = new Date();
|
||||||
|
// The following format is used [01.01.2000, 23:59:00]. The API allows usage of DD.MM.YYYY format and HH:mm format
|
||||||
|
const [date, time] = now.toLocaleString("en-CH", { timeZone: "Europe/Zurich" }).split(", ") as [string, string];
|
||||||
|
|
||||||
|
const response = await fetchWithTrustedCertificatesAsync(
|
||||||
|
this.url("/timetable/api/stationboard.json", {
|
||||||
|
stop: options.stationId,
|
||||||
|
limit: options.limit,
|
||||||
|
show_delays: 1,
|
||||||
|
show_tracks: 1,
|
||||||
|
date,
|
||||||
|
time: time.substring(0, 5), // Only keep the HH:mm part of the time, as that's what the API expects
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new ResponseError(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await timetableSchema.parseAsync(await response.json());
|
||||||
|
|
||||||
|
return {
|
||||||
|
stationId: options.stationId,
|
||||||
|
timestamp: now,
|
||||||
|
entries: data.connections.map((connection) => {
|
||||||
|
// Color is in format A35~F10~ for foreground and background color. Some only have ~~ and therefore no color
|
||||||
|
const color = connection.color.split("~")[0];
|
||||||
|
|
||||||
|
return {
|
||||||
|
timestamp: connection.time,
|
||||||
|
line: connection.line
|
||||||
|
? {
|
||||||
|
name: connection.line,
|
||||||
|
color: color && color.length >= 1 ? `#${color}` : null,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
location: connection.terminal.name,
|
||||||
|
delay: connection.dep_delay,
|
||||||
|
platform: connection.track
|
||||||
|
? {
|
||||||
|
// If the track name contains "!", it indicates a change in the track
|
||||||
|
// so we remove the "!" from the name and set hasChanged to true
|
||||||
|
name: connection.track.replace("!", ""),
|
||||||
|
hasChanged: connection.track.includes("!"),
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const timetableSchema = z.object({
|
||||||
|
connections: z.array(
|
||||||
|
z.object({
|
||||||
|
time: z.string().transform((str) => new Date(str)),
|
||||||
|
line: z.string().optional(),
|
||||||
|
color: z.string(),
|
||||||
|
terminal: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
}),
|
||||||
|
track: z.string().optional(),
|
||||||
|
dep_delay: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.transform((str) => (str ? parseInt(str) : 0)),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchSchema = z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string().optional(),
|
||||||
|
label: z.string(),
|
||||||
|
iconclass: z.string(), // This is in format sl-icon-type-{type}
|
||||||
|
}),
|
||||||
|
);
|
||||||
@@ -12,4 +12,5 @@ export * from "./unifi-controller/unifi-controller-types";
|
|||||||
export * from "./opnsense/opnsense-types";
|
export * from "./opnsense/opnsense-types";
|
||||||
export * from "./interfaces/media-releases";
|
export * from "./interfaces/media-releases";
|
||||||
export * from "./coolify/coolify-types";
|
export * from "./coolify/coolify-types";
|
||||||
|
export * from "./interfaces/timetable/timetable-types";
|
||||||
export * from "./tracearr/tracearr-types";
|
export * from "./tracearr/tracearr-types";
|
||||||
@@ -0,0 +1,454 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
|
import type { StartedTestContainer } from "testcontainers";
|
||||||
|
import { GenericContainer, getContainerRuntimeClient, ImageName, Wait } from "testcontainers";
|
||||||
|
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
import { createId } from "@homarr/common";
|
||||||
|
import { createDb } from "@homarr/db/test";
|
||||||
|
|
||||||
|
import { NextcloudIntegration } from "../src";
|
||||||
|
|
||||||
|
// Mock the database
|
||||||
|
vi.mock("@homarr/db", async (importActual) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||||
|
const actual = await importActual<typeof import("@homarr/db")>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
db: createDb(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mock certificate verification
|
||||||
|
vi.mock("@homarr/core/infrastructure/certificates", async (importActual) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||||
|
const actual = await importActual<typeof import("@homarr/core/infrastructure/certificates")>();
|
||||||
|
return {
|
||||||
|
...actual,
|
||||||
|
getTrustedCertificateHostnamesAsync: vi.fn().mockImplementation(() => {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const IMAGE_NAME = "nextcloud:latest";
|
||||||
|
const DEFAULT_USERNAME = "admin";
|
||||||
|
const DEFAULT_PASSWORD = "admin123";
|
||||||
|
|
||||||
|
interface CalendarTestEvent {
|
||||||
|
summary: string;
|
||||||
|
description?: string;
|
||||||
|
location?: string;
|
||||||
|
color?: string;
|
||||||
|
dtstart: string;
|
||||||
|
dtend: string;
|
||||||
|
rrule?: string;
|
||||||
|
timezone?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Nextcloud integration", () => {
|
||||||
|
let startedContainer: StartedTestContainer | null = null;
|
||||||
|
let nextcloudIntegration: NextcloudIntegration | null = null;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const containerRuntimeClient = await getContainerRuntimeClient();
|
||||||
|
await containerRuntimeClient.image.pull(ImageName.fromString(IMAGE_NAME));
|
||||||
|
|
||||||
|
startedContainer = await prepareNextcloudContainerAsync();
|
||||||
|
nextcloudIntegration = createNextcloudIntegration(startedContainer);
|
||||||
|
}, 100_000);
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
if (startedContainer) {
|
||||||
|
await startedContainer.stop();
|
||||||
|
startedContainer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test connection", () => {
|
||||||
|
test("Test connection > Should work with valid credentials", async () => {
|
||||||
|
// Act
|
||||||
|
const result = await nextcloudIntegration!.testConnectionAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
}, 20_000);
|
||||||
|
|
||||||
|
test("Test connection > Should fail with invalid credentials", async () => {
|
||||||
|
// Arrange
|
||||||
|
const invalidIntegration = createNextcloudIntegration(startedContainer!, "wrong-user", "wrong-pass");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const result = await invalidIntegration.testConnectionAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result.success).toBe(false);
|
||||||
|
}, 20_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Retrieve calendar events", () => {
|
||||||
|
test("Retrieve calendar events > Should retrieve all fields correctly", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Test Meeting",
|
||||||
|
description: "This is a test meeting",
|
||||||
|
location: "Conference Room A",
|
||||||
|
color: "#FF5733",
|
||||||
|
dtstart: "20260415T140000Z",
|
||||||
|
dtend: "20260415T150000Z",
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
const retrievedEvent = relevantEvents[0];
|
||||||
|
expect(retrievedEvent).toMatchObject({
|
||||||
|
title: testEvent.summary,
|
||||||
|
description: testEvent.description,
|
||||||
|
location: testEvent.location,
|
||||||
|
indicatorColor: testEvent.color,
|
||||||
|
});
|
||||||
|
expect(retrievedEvent!.startDate.toISOString()).toBe("2026-04-15T14:00:00.000Z");
|
||||||
|
expect(retrievedEvent!.endDate?.toISOString()).toBe("2026-04-15T15:00:00.000Z");
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with only required fields", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Simple Event",
|
||||||
|
dtstart: "20260415T140000Z",
|
||||||
|
dtend: "20260415T150000Z",
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
const retrievedEvent = relevantEvents[0];
|
||||||
|
expect(retrievedEvent?.location).toBeNull();
|
||||||
|
expect(retrievedEvent?.description).toBeNull();
|
||||||
|
expect(retrievedEvent?.indicatorColor).toBe("#ff8600"); // Default color
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with timezone specified", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Timezone Event",
|
||||||
|
dtstart: "20260415T140000",
|
||||||
|
dtend: "20260415T150000",
|
||||||
|
timezone: "Asia/Tokyo",
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
const retrievedEvent = relevantEvents[0];
|
||||||
|
|
||||||
|
expect(retrievedEvent!.startDate.toISOString()).toBe("2026-04-15T05:00:00.000Z"); // 14:00 in Tokyo is 05:00 UTC
|
||||||
|
expect(retrievedEvent!.endDate?.toISOString()).toBe("2026-04-15T06:00:00.000Z"); // 15:00 in Tokyo is 06:00 UTC
|
||||||
|
}, 120_000);
|
||||||
|
test("Retrieve calendar events > Should work with event that starts before the range but ends within the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Early Meeting",
|
||||||
|
dtstart: "20260401T230000Z", // Starts before the range
|
||||||
|
dtend: "20260402T010000Z", // Ends within the range
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-02T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with event that starts within the range but ends after the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Late Meeting",
|
||||||
|
dtstart: "20260430T230000Z", // Starts within the range
|
||||||
|
dtend: "20260501T010000Z", // Ends after the range
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should not retrieve events outside the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Out of Range Meeting",
|
||||||
|
dtstart: "20260301T140000Z", // Starts before the range
|
||||||
|
dtend: "20260301T150000Z", // Ends before the range
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(0);
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with events that begin before the range and end after the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Spanning Meeting",
|
||||||
|
dtstart: "20260330T230000Z", // Starts before the range
|
||||||
|
dtend: "20260501T010000Z", // Ends after the range
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(1);
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with recurring events first occurrence before the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Recurring Meeting",
|
||||||
|
dtstart: "20260330T140000Z", // First occurrence starts before the range
|
||||||
|
dtend: "20260330T150000Z",
|
||||||
|
rrule: "FREQ=DAILY;COUNT=5", // Daily for 5 occurrences
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(3);
|
||||||
|
}, 20_000);
|
||||||
|
test("Retrieve calendar events > Should work with recurring events that go beyond the range", async () => {
|
||||||
|
// Arrange
|
||||||
|
const calendarName = createId();
|
||||||
|
const testEvent: CalendarTestEvent = {
|
||||||
|
summary: "Working Week",
|
||||||
|
dtstart: "20260302T090000Z",
|
||||||
|
dtend: "20260306T170000Z",
|
||||||
|
rrule: "FREQ=WEEKLY;COUNT=10",
|
||||||
|
};
|
||||||
|
const start = new Date("2026-04-01T00:00:00Z");
|
||||||
|
const end = new Date("2026-04-30T23:59:59Z");
|
||||||
|
|
||||||
|
await createCalendarAsync(startedContainer!, calendarName);
|
||||||
|
await createCalendarEventAsync(startedContainer!, calendarName, testEvent);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const events = await nextcloudIntegration!.getCalendarEventsAsync(start, end);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
const relevantEvents = events.filter((event) => event.title === testEvent.summary);
|
||||||
|
expect(relevantEvents).toHaveLength(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares a Nextcloud container with proper configuration
|
||||||
|
*/
|
||||||
|
async function prepareNextcloudContainerAsync(): Promise<StartedTestContainer> {
|
||||||
|
const container = createNextcloudContainer();
|
||||||
|
const startedContainer = await container.start();
|
||||||
|
|
||||||
|
return startedContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Nextcloud container with proper configuration
|
||||||
|
*/
|
||||||
|
function createNextcloudContainer() {
|
||||||
|
return new GenericContainer(IMAGE_NAME)
|
||||||
|
.withEnvironment({
|
||||||
|
NEXTCLOUD_ADMIN_USER: DEFAULT_USERNAME,
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD: DEFAULT_PASSWORD,
|
||||||
|
NEXTCLOUD_TRUSTED_DOMAINS: "*",
|
||||||
|
SQLITE_DATABASE: "nextcloud", // Use SQLite for faster startup
|
||||||
|
})
|
||||||
|
.withExposedPorts(80)
|
||||||
|
.withWaitStrategy(Wait.forHttp("/status.php", 80).forStatusCode(200))
|
||||||
|
.withStartupTimeout(120_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Nextcloud integration instance
|
||||||
|
*/
|
||||||
|
function createNextcloudIntegration(
|
||||||
|
container: StartedTestContainer,
|
||||||
|
username?: string,
|
||||||
|
password?: string,
|
||||||
|
): NextcloudIntegration {
|
||||||
|
return new NextcloudIntegration({
|
||||||
|
id: "1",
|
||||||
|
decryptedSecrets: [
|
||||||
|
{
|
||||||
|
kind: "username",
|
||||||
|
value: username ?? DEFAULT_USERNAME,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kind: "password",
|
||||||
|
value: password ?? DEFAULT_PASSWORD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: "Nextcloud",
|
||||||
|
url: `http://${container.getHost()}:${container.getMappedPort(80)}`,
|
||||||
|
externalUrl: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a calendar in Nextcloud via OCS API
|
||||||
|
*/
|
||||||
|
async function createCalendarAsync(container: StartedTestContainer, calendarName: string): Promise<void> {
|
||||||
|
const host = container.getHost();
|
||||||
|
const port = container.getMappedPort(80);
|
||||||
|
const url = `http://${host}:${port}/remote.php/dav/calendars/${DEFAULT_USERNAME}/${calendarName}`;
|
||||||
|
|
||||||
|
const auth = Buffer.from(`${DEFAULT_USERNAME}:${DEFAULT_PASSWORD}`).toString("base64");
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "MKCALENDAR",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${auth}`,
|
||||||
|
"Content-Type": "application/xml",
|
||||||
|
},
|
||||||
|
body: `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<c:mkcalendar xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:d="DAV:">
|
||||||
|
<d:set>
|
||||||
|
<d:prop>
|
||||||
|
<d:displayname>${calendarName}</d:displayname>
|
||||||
|
</d:prop>
|
||||||
|
</d:set>
|
||||||
|
</c:mkcalendar>`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok && response.status !== 201) {
|
||||||
|
throw new Error(`Failed to create calendar: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a calendar event in Nextcloud via CalDAV
|
||||||
|
*/
|
||||||
|
async function createCalendarEventAsync(
|
||||||
|
container: StartedTestContainer,
|
||||||
|
calendarName: string,
|
||||||
|
event: CalendarTestEvent,
|
||||||
|
): Promise<void> {
|
||||||
|
const host = container.getHost();
|
||||||
|
const port = container.getMappedPort(80);
|
||||||
|
const id = createId();
|
||||||
|
const url = `http://${host}:${port}/remote.php/dav/calendars/${DEFAULT_USERNAME}/${calendarName}/${id}.ics`;
|
||||||
|
|
||||||
|
const auth = Buffer.from(`${DEFAULT_USERNAME}:${DEFAULT_PASSWORD}`).toString("base64");
|
||||||
|
|
||||||
|
// Build iCalendar format
|
||||||
|
const icalData = buildICalEvent(id, event);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${auth}`,
|
||||||
|
"Content-Type": "text/calendar",
|
||||||
|
},
|
||||||
|
body: icalData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok && response.status !== 201) {
|
||||||
|
throw new Error(`Failed to create event: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an iCalendar format string from event data
|
||||||
|
*/
|
||||||
|
function buildICalEvent(uid: string, event: CalendarTestEvent): string {
|
||||||
|
const lines = [
|
||||||
|
"BEGIN:VCALENDAR",
|
||||||
|
"VERSION:2.0",
|
||||||
|
"PRODID:-//Homarr Tests//EN",
|
||||||
|
"BEGIN:VEVENT",
|
||||||
|
`UID:${uid}`,
|
||||||
|
`DTSTAMP:${new Date().toISOString().replace(/[-:]/g, "").split(".")[0]}Z`,
|
||||||
|
`DTSTART${event.timezone ? `;TZID=${event.timezone}` : ""}:${event.dtstart}`,
|
||||||
|
`DTEND${event.timezone ? `;TZID=${event.timezone}` : ""}:${event.dtend}`,
|
||||||
|
`SUMMARY:${event.summary}`,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (event.description) {
|
||||||
|
lines.push(`DESCRIPTION:${event.description}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.location) {
|
||||||
|
lines.push(`LOCATION:${event.location}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.color) {
|
||||||
|
lines.push(`COLOR:${event.color}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.rrule) {
|
||||||
|
lines.push(`RRULE:${event.rrule}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("END:VEVENT", "END:VCALENDAR");
|
||||||
|
|
||||||
|
return lines.join("\r\n");
|
||||||
|
}
|
||||||
@@ -34,12 +34,12 @@
|
|||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.0",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@mantine/notifications": "^8.3.18",
|
"@mantine/notifications": "^8.3.18",
|
||||||
"@tabler/icons-react": "^3.40.0"
|
"@tabler/icons-react": "^3.41.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"zod": "^4.2.1",
|
"zod": "^4.3.6",
|
||||||
"zod-form-data": "^3.0.1"
|
"zod-form-data": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"superjson": "2.2.6",
|
"superjson": "2.2.6",
|
||||||
"undici": "7.24.5",
|
"undici": "7.24.6",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
import type { IntegrationKindByCategory } from "@homarr/definitions";
|
||||||
|
import { createIntegrationAsync } from "@homarr/integrations";
|
||||||
|
import type { Station, Timetable } from "@homarr/integrations/types";
|
||||||
|
|
||||||
|
import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler";
|
||||||
|
|
||||||
|
export const timetableSearchStationsRequestHandler = createCachedIntegrationRequestHandler<
|
||||||
|
Station[],
|
||||||
|
IntegrationKindByCategory<"timetable">,
|
||||||
|
{ query: string }
|
||||||
|
>({
|
||||||
|
async requestAsync(integration, input) {
|
||||||
|
const integrationInstance = await createIntegrationAsync(integration);
|
||||||
|
return await integrationInstance.searchStationsAsync(input.query);
|
||||||
|
},
|
||||||
|
queryKey: "timetableSearchStations",
|
||||||
|
cacheDuration: dayjs.duration(1, "day"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const timetableGetTimetableRequestHandler = createCachedIntegrationRequestHandler<
|
||||||
|
Timetable,
|
||||||
|
IntegrationKindByCategory<"timetable">,
|
||||||
|
{ stationId: string; limit: number }
|
||||||
|
>({
|
||||||
|
async requestAsync(integration, input) {
|
||||||
|
const integrationInstance = await createIntegrationAsync(integration);
|
||||||
|
return await integrationInstance.getTimetableAsync({
|
||||||
|
stationId: input.stationId,
|
||||||
|
limit: input.limit,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
queryKey: "timetableGetTimetable",
|
||||||
|
cacheDuration: dayjs.duration(1, "minute"),
|
||||||
|
});
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"@mantine/hooks": "^8.3.18",
|
"@mantine/hooks": "^8.3.18",
|
||||||
"@mantine/spotlight": "^8.3.18",
|
"@mantine/spotlight": "^8.3.18",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.0",
|
||||||
"jotai": "^2.18.1",
|
"jotai": "^2.19.0",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": ""
|
"label": ""
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "允许地理位置"
|
"label": "允许地理位置"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "显示内存信息"
|
"label": "显示内存信息"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "显示运行时间"
|
"label": "显示运行时间"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "内存",
|
"memory": "内存",
|
||||||
|
"gpu": "",
|
||||||
"network": "网络"
|
"network": "网络"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "内存",
|
"memory": "内存",
|
||||||
|
"gpu": "",
|
||||||
"network": "网络",
|
"network": "网络",
|
||||||
"up": "上传",
|
"up": "上传",
|
||||||
"down": "下载"
|
"down": "下载"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "crwdns970:0crwdne970:0"
|
"label": "crwdns970:0crwdne970:0"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": "crwdns3992:0crwdne3992:0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "crwdns1080:0crwdne1080:0"
|
"label": "crwdns1080:0crwdne1080:0"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": "crwdns3994:0crwdne3994:0"
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "crwdns3446:0crwdne3446:0"
|
"label": "crwdns3446:0crwdne3446:0"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "crwdns3700:0crwdne3700:0",
|
"cpu": "crwdns3700:0crwdne3700:0",
|
||||||
"memory": "crwdns3702:0crwdne3702:0",
|
"memory": "crwdns3702:0crwdne3702:0",
|
||||||
|
"gpu": "crwdns3996:0crwdne3996:0",
|
||||||
"network": "crwdns3704:0crwdne3704:0"
|
"network": "crwdns3704:0crwdne3704:0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "crwdns3604:0crwdne3604:0",
|
"cpu": "crwdns3604:0crwdne3604:0",
|
||||||
"memory": "crwdns3606:0crwdne3606:0",
|
"memory": "crwdns3606:0crwdne3606:0",
|
||||||
|
"gpu": "crwdns3998:0crwdne3998:0",
|
||||||
"network": "crwdns3608:0crwdne3608:0",
|
"network": "crwdns3608:0crwdne3608:0",
|
||||||
"up": "crwdns3610:0crwdne3610:0",
|
"up": "crwdns3610:0crwdne3610:0",
|
||||||
"down": "crwdns3612:0crwdne3612:0"
|
"down": "crwdns3612:0crwdne3612:0"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Povolit polohu"
|
"label": "Povolit polohu"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Zobrazit informace o paměti"
|
"label": "Zobrazit informace o paměti"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Tillad geolokalisering"
|
"label": "Tillad geolokalisering"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Vis hukommelsesoplysninger"
|
"label": "Vis hukommelsesoplysninger"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Vis Oppetid"
|
"label": "Vis Oppetid"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Hukommelse",
|
"memory": "Hukommelse",
|
||||||
|
"gpu": "",
|
||||||
"network": "Netværk"
|
"network": "Netværk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "",
|
||||||
"network": "NET",
|
"network": "NET",
|
||||||
"up": "OP",
|
"up": "OP",
|
||||||
"down": "NED"
|
"down": "NED"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Geolokalisierung zulassen"
|
"label": "Geolokalisierung zulassen"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Speicher-Info anzeigen"
|
"label": "Speicher-Info anzeigen"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Geolokalisierung zulassen"
|
"label": "Geolokalisierung zulassen"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Speicher-Info anzeigen"
|
"label": "Speicher-Info anzeigen"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Laufzeit anzeigen"
|
"label": "Laufzeit anzeigen"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Speicher",
|
"memory": "Speicher",
|
||||||
|
"gpu": "",
|
||||||
"network": "Netzwerk"
|
"network": "Netzwerk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Arbeitsspeicher",
|
"memory": "Arbeitsspeicher",
|
||||||
|
"gpu": "",
|
||||||
"network": "Netzwerk",
|
"network": "Netzwerk",
|
||||||
"up": "OBEN",
|
"up": "OBEN",
|
||||||
"down": "UNTEN"
|
"down": "UNTEN"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Επιτρέπεται ο γεωεντοπισμός"
|
"label": "Επιτρέπεται ο γεωεντοπισμός"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Εμφάνιση Πληροφοριών Μνήμης"
|
"label": "Εμφάνιση Πληροφοριών Μνήμης"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1125,17 +1125,17 @@
|
|||||||
"userAvatar": {
|
"userAvatar": {
|
||||||
"menu": {
|
"menu": {
|
||||||
"switchToDarkMode": "Switch to dark mode",
|
"switchToDarkMode": "Switch to dark mode",
|
||||||
"switchToLightMode": "Switch to light mode",
|
"switchToLightMode": "التبديل إلى الوضع الفاتح",
|
||||||
"management": "Management",
|
"management": "الإدارة",
|
||||||
"preferences": "Your preferences",
|
"preferences": "تفضيلاتك",
|
||||||
"logout": "Log-out",
|
"logout": "تسجيل الخروج",
|
||||||
"login": "Log-in",
|
"login": "Log-in",
|
||||||
"homeBoard": "Your home board",
|
"homeBoard": "لوحة منزلك",
|
||||||
"loggedOut": "Logged out",
|
"loggedOut": "Logged out",
|
||||||
"updateAvailable": "New update available: {tag}"
|
"updateAvailable": "{countUpdates} يتوفر تحديث جديد: {tag}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dangerZone": "Danger zone",
|
"dangerZone": "المنطقة الخطرة",
|
||||||
"noResults": "No results have been found",
|
"noResults": "No results have been found",
|
||||||
"unsavedChanges": "You have unsaved changes!",
|
"unsavedChanges": "You have unsaved changes!",
|
||||||
"servers": "Servers",
|
"servers": "Servers",
|
||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Allow geolocation"
|
"label": "Allow geolocation"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": "Allow modals"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1856,107 +1859,110 @@
|
|||||||
"label": "Show CPU Info"
|
"label": "Show CPU Info"
|
||||||
},
|
},
|
||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": "Show Memory Info"
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": "Show GPU Info"
|
||||||
},
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": "Show Uptime"
|
||||||
},
|
},
|
||||||
"fileSystem": {
|
"fileSystem": {
|
||||||
"label": ""
|
"label": "Show Filesystem Info"
|
||||||
},
|
},
|
||||||
"defaultTab": {
|
"defaultTab": {
|
||||||
"label": ""
|
"label": "Default tab"
|
||||||
},
|
},
|
||||||
"visibleClusterSections": {
|
"visibleClusterSections": {
|
||||||
"label": ""
|
"label": "Visible cluster sections"
|
||||||
},
|
},
|
||||||
"sectionIndicatorRequirement": {
|
"sectionIndicatorRequirement": {
|
||||||
"label": ""
|
"label": "Section indicator requirement"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"popover": {
|
"popover": {
|
||||||
"information": "",
|
"information": "Information",
|
||||||
"processor": "",
|
"processor": "Processor: {cpuModelName}",
|
||||||
"memory": "",
|
"memory": "Memory: {memory}GiB",
|
||||||
"memoryAvailable": "",
|
"memoryAvailable": "Available: {memoryAvailable}GiB ({percent}%)",
|
||||||
"version": "",
|
"version": "Version: {version}",
|
||||||
"uptime": "",
|
"uptime": "Uptime: {months} Months, {days} Days, {hours} Hours, {minutes} Minutes",
|
||||||
"loadAverage": "",
|
"loadAverage": "Load average:",
|
||||||
"minute": "",
|
"minute": "1 minute",
|
||||||
"minutes": "",
|
"minutes": "{count} minutes",
|
||||||
"used": "",
|
"used": "Used",
|
||||||
"available": "",
|
"available": "Available",
|
||||||
"lastSeen": ""
|
"lastSeen": "Last status update: {lastSeen}"
|
||||||
},
|
},
|
||||||
"memory": {},
|
"memory": {},
|
||||||
"error": {
|
"error": {
|
||||||
"internalServerError": ""
|
"internalServerError": "Failed to fetch health status"
|
||||||
},
|
},
|
||||||
"cluster": {
|
"cluster": {
|
||||||
"summary": {
|
"summary": {
|
||||||
"cpu": "",
|
"cpu": "CPU",
|
||||||
"memory": ""
|
"memory": "RAM"
|
||||||
},
|
},
|
||||||
"resource": {
|
"resource": {
|
||||||
"node": {
|
"node": {
|
||||||
"name": ""
|
"name": "Nodes"
|
||||||
},
|
},
|
||||||
"qemu": {
|
"qemu": {
|
||||||
"name": ""
|
"name": "VMs"
|
||||||
},
|
},
|
||||||
"lxc": {
|
"lxc": {
|
||||||
"name": ""
|
"name": "LXCs"
|
||||||
},
|
},
|
||||||
"storage": {
|
"storage": {
|
||||||
"name": ""
|
"name": "Storage"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"popover": {
|
"popover": {
|
||||||
"rightSection": {
|
"rightSection": {
|
||||||
"node": "",
|
"node": "Node",
|
||||||
"vmId": "",
|
"vmId": "VM ID",
|
||||||
"plugin": ""
|
"plugin": "Plugin"
|
||||||
},
|
},
|
||||||
"detail": {
|
"detail": {
|
||||||
"cpu": "",
|
"cpu": "Cores",
|
||||||
"memory": "",
|
"memory": "Memory",
|
||||||
"storage": "",
|
"storage": "Storage",
|
||||||
"uptime": "",
|
"uptime": "Uptime",
|
||||||
"haState": "",
|
"haState": "HA State",
|
||||||
"storageType": {
|
"storageType": {
|
||||||
"local": "",
|
"local": "Local storage",
|
||||||
"shared": ""
|
"shared": "Shared storage"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
"header": {
|
"header": {
|
||||||
"name": "",
|
"name": "Name",
|
||||||
"cpu": "",
|
"cpu": "CPU",
|
||||||
"memory": "",
|
"memory": "RAM",
|
||||||
"node": ""
|
"node": "Node"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dockerContainers": {
|
"dockerContainers": {
|
||||||
"name": "",
|
"name": "Docker stats",
|
||||||
"description": "",
|
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
|
||||||
"option": {
|
"option": {
|
||||||
"enableRowSorting": {
|
"enableRowSorting": {
|
||||||
"label": ""
|
"label": "Enable items sorting"
|
||||||
},
|
},
|
||||||
"defaultSort": {
|
"defaultSort": {
|
||||||
"label": "",
|
"label": "Column used for sorting by default",
|
||||||
"option": {
|
"option": {
|
||||||
"name": "",
|
"name": "Name",
|
||||||
"state": "",
|
"state": "State",
|
||||||
"cpuUsage": "",
|
"cpuUsage": "CPU usage",
|
||||||
"memoryUsage": ""
|
"memoryUsage": "Memory usage"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"descendingDefaultSort": {
|
"descendingDefaultSort": {
|
||||||
"label": ""
|
"label": "Invert sorting"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
@@ -3149,98 +3157,98 @@
|
|||||||
},
|
},
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"items": {
|
"items": {
|
||||||
"home": "",
|
"home": "الصفحة الرئسية",
|
||||||
"boards": "",
|
"boards": "الألواح",
|
||||||
"apps": "",
|
"apps": "التطبيقات",
|
||||||
"integrations": "",
|
"integrations": "التكاملات",
|
||||||
"searchEngies": "",
|
"searchEngies": "محركات البحث",
|
||||||
"medias": "",
|
"medias": "الوسائط",
|
||||||
"users": {
|
"users": {
|
||||||
"label": "",
|
"label": "المستخدمين",
|
||||||
"items": {
|
"items": {
|
||||||
"manage": "",
|
"manage": "إدارة المستخدمين",
|
||||||
"invites": "",
|
"invites": "الدعوات",
|
||||||
"groups": ""
|
"groups": "المجموعات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
"label": "",
|
"label": "الأدوات",
|
||||||
"items": {
|
"items": {
|
||||||
"docker": "",
|
"docker": "الحاويات",
|
||||||
"kubernetes": "",
|
"kubernetes": "",
|
||||||
"logs": "",
|
"logs": "السجلات",
|
||||||
"api": "",
|
"api": "API",
|
||||||
"certificates": "",
|
"certificates": "الشهادات",
|
||||||
"tasks": ""
|
"tasks": "المهام"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": "",
|
"settings": "الإعدادات",
|
||||||
"help": {
|
"help": {
|
||||||
"label": "",
|
"label": "المساعدة",
|
||||||
"items": {
|
"items": {
|
||||||
"documentation": "",
|
"documentation": "المستندات",
|
||||||
"submitIssue": "",
|
"submitIssue": "إبلاغ عن مشكلة",
|
||||||
"discord": "",
|
"discord": "مجتمع ديسكورد",
|
||||||
"sourceCode": ""
|
"sourceCode": "كود المصدر"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": ""
|
"about": "حول"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page": {
|
"page": {
|
||||||
"home": {
|
"home": {
|
||||||
"statistic": {
|
"statistic": {
|
||||||
"board": "",
|
"board": "الألواح",
|
||||||
"user": "",
|
"user": "مستخدمين",
|
||||||
"invite": "",
|
"invite": "دعوات",
|
||||||
"integration": "",
|
"integration": "التكاملات",
|
||||||
"app": "",
|
"app": "البرامج",
|
||||||
"group": "",
|
"group": "المجموعات",
|
||||||
"searchEngine": "",
|
"searchEngine": "محركات البحث",
|
||||||
"media": ""
|
"media": "الوسائط"
|
||||||
},
|
},
|
||||||
"statisticLabel": {
|
"statisticLabel": {
|
||||||
"boards": "",
|
"boards": "اللوحات",
|
||||||
"resources": "",
|
"resources": "الموارد",
|
||||||
"authentication": "",
|
"authentication": "المصادقة",
|
||||||
"authorization": ""
|
"authorization": "الأذونات"
|
||||||
},
|
},
|
||||||
"heroBanner": {
|
"heroBanner": {
|
||||||
"title": "",
|
"title": "مرحبًا بعودتك إلى",
|
||||||
"subtitle": ""
|
"subtitle": "{app} اللوحات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"board": {
|
"board": {
|
||||||
"title": "",
|
"title": "لوحاتك",
|
||||||
"action": {
|
"action": {
|
||||||
"new": {
|
"new": {
|
||||||
"label": ""
|
"label": "لوحة جديدة"
|
||||||
},
|
},
|
||||||
"open": {
|
"open": {
|
||||||
"label": ""
|
"label": "فتح اللوحة"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"label": ""
|
"label": "الإعدادات"
|
||||||
},
|
},
|
||||||
"setHomeBoard": {
|
"setHomeBoard": {
|
||||||
"label": "",
|
"label": "تعيينه كلوحة رئيسية",
|
||||||
"badge": {
|
"badge": {
|
||||||
"label": "",
|
"label": "الرئيسية",
|
||||||
"tooltip": ""
|
"tooltip": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"setMobileHomeBoard": {
|
"setMobileHomeBoard": {
|
||||||
"label": "",
|
"label": "تعيينه كصفحتك الرئيسية للجوال",
|
||||||
"badge": {
|
"badge": {
|
||||||
"label": "",
|
"label": "الجوال",
|
||||||
"tooltip": ""
|
"tooltip": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duplicate": {
|
"duplicate": {
|
||||||
"label": ""
|
"label": "تكرار اللوحة"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"label": "",
|
"label": "حذف نهائيًا",
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"title": "",
|
"title": "",
|
||||||
"description": ""
|
"description": ""
|
||||||
@@ -3329,10 +3337,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
"title": "",
|
"title": "إدارة دعوات المستخدمين",
|
||||||
"action": {
|
"action": {
|
||||||
"new": {
|
"new": {
|
||||||
"title": "",
|
"title": "دعوة جديدة",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"copy": {
|
"copy": {
|
||||||
@@ -3348,13 +3356,13 @@
|
|||||||
},
|
},
|
||||||
"field": {
|
"field": {
|
||||||
"id": {
|
"id": {
|
||||||
"label": ""
|
"label": "المعرّف"
|
||||||
},
|
},
|
||||||
"creator": {
|
"creator": {
|
||||||
"label": ""
|
"label": "المنشئ"
|
||||||
},
|
},
|
||||||
"expirationDate": {
|
"expirationDate": {
|
||||||
"label": ""
|
"label": "انتهاء الصلاحية"
|
||||||
},
|
},
|
||||||
"token": {
|
"token": {
|
||||||
"label": ""
|
"label": ""
|
||||||
@@ -4121,7 +4129,7 @@
|
|||||||
"manage": {
|
"manage": {
|
||||||
"label": "",
|
"label": "",
|
||||||
"boards": {
|
"boards": {
|
||||||
"label": ""
|
"label": "الألواح"
|
||||||
},
|
},
|
||||||
"integrations": {
|
"integrations": {
|
||||||
"label": "",
|
"label": "",
|
||||||
@@ -4154,7 +4162,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"label": "",
|
"label": "المستخدمين",
|
||||||
"create": {
|
"create": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -4165,7 +4173,7 @@
|
|||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
"invites": {
|
"invites": {
|
||||||
"label": ""
|
"label": "الدعوات"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tools": {
|
"tools": {
|
||||||
@@ -4222,7 +4230,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"placeholder": "",
|
"placeholder": "البحث عن",
|
||||||
"nothingFound": "",
|
"nothingFound": "",
|
||||||
"error": {
|
"error": {
|
||||||
"fetch": ""
|
"fetch": ""
|
||||||
@@ -4382,13 +4390,13 @@
|
|||||||
"title": "",
|
"title": "",
|
||||||
"option": {
|
"option": {
|
||||||
"documentation": {
|
"documentation": {
|
||||||
"label": ""
|
"label": "Documentation"
|
||||||
},
|
},
|
||||||
"submitIssue": {
|
"submitIssue": {
|
||||||
"label": ""
|
"label": "Submit an issue"
|
||||||
},
|
},
|
||||||
"discord": {
|
"discord": {
|
||||||
"label": ""
|
"label": "Community Discord"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4397,20 +4405,20 @@
|
|||||||
"home": {
|
"home": {
|
||||||
"group": {
|
"group": {
|
||||||
"search": {
|
"search": {
|
||||||
"title": "",
|
"title": "Search",
|
||||||
"option": {
|
"option": {
|
||||||
"other": {
|
"other": {
|
||||||
"label": ""
|
"label": "Search with another search engine"
|
||||||
},
|
},
|
||||||
"no-default": {
|
"no-default": {
|
||||||
"label": "",
|
"label": "No default search engine",
|
||||||
"description": ""
|
"description": "Set a default search engine in preferences"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"label": ""
|
"label": "Search for \"{query}\" with {name}"
|
||||||
},
|
},
|
||||||
"from-integration": {
|
"from-integration": {
|
||||||
"description": ""
|
"description": "Start typing to search"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1525,6 +1525,17 @@
|
|||||||
"offline": "Offline"
|
"offline": "Offline"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"timetable": {
|
||||||
|
"name": "Timetable",
|
||||||
|
"description": "Displays departure times for a station",
|
||||||
|
"title": "Departures {station}",
|
||||||
|
"noStation": "No station selected",
|
||||||
|
"option": {
|
||||||
|
"station": {
|
||||||
|
"label": "Station"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"notebook": {
|
"notebook": {
|
||||||
"name": "Notebook",
|
"name": "Notebook",
|
||||||
"description": "A simple notebook widget that supports markdown",
|
"description": "A simple notebook widget that supports markdown",
|
||||||
@@ -3513,6 +3524,9 @@
|
|||||||
"minecraftServerStatus": {
|
"minecraftServerStatus": {
|
||||||
"label": "Minecraft server status"
|
"label": "Minecraft server status"
|
||||||
},
|
},
|
||||||
|
"timetable": {
|
||||||
|
"label": "Timetable"
|
||||||
|
},
|
||||||
"iconsUpdater": {
|
"iconsUpdater": {
|
||||||
"label": "Icons Updater"
|
"label": "Icons Updater"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Permitir geolocalización"
|
"label": "Permitir geolocalización"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Mostrar información de la memoria"
|
"label": "Mostrar información de la memoria"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Mostrar tiempo de actividad"
|
"label": "Mostrar tiempo de actividad"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Memoria",
|
"memory": "Memoria",
|
||||||
|
"gpu": "",
|
||||||
"network": "Red"
|
"network": "Red"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "",
|
||||||
"network": "RED",
|
"network": "RED",
|
||||||
"up": "ENCENDIDO",
|
"up": "ENCENDIDO",
|
||||||
"down": "APAGADO"
|
"down": "APAGADO"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": ""
|
"label": ""
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
},
|
},
|
||||||
"invite": {
|
"invite": {
|
||||||
"title": "Rejoignez Homarr",
|
"title": "Rejoignez Homarr",
|
||||||
"subtitle": "Bienvenue sur Homarr! Veuillez créer votre compte",
|
"subtitle": "Bienvenue sur Homarr ! Veuillez créer votre compte",
|
||||||
"description": "Vous avez été invité par {username}"
|
"description": "Vous avez été invité par {username}"
|
||||||
},
|
},
|
||||||
"init": {
|
"init": {
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"forgotPassword": {
|
"forgotPassword": {
|
||||||
"label": "Mot de passe oublié?",
|
"label": "Mot de passe oublié ?",
|
||||||
"description": "Un administrateur peut utiliser la commande suivante pour réinitialiser votre mot de passe :"
|
"description": "Un administrateur peut utiliser la commande suivante pour réinitialiser votre mot de passe :"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -578,7 +578,7 @@
|
|||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"title": "Supprimer l'app",
|
"title": "Supprimer l'app",
|
||||||
"message": "Êtes-vous sûr de vouloir supprimer l'app {name}?",
|
"message": "Êtes-vous sûr de vouloir supprimer l'app {name} ?",
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"title": "Suppression effectuée avec succès",
|
"title": "Suppression effectuée avec succès",
|
||||||
@@ -684,7 +684,7 @@
|
|||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"title": "Supprimer l'intégration",
|
"title": "Supprimer l'intégration",
|
||||||
"message": "Êtes-vous sûr(e) de vouloir supprimer l'intégration {name}?",
|
"message": "Êtes-vous sûr(e) de vouloir supprimer l'intégration {name} ?",
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"title": "Suppression réussie",
|
"title": "Suppression réussie",
|
||||||
@@ -742,7 +742,7 @@
|
|||||||
"description": "La réponse n'a pas pu être analysée. Veuillez vérifier que l'URL pointe vers l'URL de base du service."
|
"description": "La réponse n'a pas pu être analysée. Veuillez vérifier que l'URL pointe vers l'URL de base du service."
|
||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"title": "",
|
"title": "Erreur d'autorisation",
|
||||||
"description": "La requête n'a pas été autorisée. Veuillez vérifier que les informations d'identification sont correctes et que vous les avez configurées avec suffisamment d'autorisations."
|
"description": "La requête n'a pas été autorisée. Veuillez vérifier que les informations d'identification sont correctes et que vous les avez configurées avec suffisamment d'autorisations."
|
||||||
},
|
},
|
||||||
"statusCode": {
|
"statusCode": {
|
||||||
@@ -794,7 +794,7 @@
|
|||||||
"hostnameMismatch": {
|
"hostnameMismatch": {
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"title": "Faire confiant à l'incohérence du nom d'hôte",
|
"title": "Faire confiant à l'incohérence du nom d'hôte",
|
||||||
"message": ""
|
"message": "Êtes-vous sûr de vouloir faire confiance ce certificat avec un nom d'hôte incohérent ?"
|
||||||
},
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
@@ -1164,8 +1164,8 @@
|
|||||||
"number": "Ce champ doit être inférieur ou égal à {maximum}"
|
"number": "Ce champ doit être inférieur ou égal à {maximum}"
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas.",
|
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
|
||||||
"passwordRequirements": "Le mot de passe ne respecte pas les exigences requises.",
|
"passwordRequirements": "Le mot de passe ne respecte pas les exigences requises",
|
||||||
"boardAlreadyExists": "Un tableau avec ce nom existe déjà",
|
"boardAlreadyExists": "Un tableau avec ce nom existe déjà",
|
||||||
"invalidFileType": "Type de fichier invalide, {expected} attendu",
|
"invalidFileType": "Type de fichier invalide, {expected} attendu",
|
||||||
"invalidFileName": "Nom de fichier invalide",
|
"invalidFileName": "Nom de fichier invalide",
|
||||||
@@ -1248,7 +1248,7 @@
|
|||||||
"action": {
|
"action": {
|
||||||
"create": "Nouvel élément",
|
"create": "Nouvel élément",
|
||||||
"import": "Importer un élément",
|
"import": "Importer un élément",
|
||||||
"edit": "Editer l'élément",
|
"edit": "Éditer l'élément",
|
||||||
"moveResize": "Déplacer / redimensionner l'élément",
|
"moveResize": "Déplacer / redimensionner l'élément",
|
||||||
"duplicate": "Dupliquer l'élément",
|
"duplicate": "Dupliquer l'élément",
|
||||||
"remove": "Supprimer l'élément"
|
"remove": "Supprimer l'élément"
|
||||||
@@ -1281,7 +1281,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
"title": "Editer l'élément",
|
"title": "Éditer l'élément",
|
||||||
"advancedOptions": {
|
"advancedOptions": {
|
||||||
"label": "Options avancées",
|
"label": "Options avancées",
|
||||||
"title": "Options avancées de l'élément"
|
"title": "Options avancées de l'élément"
|
||||||
@@ -1309,7 +1309,7 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"app": {
|
"app": {
|
||||||
"name": "App",
|
"name": "App",
|
||||||
"description": "Intégre une application dans le tableau.",
|
"description": "Intègre une application dans le tableau.",
|
||||||
"option": {
|
"option": {
|
||||||
"appId": {
|
"appId": {
|
||||||
"label": "Choisir une application"
|
"label": "Choisir une application"
|
||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Autoriser la géolocalisation"
|
"label": "Autoriser la géolocalisation"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1634,7 +1637,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"smartHome-entityState": {
|
"smartHome-entityState": {
|
||||||
"name": "Etat de l'entité",
|
"name": "État de l'entité",
|
||||||
"description": "Affichez l'état d'une entité et optionnellement activez la",
|
"description": "Affichez l'état d'une entité et optionnellement activez la",
|
||||||
"option": {
|
"option": {
|
||||||
"entityId": {
|
"entityId": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Afficher les infos de la mémoire"
|
"label": "Afficher les infos de la mémoire"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Afficher le temps de disponibilité"
|
"label": "Afficher le temps de disponibilité"
|
||||||
},
|
},
|
||||||
@@ -1877,16 +1883,16 @@
|
|||||||
"popover": {
|
"popover": {
|
||||||
"information": "Information",
|
"information": "Information",
|
||||||
"processor": "Processeur : {cpuModelName}",
|
"processor": "Processeur : {cpuModelName}",
|
||||||
"memory": "Mémoire: {memory}GiB",
|
"memory": "Mémoire : {memory}GiB",
|
||||||
"memoryAvailable": "Disponible: {memoryAvailable}GiB ({percent}%)",
|
"memoryAvailable": "Disponible : {memoryAvailable}GiB ({percent}%)",
|
||||||
"version": "Version : {version}",
|
"version": "Version : {version}",
|
||||||
"uptime": "Disponibilité: {months} Mois, {days} Jours, {hours} Heures, {minutes} Minutes",
|
"uptime": "Disponibilité : {months} Mois, {days} Jours, {hours} Heures, {minutes} Minutes",
|
||||||
"loadAverage": "Charge moyenne:",
|
"loadAverage": "Charge moyenne :",
|
||||||
"minute": "1 minute",
|
"minute": "1 minute",
|
||||||
"minutes": "{count} minutes",
|
"minutes": "{count} minutes",
|
||||||
"used": "Utilisé ",
|
"used": "Utilisé ",
|
||||||
"available": "Disponible",
|
"available": "Disponible",
|
||||||
"lastSeen": "Dernière mise à jour de statut: {lastSeen}"
|
"lastSeen": "Dernière mise à jour de statut : {lastSeen}"
|
||||||
},
|
},
|
||||||
"memory": {},
|
"memory": {},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1922,7 +1928,7 @@
|
|||||||
"memory": "Mémoire",
|
"memory": "Mémoire",
|
||||||
"storage": "Stockage",
|
"storage": "Stockage",
|
||||||
"uptime": "Disponibilité",
|
"uptime": "Disponibilité",
|
||||||
"haState": "Etat HA",
|
"haState": "État HA",
|
||||||
"storageType": {
|
"storageType": {
|
||||||
"local": "Stockage local",
|
"local": "Stockage local",
|
||||||
"shared": "Stockage partagé"
|
"shared": "Stockage partagé"
|
||||||
@@ -2056,7 +2062,7 @@
|
|||||||
"query": "Ville / Code Postal",
|
"query": "Ville / Code Postal",
|
||||||
"latitude": "Latitude",
|
"latitude": "Latitude",
|
||||||
"longitude": "Longitude",
|
"longitude": "Longitude",
|
||||||
"disabledTooltip": "Veuillez saisir une ville ou un code postal.",
|
"disabledTooltip": "Veuillez saisir une ville ou un code postal",
|
||||||
"unknownLocation": "Lieu inconnu",
|
"unknownLocation": "Lieu inconnu",
|
||||||
"search": "Rechercher",
|
"search": "Rechercher",
|
||||||
"table": {
|
"table": {
|
||||||
@@ -2075,7 +2081,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"integration": {
|
"integration": {
|
||||||
"noData": "Aucune intégration trouvée.",
|
"noData": "Aucune intégration trouvée",
|
||||||
"description": "Cliquez sur <here></here> pour créer une nouvelle intégration"
|
"description": "Cliquez sur <here></here> pour créer une nouvelle intégration"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
@@ -2091,7 +2097,7 @@
|
|||||||
},
|
},
|
||||||
"video": {
|
"video": {
|
||||||
"name": "Flux vidéo",
|
"name": "Flux vidéo",
|
||||||
"description": "Intégre un flux vidéo ou une vidéo provenant d'une caméra ou d'un site web",
|
"description": "Intègre un flux vidéo ou une vidéo provenant d'une caméra ou d'un site web",
|
||||||
"option": {
|
"option": {
|
||||||
"feedUrl": {
|
"feedUrl": {
|
||||||
"label": "URL du flux"
|
"label": "URL du flux"
|
||||||
@@ -2104,7 +2110,7 @@
|
|||||||
"label": "Muet"
|
"label": "Muet"
|
||||||
},
|
},
|
||||||
"hasControls": {
|
"hasControls": {
|
||||||
"label": "Afficher les controles"
|
"label": "Afficher les contrôles"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -2330,7 +2336,7 @@
|
|||||||
"pause": "Mettre en pause l'élément",
|
"pause": "Mettre en pause l'élément",
|
||||||
"resume": "Reprendre l'élément",
|
"resume": "Reprendre l'élément",
|
||||||
"delete": {
|
"delete": {
|
||||||
"title": "Supprimer l'élement",
|
"title": "Supprimer l'élément",
|
||||||
"modalTitle": "Êtes-vous sûr de vouloir supprimer cette tâche ?",
|
"modalTitle": "Êtes-vous sûr de vouloir supprimer cette tâche ?",
|
||||||
"entry": "Supprimer l'entrée",
|
"entry": "Supprimer l'entrée",
|
||||||
"entryAndFiles": "Supprimer l'entrée et le(s) fichier(s)"
|
"entryAndFiles": "Supprimer l'entrée et le(s) fichier(s)"
|
||||||
@@ -2542,7 +2548,7 @@
|
|||||||
"allImagesAlreadyImported": "Toutes les images déjà importées",
|
"allImagesAlreadyImported": "Toutes les images déjà importées",
|
||||||
"onlyAdminCanImport": "Seuls les administrateurs peuvent importer depuis docker",
|
"onlyAdminCanImport": "Seuls les administrateurs peuvent importer depuis docker",
|
||||||
"selectAll": "Tout sélectionner",
|
"selectAll": "Tout sélectionner",
|
||||||
"deselectAll": "Tout déselectionner"
|
"deselectAll": "Tout désélectionner"
|
||||||
},
|
},
|
||||||
"provider": {
|
"provider": {
|
||||||
"label": "Fournisseur"
|
"label": "Fournisseur"
|
||||||
@@ -2667,7 +2673,7 @@
|
|||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"integrationsDisconnected": "Aucune donnée disponible, toutes les intégrations sont déconnectées",
|
"integrationsDisconnected": "Aucune donnée disponible, toutes les intégrations sont déconnectées",
|
||||||
"unknownContentOption": "Option de contenu inconnue pour le widget d'état du réseau: "
|
"unknownContentOption": "Option de contenu inconnue pour le widget d'état du réseau : "
|
||||||
},
|
},
|
||||||
"name": "État du réseau",
|
"name": "État du réseau",
|
||||||
"description": "Afficher les périphériques connectés sur un réseau"
|
"description": "Afficher les périphériques connectés sur un réseau"
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Mémoire",
|
"memory": "Mémoire",
|
||||||
|
"gpu": "",
|
||||||
"network": "Réseau"
|
"network": "Réseau"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "RAM",
|
"memory": "RAM",
|
||||||
|
"gpu": "",
|
||||||
"network": "NET",
|
"network": "NET",
|
||||||
"up": "UP",
|
"up": "UP",
|
||||||
"down": "HORS SERVICE"
|
"down": "HORS SERVICE"
|
||||||
@@ -2757,7 +2765,7 @@
|
|||||||
"label": "Mode d'affichage",
|
"label": "Mode d'affichage",
|
||||||
"option": {
|
"option": {
|
||||||
"percentage": {
|
"percentage": {
|
||||||
"label": "Pourcentage (ex : 70%)"
|
"label": "Pourcentage (ex : 76%)"
|
||||||
},
|
},
|
||||||
"absolute": {
|
"absolute": {
|
||||||
"label": "Valeurs absolues (ex. : 800 Go / 1 To)"
|
"label": "Valeurs absolues (ex. : 800 Go / 1 To)"
|
||||||
@@ -2965,7 +2973,7 @@
|
|||||||
},
|
},
|
||||||
"customCss": {
|
"customCss": {
|
||||||
"label": "CSS personnalisé pour ce tableau",
|
"label": "CSS personnalisé pour ce tableau",
|
||||||
"description": "En outre, vous pouvez personnaliser votre tableau de bord à l'aide de CSS. Réservé aux utilisateurs expérimentés.",
|
"description": "De plus, personnalisez votre tableau de bord à l'aide de CSS, recommandé uniquement pour les utilisateurs expérimentés",
|
||||||
"customClassesAlert": {
|
"customClassesAlert": {
|
||||||
"title": "Classes personnalisées",
|
"title": "Classes personnalisées",
|
||||||
"description": "Vous pouvez ajouter des classes personnalisées aux éléments de votre tableau dans les options avancées de chaque élément et les utiliser dans le CSS personnalisé ci-dessus."
|
"description": "Vous pouvez ajouter des classes personnalisées aux éléments de votre tableau dans les options avancées de chaque élément et les utiliser dans le CSS personnalisé ci-dessus."
|
||||||
@@ -3243,7 +3251,7 @@
|
|||||||
"label": "Supprimer définitivement",
|
"label": "Supprimer définitivement",
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"title": "Supprimer le tableau de bord",
|
"title": "Supprimer le tableau de bord",
|
||||||
"description": "Êtes-vous sûr de vouloir supprimer le tableau {name}?"
|
"description": "Êtes-vous sûr de vouloir supprimer le tableau {name} ?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "אפשר מיקום גיאוגרפי"
|
"label": "אפשר מיקום גיאוגרפי"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "הצג מידע זיכרון"
|
"label": "הצג מידע זיכרון"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "הצג זמן פעולה"
|
"label": "הצג זמן פעולה"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "מעבד",
|
"cpu": "מעבד",
|
||||||
"memory": "זיכרון",
|
"memory": "זיכרון",
|
||||||
|
"gpu": "",
|
||||||
"network": "רשת"
|
"network": "רשת"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "מעבד",
|
"cpu": "מעבד",
|
||||||
"memory": "זיכרון",
|
"memory": "זיכרון",
|
||||||
|
"gpu": "",
|
||||||
"network": "רשת",
|
"network": "רשת",
|
||||||
"up": "העלאה",
|
"up": "העלאה",
|
||||||
"down": "הורדה"
|
"down": "הורדה"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Dopusti geolociranje"
|
"label": "Dopusti geolociranje"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"title": "Import token megadása",
|
"title": "Import token megadása",
|
||||||
"field": {
|
"field": {
|
||||||
"token": {
|
"token": {
|
||||||
"label": "",
|
"label": "Token",
|
||||||
"description": "Írja be a megjelenített import tokent az előző homarr példányból"
|
"description": "Írja be a megjelenített import tokent az előző homarr példányból"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -153,10 +153,10 @@
|
|||||||
"label": "Ikonok használata a pingekhez"
|
"label": "Ikonok használata a pingekhez"
|
||||||
},
|
},
|
||||||
"defaultSearchEngine": {
|
"defaultSearchEngine": {
|
||||||
"label": ""
|
"label": "Alapértelmezett kereső"
|
||||||
},
|
},
|
||||||
"openSearchInNewTab": {
|
"openSearchInNewTab": {
|
||||||
"label": ""
|
"label": "Nyissa meg a keresési eredményeket új ablakban"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -219,10 +219,10 @@
|
|||||||
"changeSearchPreferences": {
|
"changeSearchPreferences": {
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"message": ""
|
"message": "A keresési beállítások sikeresen megváltoztak"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"message": ""
|
"message": "A keresési beállításokat nem sikerült megváltoztatni"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -307,12 +307,12 @@
|
|||||||
"name": "Név",
|
"name": "Név",
|
||||||
"members": "Tagok",
|
"members": "Tagok",
|
||||||
"homeBoard": {
|
"homeBoard": {
|
||||||
"label": "",
|
"label": "Főoldal",
|
||||||
"description": ""
|
"description": "Csak a csoport számára elérhető oldalak választhatók ki"
|
||||||
},
|
},
|
||||||
"mobileBoard": {
|
"mobileBoard": {
|
||||||
"label": "",
|
"label": "Mobiloldal",
|
||||||
"description": ""
|
"description": "Csak a csoport számára elérhető oldalak választhatók ki"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permission": {
|
"permission": {
|
||||||
@@ -514,12 +514,12 @@
|
|||||||
"board": {
|
"board": {
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"title": "",
|
"title": "Beállítások elmentve",
|
||||||
"message": ""
|
"message": "Oldal beállítások sikeresen elmentve"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"title": "",
|
"title": "Nem sikerült menteni a beállításokat",
|
||||||
"message": ""
|
"message": "Az oldalbeállítások nem menthetők"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,21 +527,21 @@
|
|||||||
"changePosition": {
|
"changePosition": {
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"message": ""
|
"message": "Pozíció sikeresen megváltozott"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"message": ""
|
"message": "Pozíció nem módosítható"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultGroup": {
|
"defaultGroup": {
|
||||||
"name": "",
|
"name": "Alapértelmezett csoport",
|
||||||
"description": ""
|
"description": "{name} - Minden bejelentkezett felhasználó"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"search": "",
|
"search": "Alkalmazás megtalálása",
|
||||||
"page": {
|
"page": {
|
||||||
"list": {
|
"list": {
|
||||||
"title": "Alkalmazások",
|
"title": "Alkalmazások",
|
||||||
@@ -599,12 +599,12 @@
|
|||||||
"label": "Leírás"
|
"label": "Leírás"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"label": ""
|
"label": "Url"
|
||||||
},
|
},
|
||||||
"useDifferentUrlForPing": {
|
"useDifferentUrlForPing": {
|
||||||
"checkbox": {
|
"checkbox": {
|
||||||
"label": "",
|
"label": "Más URL használata a ping-hez",
|
||||||
"description": ""
|
"description": "Hasznos, ha a Homarr közvetlenül, egy belső hosztnév vagy hálózaton keresztül fér hozzá, hogy elkerülje az internetszolgáltató által használt sávszélesség terhelését"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -612,17 +612,17 @@
|
|||||||
"select": {
|
"select": {
|
||||||
"label": "Alkalmazás kiválasztása",
|
"label": "Alkalmazás kiválasztása",
|
||||||
"notFound": "Nem található alkalmazás",
|
"notFound": "Nem található alkalmazás",
|
||||||
"search": "",
|
"search": "Alkalmazás keresése",
|
||||||
"noResults": "",
|
"noResults": "Nincs találat",
|
||||||
"action": "",
|
"action": "Kiválasztás {app}",
|
||||||
"title": ""
|
"title": "Válassz egy programot az oldalhoz adáshoz"
|
||||||
},
|
},
|
||||||
"create": {
|
"create": {
|
||||||
"title": "",
|
"title": "Új alkalmazás készítése",
|
||||||
"description": "",
|
"description": "Új alkalmazás létrehozása ",
|
||||||
"action": ""
|
"action": "Alkalmazás készítő megnyitása"
|
||||||
},
|
},
|
||||||
"add": ""
|
"add": "Alkalmazás hozzáadása"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"integration": {
|
"integration": {
|
||||||
@@ -649,14 +649,14 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"option": {
|
"option": {
|
||||||
"existing": {
|
"existing": {
|
||||||
"title": "",
|
"title": "Meglévő",
|
||||||
"label": ""
|
"label": "Meglévő alkalmazás kiválasztása"
|
||||||
},
|
},
|
||||||
"new": {
|
"new": {
|
||||||
"title": "",
|
"title": "Új",
|
||||||
"url": {
|
"url": {
|
||||||
"label": "",
|
"label": "Alkalmazás url",
|
||||||
"description": ""
|
"description": "Az url, amelyre az alkalmazás a műszerfalról történő eléréskor irányít"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,9 +676,9 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"action": {
|
"action": {
|
||||||
"add": "",
|
"add": "Alkalmazás megtalálása",
|
||||||
"remove": "",
|
"remove": "Leválasztás",
|
||||||
"select": ""
|
"select": "Válasszon ki egy alkalmazást a hivatkozáshoz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -702,21 +702,21 @@
|
|||||||
"label": "Név"
|
"label": "Név"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"label": ""
|
"label": "Url"
|
||||||
},
|
},
|
||||||
"attemptSearchEngineCreation": {
|
"attemptSearchEngineCreation": {
|
||||||
"label": "",
|
"label": "Keresőmotor létrehozása",
|
||||||
"description": ""
|
"description": "A \"{kind}\" integráció használható a keresőmotorokkal. Jelölje be ezt a jelölőnégyzetet, ha automatikusan szeretné konfigurálni a keresőmotort."
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"sectionTitle": ""
|
"sectionTitle": "Hivattkozott alkalmazás"
|
||||||
},
|
},
|
||||||
"createApp": {
|
"createApp": {
|
||||||
"label": "",
|
"label": "Alkalmazás létrehozása",
|
||||||
"description": ""
|
"description": "Hozzon létre egy alkalmazást, amelynek ugyanaz a neve és ikonja van, mint az integrációnak. Hagyja üresen az alábbi beviteli mezőt, hogy az alkalmazás az integrációs URL-lel jöjjön létre."
|
||||||
},
|
},
|
||||||
"appHref": {
|
"appHref": {
|
||||||
"placeholder": ""
|
"placeholder": "Egyéni alkalmazás URL"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
@@ -730,59 +730,59 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"common": {
|
"common": {
|
||||||
"cause": {
|
"cause": {
|
||||||
"title": ""
|
"title": "Részletesebb leírás a problémáról"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unknown": {
|
"unknown": {
|
||||||
"title": "",
|
"title": "Ismeretlen hiba",
|
||||||
"description": ""
|
"description": "Egy ismeretlen hiba történt, nyissa meg a részleteket alul, hogy többet megtudjon"
|
||||||
},
|
},
|
||||||
"parse": {
|
"parse": {
|
||||||
"title": "",
|
"title": "Elemzési hiba",
|
||||||
"description": ""
|
"description": "A válasz nem volt elemezhető. Kérjük, ellenőrizze, hogy az URL a szolgáltatás alap URL-jére mutat-e."
|
||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"title": "",
|
"title": "Hitelesítési hiba",
|
||||||
"description": ""
|
"description": "A kérés nem volt engedélyezett. Kérjük, ellenőrizze, hogy a hitelesítő adatok helyesek-e, és hogy a megfelelő engedélyekkel vannak-e beállítva."
|
||||||
},
|
},
|
||||||
"statusCode": {
|
"statusCode": {
|
||||||
"title": "",
|
"title": "Válaszhiba",
|
||||||
"description": "",
|
"description": "Váratlan {statusCode} ({reason}) választ kapott a <url></url> címen. Kérjük, ellenőrizze, hogy az URL az integráció alap URL-jére mutat-e.",
|
||||||
"otherDescription": "",
|
"otherDescription": "Váratlan {statusCode} választ kapott a <url></url> címen. Kérjük, ellenőrizze, hogy az URL az integráció alap URL-jére mutat-e.",
|
||||||
"reason": {
|
"reason": {
|
||||||
"badRequest": "",
|
"badRequest": "Hibás kérés",
|
||||||
"notFound": "",
|
"notFound": "Nem található",
|
||||||
"tooManyRequests": "",
|
"tooManyRequests": "Túl sok kérés",
|
||||||
"internalServerError": "",
|
"internalServerError": "Belső szerverhiba",
|
||||||
"serviceUnavailable": "",
|
"serviceUnavailable": "A szolgáltatás nem elérhető",
|
||||||
"gatewayTimeout": ""
|
"gatewayTimeout": "Átjáró időtúllépés"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"certificate": {
|
"certificate": {
|
||||||
"title": "",
|
"title": "Tanúsítványhiba",
|
||||||
"description": {
|
"description": {
|
||||||
"expired": "",
|
"expired": "A tanúsítvány lejárt.",
|
||||||
"notYetValid": "",
|
"notYetValid": "A tanúsítvány még nem érvényes.",
|
||||||
"untrusted": "",
|
"untrusted": "A tanúsítvány nem megbízható.",
|
||||||
"hostnameMismatch": ""
|
"hostnameMismatch": "A tanúsítványban szereplő hosztnév nem egyezik meg az URL-lel."
|
||||||
},
|
},
|
||||||
"alert": {
|
"alert": {
|
||||||
"permission": {
|
"permission": {
|
||||||
"title": "",
|
"title": "Nincsenek megfelelő engedélyek",
|
||||||
"message": ""
|
"message": "Önnek nincs joga tanúsítványokat megbízhatónak nyilvánítani vagy feltölteni. Kérjük, lépjen kapcsolatba a rendszergazdájával, hogy feltölthesse a szükséges gyökér tanúsítványt."
|
||||||
},
|
},
|
||||||
"hostnameMismatch": {
|
"hostnameMismatch": {
|
||||||
"title": "",
|
"title": "Állomásnév eltérés",
|
||||||
"message": ""
|
"message": "A tanúsítványban szereplő hosztnév nem egyezik meg azzal a hosztnévvel, amelyhez kapcsolódik. Ez biztonsági kockázatot jelezhet, de mégis dönthet úgy, hogy megbízik ebben a tanúsítványban."
|
||||||
},
|
},
|
||||||
"extract": {
|
"extract": {
|
||||||
"title": "",
|
"title": "A tanúsító hatóság (CA) tanúsítványának kinyerése sikertelen",
|
||||||
"message": ""
|
"message": "Csak a lánc nélküli, önaláírt tanúsítványok tölthetők le automatikusan. Ha önaláírt tanúsítványt használ, kérjük, feltétlenül töltse fel manuálisan a tanúsító hatóság (CA) tanúsítványát. Az ehhez szükséges lépések leírását itt találja: <docsLink></docsLink>."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"retry": {
|
"retry": {
|
||||||
"label": ""
|
"label": "Újrapróbál"
|
||||||
},
|
},
|
||||||
"trust": {
|
"trust": {
|
||||||
"label": ""
|
"label": ""
|
||||||
@@ -920,8 +920,8 @@
|
|||||||
"message": "Az útvonal valószínűleg nem helyes"
|
"message": "Az útvonal valószínűleg nem helyes"
|
||||||
},
|
},
|
||||||
"tooManyRequests": {
|
"tooManyRequests": {
|
||||||
"title": "",
|
"title": "Túl sok kérés adott idő alatt",
|
||||||
"message": ""
|
"message": "Túl sok kérést küldött. Valószínűleg a célrendszer korlátozza vagy elutasítja a kéréseket"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -955,36 +955,36 @@
|
|||||||
"newLabel": "Új jelszó"
|
"newLabel": "Új jelszó"
|
||||||
},
|
},
|
||||||
"tokenId": {
|
"tokenId": {
|
||||||
"label": "",
|
"label": "Token azonosító",
|
||||||
"newLabel": ""
|
"newLabel": "Új token azonosító"
|
||||||
},
|
},
|
||||||
"realm": {
|
"realm": {
|
||||||
"label": "",
|
"label": "Tartomány",
|
||||||
"newLabel": ""
|
"newLabel": "Új tartomány"
|
||||||
},
|
},
|
||||||
"personalAccessToken": {
|
"personalAccessToken": {
|
||||||
"label": "",
|
"label": "Személyes Hozzáférési Token",
|
||||||
"newLabel": ""
|
"newLabel": "Új Személyes Hozzáférési Token"
|
||||||
},
|
},
|
||||||
"topic": {
|
"topic": {
|
||||||
"label": "",
|
"label": "Téma",
|
||||||
"newLabel": ""
|
"newLabel": "Új téma"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"label": "",
|
"label": "Url",
|
||||||
"newLabel": ""
|
"newLabel": "Új url"
|
||||||
},
|
},
|
||||||
"opnsenseApiKey": {
|
"opnsenseApiKey": {
|
||||||
"label": "",
|
"label": "API kulcs (Kulcs)",
|
||||||
"newLabel": ""
|
"newLabel": "Új API Kulcs (Kulcs)"
|
||||||
},
|
},
|
||||||
"opnsenseApiSecret": {
|
"opnsenseApiSecret": {
|
||||||
"label": "",
|
"label": "Api Kulcs (Titkos)",
|
||||||
"newLabel": ""
|
"newLabel": "Új API Kulcs (Titkos)"
|
||||||
},
|
},
|
||||||
"githubAppId": {
|
"githubAppId": {
|
||||||
"label": "",
|
"label": "App Azonosító",
|
||||||
"newLabel": ""
|
"newLabel": "Új App Azonosító"
|
||||||
},
|
},
|
||||||
"githubInstallationId": {
|
"githubInstallationId": {
|
||||||
"label": "",
|
"label": "",
|
||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Geolokáció engedélyezése"
|
"label": "Geolokáció engedélyezése"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Memóriainformációk megjelenítése"
|
"label": "Memóriainformációk megjelenítése"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Consenti geo-localizzazione"
|
"label": "Consenti geo-localizzazione"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": "Consenti modali"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Mostra Informazioni Memoria"
|
"label": "Mostra Informazioni Memoria"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": "Mostra informazioni sulla GPU"
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Mostra Uptime"
|
"label": "Mostra Uptime"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Memoria",
|
"memory": "Memoria",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "Rete"
|
"network": "Rete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "NET",
|
"network": "NET",
|
||||||
"up": "SU",
|
"up": "SU",
|
||||||
"down": "DOWN"
|
"down": "DOWN"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "位置情報を許可する"
|
"label": "位置情報を許可する"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "メモリー情報を表示"
|
"label": "メモリー情報を表示"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "稼働時間を表示"
|
"label": "稼働時間を表示"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "メモリ",
|
"memory": "メモリ",
|
||||||
|
"gpu": "",
|
||||||
"network": "ネットワーク"
|
"network": "ネットワーク"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "",
|
||||||
"network": "NET",
|
"network": "NET",
|
||||||
"up": "UP",
|
"up": "UP",
|
||||||
"down": "DOWN"
|
"down": "DOWN"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "지리적 위치 허용"
|
"label": "지리적 위치 허용"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Leisti nustatyti geografinę buvimo vietą"
|
"label": "Leisti nustatyti geografinę buvimo vietą"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Atļaut ģeogrāfiskās atrašanās vietas noteikšanu"
|
"label": "Atļaut ģeogrāfiskās atrašanās vietas noteikšanu"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Rādīt atmiņas informāciju"
|
"label": "Rādīt atmiņas informāciju"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Geolocatie toestaan"
|
"label": "Geolocatie toestaan"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Werkgeheugen info weergeven"
|
"label": "Werkgeheugen info weergeven"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Uptime weergeven"
|
"label": "Uptime weergeven"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "Processor",
|
"cpu": "Processor",
|
||||||
"memory": "Geheugen",
|
"memory": "Geheugen",
|
||||||
|
"gpu": "",
|
||||||
"network": "Netwerk"
|
"network": "Netwerk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "",
|
||||||
"network": "NET",
|
"network": "NET",
|
||||||
"up": "OMHOOG",
|
"up": "OMHOOG",
|
||||||
"down": "OMLAAG"
|
"down": "OMLAAG"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Tillat geolokalisering"
|
"label": "Tillat geolokalisering"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Vis minneinfo"
|
"label": "Vis minneinfo"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Vis oppetid"
|
"label": "Vis oppetid"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Minne",
|
"memory": "Minne",
|
||||||
|
"gpu": "",
|
||||||
"network": "Nettverk"
|
"network": "Nettverk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Minne",
|
"memory": "Minne",
|
||||||
|
"gpu": "",
|
||||||
"network": "NETT",
|
"network": "NETT",
|
||||||
"up": "OPP",
|
"up": "OPP",
|
||||||
"down": "NED"
|
"down": "NED"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Zezwalaj na geolokalizację"
|
"label": "Zezwalaj na geolokalizację"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Pokaż informacje o pamięci"
|
"label": "Pokaż informacje o pamięci"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Pokaż czas pracy"
|
"label": "Pokaż czas pracy"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "Procesor",
|
"cpu": "Procesor",
|
||||||
"memory": "Pamięć",
|
"memory": "Pamięć",
|
||||||
|
"gpu": "",
|
||||||
"network": "Sieć"
|
"network": "Sieć"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "Procesor",
|
"cpu": "Procesor",
|
||||||
"memory": "Pamięć",
|
"memory": "Pamięć",
|
||||||
|
"gpu": "",
|
||||||
"network": "Sieć",
|
"network": "Sieć",
|
||||||
"up": "Aktywny",
|
"up": "Aktywny",
|
||||||
"down": "Nieaktywny"
|
"down": "Nieaktywny"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Permitir geolocalização"
|
"label": "Permitir geolocalização"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": "Permitir modais"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Mostrar informações da memória"
|
"label": "Mostrar informações da memória"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": "Mostrar informações da GPU"
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Exibir tempo de atividade"
|
"label": "Exibir tempo de atividade"
|
||||||
},
|
},
|
||||||
@@ -1997,58 +2003,58 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tracearr": {
|
"tracearr": {
|
||||||
"name": "",
|
"name": "Tracearr",
|
||||||
"description": "",
|
"description": "Monitoramento avançado de servidor de mídia com dados detalhados de transmissão e transcodificação\n",
|
||||||
"option": {
|
"option": {
|
||||||
"showStreams": {
|
"showStreams": {
|
||||||
"label": ""
|
"label": "Exibir transmissões ativas"
|
||||||
},
|
},
|
||||||
"showStats": {
|
"showStats": {
|
||||||
"label": ""
|
"label": "Exibir resumo de estatísticas"
|
||||||
},
|
},
|
||||||
"showRecentActivity": {
|
"showRecentActivity": {
|
||||||
"label": ""
|
"label": "Exibir Atividade Recente"
|
||||||
},
|
},
|
||||||
"showViolations": {
|
"showViolations": {
|
||||||
"label": ""
|
"label": "Mostrar Violações"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"stats": {
|
"stats": {
|
||||||
"activeStreams": "",
|
"activeStreams": "Streams Ativas",
|
||||||
"totalUsers": "",
|
"totalUsers": "Total de usuários",
|
||||||
"transcodes": "",
|
"transcodes": "Transcodificações",
|
||||||
"bandwidth": ""
|
"bandwidth": "Largura da banda"
|
||||||
},
|
},
|
||||||
"streams": {
|
"streams": {
|
||||||
"empty": "",
|
"empty": "Sem transmissões ativas",
|
||||||
"user": "",
|
"user": "Usuário",
|
||||||
"media": "",
|
"media": "Mídia",
|
||||||
"state": "",
|
"state": "Estado",
|
||||||
"quality": "",
|
"quality": "Qualidade",
|
||||||
"device": "",
|
"device": "Dispositivo",
|
||||||
"progress": "",
|
"progress": "Progresso",
|
||||||
"videoDecision": {
|
"videoDecision": {
|
||||||
"directPlay": "",
|
"directPlay": "Reprodução direta",
|
||||||
"transcode": "",
|
"transcode": "Transcodificação",
|
||||||
"directStream": ""
|
"directStream": "Transmissão direta"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"recentActivity": {
|
"recentActivity": {
|
||||||
"title": "",
|
"title": "Atividade recente",
|
||||||
"empty": "",
|
"empty": "Nenhuma atividade recente",
|
||||||
"watched": "",
|
"watched": "Assistido",
|
||||||
"partial": ""
|
"partial": "Parcial"
|
||||||
},
|
},
|
||||||
"violations": {
|
"violations": {
|
||||||
"title": "",
|
"title": "Violações",
|
||||||
"empty": "",
|
"empty": "Não há violações recentes",
|
||||||
"rule": "",
|
"rule": "Regra",
|
||||||
"user": ""
|
"user": "Usuário"
|
||||||
},
|
},
|
||||||
"noSectionsEnabled": "",
|
"noSectionsEnabled": "Nenhuma seção habilitada",
|
||||||
"error": {
|
"error": {
|
||||||
"noIntegration": "",
|
"noIntegration": "Nenhuma integração Coolify configurada",
|
||||||
"internalServerError": ""
|
"internalServerError": "Falha ao buscar dados do Tracearr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
@@ -2147,50 +2153,50 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"immich-serverStats": {
|
"immich-serverStats": {
|
||||||
"name": "",
|
"name": "Estatísticas do Servidor Immich",
|
||||||
"description": "",
|
"description": "Informações sobre sua instância do Immich",
|
||||||
"option": {
|
"option": {
|
||||||
"showUsers": {
|
"showUsers": {
|
||||||
"label": "",
|
"label": "Mostrar usuários",
|
||||||
"description": ""
|
"description": "Mostrar a contagem de usuários na sua instância"
|
||||||
},
|
},
|
||||||
"showPhotos": {
|
"showPhotos": {
|
||||||
"label": "",
|
"label": "Mostrar Fotos",
|
||||||
"description": ""
|
"description": "Mostrar a contagem de fotos na sua instância"
|
||||||
},
|
},
|
||||||
"showVideos": {
|
"showVideos": {
|
||||||
"label": "",
|
"label": "Mostrar vídeos",
|
||||||
"description": ""
|
"description": "Mostrar contagem de vídeos na sua instância"
|
||||||
},
|
},
|
||||||
"showStorage": {
|
"showStorage": {
|
||||||
"label": "",
|
"label": "Mostrar armazenamento",
|
||||||
"description": ""
|
"description": "Mostrar a quantidade total de armazenamento utilizado"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"users": "",
|
"users": "Usuários",
|
||||||
"photos": "",
|
"photos": "Fotos",
|
||||||
"videos": "",
|
"videos": "Vídeos",
|
||||||
"storage": ""
|
"storage": "Armazenamento Utilizado"
|
||||||
},
|
},
|
||||||
"immich-albumCarousel": {
|
"immich-albumCarousel": {
|
||||||
"name": "",
|
"name": "Álbum do Immich",
|
||||||
"option": {
|
"option": {
|
||||||
"albumId": {
|
"albumId": {
|
||||||
"label": "",
|
"label": "ID do Álbum",
|
||||||
"description": ""
|
"description": "Esta é uma identificação única que se refere ao seu álbum Immich. Você pode encontrar essa identificação abrindo um álbum e copiando a string única da URL, por exemplo 'a21aca09-9f05-47dc-b1a1-7b53c547226e'"
|
||||||
},
|
},
|
||||||
"rotationIntervalSeconds": {
|
"rotationIntervalSeconds": {
|
||||||
"label": "",
|
"label": "Intervalo em segundos",
|
||||||
"description": ""
|
"description": "Girar entre as imagens no álbum a cada X segundos. Deve ser pelo menos 1. Deve estar abaixo de 3600."
|
||||||
},
|
},
|
||||||
"showPhotoInfo": {
|
"showPhotoInfo": {
|
||||||
"label": "",
|
"label": "Mostrar informações da foto",
|
||||||
"description": ""
|
"description": "Exibir a data da imagem e o índice atual na parte inferior da apresentação"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "",
|
"description": "Apresentação de imagens em seu álbum Imich",
|
||||||
"noAlbumSelected": "",
|
"noAlbumSelected": "Nenhum álbum selecionado, edite o widget e escolha um álbum",
|
||||||
"noPhotos": ""
|
"noPhotos": "Nenhuma foto neste álbum"
|
||||||
},
|
},
|
||||||
"downloads": {
|
"downloads": {
|
||||||
"name": "Cliente de Download",
|
"name": "Cliente de Download",
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "Memória",
|
"memory": "Memória",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "Rede"
|
"network": "Rede"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "CPU",
|
"cpu": "CPU",
|
||||||
"memory": "MEM",
|
"memory": "MEM",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "REDE",
|
"network": "REDE",
|
||||||
"up": "ENVIO",
|
"up": "ENVIO",
|
||||||
"down": "RECEBIDO"
|
"down": "RECEBIDO"
|
||||||
@@ -3575,7 +3583,7 @@
|
|||||||
"label": "Clima"
|
"label": "Clima"
|
||||||
},
|
},
|
||||||
"tracearr": {
|
"tracearr": {
|
||||||
"label": ""
|
"label": "Tracearr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"interval": {
|
"interval": {
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Permiteți geolocalizarea"
|
"label": "Permiteți geolocalizarea"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Afișare informații memorie"
|
"label": "Afișare informații memorie"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Разрешить геолокацию"
|
"label": "Разрешить геолокацию"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": "Разрешить модальные окна"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Показать информацию о памяти"
|
"label": "Показать информацию о памяти"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": "Показать информацию о GPU"
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Показывать время работы"
|
"label": "Показывать время работы"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "ЦП",
|
"cpu": "ЦП",
|
||||||
"memory": "Память",
|
"memory": "Память",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "Сеть"
|
"network": "Сеть"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "ЦП",
|
"cpu": "ЦП",
|
||||||
"memory": "ОЗУ",
|
"memory": "ОЗУ",
|
||||||
|
"gpu": "GPU",
|
||||||
"network": "Сеть",
|
"network": "Сеть",
|
||||||
"up": "Исх.",
|
"up": "Исх.",
|
||||||
"down": "Вх."
|
"down": "Вх."
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Povolenie geografickej lokalizácie"
|
"label": "Povolenie geografickej lokalizácie"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Zobraziť informácie o pamäti"
|
"label": "Zobraziť informácie o pamäti"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Zobraziť Uptime"
|
"label": "Zobraziť Uptime"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Omogočanje zemljepisne lokacije"
|
"label": "Omogočanje zemljepisne lokacije"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Tillåt geografisk lokalisering"
|
"label": "Tillåt geografisk lokalisering"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Visa minnesinformation"
|
"label": "Visa minnesinformation"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Coğrafi konuma izin ver (geolocation)"
|
"label": "Coğrafi konuma izin ver (geolocation)"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Bellek Bilgilerini Göster"
|
"label": "Bellek Bilgilerini Göster"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": "Çalışma Süresini Göster"
|
"label": "Çalışma Süresini Göster"
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "İşlemci",
|
"cpu": "İşlemci",
|
||||||
"memory": "Bellek",
|
"memory": "Bellek",
|
||||||
|
"gpu": "",
|
||||||
"network": "Ağ"
|
"network": "Ağ"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "İşlemci",
|
"cpu": "İşlemci",
|
||||||
"memory": "BELLEK",
|
"memory": "BELLEK",
|
||||||
|
"gpu": "",
|
||||||
"network": "AĞ",
|
"network": "AĞ",
|
||||||
"up": "YÜKLEME",
|
"up": "YÜKLEME",
|
||||||
"down": "İNDİRME"
|
"down": "İNDİRME"
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Дозволити геолокацію"
|
"label": "Дозволити геолокацію"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "Показати інформацію про пам'ять"
|
"label": "Показати інформацію про пам'ять"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "Cho phép định vị"
|
"label": "Cho phép định vị"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -1625,6 +1625,9 @@
|
|||||||
},
|
},
|
||||||
"allowGeolocation": {
|
"allowGeolocation": {
|
||||||
"label": "允許地址位置"
|
"label": "允許地址位置"
|
||||||
|
},
|
||||||
|
"allowModals": {
|
||||||
|
"label": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -1858,6 +1861,9 @@
|
|||||||
"memory": {
|
"memory": {
|
||||||
"label": "顯示記憶體訊息"
|
"label": "顯示記憶體訊息"
|
||||||
},
|
},
|
||||||
|
"gpu": {
|
||||||
|
"label": ""
|
||||||
|
},
|
||||||
"showUptime": {
|
"showUptime": {
|
||||||
"label": ""
|
"label": ""
|
||||||
},
|
},
|
||||||
@@ -2725,6 +2731,7 @@
|
|||||||
"option": {
|
"option": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": ""
|
"network": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2741,6 +2748,7 @@
|
|||||||
"card": {
|
"card": {
|
||||||
"cpu": "",
|
"cpu": "",
|
||||||
"memory": "",
|
"memory": "",
|
||||||
|
"gpu": "",
|
||||||
"network": "",
|
"network": "",
|
||||||
"up": "",
|
"up": "",
|
||||||
"down": ""
|
"down": ""
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"@mantine/dates": "^8.3.18",
|
"@mantine/dates": "^8.3.18",
|
||||||
"@mantine/hooks": "^8.3.18",
|
"@mantine/hooks": "^8.3.18",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.2.1",
|
"next": "16.2.1",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/definitions": "workspace:^0.1.0",
|
"@homarr/definitions": "workspace:^0.1.0",
|
||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"zod": "^4.2.1",
|
"zod": "^4.3.6",
|
||||||
"zod-form-data": "^3.0.1"
|
"zod-form-data": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -57,12 +57,13 @@ export const userBaseCreateSchema = z.object({
|
|||||||
password: userPasswordSchema,
|
password: userPasswordSchema,
|
||||||
confirmPassword: z.string(),
|
confirmPassword: z.string(),
|
||||||
email: z.string().email().or(z.string().length(0)).optional(),
|
email: z.string().email().or(z.string().length(0)).optional(),
|
||||||
groupIds: z.array(z.string()),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const userCreateSchema = addConfirmPasswordRefinement(userBaseCreateSchema);
|
export const userCreateSchema = addConfirmPasswordRefinement(userBaseCreateSchema).and(
|
||||||
|
z.object({ groupIds: z.array(z.string()) }),
|
||||||
|
);
|
||||||
|
|
||||||
export const userInitSchema = addConfirmPasswordRefinement(userBaseCreateSchema.omit({ groupIds: true }));
|
export const userInitSchema = addConfirmPasswordRefinement(userBaseCreateSchema);
|
||||||
|
|
||||||
export const userSignInSchema = z.object({
|
export const userSignInSchema = z.object({
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
@@ -111,12 +112,15 @@ const baseChangePasswordSchema = z.object({
|
|||||||
previousPassword: z.string().min(1),
|
previousPassword: z.string().min(1),
|
||||||
password: userPasswordSchema,
|
password: userPasswordSchema,
|
||||||
confirmPassword: z.string(),
|
confirmPassword: z.string(),
|
||||||
userId: z.string(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const userChangePasswordSchema = addConfirmPasswordRefinement(baseChangePasswordSchema.omit({ userId: true }));
|
export const userChangePasswordSchema = addConfirmPasswordRefinement(baseChangePasswordSchema);
|
||||||
|
|
||||||
export const userChangePasswordApiSchema = addConfirmPasswordRefinement(baseChangePasswordSchema);
|
export const userChangePasswordApiSchema = addConfirmPasswordRefinement(baseChangePasswordSchema).and(
|
||||||
|
z.object({
|
||||||
|
userId: z.string(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const userChangeHomeBoardsSchema = z.object({
|
export const userChangeHomeBoardsSchema = z.object({
|
||||||
homeBoardId: z.string().nullable(),
|
homeBoardId: z.string().nullable(),
|
||||||
|
|||||||
@@ -51,23 +51,23 @@
|
|||||||
"@mantine/charts": "^8.3.18",
|
"@mantine/charts": "^8.3.18",
|
||||||
"@mantine/core": "^8.3.18",
|
"@mantine/core": "^8.3.18",
|
||||||
"@mantine/hooks": "^8.3.18",
|
"@mantine/hooks": "^8.3.18",
|
||||||
"@tabler/icons-react": "^3.40.0",
|
"@tabler/icons-react": "^3.41.0",
|
||||||
"@tiptap/extension-color": "3.20.4",
|
"@tiptap/extension-color": "3.21.0",
|
||||||
"@tiptap/extension-highlight": "3.20.4",
|
"@tiptap/extension-highlight": "3.21.0",
|
||||||
"@tiptap/extension-image": "3.20.4",
|
"@tiptap/extension-image": "3.21.0",
|
||||||
"@tiptap/extension-link": "^3.20.4",
|
"@tiptap/extension-link": "^3.21.0",
|
||||||
"@tiptap/extension-placeholder": "^3.20.4",
|
"@tiptap/extension-placeholder": "^3.21.0",
|
||||||
"@tiptap/extension-table": "3.20.4",
|
"@tiptap/extension-table": "3.21.0",
|
||||||
"@tiptap/extension-table-cell": "3.20.4",
|
"@tiptap/extension-table-cell": "3.21.0",
|
||||||
"@tiptap/extension-table-header": "3.20.4",
|
"@tiptap/extension-table-header": "3.21.0",
|
||||||
"@tiptap/extension-table-row": "3.20.4",
|
"@tiptap/extension-table-row": "3.21.0",
|
||||||
"@tiptap/extension-task-item": "3.20.4",
|
"@tiptap/extension-task-item": "3.21.0",
|
||||||
"@tiptap/extension-task-list": "3.20.4",
|
"@tiptap/extension-task-list": "3.21.0",
|
||||||
"@tiptap/extension-text-align": "3.20.4",
|
"@tiptap/extension-text-align": "3.21.0",
|
||||||
"@tiptap/extension-text-style": "3.20.4",
|
"@tiptap/extension-text-style": "3.21.0",
|
||||||
"@tiptap/extension-underline": "3.20.4",
|
"@tiptap/extension-underline": "3.21.0",
|
||||||
"@tiptap/react": "^3.20.4",
|
"@tiptap/react": "^3.21.0",
|
||||||
"@tiptap/starter-kit": "^3.20.4",
|
"@tiptap/starter-kit": "^3.21.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.20",
|
"dayjs": "^1.11.20",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"video.js": "^8.23.7",
|
"video.js": "^8.23.7",
|
||||||
"zod": "^4.2.1"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { WidgetOptionType } from "../options";
|
import type { WidgetOptionType } from "../options";
|
||||||
import { WidgetAppInput } from "./widget-app-input";
|
import { WidgetAppInput } from "./widget-app-input";
|
||||||
|
import { WidgetDynamicSelectInput } from "./widget-dynamic-select-input";
|
||||||
import { WidgetLocationInput } from "./widget-location-input";
|
import { WidgetLocationInput } from "./widget-location-input";
|
||||||
import { WidgetMultiTextInput } from "./widget-multi-text-input";
|
import { WidgetMultiTextInput } from "./widget-multi-text-input";
|
||||||
import { WidgetMultiReleasesRepositoriesInput } from "./widget-multiReleasesRepositories-input";
|
import { WidgetMultiReleasesRepositoriesInput } from "./widget-multiReleasesRepositories-input";
|
||||||
@@ -23,6 +24,7 @@ const mapping = {
|
|||||||
app: WidgetAppInput,
|
app: WidgetAppInput,
|
||||||
sortableItemList: WidgetSortedItemListInput,
|
sortableItemList: WidgetSortedItemListInput,
|
||||||
multiReleasesRepositories: WidgetMultiReleasesRepositoriesInput,
|
multiReleasesRepositories: WidgetMultiReleasesRepositoriesInput,
|
||||||
|
dynamicSelect: WidgetDynamicSelectInput,
|
||||||
} satisfies Record<WidgetOptionType, unknown>;
|
} satisfies Record<WidgetOptionType, unknown>;
|
||||||
|
|
||||||
export const getInputForType = <TType extends WidgetOptionType>(type: TType) => {
|
export const getInputForType = <TType extends WidgetOptionType>(type: TType) => {
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Group, Loader, Select } from "@mantine/core";
|
||||||
|
import { useDebouncedValue } from "@mantine/hooks";
|
||||||
|
import { IconCheck } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
import { translateIfNecessary } from "@homarr/translation";
|
||||||
|
import { useI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
|
import type { CommonWidgetInputProps } from "./common";
|
||||||
|
import { useWidgetInputTranslation } from "./common";
|
||||||
|
import { useFormContext } from "./form";
|
||||||
|
|
||||||
|
export interface DynamicSelectOption {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WidgetDynamicSelectInput = ({ property, kind, options }: CommonWidgetInputProps<"dynamicSelect">) => {
|
||||||
|
const t = useI18n();
|
||||||
|
const tWidget = useWidgetInputTranslation(kind, property);
|
||||||
|
const form = useFormContext();
|
||||||
|
const inputProps = form.getInputProps(`options.${property}`);
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 300);
|
||||||
|
const { isPending, options: selectOptions } = options.useOptions(debouncedSearch, form.values.integrationIds);
|
||||||
|
const value = inputProps.value as DynamicSelectOption | null;
|
||||||
|
const onChange = inputProps.onChange as (value: DynamicSelectOption | null) => void;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label={tWidget("label")}
|
||||||
|
data={selectOptions
|
||||||
|
.map((option) =>
|
||||||
|
typeof option === "string"
|
||||||
|
? option
|
||||||
|
: {
|
||||||
|
value: option.value,
|
||||||
|
label: translateIfNecessary(t, option.label) ?? option.value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.concat(
|
||||||
|
typeof value === "object" &&
|
||||||
|
value !== null &&
|
||||||
|
!selectOptions.some((option) =>
|
||||||
|
typeof option === "string" ? option === value.value : option.value === value.value,
|
||||||
|
)
|
||||||
|
? {
|
||||||
|
value: value.value,
|
||||||
|
label: value.label,
|
||||||
|
}
|
||||||
|
: [],
|
||||||
|
)}
|
||||||
|
searchValue={search}
|
||||||
|
onSearchChange={setSearch}
|
||||||
|
leftSection={isPending && <Loader size="xs" />}
|
||||||
|
renderOption={({ option, checked }) => {
|
||||||
|
return (
|
||||||
|
<Group flex="1" gap="xs">
|
||||||
|
{option.label}
|
||||||
|
{checked && (
|
||||||
|
<IconCheck
|
||||||
|
style={{ marginInlineStart: "auto" }}
|
||||||
|
color="currentColor"
|
||||||
|
opacity={0.6}
|
||||||
|
size={18}
|
||||||
|
stroke={1.5}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
description={options.withDescription ? tWidget("description") : undefined}
|
||||||
|
searchable
|
||||||
|
{...inputProps}
|
||||||
|
value={value?.value ?? null}
|
||||||
|
onChange={(value) =>
|
||||||
|
onChange(
|
||||||
|
value
|
||||||
|
? {
|
||||||
|
value,
|
||||||
|
label:
|
||||||
|
selectOptions.filter((option) => typeof option === "object").find((option) => option.value === value)
|
||||||
|
?.label ?? value,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -42,6 +42,7 @@ import * as smartHomeExecuteAutomation from "./smart-home/execute-automation";
|
|||||||
import * as stockPrice from "./stocks";
|
import * as stockPrice from "./stocks";
|
||||||
import * as systemDisks from "./system-disks";
|
import * as systemDisks from "./system-disks";
|
||||||
import * as systemResources from "./system-resources";
|
import * as systemResources from "./system-resources";
|
||||||
|
import * as timetable from "./timetable";
|
||||||
import * as tracearr from "./tracearr";
|
import * as tracearr from "./tracearr";
|
||||||
import * as video from "./video";
|
import * as video from "./video";
|
||||||
import * as weather from "./weather";
|
import * as weather from "./weather";
|
||||||
@@ -82,6 +83,7 @@ export const widgetImports = {
|
|||||||
systemResources,
|
systemResources,
|
||||||
coolify,
|
coolify,
|
||||||
systemDisks,
|
systemDisks,
|
||||||
|
timetable,
|
||||||
"immich-serverStats": immichServerStats,
|
"immich-serverStats": immichServerStats,
|
||||||
"immich-albumCarousel": immichAlbumCarousel,
|
"immich-albumCarousel": immichAlbumCarousel,
|
||||||
tracearr,
|
tracearr,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { ZodType } from "zod/v4";
|
|||||||
|
|
||||||
import type { IntegrationKind } from "@homarr/definitions";
|
import type { IntegrationKind } from "@homarr/definitions";
|
||||||
|
|
||||||
|
import type { DynamicSelectOption } from "./_inputs/widget-dynamic-select-input";
|
||||||
import type { inferSelectOptionValue, SelectOption } from "./_inputs/widget-select-input";
|
import type { inferSelectOptionValue, SelectOption } from "./_inputs/widget-select-input";
|
||||||
import type { ReleasesRepository } from "./releases/releases-repository";
|
import type { ReleasesRepository } from "./releases/releases-repository";
|
||||||
|
|
||||||
@@ -47,6 +48,16 @@ interface SelectInput<TOptions extends readonly SelectOption[]> extends CommonIn
|
|||||||
searchable?: boolean;
|
searchable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DynamicSelectInput extends CommonInput<DynamicSelectOption | null> {
|
||||||
|
useOptions: (
|
||||||
|
query: string,
|
||||||
|
integrationIds: string[],
|
||||||
|
) => {
|
||||||
|
isPending: boolean;
|
||||||
|
options: DynamicSelectOption[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface NumberInput extends CommonInput<number> {
|
interface NumberInput extends CommonInput<number> {
|
||||||
validate: z.ZodNumber;
|
validate: z.ZodNumber;
|
||||||
step?: number;
|
step?: number;
|
||||||
@@ -82,6 +93,12 @@ const optionsFactory = {
|
|||||||
searchable: input.searchable ?? false,
|
searchable: input.searchable ?? false,
|
||||||
withDescription: input.withDescription ?? false,
|
withDescription: input.withDescription ?? false,
|
||||||
}),
|
}),
|
||||||
|
dynamicSelect: (input: DynamicSelectInput) => ({
|
||||||
|
type: "dynamicSelect" as const,
|
||||||
|
defaultValue: input.defaultValue ?? null,
|
||||||
|
useOptions: input.useOptions,
|
||||||
|
withDescription: input.withDescription ?? false,
|
||||||
|
}),
|
||||||
select: <const TOptions extends SelectOption[]>(input: SelectInput<TOptions>) => ({
|
select: <const TOptions extends SelectOption[]>(input: SelectInput<TOptions>) => ({
|
||||||
type: "select" as const,
|
type: "select" as const,
|
||||||
defaultValue: (input.defaultValue ?? input.options[0]) as inferSelectOptionValue<TOptions[number]>,
|
defaultValue: (input.defaultValue ?? input.options[0]) as inferSelectOptionValue<TOptions[number]>,
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { Badge, Center, Group, Stack, Text } from "@mantine/core";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
import { clientApi } from "@homarr/api/client";
|
||||||
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
|
|
||||||
|
import type { DynamicSelectOption } from "../_inputs/widget-dynamic-select-input";
|
||||||
|
import type { WidgetComponentProps } from "../definition";
|
||||||
|
|
||||||
|
export default function TimetableWidget({ options, integrationIds }: WidgetComponentProps<"timetable">) {
|
||||||
|
// It will always have at least one integration as otherwise the NoIntegrationSelectedError would be thrown in item-content.tsx
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const integrationId = integrationIds[0]!;
|
||||||
|
const t = useScopedI18n("widget.timetable");
|
||||||
|
|
||||||
|
if (!options.station) {
|
||||||
|
return <Center h="100%">{t("noStation")}</Center>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <TimetableWidgetInner station={options.station} integrationId={integrationId} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimetableWidgetInnerProps {
|
||||||
|
station: DynamicSelectOption;
|
||||||
|
integrationId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimetableWidgetInner = ({ station, integrationId }: TimetableWidgetInnerProps) => {
|
||||||
|
const [timetable] = clientApi.widget.timetable.getTimetable.useSuspenseQuery({
|
||||||
|
integrationId,
|
||||||
|
stationId: station.value,
|
||||||
|
limit: 10,
|
||||||
|
});
|
||||||
|
const t = useScopedI18n("widget.timetable");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack w="100%" gap="xs" p="sm">
|
||||||
|
<Text fw="bold">{t("title", { station: station.label })}</Text>
|
||||||
|
{timetable.entries.map((entry) => (
|
||||||
|
<Group key={`${entry.timestamp.toISOString()}-${entry.location}`} justify="space-between" w="100%">
|
||||||
|
<Group gap="sm">
|
||||||
|
{entry.line && (
|
||||||
|
<Badge
|
||||||
|
size="sm"
|
||||||
|
color={entry.line.color ?? undefined}
|
||||||
|
variant={entry.line.color ? "filled" : "default"}
|
||||||
|
w={32}
|
||||||
|
p={0}
|
||||||
|
radius={0}
|
||||||
|
>
|
||||||
|
{entry.line.name}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
<Text size="sm">
|
||||||
|
{dayjs(entry.timestamp).format("HH:mm")}{" "}
|
||||||
|
{entry.delay >= 1 && (
|
||||||
|
<Text size="sm" span c="red">
|
||||||
|
+{entry.delay}'
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text size="sm">{entry.location}</Text>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{entry.platform && (
|
||||||
|
<Text size="sm" c={entry.platform.hasChanged ? "red" : undefined}>
|
||||||
|
{entry.platform.name}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { IconBusStop } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
import { clientApi } from "@homarr/api/client";
|
||||||
|
|
||||||
|
import { createWidgetDefinition } from "../definition";
|
||||||
|
import { optionsBuilder } from "../options";
|
||||||
|
|
||||||
|
export const { componentLoader, definition } = createWidgetDefinition("timetable", {
|
||||||
|
icon: IconBusStop,
|
||||||
|
supportedIntegrations: ["searchCh"],
|
||||||
|
createOptions() {
|
||||||
|
return optionsBuilder.from((factory) => ({
|
||||||
|
station: factory.dynamicSelect({
|
||||||
|
useOptions(query, integrationIds) {
|
||||||
|
const { data: stations, isPending } = clientApi.widget.timetable.searchStations.useQuery(
|
||||||
|
{
|
||||||
|
integrationId: integrationIds[0] ?? "",
|
||||||
|
query,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: integrationIds.length > 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isPending,
|
||||||
|
options:
|
||||||
|
stations?.map((station) => ({
|
||||||
|
label: station.name,
|
||||||
|
value: station.id,
|
||||||
|
})) ?? [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
}).withDynamicImport(() => import("./component"));
|
||||||
Generated
+916
-1077
File diff suppressed because it is too large.
Load diff
@@ -1 +1 @@
|
|||||||
[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"tancak","avatar_url":"https://avatars.githubusercontent.com/u/11760749?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"alotlikebeans","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/uLine truncated
|
[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"tancak","avatar_url":"https://avatars.githubusercontent.com/u/11760749?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"alotlikebeans","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/uLine truncated
|
||||||
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user