Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0e0b1d43f | ||
|
|
cc403b89eb | ||
|
|
dd24925d90 | ||
|
|
984b29d951 | ||
|
|
2b2c0e7e3a | ||
|
|
e7b3be2edb | ||
|
|
3b1c564a5a | ||
|
|
e37325f5e0 | ||
|
|
8a14a6cb45 | ||
|
|
d111eee0e0 | ||
|
|
0b4ca93aa1 | ||
|
|
6a908397cd | ||
|
|
85689caf6c | ||
|
|
cab5d19141 | ||
|
|
5cbab28099 | ||
|
|
1dd9694719 | ||
|
|
681aee05f0 | ||
|
|
c3ed7090c2 | ||
|
|
a20248d0b6 | ||
|
|
5a95cd3753 | ||
|
|
efc0384b37 | ||
|
|
fb04875253 | ||
|
|
4689ec9933 | ||
|
|
d084dfb470 | ||
|
|
7de45e6fe5 | ||
|
|
f6d16fe44b | ||
|
|
340f5606a9 | ||
|
|
ca9478dce7 | ||
|
|
1bb3654bf7 | ||
|
|
d88c6027fe | ||
|
|
020cbd72d3 | ||
|
|
aed2025b30 | ||
|
|
54809823e9 | ||
|
|
4f92e5265a | ||
|
|
234266ebd9 | ||
|
|
6b28aa86d0 | ||
|
|
ed638d4767 | ||
|
|
a2f7d63d2a | ||
|
|
9639f44560 | ||
|
|
bc087e6e60 | ||
|
|
d347d4455b | ||
|
|
10572ca962 | ||
|
|
d350e48998 | ||
|
|
2c48b18968 | ||
|
|
069ed0a267 | ||
|
|
a3e53ec291 | ||
|
|
38a1c9ca83 | ||
|
|
b40deba9ff | ||
|
|
d5d59dd256 | ||
|
|
3453482ed4 | ||
|
|
d2c1dc3cc1 | ||
|
|
59bcbc8b4d | ||
|
|
b2c46d33d6 | ||
|
|
ca01a31fe5 | ||
|
|
deb5e9d960 | ||
|
|
16f12d98e6 | ||
|
|
10bdd74b2b | ||
|
|
a91955a35b | ||
|
|
87deba417f | ||
|
|
220f68ee04 | ||
|
|
d6fc46df3b | ||
|
|
7a8c50fa4c | ||
|
|
59eecaf842 | ||
|
|
879a77ff2a | ||
|
|
b53bcb77e9 | ||
|
|
3062ddafbe | ||
|
|
7f782220a1 | ||
|
|
aa2ec5d221 | ||
|
|
e6db47aaab | ||
|
|
f3d2026746 |
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.45.1
|
||||||
|
- 1.45.0
|
||||||
- 1.44.0
|
- 1.44.0
|
||||||
- 1.43.1
|
- 1.43.1
|
||||||
- 1.43.0
|
- 1.43.0
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: Extract Build Artifact
|
||||||
|
description: Extracts artifacts from an existing Docker image to be used for from source installation
|
||||||
|
inputs:
|
||||||
|
digest:
|
||||||
|
description: Digest of Docker image to use
|
||||||
|
required: true
|
||||||
|
architecture:
|
||||||
|
description: Name of architecture, will be used to create directories (e.g. amd64, arm64)
|
||||||
|
required: true
|
||||||
|
release-tag:
|
||||||
|
description: Tag of the release to which the artifact will be attached
|
||||||
|
required: true
|
||||||
|
repository:
|
||||||
|
description: Repository to which the release belongs, e.g. owner/repo
|
||||||
|
required: true
|
||||||
|
token:
|
||||||
|
description: GitHub token with permissions to upload release assets
|
||||||
|
required: true
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Start docker container for ${{ inputs.architecture }}
|
||||||
|
run: |
|
||||||
|
docker run --name homarr \
|
||||||
|
-e "SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000" \
|
||||||
|
--detach --rm ${{ inputs.digest }}
|
||||||
|
shell: bash
|
||||||
|
- name: Extract build from ${{ inputs.architecture }} container
|
||||||
|
run: |
|
||||||
|
docker exec homarr cp /etc/nginx/templates/nginx.conf /app && \
|
||||||
|
docker exec homarr tar -czf extraction.tar.gz -C /app . && \
|
||||||
|
mkdir -p ${{ runner.temp }}/extraction/${{ inputs.architecture }} && \
|
||||||
|
docker cp homarr:/app/extraction.tar.gz ${{ runner.temp }}/extraction/${{ inputs.architecture }}/build-${{ inputs.architecture }}.tar.gz
|
||||||
|
shell: bash
|
||||||
|
- name: Stop ${{ inputs.architecture }} container
|
||||||
|
if: always()
|
||||||
|
run: docker container remove --force --volumes homarr
|
||||||
|
shell: bash
|
||||||
|
- name: Add build archive to release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ inputs.token }}
|
||||||
|
run: gh release upload --repo ${{ inputs.repository }} ${{ inputs.release-tag }} ${{ runner.temp }}/extraction/${{ inputs.architecture }}/build-${{ inputs.architecture }}.tar.gz --clobber
|
||||||
|
shell: bash
|
||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
if: github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 # Id of renovate bot and crowdin bot see https://api.github.com/users/homarr-renovate%5Bbot%5D and https://api.github.com/users/homarr-crowdin%5Bbot%5D and https://api.github.com/users/homarr-update-contributors%5Bbot%5D
|
if: github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 # Id of renovate bot and crowdin bot see https://api.github.com/users/homarr-renovate%5Bbot%5D and https://api.github.com/users/homarr-crowdin%5Bbot%5D and https://api.github.com/users/homarr-update-contributors%5Bbot%5D
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
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@v2
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
format:
|
format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
typecheck:
|
typecheck:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
- name: Build docker image
|
- name: Build docker image
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: ./tooling/github/setup
|
uses: ./tooling/github/setup
|
||||||
- name: Copy env
|
- name: Copy env
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Obtain token
|
- name: Obtain token
|
||||||
id: obtainToken
|
id: obtainToken
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Upload Crowdin translations
|
- name: Upload Crowdin translations
|
||||||
uses: crowdin/github-action@v2
|
uses: crowdin/github-action@v2
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.read-semver.outputs.version || steps.version-fallback.outputs.version }}
|
version: ${{ steps.read-semver.outputs.version || steps.version-fallback.outputs.version }}
|
||||||
git_ref: ${{ steps.read-git-ref.outputs.ref || github.ref }}
|
git_ref: ${{ steps.read-git-ref.outputs.ref || github.ref }}
|
||||||
|
skipped: ${{ env.SKIP_RELEASE }}
|
||||||
steps:
|
steps:
|
||||||
- run: echo "Skipping release for workflow_dispatch event"
|
- run: echo "Skipping release for workflow_dispatch event"
|
||||||
if: env.SKIP_RELEASE == 'true'
|
if: env.SKIP_RELEASE == 'true'
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
|
||||||
permission-contents: write # required to commit package.json & changelog changes, merge them to dev and publish the release
|
permission-contents: write # required to commit package.json & changelog changes, merge them to dev and publish the release
|
||||||
|
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
if: env.SKIP_RELEASE == 'false'
|
if: env.SKIP_RELEASE == 'false'
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -115,7 +115,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
digest: ${{ steps.build.outputs.digest }}
|
digest: ${{ steps.build.outputs.digest }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.release.outputs.git_ref }}
|
ref: ${{ needs.release.outputs.git_ref }}
|
||||||
|
|
||||||
@@ -146,7 +146,6 @@ jobs:
|
|||||||
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
env:
|
env:
|
||||||
SKIP_ENV_VALIDATION: true
|
SKIP_ENV_VALIDATION: true
|
||||||
|
|
||||||
build-arm64:
|
build-arm64:
|
||||||
name: Build docker image for arm64
|
name: Build docker image for arm64
|
||||||
needs: release
|
needs: release
|
||||||
@@ -154,7 +153,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
digest: ${{ steps.build.outputs.digest }}
|
digest: ${{ steps.build.outputs.digest }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.release.outputs.git_ref }}
|
ref: ${{ needs.release.outputs.git_ref }}
|
||||||
|
|
||||||
@@ -185,10 +184,38 @@ jobs:
|
|||||||
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
|
||||||
env:
|
env:
|
||||||
SKIP_ENV_VALIDATION: true
|
SKIP_ENV_VALIDATION: true
|
||||||
|
extract-asset-amd64:
|
||||||
|
name: Extract amd64 asset from docker image
|
||||||
|
needs: [release, build-amd64]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Extract amd64
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev
|
||||||
|
with:
|
||||||
|
digest: "${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }}"
|
||||||
|
architecture: amd64
|
||||||
|
release-tag: ${{ needs.release.outputs.version }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
repository: ${{ github.repository }}
|
||||||
|
|
||||||
|
extract-asset-arm64:
|
||||||
|
name: Extract arm64 asset from docker image
|
||||||
|
needs: [release, build-arm64]
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Extract arm64
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
uses: homarr-labs/homarr/.github/actions/extract-build-artifact@dev
|
||||||
|
with:
|
||||||
|
digest: "${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}"
|
||||||
|
architecture: arm64
|
||||||
|
release-tag: ${{ needs.release.outputs.version }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
repository: ${{ github.repository }}
|
||||||
publish:
|
publish:
|
||||||
name: Complete deployment and notify
|
name: Complete deployment and notify
|
||||||
needs: [release, build-amd64, build-arm64]
|
needs: [release, build-amd64, build-arm64, extract-asset-amd64, extract-asset-arm64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NEXT_VERSION: ${{ needs.release.outputs.version }}
|
NEXT_VERSION: ${{ needs.release.outputs.version }}
|
||||||
@@ -222,6 +249,13 @@ jobs:
|
|||||||
${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }} \
|
${{ env.GHCR_REPO }}@${{ needs.build-amd64.outputs.digest }} \
|
||||||
${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}
|
${{ env.GHCR_REPO }}@${{ needs.build-arm64.outputs.digest }}
|
||||||
|
|
||||||
|
- name: Publish release
|
||||||
|
if: needs.release.outputs.skipped == 'false'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh release edit --repo ${{ github.repository }} ${{ needs.release.outputs.version }} --draft=false
|
||||||
|
|
||||||
- name: Discord notification
|
- name: Discord notification
|
||||||
env:
|
env:
|
||||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
args: "Automatic release has been triggered: [run ${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
|
args: "Automatic release has been triggered: [run ${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Get Next Version
|
- name: Get Next Version
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
renovate-validate:
|
renovate-validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v6
|
||||||
- run: |
|
- run: |
|
||||||
npx --yes --package renovate -- \
|
npx --yes --package renovate -- \
|
||||||
renovate-config-validator --strict .github/renovate.json5
|
renovate-config-validator --strict .github/renovate.json5
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
permission-contents: write # required to commit to branch
|
permission-contents: write # required to commit to branch
|
||||||
permission-pull-requests: write # required to create pr & enable automerge
|
permission-pull-requests: write # required to create pr & enable automerge
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.obtainToken.outputs.token }}
|
token: ${{ steps.obtainToken.outputs.token }}
|
||||||
- name: Setup
|
- name: Setup
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
permission-pull-requests: write # required to create pr & enable automerge
|
permission-pull-requests: write # required to create pr & enable automerge
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
permission-contents: write # required to commit to branch
|
permission-contents: write # required to commit to branch
|
||||||
permission-pull-requests: write # required to create pr & enable automerge
|
permission-pull-requests: write # required to create pr & enable automerge
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||||
- name: Setup
|
- name: Setup
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
{
|
{
|
||||||
"successComment": false,
|
"successComment": false,
|
||||||
"failComment": false,
|
"failComment": false,
|
||||||
|
"draftRelease": true,
|
||||||
"releaseBodyTemplate": "<%= _.truncate(nextRelease.notes, { 'length': 124000, 'omission': '' }) %>"
|
"releaseBodyTemplate": "<%= _.truncate(nextRelease.notes, { 'length': 124000, 'omission': '' }) %>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +1,67 @@
|
|||||||
|
## [1.46.0](https://github.com/homarr-labs/homarr/compare/v1.45.3...v1.46.0) (2025-12-12)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **docker:** add widget options to sort containers ([#4636](https://github.com/homarr-labs/homarr/issues/4636)) ([dd24925](https://github.com/homarr-labs/homarr/commit/dd24925d906dc13d73c52a47fdd07bec89798789))
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add autocomplete and id attributes for password manager compatibility ([#4602](https://github.com/homarr-labs/homarr/issues/4602)) ([681aee0](https://github.com/homarr-labs/homarr/commit/681aee05f07a6e09371ed089d2b9ef361494c416))
|
||||||
|
* **deps:** update dependency @tanstack/react-query to ^5.90.12 ([#4615](https://github.com/homarr-labs/homarr/issues/4615)) ([efc0384](https://github.com/homarr-labs/homarr/commit/efc0384b372fadafb65f61f715f08edd2a8f8573))
|
||||||
|
* **deps:** update dependency better-sqlite3 to ^12.5.0 ([#4569](https://github.com/homarr-labs/homarr/issues/4569)) ([a20248d](https://github.com/homarr-labs/homarr/commit/a20248d0b689ab1ca475f606edfca458897ce442))
|
||||||
|
* **deps:** update dependency drizzle-kit to ^0.31.8 ([#4618](https://github.com/homarr-labs/homarr/issues/4618)) ([5cbab28](https://github.com/homarr-labs/homarr/commit/5cbab28099d41b8ade6cc8a42e69c4191310296c))
|
||||||
|
* **deps:** update dependency drizzle-orm to ^0.45.0 ([#4619](https://github.com/homarr-labs/homarr/issues/4619)) ([cab5d19](https://github.com/homarr-labs/homarr/commit/cab5d19141a38fbb977f4ef6e9c2ddbfdfea6aff))
|
||||||
|
* **deps:** update dependency ldapts to v8.0.12 ([#4613](https://github.com/homarr-labs/homarr/issues/4613)) ([4689ec9](https://github.com/homarr-labs/homarr/commit/4689ec9933e5286c0d19c66989023b5b3376ffb1))
|
||||||
|
* **deps:** update dependency ldapts to v8.0.13 ([#4626](https://github.com/homarr-labs/homarr/issues/4626)) ([8a14a6c](https://github.com/homarr-labs/homarr/commit/8a14a6cb456a6f16975372f64451e3b54ebfd88d))
|
||||||
|
* **deps:** update dependency ldapts to v8.0.14 ([#4627](https://github.com/homarr-labs/homarr/issues/4627)) ([e37325f](https://github.com/homarr-labs/homarr/commit/e37325f5e0314b13d031fba1bff591b881baf8d1))
|
||||||
|
* **deps:** update dependency winston to v3.19.0 ([#4632](https://github.com/homarr-labs/homarr/issues/4632)) ([3b1c564](https://github.com/homarr-labs/homarr/commit/3b1c564a5abbf1d1fca6ecab46e173c8f6938130))
|
||||||
|
* **deps:** update next monorepo to v16.0.10 [security] ([#4634](https://github.com/homarr-labs/homarr/issues/4634)) ([2b2c0e7](https://github.com/homarr-labs/homarr/commit/2b2c0e7e3a813525bd977276df6e5594bc283055))
|
||||||
|
* **deps:** update react monorepo to v19.2.1 ([#4608](https://github.com/homarr-labs/homarr/issues/4608)) ([f6d16fe](https://github.com/homarr-labs/homarr/commit/f6d16fe44bf239fb85a4ee3e9ae6491131315dce))
|
||||||
|
* **deps:** update tiptap monorepo to v3 (major) ([#3612](https://github.com/homarr-labs/homarr/issues/3612)) ([d111eee](https://github.com/homarr-labs/homarr/commit/d111eee0e0a41e55de87049f3cb0a9154ae82ea1))
|
||||||
|
* **deps:** update turbo monorepo to ^2.6.2 ([#4612](https://github.com/homarr-labs/homarr/issues/4612)) ([7de45e6](https://github.com/homarr-labs/homarr/commit/7de45e6fe50ccf4333959f924889463a22316984))
|
||||||
|
* **deps:** update turbo monorepo to ^2.6.3 ([#4622](https://github.com/homarr-labs/homarr/issues/4622)) ([85689ca](https://github.com/homarr-labs/homarr/commit/85689caf6c25b80cb4ce04a0baf2980a1a4deece))
|
||||||
|
* format issues ([1dd9694](https://github.com/homarr-labs/homarr/commit/1dd9694719ec4dcefe3c8d221015ba9aecede78c))
|
||||||
|
* improve run script ([#4609](https://github.com/homarr-labs/homarr/issues/4609)) ([d084dfb](https://github.com/homarr-labs/homarr/commit/d084dfb4705fca68bb9f9465ec9564050d0b04b2))
|
||||||
|
* **plex:** test connection not fully checking connection ([#4617](https://github.com/homarr-labs/homarr/issues/4617)) ([6a90839](https://github.com/homarr-labs/homarr/commit/6a908397cd8a6189123b91ea9d68f683af2bed05))
|
||||||
|
* **transmission:** total download incorrect for cross seeded torrents ([#3211](https://github.com/homarr-labs/homarr/issues/3211)) ([0b4ca93](https://github.com/homarr-labs/homarr/commit/0b4ca93aa13e9838b481daed5703640d30a52ffc))
|
||||||
|
|
||||||
|
## [1.45.3](https://github.com/homarr-labs/homarr/compare/v1.45.2...v1.45.3) (2025-12-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deps:** update dependency glob to v13 ([#4584](https://github.com/homarr-labs/homarr/issues/4584)) ([020cbd7](https://github.com/homarr-labs/homarr/commit/020cbd72d387c9f50f4eddcbc2685829cf7787de))
|
||||||
|
* **deps:** update dependency jotai to ^2.15.2 ([#4597](https://github.com/homarr-labs/homarr/issues/4597)) ([ed638d4](https://github.com/homarr-labs/homarr/commit/ed638d47679594eab3cc19a12473722644ebf694))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.7 ([#4598](https://github.com/homarr-labs/homarr/issues/4598)) ([6b28aa8](https://github.com/homarr-labs/homarr/commit/6b28aa86d0bad29e4806592079a7f5d2e22b5ade))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.8 ([#4606](https://github.com/homarr-labs/homarr/issues/4606)) ([4f92e52](https://github.com/homarr-labs/homarr/commit/4f92e5265a40c636f303406e728e88cc056da23c))
|
||||||
|
* **deps:** update dependency prettier to ^3.7.4 ([#4582](https://github.com/homarr-labs/homarr/issues/4582)) ([5480982](https://github.com/homarr-labs/homarr/commit/54809823e9edeacc245b560747b622aba683b3bf))
|
||||||
|
* **deps:** update dependency typescript-eslint to ^8.48.1 ([#4438](https://github.com/homarr-labs/homarr/issues/4438)) ([d88c602](https://github.com/homarr-labs/homarr/commit/d88c6027fe3accf7a6872ada8aa2724d30bf691c))
|
||||||
|
|
||||||
|
## [1.45.2](https://github.com/homarr-labs/homarr/compare/v1.45.1...v1.45.2) (2025-12-05)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add ipv6 support for internal nginx proxy ([2c48b18](https://github.com/homarr-labs/homarr/commit/2c48b18968a74cb7150c246ebb2505d07764f109))
|
||||||
|
* disable react-compiler due to issue with mantine-react-table data updates ([#4593](https://github.com/homarr-labs/homarr/issues/4593)) ([10572ca](https://github.com/homarr-labs/homarr/commit/10572ca962081961fb63b3ad9f164c610edf35e4))
|
||||||
|
|
||||||
|
## [1.45.1](https://github.com/homarr-labs/homarr/compare/v1.45.0...v1.45.1) (2025-12-03)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deps:** update dependency chroma-js to ^3.1.4 ([#4570](https://github.com/homarr-labs/homarr/issues/4570)) ([d6fc46d](https://github.com/homarr-labs/homarr/commit/d6fc46df3b5e2dd79ff6f9a3dd3a3e2050a0eeef))
|
||||||
|
* **deps:** update dependency chroma-js to ^3.2.0 ([#4585](https://github.com/homarr-labs/homarr/issues/4585)) ([b2c46d3](https://github.com/homarr-labs/homarr/commit/b2c46d33d6cc769e89e208fd29d3a1d143cf74c7))
|
||||||
|
* **deps:** update dependency isomorphic-dompurify to ^2.33.0 ([#4581](https://github.com/homarr-labs/homarr/issues/4581)) ([ca01a31](https://github.com/homarr-labs/homarr/commit/ca01a31fe5cbce53eb0e6bd1a943320c092161ef))
|
||||||
|
* **deps:** update dependency next-intl to v4.5.6 ([#4571](https://github.com/homarr-labs/homarr/issues/4571)) ([3062dda](https://github.com/homarr-labs/homarr/commit/3062ddafbe0bc1dbac9259af4036f0fa32d85237))
|
||||||
|
* **deps:** update dependency sass to ^1.94.2 ([#4572](https://github.com/homarr-labs/homarr/issues/4572)) ([7a8c50f](https://github.com/homarr-labs/homarr/commit/7a8c50fa4c5224dd74af3c17f56e2e5b8d6a4f43))
|
||||||
|
* **deps:** update dependency superjson to v2.2.6 ([#4573](https://github.com/homarr-labs/homarr/issues/4573)) ([deb5e9d](https://github.com/homarr-labs/homarr/commit/deb5e9d96092069e296ba473eaad58367b516f85))
|
||||||
|
* **deps:** update dependency swagger-ui-react to ^5.30.3 ([#4574](https://github.com/homarr-labs/homarr/issues/4574)) ([d2c1dc3](https://github.com/homarr-labs/homarr/commit/d2c1dc3cc1dd72fc9fc8ae9613467fa0b0b8d75a))
|
||||||
|
* **deps:** update dependency zod to ^4.1.13 ([#4575](https://github.com/homarr-labs/homarr/issues/4575)) ([879a77f](https://github.com/homarr-labs/homarr/commit/879a77ff2a81b0d0a17d1487eaf6d8539a955301))
|
||||||
|
* **deps:** update mantine monorepo to ^8.3.9 ([#4576](https://github.com/homarr-labs/homarr/issues/4576)) ([d5d59dd](https://github.com/homarr-labs/homarr/commit/d5d59dd2561f0be2f4f4c689f33c6a9a7840a21c))
|
||||||
|
* **deps:** update nextjs monorepo to v16.0.5 ([#4577](https://github.com/homarr-labs/homarr/issues/4577)) ([16f12d9](https://github.com/homarr-labs/homarr/commit/16f12d98e6cdae50fe2989db0911cb1350fcb93b))
|
||||||
|
* **deps:** update tanstack-query monorepo ([#4578](https://github.com/homarr-labs/homarr/issues/4578)) ([59bcbc8](https://github.com/homarr-labs/homarr/commit/59bcbc8b4de4a0a8cee8adf6336c7c10477c766a))
|
||||||
|
* **deps:** update testcontainers-node monorepo to ^11.9.0 ([#4583](https://github.com/homarr-labs/homarr/issues/4583)) ([10bdd74](https://github.com/homarr-labs/homarr/commit/10bdd74b2b287cb08ec0926147ac0e7fcfd492bb))
|
||||||
|
* **deps:** update trpc monorepo to ^11.7.2 ([#4579](https://github.com/homarr-labs/homarr/issues/4579)) ([3453482](https://github.com/homarr-labs/homarr/commit/3453482ed43644025c39dee8e20549e1beb86be0))
|
||||||
|
* **security:** rce vulnerability in nextjs ([b40deba](https://github.com/homarr-labs/homarr/commit/b40deba9ff1a3d629b6027565378d9f3ad2f1980))
|
||||||
|
|
||||||
## [1.45.0](https://github.com/homarr-labs/homarr/compare/v1.44.0...v1.45.0) (2025-11-28)
|
## [1.45.0](https://github.com/homarr-labs/homarr/compare/v1.44.0...v1.45.0) (2025-11-28)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ const withNextIntl = createNextIntlPlugin({
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
reactCompiler: true,
|
// react compiler breaks mantine-react-table, so disabled for now
|
||||||
|
//reactCompiler: true,
|
||||||
/** We already do typechecking as separate tasks in CI */
|
/** We already do typechecking as separate tasks in CI */
|
||||||
typescript: { ignoreBuildErrors: true },
|
typescript: { ignoreBuildErrors: true },
|
||||||
/**
|
/**
|
||||||
|
|||||||
+25
-25
@@ -50,46 +50,46 @@
|
|||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"@homarr/widgets": "workspace:^0.1.0",
|
"@homarr/widgets": "workspace:^0.1.0",
|
||||||
"@mantine/colors-generator": "^8.3.8",
|
"@mantine/colors-generator": "^8.3.9",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/dropzone": "^8.3.8",
|
"@mantine/dropzone": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@mantine/modals": "^8.3.8",
|
"@mantine/modals": "^8.3.9",
|
||||||
"@mantine/tiptap": "^8.3.8",
|
"@mantine/tiptap": "^8.3.9",
|
||||||
"@million/lint": "1.0.14",
|
"@million/lint": "1.0.14",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tanstack/react-query": "^5.90.10",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@tanstack/react-query-devtools": "^5.90.2",
|
"@tanstack/react-query-devtools": "^5.91.1",
|
||||||
"@tanstack/react-query-next-experimental": "^5.91.0",
|
"@tanstack/react-query-next-experimental": "^5.91.0",
|
||||||
"@trpc/client": "^11.7.1",
|
"@trpc/client": "^11.7.2",
|
||||||
"@trpc/next": "^11.7.1",
|
"@trpc/next": "^11.7.2",
|
||||||
"@trpc/react-query": "^11.7.1",
|
"@trpc/react-query": "^11.7.2",
|
||||||
"@trpc/server": "^11.7.1",
|
"@trpc/server": "^11.7.2",
|
||||||
"@xterm/addon-canvas": "^0.7.0",
|
"@xterm/addon-canvas": "^0.7.0",
|
||||||
"@xterm/addon-fit": "0.10.0",
|
"@xterm/addon-fit": "0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
"chroma-js": "^3.1.2",
|
"chroma-js": "^3.2.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"flag-icons": "^7.5.0",
|
"flag-icons": "^7.5.0",
|
||||||
"glob": "^12.0.0",
|
"glob": "^13.0.0",
|
||||||
"isomorphic-dompurify": "^2.32.0",
|
"isomorphic-dompurify": "^2.33.0",
|
||||||
"jotai": "^2.15.1",
|
"jotai": "^2.15.2",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"postcss-preset-mantine": "^1.18.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
"prismjs": "^1.30.0",
|
"prismjs": "^1.30.0",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^6.0.0",
|
||||||
"react-simple-code-editor": "^0.14.1",
|
"react-simple-code-editor": "^0.14.1",
|
||||||
"sass": "^1.94.1",
|
"sass": "^1.94.2",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"swagger-ui-react": "^5.30.2",
|
"swagger-ui-react": "^5.30.3",
|
||||||
"use-deep-compare-effect": "^1.8.1",
|
"use-deep-compare-effect": "^1.8.1",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
@@ -98,13 +98,13 @@
|
|||||||
"@types/chroma-js": "3.1.2",
|
"@types/chroma-js": "3.1.2",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@types/prismjs": "^1.26.5",
|
"@types/prismjs": "^1.26.5",
|
||||||
"@types/react": "19.2.6",
|
"@types/react": "19.2.7",
|
||||||
"@types/react-dom": "19.2.3",
|
"@types/react-dom": "19.2.3",
|
||||||
"@types/swagger-ui-react": "^5.18.0",
|
"@types/swagger-ui-react": "^5.18.0",
|
||||||
"concurrently": "^9.2.1",
|
"concurrently": "^9.2.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"node-loader": "^2.1.0",
|
"node-loader": "^2.1.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,16 +64,23 @@ export const RegistrationForm = ({ invite }: RegistrationFormProps) => {
|
|||||||
<Stack gap="xl">
|
<Stack gap="xl">
|
||||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<TextInput label={t("field.username.label")} autoComplete="off" {...form.getInputProps("username")} />
|
<TextInput
|
||||||
|
label={t("field.username.label")}
|
||||||
|
id="username"
|
||||||
|
autoComplete="username"
|
||||||
|
{...form.getInputProps("username")}
|
||||||
|
/>
|
||||||
<CustomPasswordInput
|
<CustomPasswordInput
|
||||||
withPasswordRequirements
|
withPasswordRequirements
|
||||||
label={t("field.password.label")}
|
label={t("field.password.label")}
|
||||||
|
id="password"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
{...form.getInputProps("password")}
|
{...form.getInputProps("password")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={t("field.passwordConfirm.label")}
|
label={t("field.passwordConfirm.label")}
|
||||||
|
id="password-confirm"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
{...form.getInputProps("confirmPassword")}
|
{...form.getInputProps("confirmPassword")}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -116,8 +116,18 @@ export const LoginForm = ({ providers, oidcClientName, isOidcAutoLoginEnabled, c
|
|||||||
<>
|
<>
|
||||||
<form onSubmit={form.onSubmit((credentials) => void signInAsync(credentials.provider, credentials))}>
|
<form onSubmit={form.onSubmit((credentials) => void signInAsync(credentials.provider, credentials))}>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<TextInput label={t("field.username.label")} {...form.getInputProps("name")} />
|
<TextInput
|
||||||
<PasswordInput label={t("field.password.label")} {...form.getInputProps("password")} />
|
label={t("field.username.label")}
|
||||||
|
id="username"
|
||||||
|
autoComplete="username"
|
||||||
|
{...form.getInputProps("name")}
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
label={t("field.password.label")}
|
||||||
|
id="password"
|
||||||
|
autoComplete="current-password"
|
||||||
|
{...form.getInputProps("password")}
|
||||||
|
/>
|
||||||
|
|
||||||
{providers.includes("credentials") && (
|
{providers.includes("credentials") && (
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ import { groupCreateSchema } from "@homarr/validation/group";
|
|||||||
|
|
||||||
export const InitGroup = () => {
|
export const InitGroup = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { mutateAsync } = clientApi.group.createInitialExternalGroup.useMutation();
|
const { mutateAsync } = clientApi.group.createInitialExternalGroup.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/init");
|
||||||
|
},
|
||||||
|
});
|
||||||
const form = useZodForm(groupCreateSchema, {
|
const form = useZodForm(groupCreateSchema, {
|
||||||
initialValues: {
|
initialValues: {
|
||||||
name: "",
|
name: "",
|
||||||
@@ -21,9 +25,6 @@ export const InitGroup = () => {
|
|||||||
|
|
||||||
const handleSubmitAsync = async (values: z.infer<typeof groupCreateSchema>) => {
|
const handleSubmitAsync = async (values: z.infer<typeof groupCreateSchema>) => {
|
||||||
await mutateAsync(values, {
|
await mutateAsync(values, {
|
||||||
async onSuccess() {
|
|
||||||
await revalidatePathActionAsync("/init");
|
|
||||||
},
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
if (error.data?.code === "CONFLICT") {
|
if (error.data?.code === "CONFLICT") {
|
||||||
form.setErrors({ name: t("common.zod.errors.custom.groupNameTaken") });
|
form.setErrors({ name: t("common.zod.errors.custom.groupNameTaken") });
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ import { settingsInitSchema } from "@homarr/validation/settings";
|
|||||||
export const InitSettings = () => {
|
export const InitSettings = () => {
|
||||||
const tSection = useScopedI18n("management.page.settings.section");
|
const tSection = useScopedI18n("management.page.settings.section");
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { mutateAsync } = clientApi.serverSettings.initSettings.useMutation();
|
const { mutateAsync } = clientApi.serverSettings.initSettings.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/init");
|
||||||
|
},
|
||||||
|
});
|
||||||
const form = useZodForm(settingsInitSchema, { initialValues: defaultServerSettings });
|
const form = useZodForm(settingsInitSchema, { initialValues: defaultServerSettings });
|
||||||
|
|
||||||
form.watch("analytics.enableGeneral", ({ value }) => {
|
form.watch("analytics.enableGeneral", ({ value }) => {
|
||||||
@@ -31,11 +35,7 @@ export const InitSettings = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmitAsync = async (values: z.infer<typeof settingsInitSchema>) => {
|
const handleSubmitAsync = async (values: z.infer<typeof settingsInitSchema>) => {
|
||||||
await mutateAsync(values, {
|
await mutateAsync(values);
|
||||||
async onSuccess() {
|
|
||||||
await revalidatePathActionAsync("/init");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -26,19 +26,19 @@ export const InitUserForm = () => {
|
|||||||
|
|
||||||
const handleSubmitAsync = async (values: FormType) => {
|
const handleSubmitAsync = async (values: FormType) => {
|
||||||
await mutateAsync(values, {
|
await mutateAsync(values, {
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: tUser("notification.success.title"),
|
title: tUser("notification.success.title"),
|
||||||
message: tUser("notification.success.message"),
|
message: tUser("notification.success.message"),
|
||||||
});
|
});
|
||||||
|
|
||||||
await signIn("credentials", {
|
void signIn("credentials", {
|
||||||
name: values.username,
|
name: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
redirect: false,
|
redirect: false,
|
||||||
|
}).then(async () => {
|
||||||
|
await revalidatePathActionAsync("/init");
|
||||||
});
|
});
|
||||||
|
|
||||||
await revalidatePathActionAsync("/init");
|
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
|
|||||||
@@ -84,9 +84,6 @@ export const BoardCardMenuDropdown = ({ board }: BoardCardMenuDropdownProps) =>
|
|||||||
id: board.id,
|
id: board.id,
|
||||||
name: board.name,
|
name: board.name,
|
||||||
},
|
},
|
||||||
onSuccess: async () => {
|
|
||||||
await revalidatePathActionAsync("/manage/boards");
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}, [board.id, board.name, openDuplicateModal]);
|
}, [board.id, board.name, openDuplicateModal]);
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { mutateAsync: createIntegrationAsync, isPending } = clientApi.integration.create.useMutation();
|
const { mutateAsync: createIntegrationAsync, isPending } = clientApi.integration.create.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/integrations");
|
||||||
|
},
|
||||||
|
});
|
||||||
const [error, setError] = useState<null | AnyMappedTestConnectionError>(null);
|
const [error, setError] = useState<null | AnyMappedTestConnectionError>(null);
|
||||||
|
|
||||||
const handleSubmitAsync = async ({ appId, appHref, hasApp, ...values }: FormType) => {
|
const handleSubmitAsync = async ({ appId, appHref, hasApp, ...values }: FormType) => {
|
||||||
@@ -116,7 +120,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
|
|||||||
app,
|
app,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onSuccess(data) {
|
onSuccess(data) {
|
||||||
// We do it this way as we are unable to send a typesafe error through onError
|
// We do it this way as we are unable to send a typesafe error through onError
|
||||||
if (data?.error) {
|
if (data?.error) {
|
||||||
setError(data.error);
|
setError(data.error);
|
||||||
@@ -132,7 +136,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
|
|||||||
message: t("integration.page.create.notification.success.message"),
|
message: t("integration.page.create.notification.success.message"),
|
||||||
});
|
});
|
||||||
|
|
||||||
await revalidatePathActionAsync("/manage/integrations").then(() => router.push("/manage/integrations"));
|
router.push("/manage/integrations");
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
|
|||||||
+6
-3
@@ -15,7 +15,11 @@ interface RemoveCertificateProps {
|
|||||||
|
|
||||||
export const RemoveCertificate = ({ fileName }: RemoveCertificateProps) => {
|
export const RemoveCertificate = ({ fileName }: RemoveCertificateProps) => {
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const { mutateAsync } = clientApi.certificates.removeCertificate.useMutation();
|
const { mutateAsync } = clientApi.certificates.removeCertificate.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/tools/certificates");
|
||||||
|
},
|
||||||
|
});
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@@ -27,12 +31,11 @@ export const RemoveCertificate = ({ fileName }: RemoveCertificateProps) => {
|
|||||||
await mutateAsync(
|
await mutateAsync(
|
||||||
{ fileName },
|
{ fileName },
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t("certificate.action.remove.notification.success.title"),
|
title: t("certificate.action.remove.notification.success.title"),
|
||||||
message: t("certificate.action.remove.notification.success.message"),
|
message: t("certificate.action.remove.notification.success.message"),
|
||||||
});
|
});
|
||||||
await revalidatePathActionAsync("/manage/tools/certificates");
|
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
|
|||||||
+6
-3
@@ -15,7 +15,11 @@ interface RemoveHostnameActionIconProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const RemoveHostnameActionIcon = (input: RemoveHostnameActionIconProps) => {
|
export const RemoveHostnameActionIcon = (input: RemoveHostnameActionIconProps) => {
|
||||||
const { mutateAsync } = clientApi.certificates.removeTrustedHostname.useMutation();
|
const { mutateAsync } = clientApi.certificates.removeTrustedHostname.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/tools/certificates/hostnames");
|
||||||
|
},
|
||||||
|
});
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
@@ -26,8 +30,7 @@ export const RemoveHostnameActionIcon = (input: RemoveHostnameActionIconProps) =
|
|||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
await mutateAsync(input, {
|
await mutateAsync(input, {
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
await revalidatePathActionAsync("/manage/tools/certificates/hostnames");
|
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t("certificate.action.removeHostname.notification.success.title"),
|
title: t("certificate.action.removeHostname.notification.success.title"),
|
||||||
message: t("certificate.action.removeHostname.notification.success.message"),
|
message: t("certificate.action.removeHostname.notification.success.message"),
|
||||||
|
|||||||
@@ -206,15 +206,16 @@ const ContainerActionBarButton = (props: ContainerActionBarButtonProps) => {
|
|||||||
const t = useScopedI18n("docker.action");
|
const t = useScopedI18n("docker.action");
|
||||||
const utils = clientApi.useUtils();
|
const utils = clientApi.useUtils();
|
||||||
|
|
||||||
const { mutateAsync, isPending } = clientApi.docker[`${props.action}All`].useMutation();
|
const { mutateAsync, isPending } = clientApi.docker[`${props.action}All`].useMutation({
|
||||||
|
async onSettled() {
|
||||||
|
await utils.docker.getContainers.invalidate();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const handleClickAsync = async () => {
|
const handleClickAsync = async () => {
|
||||||
await mutateAsync(
|
await mutateAsync(
|
||||||
{ ids: props.selectedIds },
|
{ ids: props.selectedIds },
|
||||||
{
|
{
|
||||||
async onSettled() {
|
|
||||||
await utils.docker.getContainers.invalidate();
|
|
||||||
},
|
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t(`${props.action}.notification.success.title`),
|
title: t(`${props.action}.notification.success.title`),
|
||||||
|
|||||||
+8
-7
@@ -18,7 +18,12 @@ interface UserProfileAvatarForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => {
|
export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => {
|
||||||
const { mutate } = clientApi.user.setProfileImage.useMutation();
|
const { mutate } = clientApi.user.setProfileImage.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
// Revalidate all as the avatar is used in multiple places
|
||||||
|
await revalidatePathActionAsync("/");
|
||||||
|
},
|
||||||
|
});
|
||||||
const [opened, { toggle }] = useDisclosure(false);
|
const [opened, { toggle }] = useDisclosure(false);
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
@@ -38,9 +43,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => {
|
|||||||
image: base64Url,
|
image: base64Url,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
// Revalidate all as the avatar is used in multiple places
|
|
||||||
await revalidatePathActionAsync("/");
|
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
message: tManageAvatar("changeImage.notification.success.message"),
|
message: tManageAvatar("changeImage.notification.success.message"),
|
||||||
});
|
});
|
||||||
@@ -74,9 +77,7 @@ export const UserProfileAvatarForm = ({ user }: UserProfileAvatarForm) => {
|
|||||||
image: null,
|
image: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
// Revalidate all as the avatar is used in multiple places
|
|
||||||
await revalidatePathActionAsync("/");
|
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
message: tManageAvatar("removeImage.notification.success.message"),
|
message: tManageAvatar("removeImage.notification.success.message"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ export const TransferGroupOwnership = ({ group }: TransferGroupOwnershipProps) =
|
|||||||
const [innerOwnerId, setInnerOwnerId] = useState(group.ownerId);
|
const [innerOwnerId, setInnerOwnerId] = useState(group.ownerId);
|
||||||
const { openModal } = useModalAction(UserSelectModal);
|
const { openModal } = useModalAction(UserSelectModal);
|
||||||
const { openConfirmModal } = useConfirmModal();
|
const { openConfirmModal } = useConfirmModal();
|
||||||
const { mutateAsync } = clientApi.group.transferOwnership.useMutation();
|
const { mutateAsync } = clientApi.group.transferOwnership.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync(`/manage/users/groups/${group.id}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const handleTransfer = useCallback(() => {
|
const handleTransfer = useCallback(() => {
|
||||||
openModal(
|
openModal(
|
||||||
@@ -47,7 +51,7 @@ export const TransferGroupOwnership = ({ group }: TransferGroupOwnershipProps) =
|
|||||||
userId: id,
|
userId: id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
setInnerOwnerId(id);
|
setInnerOwnerId(id);
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: tRoot("common.notification.transfer.success"),
|
title: tRoot("common.notification.transfer.success"),
|
||||||
@@ -56,7 +60,6 @@ export const TransferGroupOwnership = ({ group }: TransferGroupOwnershipProps) =
|
|||||||
user: name,
|
user: name,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
await revalidatePathActionAsync(`/manage/users/groups/${group.id}`);
|
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
|
|||||||
@@ -56,16 +56,19 @@ export const GroupsTable = ({ groups, initialGroupIds, hasFilter }: GroupsTableP
|
|||||||
() => initialGroupIds.some((groupId, index) => groupIds.indexOf(groupId) !== index),
|
() => initialGroupIds.some((groupId, index) => groupIds.indexOf(groupId) !== index),
|
||||||
[groupIds, initialGroupIds],
|
[groupIds, initialGroupIds],
|
||||||
);
|
);
|
||||||
const { mutateAsync, isPending } = clientApi.group.savePositions.useMutation();
|
const { mutateAsync, isPending } = clientApi.group.savePositions.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/users/groups");
|
||||||
|
},
|
||||||
|
});
|
||||||
const handleSavePositionsAsync = async () => {
|
const handleSavePositionsAsync = async () => {
|
||||||
await mutateAsync(
|
await mutateAsync(
|
||||||
{ positions: groupIds },
|
{ positions: groupIds },
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
message: t("group.action.changePosition.notification.success.message"),
|
message: t("group.action.changePosition.notification.success.message"),
|
||||||
});
|
});
|
||||||
await revalidatePathActionAsync("/manage/users/groups");
|
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"fastify": "^5.6.2",
|
"fastify": "^5.6.2",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"undici": "7.16.0"
|
"undici": "7.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -49,9 +49,9 @@
|
|||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"tsx": "4.20.4",
|
"tsx": "4.20.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,9 @@
|
|||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -5,6 +5,7 @@ events {
|
|||||||
http {
|
http {
|
||||||
server {
|
server {
|
||||||
listen 7575;
|
listen 7575;
|
||||||
|
listen [::]:7575;
|
||||||
|
|
||||||
# Route websockets traffic to port 3001
|
# Route websockets traffic to port 3001
|
||||||
location /websockets {
|
location /websockets {
|
||||||
@@ -25,4 +26,4 @@ http {
|
|||||||
client_max_body_size 32M;
|
client_max_body_size 32M;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-15
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "homarr",
|
"name": "homarr",
|
||||||
"version": "1.45.0",
|
"version": "1.46.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env CI=true turbo build",
|
"build": "cross-env CI=true turbo build",
|
||||||
@@ -42,27 +42,27 @@
|
|||||||
"@semantic-release/github": "^12.0.2",
|
"@semantic-release/github": "^12.0.2",
|
||||||
"@semantic-release/npm": "^13.1.2",
|
"@semantic-release/npm": "^13.1.2",
|
||||||
"@semantic-release/release-notes-generator": "^14.1.0",
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
||||||
"@testcontainers/redis": "^11.8.1",
|
"@testcontainers/redis": "^11.9.0",
|
||||||
"@turbo/gen": "^2.6.1",
|
"@turbo/gen": "^2.6.3",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
"@vitest/coverage-v8": "^4.0.10",
|
"@vitest/coverage-v8": "^4.0.15",
|
||||||
"@vitest/ui": "^4.0.10",
|
"@vitest/ui": "^4.0.15",
|
||||||
"conventional-changelog-conventionalcommits": "^9.1.0",
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"jsdom": "^27.2.0",
|
"jsdom": "^27.2.0",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"semantic-release": "^25.0.2",
|
"semantic-release": "^25.0.2",
|
||||||
"testcontainers": "^11.8.1",
|
"testcontainers": "^11.9.0",
|
||||||
"turbo": "^2.6.1",
|
"turbo": "^2.6.3",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^4.0.10"
|
"vitest": "^4.0.15"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.22.0",
|
"packageManager": "pnpm@10.24.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=24.11.1",
|
"node": ">=24.11.1",
|
||||||
"pnpm": ">=10.22.0"
|
"pnpm": ">=10.24.0"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
@@ -82,20 +82,20 @@
|
|||||||
"axios@>=1.0.0 <1.8.2": ">=1.13.2",
|
"axios@>=1.0.0 <1.8.2": ">=1.13.2",
|
||||||
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
|
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
|
||||||
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
|
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
|
||||||
"esbuild@<=0.24.2": ">=0.27.0",
|
"esbuild@<=0.24.2": ">=0.27.1",
|
||||||
"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.10.6",
|
"hono@<4.6.5": ">=4.10.7",
|
||||||
"linkifyjs@<4.3.2": ">=4.3.2",
|
"linkifyjs@<4.3.2": ">=4.3.2",
|
||||||
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
|
||||||
"prismjs@<1.30.0": ">=1.30.0",
|
"prismjs@<1.30.0": ">=1.30.0",
|
||||||
"proxmox-api>undici": "7.16.0",
|
"proxmox-api>undici": "7.16.0",
|
||||||
"react-is": "^19.2.0",
|
"react-is": "^19.2.1",
|
||||||
"rollup@>=4.0.0 <4.22.4": ">=4.53.3",
|
"rollup@>=4.0.0 <4.22.4": ">=4.53.3",
|
||||||
"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.1",
|
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.1",
|
||||||
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.1",
|
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.1",
|
||||||
"tmp@<=0.2.3": ">=0.2.5",
|
"tmp@<=0.2.3": ">=0.2.5",
|
||||||
"vite@>=5.0.0 <=5.4.18": ">=7.2.2"
|
"vite@>=5.0.0 <=5.4.18": ">=7.2.6"
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"@types/node-unifi": "patches/@types__node-unifi.patch",
|
"@types/node-unifi": "patches/@types__node-unifi.patch",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@homarr/server-settings": "workspace:^0.1.0",
|
"@homarr/server-settings": "workspace:^0.1.0",
|
||||||
"@umami/node": "^0.4.0",
|
"@umami/node": "^0.4.0",
|
||||||
"superjson": "2.2.5"
|
"superjson": "2.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
+11
-11
@@ -43,25 +43,25 @@
|
|||||||
"@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.90.10",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@trpc/client": "^11.7.1",
|
"@trpc/client": "^11.7.2",
|
||||||
"@trpc/react-query": "^11.7.1",
|
"@trpc/react-query": "^11.7.2",
|
||||||
"@trpc/server": "^11.7.1",
|
"@trpc/server": "^11.7.2",
|
||||||
"@trpc/tanstack-react-query": "^11.7.1",
|
"@trpc/tanstack-react-query": "^11.7.2",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"trpc-to-openapi": "^3.1.0",
|
"trpc-to-openapi": "^3.1.0",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,12 +34,12 @@
|
|||||||
"@homarr/validation": "workspace:^0.1.0",
|
"@homarr/validation": "workspace:^0.1.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"cookies": "^0.9.1",
|
"cookies": "^0.9.1",
|
||||||
"ldapts": "8.0.9",
|
"ldapts": "8.0.14",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"next-auth": "5.0.0-beta.30",
|
"next-auth": "5.0.0-beta.30",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
"@types/bcrypt": "6.0.0",
|
"@types/bcrypt": "6.0.0",
|
||||||
"@types/cookies": "0.9.2",
|
"@types/cookies": "0.9.2",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,14 +6,14 @@ import type { Database, InferInsertModel } from "@homarr/db";
|
|||||||
import { and, eq } from "@homarr/db";
|
import { and, eq } from "@homarr/db";
|
||||||
import { users } from "@homarr/db/schema";
|
import { users } from "@homarr/db/schema";
|
||||||
import { logger } from "@homarr/log";
|
import { logger } from "@homarr/log";
|
||||||
import type { userSignInSchema } from "@homarr/validation/user";
|
import type { ldapSignInSchema } from "@homarr/validation/user";
|
||||||
|
|
||||||
import { env } from "../../../env";
|
import { env } from "../../../env";
|
||||||
import { LdapClient } from "../ldap-client";
|
import { LdapClient } from "../ldap-client";
|
||||||
|
|
||||||
export const authorizeWithLdapCredentialsAsync = async (
|
export const authorizeWithLdapCredentialsAsync = async (
|
||||||
db: Database,
|
db: Database,
|
||||||
credentials: z.infer<typeof userSignInSchema>,
|
credentials: z.infer<typeof ldapSignInSchema>,
|
||||||
) => {
|
) => {
|
||||||
logger.info(`user ${credentials.name} is trying to log in using LDAP. Connecting to LDAP server...`);
|
logger.info(`user ${credentials.name} is trying to log in using LDAP. Connecting to LDAP server...`);
|
||||||
const client = new LdapClient();
|
const client = new LdapClient();
|
||||||
@@ -38,7 +38,14 @@ export const authorizeWithLdapCredentialsAsync = async (
|
|||||||
attributes: [env.AUTH_LDAP_USERNAME_ATTRIBUTE, env.AUTH_LDAP_USER_MAIL_ATTRIBUTE],
|
attributes: [env.AUTH_LDAP_USERNAME_ATTRIBUTE, env.AUTH_LDAP_USER_MAIL_ATTRIBUTE],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((entries) => entries.at(0));
|
.then((entries) => {
|
||||||
|
if (entries.length > 1) {
|
||||||
|
logger.warn(`Multiple LDAP users found for ${credentials.name}, expected only one.`);
|
||||||
|
throw new CredentialsSignin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries.at(0);
|
||||||
|
});
|
||||||
|
|
||||||
if (!ldapUser) {
|
if (!ldapUser) {
|
||||||
logger.warn(`User ${credentials.name} not found in LDAP`);
|
logger.warn(`User ${credentials.name} not found in LDAP`);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type Credentials from "@auth/core/providers/credentials";
|
import type Credentials from "@auth/core/providers/credentials";
|
||||||
|
|
||||||
import type { Database } from "@homarr/db";
|
import type { Database } from "@homarr/db";
|
||||||
import { userSignInSchema } from "@homarr/validation/user";
|
import { ldapSignInSchema, userSignInSchema } from "@homarr/validation/user";
|
||||||
|
|
||||||
import { authorizeWithBasicCredentialsAsync } from "./authorization/basic-authorization";
|
import { authorizeWithBasicCredentialsAsync } from "./authorization/basic-authorization";
|
||||||
import { authorizeWithLdapCredentialsAsync } from "./authorization/ldap-authorization";
|
import { authorizeWithLdapCredentialsAsync } from "./authorization/ldap-authorization";
|
||||||
@@ -28,7 +28,7 @@ export const createLdapConfiguration = (db: Database) =>
|
|||||||
name: "Ldap",
|
name: "Ldap",
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
async authorize(credentials) {
|
async authorize(credentials) {
|
||||||
const data = await userSignInSchema.parseAsync(credentials);
|
const data = await ldapSignInSchema.parseAsync(credentials);
|
||||||
return await authorizeWithLdapCredentialsAsync(db, data).catch(() => null);
|
return await authorizeWithLdapCredentialsAsync(db, data).catch(() => null);
|
||||||
},
|
},
|
||||||
}) satisfies CredentialsConfiguration;
|
}) satisfies CredentialsConfiguration;
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/api": "workspace:^0.1.0",
|
"@homarr/api": "workspace:^0.1.0",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,12 @@
|
|||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"dns-caching": "^0.2.7",
|
"dns-caching": "^0.2.7",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"undici": "7.16.0",
|
"undici": "7.16.0",
|
||||||
"zod": "^4.1.12",
|
"zod": "^4.1.13",
|
||||||
"zod-validation-error": "^5.0.0"
|
"zod-validation-error": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@t3-oss/env-nextjs": "^0.13.8",
|
"@t3-oss/env-nextjs": "^0.13.8",
|
||||||
"ioredis": "5.8.2",
|
"ioredis": "5.8.2",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -29,20 +29,20 @@
|
|||||||
"@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",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@tanstack/react-query": "^5.90.10",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@trpc/client": "^11.7.1",
|
"@trpc/client": "^11.7.2",
|
||||||
"@trpc/server": "^11.7.1",
|
"@trpc/server": "^11.7.2",
|
||||||
"@trpc/tanstack-react-query": "^11.7.1",
|
"@trpc/tanstack-react-query": "^11.7.2",
|
||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/react": "19.2.6",
|
"@types/react": "19.2.7",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,18 +49,18 @@
|
|||||||
"@homarr/definitions": "workspace:^0.1.0",
|
"@homarr/definitions": "workspace:^0.1.0",
|
||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "workspace:^0.1.0",
|
||||||
"@homarr/server-settings": "workspace:^0.1.0",
|
"@homarr/server-settings": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@paralleldrive/cuid2": "^3.1.0",
|
"@paralleldrive/cuid2": "^3.1.0",
|
||||||
"@testcontainers/mysql": "^11.8.1",
|
"@testcontainers/mysql": "^11.9.0",
|
||||||
"@testcontainers/postgresql": "^11.8.1",
|
"@testcontainers/postgresql": "^11.9.0",
|
||||||
"better-sqlite3": "^12.4.1",
|
"better-sqlite3": "^12.5.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"drizzle-kit": "^0.31.7",
|
"drizzle-kit": "^0.31.8",
|
||||||
"drizzle-orm": "^0.44.7",
|
"drizzle-orm": "^0.45.0",
|
||||||
"drizzle-zod": "^0.8.3",
|
"drizzle-zod": "^0.8.3",
|
||||||
"mysql2": "3.15.3",
|
"mysql2": "3.15.3",
|
||||||
"pg": "^8.16.3",
|
"pg": "^8.16.3",
|
||||||
"superjson": "2.2.5"
|
"superjson": "2.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
@@ -69,9 +69,9 @@
|
|||||||
"@types/better-sqlite3": "7.6.13",
|
"@types/better-sqlite3": "7.6.13",
|
||||||
"@types/pg": "^8.15.6",
|
"@types/pg": "^8.15.6",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.7.4",
|
||||||
"tsx": "4.20.4",
|
"tsx": "4.20.4",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "workspace:^0.1.0",
|
||||||
"fast-xml-parser": "^5.3.2",
|
"fast-xml-parser": "^5.3.2",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ export type HomarrDocumentationPath =
|
|||||||
| "/docs/getting-started/installation/proxmox"
|
| "/docs/getting-started/installation/proxmox"
|
||||||
| "/docs/getting-started/installation/qnap"
|
| "/docs/getting-started/installation/qnap"
|
||||||
| "/docs/getting-started/installation/railway"
|
| "/docs/getting-started/installation/railway"
|
||||||
|
| "/docs/getting-started/installation/runtipi"
|
||||||
| "/docs/getting-started/installation/saltbox"
|
| "/docs/getting-started/installation/saltbox"
|
||||||
| "/docs/getting-started/installation/source"
|
| "/docs/getting-started/installation/source"
|
||||||
| "/docs/getting-started/installation/synology"
|
| "/docs/getting-started/installation/synology"
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
"@homarr/common": "workspace:^0.1.0",
|
"@homarr/common": "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",
|
||||||
"@mantine/form": "^8.3.8",
|
"@mantine/form": "^8.3.9",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import type { ChangeEvent, FocusEvent } from "react";
|
import type { ChangeEvent, FocusEvent } from "react";
|
||||||
|
|
||||||
export interface InputPropsFor<T, TOnChangeArg, TComponent extends HTMLElement = HTMLInputElement>
|
export interface InputPropsFor<T, TOnChangeArg, TComponent extends HTMLElement = HTMLInputElement> extends BasePropsFor<
|
||||||
extends BasePropsFor<TOnChangeArg, TComponent> {
|
TOnChangeArg,
|
||||||
|
TComponent
|
||||||
|
> {
|
||||||
value?: T;
|
value?: T;
|
||||||
defaultValue?: T;
|
defaultValue?: T;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@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.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -16,7 +16,19 @@ interface UploadMediaProps {
|
|||||||
|
|
||||||
export const UploadMedia = ({ children, onSettled, onSuccess, multiple = false }: UploadMediaProps) => {
|
export const UploadMedia = ({ children, onSettled, onSuccess, multiple = false }: UploadMediaProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const { mutateAsync, isPending } = clientApi.media.uploadMedia.useMutation();
|
const { mutateAsync, isPending } = clientApi.media.uploadMedia.useMutation({
|
||||||
|
async onSuccess(mediaIds) {
|
||||||
|
await onSuccess?.(
|
||||||
|
mediaIds.map((id) => ({
|
||||||
|
id,
|
||||||
|
url: `/api/user-medias/${id}`,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async onSettled() {
|
||||||
|
await onSettled?.();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const handleFileUploadAsync = async (files: File[] | File | null) => {
|
const handleFileUploadAsync = async (files: File[] | File | null) => {
|
||||||
if (!files || (Array.isArray(files) && files.length === 0)) return;
|
if (!files || (Array.isArray(files) && files.length === 0)) return;
|
||||||
@@ -24,25 +36,16 @@ export const UploadMedia = ({ children, onSettled, onSuccess, multiple = false }
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
filesArray.forEach((file) => formData.append("files", file));
|
filesArray.forEach((file) => formData.append("files", file));
|
||||||
await mutateAsync(formData, {
|
await mutateAsync(formData, {
|
||||||
async onSuccess(mediaIds) {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
message: t("media.action.upload.notification.success.message"),
|
message: t("media.action.upload.notification.success.message"),
|
||||||
});
|
});
|
||||||
await onSuccess?.(
|
|
||||||
mediaIds.map((id) => ({
|
|
||||||
id,
|
|
||||||
url: `/api/user-medias/${id}`,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
message: t("media.action.upload.notification.error.message"),
|
message: t("media.action.upload.notification.error.message"),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async onSettled() {
|
|
||||||
await onSettled?.();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"tsdav": "^2.1.6",
|
"tsdav": "^2.1.6",
|
||||||
"undici": "7.16.0",
|
"undici": "7.16.0",
|
||||||
"xml2js": "^0.6.2",
|
"xml2js": "^0.6.2",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export class TransmissionIntegration extends Integration implements IDownloadCli
|
|||||||
name: torrent.name,
|
name: torrent.name,
|
||||||
size: torrent.totalSize,
|
size: torrent.totalSize,
|
||||||
sent: torrent.uploadedEver,
|
sent: torrent.uploadedEver,
|
||||||
|
received: torrent.downloadedEver,
|
||||||
downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined,
|
downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined,
|
||||||
upSpeed: torrent.rateUpload,
|
upSpeed: torrent.rateUpload,
|
||||||
time:
|
time:
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export const downloadClientItemSchema = z.object({
|
|||||||
size: z.number(),
|
size: z.number(),
|
||||||
/** Total uploaded in Bytes, only required for Torrent items */
|
/** Total uploaded in Bytes, only required for Torrent items */
|
||||||
sent: z.number().optional(),
|
sent: z.number().optional(),
|
||||||
|
/** Total downloaded in Bytes, only required for Torrent items */
|
||||||
|
received: z.number().optional(),
|
||||||
/** Download speed in Bytes/s, only required if not complete
|
/** Download speed in Bytes/s, only required if not complete
|
||||||
* (Says 0 only if it should be downloading but isn't) */
|
* (Says 0 only if it should be downloading but isn't) */
|
||||||
downSpeed: z.number().optional(),
|
downSpeed: z.number().optional(),
|
||||||
|
|||||||
@@ -169,17 +169,15 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat
|
|||||||
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
|
||||||
const token = super.getSecretValue("apiKey");
|
const token = super.getSecretValue("apiKey");
|
||||||
|
|
||||||
const response = await input.fetchAsync(this.url("/"), {
|
const response = await input.fetchAsync(super.url("/prefs"), {
|
||||||
headers: {
|
headers: {
|
||||||
"X-Plex-Token": token,
|
"X-Plex-Token": token,
|
||||||
|
Accept: "application/json",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) return TestConnectionError.StatusResult(response);
|
if (!response.ok) return TestConnectionError.StatusResult(response);
|
||||||
|
|
||||||
const result = await response.text();
|
|
||||||
|
|
||||||
await PlexIntegration.parseXmlAsync<PlexResponse>(result);
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/core": "workspace:^0.1.0",
|
"@homarr/core": "workspace:^0.1.0",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"winston": "3.18.3",
|
"winston": "3.19.0",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -33,13 +33,13 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@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.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { z } from "zod/v4";
|
|||||||
|
|
||||||
import type { RouterOutputs } from "@homarr/api";
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
import type { MaybePromise } from "@homarr/common/types";
|
|
||||||
import { AppForm } from "@homarr/forms-collection";
|
import { AppForm } from "@homarr/forms-collection";
|
||||||
import { createModal } from "@homarr/modals";
|
import { createModal } from "@homarr/modals";
|
||||||
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
||||||
@@ -10,7 +9,7 @@ import { useI18n, useScopedI18n } from "@homarr/translation/client";
|
|||||||
import type { appManageSchema } from "@homarr/validation/app";
|
import type { appManageSchema } from "@homarr/validation/app";
|
||||||
|
|
||||||
interface QuickAddAppModalProps {
|
interface QuickAddAppModalProps {
|
||||||
onClose: (createdApp: Omit<RouterOutputs["app"]["create"], "appId">) => MaybePromise<void>;
|
onClose: (createdApp: Omit<RouterOutputs["app"]["create"], "appId">) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const QuickAddAppModal = createModal<QuickAddAppModalProps>(({ actions, innerProps }) => {
|
export const QuickAddAppModal = createModal<QuickAddAppModalProps>(({ actions, innerProps }) => {
|
||||||
@@ -28,13 +27,13 @@ export const QuickAddAppModal = createModal<QuickAddAppModalProps>(({ actions, i
|
|||||||
|
|
||||||
const handleSubmit = (values: z.infer<typeof appManageSchema>) => {
|
const handleSubmit = (values: z.infer<typeof appManageSchema>) => {
|
||||||
mutate(values, {
|
mutate(values, {
|
||||||
async onSuccess(app) {
|
onSuccess(app) {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: tScoped("success.title"),
|
title: tScoped("success.title"),
|
||||||
message: tScoped("success.message"),
|
message: tScoped("success.message"),
|
||||||
});
|
});
|
||||||
|
|
||||||
await innerProps.onClose(app);
|
innerProps.onClose(app);
|
||||||
actions.closeModal();
|
actions.closeModal();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Button, Group, Stack, Text, TextInput } from "@mantine/core";
|
import { Button, Group, Stack, Text, TextInput } from "@mantine/core";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
import type { MaybePromise } from "@homarr/common/types";
|
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||||
import { useZodForm } from "@homarr/form";
|
import { useZodForm } from "@homarr/form";
|
||||||
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
||||||
import { useI18n } from "@homarr/translation/client";
|
import { useI18n } from "@homarr/translation/client";
|
||||||
@@ -15,7 +15,6 @@ interface InnerProps {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
onSuccess: () => MaybePromise<void>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DuplicateBoardModal = createModal<InnerProps>(({ actions, innerProps }) => {
|
export const DuplicateBoardModal = createModal<InnerProps>(({ actions, innerProps }) => {
|
||||||
@@ -27,7 +26,11 @@ export const DuplicateBoardModal = createModal<InnerProps>(({ actions, innerProp
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const boardNameStatus = useBoardNameStatus(form.values.name);
|
const boardNameStatus = useBoardNameStatus(form.values.name);
|
||||||
const { mutateAsync, isPending } = clientApi.board.duplicateBoard.useMutation();
|
const { mutateAsync, isPending } = clientApi.board.duplicateBoard.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/boards");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
@@ -40,13 +43,12 @@ export const DuplicateBoardModal = createModal<InnerProps>(({ actions, innerProp
|
|||||||
id: innerProps.board.id,
|
id: innerProps.board.id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
actions.closeModal();
|
actions.closeModal();
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t("board.action.duplicate.notification.success.title"),
|
title: t("board.action.duplicate.notification.success.title"),
|
||||||
message: t("board.action.duplicate.notification.success.message"),
|
message: t("board.action.duplicate.notification.success.message"),
|
||||||
});
|
});
|
||||||
await innerProps.onSuccess();
|
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
|
|||||||
@@ -65,7 +65,11 @@ export const ImportBoardModal = createModal(({ actions }) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const { mutateAsync, isPending } = clientApi.board.importOldmarrConfig.useMutation();
|
const { mutateAsync, isPending } = clientApi.board.importOldmarrConfig.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await revalidatePathActionAsync("/manage/boards");
|
||||||
|
},
|
||||||
|
});
|
||||||
const boardNameStatus = useBoardNameStatus(form.values.configuration.name);
|
const boardNameStatus = useBoardNameStatus(form.values.configuration.name);
|
||||||
|
|
||||||
const handleSubmitAsync = async (values: { file: File; configuration: OldmarrImportConfiguration }) => {
|
const handleSubmitAsync = async (values: { file: File; configuration: OldmarrImportConfiguration }) => {
|
||||||
@@ -74,9 +78,8 @@ export const ImportBoardModal = createModal(({ actions }) => {
|
|||||||
formData.set("configuration", JSON.stringify(values.configuration));
|
formData.set("configuration", JSON.stringify(values.configuration));
|
||||||
|
|
||||||
await mutateAsync(formData, {
|
await mutateAsync(formData, {
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
actions.closeModal();
|
actions.closeModal();
|
||||||
await revalidatePathActionAsync("/manage/boards");
|
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: tOldImport("notification.success.title"),
|
title: tOldImport("notification.success.title"),
|
||||||
message: tOldImport("notification.success.message"),
|
message: tOldImport("notification.success.message"),
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ export const AddCertificateModal = createModal<InnerProps>(({ actions, innerProp
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const { mutateAsync } = clientApi.certificates.addCertificate.useMutation();
|
const { mutateAsync } = clientApi.certificates.addCertificate.useMutation({
|
||||||
|
async onSuccess() {
|
||||||
|
await innerProps.onSuccess?.();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
@@ -35,12 +39,11 @@ export const AddCertificateModal = createModal<InnerProps>(({ actions, innerProp
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.set("file", values.file);
|
formData.set("file", values.file);
|
||||||
await mutateAsync(formData, {
|
await mutateAsync(formData, {
|
||||||
async onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t("certificate.action.create.notification.success.title"),
|
title: t("certificate.action.create.notification.success.title"),
|
||||||
message: t("certificate.action.create.notification.success.message"),
|
message: t("certificate.action.create.notification.success.message"),
|
||||||
});
|
});
|
||||||
await innerProps.onSuccess?.();
|
|
||||||
actions.closeModal();
|
actions.closeModal();
|
||||||
},
|
},
|
||||||
onError() {
|
onError() {
|
||||||
|
|||||||
@@ -24,9 +24,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"react": "19.2.0"
|
"react": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@mantine/notifications": "^8.3.8",
|
"@mantine/notifications": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0"
|
"@tabler/icons-react": "^3.35.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -37,14 +37,14 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@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.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"adm-zip": "0.5.16",
|
"adm-zip": "0.5.16",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"zod": "^4.1.12",
|
"zod": "^4.1.13",
|
||||||
"zod-form-data": "^3.0.1"
|
"zod-form-data": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export const ImportTokenModal = createModal<InnerProps>(({ actions, innerProps }
|
|||||||
mutate(
|
mutate(
|
||||||
{ checksum: innerProps.checksum, token: values.token },
|
{ checksum: innerProps.checksum, token: values.token },
|
||||||
{
|
{
|
||||||
async onSuccess(isValid) {
|
onSuccess(isValid) {
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
actions.closeModal();
|
actions.closeModal();
|
||||||
await innerProps.onSuccessAsync(values.token);
|
void innerProps.onSuccessAsync(values.token);
|
||||||
} else {
|
} else {
|
||||||
showErrorNotification({
|
showErrorNotification({
|
||||||
title: tTokenModal("notification.error.title"),
|
title: tTokenModal("notification.error.title"),
|
||||||
|
|||||||
@@ -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.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"@homarr/definitions": "workspace:^",
|
"@homarr/definitions": "workspace:^",
|
||||||
"@homarr/log": "workspace:^",
|
"@homarr/log": "workspace:^",
|
||||||
"ioredis": "5.8.2",
|
"ioredis": "5.8.2",
|
||||||
"superjson": "2.2.5"
|
"superjson": "2.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -32,9 +32,9 @@
|
|||||||
"@homarr/redis": "workspace:^0.1.0",
|
"@homarr/redis": "workspace:^0.1.0",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"octokit": "^5.0.5",
|
"octokit": "^5.0.5",
|
||||||
"superjson": "2.2.5",
|
"superjson": "2.2.6",
|
||||||
"undici": "7.16.0",
|
"undici": "7.16.0",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -26,10 +26,10 @@
|
|||||||
"@homarr/api": "workspace:^0.1.0",
|
"@homarr/api": "workspace:^0.1.0",
|
||||||
"@homarr/db": "workspace:^0.1.0",
|
"@homarr/db": "workspace:^0.1.0",
|
||||||
"@homarr/server-settings": "workspace:^0.1.0",
|
"@homarr/server-settings": "workspace:^0.1.0",
|
||||||
"@mantine/dates": "^8.3.8",
|
"@mantine/dates": "^8.3.9",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -33,14 +33,14 @@
|
|||||||
"@homarr/settings": "workspace:^0.1.0",
|
"@homarr/settings": "workspace:^0.1.0",
|
||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@mantine/spotlight": "^8.3.8",
|
"@mantine/spotlight": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"jotai": "^2.15.1",
|
"jotai": "^2.15.2",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"use-deep-compare-effect": "^1.8.1"
|
"use-deep-compare-effect": "^1.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -32,10 +32,10 @@
|
|||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"deepmerge": "4.3.1",
|
"deepmerge": "4.3.1",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"next-intl": "4.5.5",
|
"next-intl": "4.5.8",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -2232,7 +2232,7 @@
|
|||||||
"unknown": "Ukendt",
|
"unknown": "Ukendt",
|
||||||
"pending": "Afventende",
|
"pending": "Afventende",
|
||||||
"processing": "Behandler",
|
"processing": "Behandler",
|
||||||
"requested": "",
|
"requested": "Anmodet",
|
||||||
"partiallyAvailable": "Delvis",
|
"partiallyAvailable": "Delvis",
|
||||||
"available": "Tilgængelig",
|
"available": "Tilgængelig",
|
||||||
"blacklisted": "Blacklistet",
|
"blacklisted": "Blacklistet",
|
||||||
|
|||||||
@@ -1939,7 +1939,23 @@
|
|||||||
"dockerContainers": {
|
"dockerContainers": {
|
||||||
"name": "Docker stats",
|
"name": "Docker stats",
|
||||||
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
|
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
|
||||||
"option": {},
|
"option": {
|
||||||
|
"enableRowSorting": {
|
||||||
|
"label": "Enable items sorting"
|
||||||
|
},
|
||||||
|
"defaultSort": {
|
||||||
|
"label": "Column used for sorting by default",
|
||||||
|
"option": {
|
||||||
|
"name": "Name",
|
||||||
|
"state": "State",
|
||||||
|
"cpuUsage": "CPU usage",
|
||||||
|
"memoryUsage": "Memory usage"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"descendingDefaultSort": {
|
||||||
|
"label": "Invert sorting"
|
||||||
|
}
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"internalServerError": "Failed to fetch containers stats"
|
"internalServerError": "Failed to fetch containers stats"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2232,7 +2232,7 @@
|
|||||||
"unknown": "Desconocido",
|
"unknown": "Desconocido",
|
||||||
"pending": "Pendiente",
|
"pending": "Pendiente",
|
||||||
"processing": "Procesando",
|
"processing": "Procesando",
|
||||||
"requested": "",
|
"requested": "Solicitado",
|
||||||
"partiallyAvailable": "Parcial",
|
"partiallyAvailable": "Parcial",
|
||||||
"available": "Disponible",
|
"available": "Disponible",
|
||||||
"blacklisted": "Lista negra",
|
"blacklisted": "Lista negra",
|
||||||
|
|||||||
@@ -747,7 +747,7 @@
|
|||||||
},
|
},
|
||||||
"statusCode": {
|
"statusCode": {
|
||||||
"title": "Antwoord fout",
|
"title": "Antwoord fout",
|
||||||
"description": "",
|
"description": "Onverwachte {statusCode} ({reason}) reactie van <url></url>. Controleer of de URL wijst naar de basis-URL van de integratie.",
|
||||||
"otherDescription": "",
|
"otherDescription": "",
|
||||||
"reason": {
|
"reason": {
|
||||||
"badRequest": "Onjuist verzoek",
|
"badRequest": "Onjuist verzoek",
|
||||||
@@ -2232,7 +2232,7 @@
|
|||||||
"unknown": "Onbekend",
|
"unknown": "Onbekend",
|
||||||
"pending": "In afwachting",
|
"pending": "In afwachting",
|
||||||
"processing": "Verwerken",
|
"processing": "Verwerken",
|
||||||
"requested": "",
|
"requested": "Aangevraagd",
|
||||||
"partiallyAvailable": "Gedeeltelijk",
|
"partiallyAvailable": "Gedeeltelijk",
|
||||||
"available": "Beschikbaar",
|
"available": "Beschikbaar",
|
||||||
"blacklisted": "Geblacklist",
|
"blacklisted": "Geblacklist",
|
||||||
|
|||||||
@@ -341,7 +341,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"full-all": {
|
"full-all": {
|
||||||
"label": "",
|
"label": "Acesso completo a aplicativos",
|
||||||
"description": ""
|
"description": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,14 +30,14 @@
|
|||||||
"@homarr/log": "workspace:^0.1.0",
|
"@homarr/log": "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",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/dates": "^8.3.8",
|
"@mantine/dates": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"svgson": "^5.3.1"
|
"svgson": "^5.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ interface BaseSelectItem {
|
|||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectWithCustomItemsProps<TSelectItem extends BaseSelectItem>
|
export interface SelectWithCustomItemsProps<TSelectItem extends BaseSelectItem> extends Pick<
|
||||||
extends Pick<SelectProps, "label" | "error" | "defaultValue" | "value" | "onChange" | "placeholder" | "clearable"> {
|
SelectProps,
|
||||||
|
"label" | "error" | "defaultValue" | "value" | "onChange" | "placeholder" | "clearable"
|
||||||
|
> {
|
||||||
data: TSelectItem[];
|
data: TSelectItem[];
|
||||||
description?: string;
|
description?: string;
|
||||||
withAsterisk?: boolean;
|
withAsterisk?: boolean;
|
||||||
|
|||||||
@@ -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.1.12",
|
"zod": "^4.1.13",
|
||||||
"zod-form-data": "^3.0.1"
|
"zod-form-data": "^3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -69,6 +69,17 @@ export const userSignInSchema = z.object({
|
|||||||
password: z.string().min(1),
|
password: z.string().min(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const ldapSignInSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
// Prevent special characters that could lead to LDAP injection attacks
|
||||||
|
.regex(/^[^\\,+<>;"=)(*|!&]+$/, {
|
||||||
|
message: "Invalid characters in ldap username",
|
||||||
|
}),
|
||||||
|
password: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
export const userRegistrationSchema = addConfirmPasswordRefinement(
|
export const userRegistrationSchema = addConfirmPasswordRefinement(
|
||||||
z.object({
|
z.object({
|
||||||
username: usernameSchema,
|
username: usernameSchema,
|
||||||
|
|||||||
@@ -48,37 +48,37 @@
|
|||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@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/charts": "^8.3.8",
|
"@mantine/charts": "^8.3.9",
|
||||||
"@mantine/core": "^8.3.8",
|
"@mantine/core": "^8.3.9",
|
||||||
"@mantine/hooks": "^8.3.8",
|
"@mantine/hooks": "^8.3.9",
|
||||||
"@tabler/icons-react": "^3.35.0",
|
"@tabler/icons-react": "^3.35.0",
|
||||||
"@tiptap/extension-color": "2.27.1",
|
"@tiptap/extension-color": "3.13.0",
|
||||||
"@tiptap/extension-highlight": "2.27.1",
|
"@tiptap/extension-highlight": "3.13.0",
|
||||||
"@tiptap/extension-image": "2.27.1",
|
"@tiptap/extension-image": "3.13.0",
|
||||||
"@tiptap/extension-link": "^2.27.1",
|
"@tiptap/extension-link": "^3.13.0",
|
||||||
"@tiptap/extension-placeholder": "^2.27.1",
|
"@tiptap/extension-placeholder": "^3.13.0",
|
||||||
"@tiptap/extension-table": "2.27.1",
|
"@tiptap/extension-table": "3.13.0",
|
||||||
"@tiptap/extension-table-cell": "2.27.1",
|
"@tiptap/extension-table-cell": "3.13.0",
|
||||||
"@tiptap/extension-table-header": "2.27.1",
|
"@tiptap/extension-table-header": "3.13.0",
|
||||||
"@tiptap/extension-table-row": "2.27.1",
|
"@tiptap/extension-table-row": "3.13.0",
|
||||||
"@tiptap/extension-task-item": "2.27.1",
|
"@tiptap/extension-task-item": "3.13.0",
|
||||||
"@tiptap/extension-task-list": "2.27.1",
|
"@tiptap/extension-task-list": "3.13.0",
|
||||||
"@tiptap/extension-text-align": "2.27.1",
|
"@tiptap/extension-text-align": "3.13.0",
|
||||||
"@tiptap/extension-text-style": "2.27.1",
|
"@tiptap/extension-text-style": "3.13.0",
|
||||||
"@tiptap/extension-underline": "2.27.1",
|
"@tiptap/extension-underline": "3.13.0",
|
||||||
"@tiptap/react": "^2.27.1",
|
"@tiptap/react": "^3.13.0",
|
||||||
"@tiptap/starter-kit": "^2.27.1",
|
"@tiptap/starter-kit": "^3.13.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"mantine-form-zod-resolver": "^1.3.0",
|
"mantine-form-zod-resolver": "^1.3.0",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "16.0.3",
|
"next": "16.0.10",
|
||||||
"react": "19.2.0",
|
"react": "19.2.1",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.1",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"video.js": "^8.23.4",
|
"video.js": "^8.23.4",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ export const WidgetAppInput = ({ property, kind }: CommonWidgetInputProps<"app">
|
|||||||
variant="default"
|
variant="default"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openModal({
|
openModal({
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
onClose(createdAppId) {
|
||||||
async onClose(createdAppId) {
|
void refetch().then(() => {
|
||||||
await refetch();
|
form.setFieldValue(`options.${property}`, createdAppId);
|
||||||
form.setFieldValue(`options.${property}`, createdAppId);
|
});
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ const createColumns = (
|
|||||||
t: ReturnType<typeof useScopedI18n<"docker">>,
|
t: ReturnType<typeof useScopedI18n<"docker">>,
|
||||||
): MRT_ColumnDef<RouterOutputs["docker"]["getContainers"]["containers"][number]>[] => [
|
): MRT_ColumnDef<RouterOutputs["docker"]["getContainers"]["containers"][number]>[] => [
|
||||||
{
|
{
|
||||||
|
id: "name",
|
||||||
accessorKey: "name",
|
accessorKey: "name",
|
||||||
header: t("field.name.label"),
|
header: t("field.name.label"),
|
||||||
Cell({ renderedCellValue, row }) {
|
Cell({ renderedCellValue, row }) {
|
||||||
@@ -70,6 +71,7 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "state",
|
||||||
accessorKey: "state",
|
accessorKey: "state",
|
||||||
size: 100,
|
size: 100,
|
||||||
header: t("field.state.label"),
|
header: t("field.state.label"),
|
||||||
@@ -78,6 +80,13 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "cpuUsage",
|
||||||
|
sortingFn: (rowA, rowB) => {
|
||||||
|
const cpuUsageA = safeValue(rowA.original.cpuUsage);
|
||||||
|
const cpuUsageB = safeValue(rowB.original.cpuUsage);
|
||||||
|
|
||||||
|
return cpuUsageA - cpuUsageB;
|
||||||
|
},
|
||||||
accessorKey: "cpuUsage",
|
accessorKey: "cpuUsage",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("field.stats.cpu.label"),
|
header: t("field.stats.cpu.label"),
|
||||||
@@ -92,6 +101,13 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "memoryUsage",
|
||||||
|
sortingFn: (rowA, rowB) => {
|
||||||
|
const memoryUsageA = safeValue(rowA.original.memoryUsage);
|
||||||
|
const memoryUsageB = safeValue(rowB.original.memoryUsage);
|
||||||
|
|
||||||
|
return memoryUsageA - memoryUsageB;
|
||||||
|
},
|
||||||
accessorKey: "memoryUsage",
|
accessorKey: "memoryUsage",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("field.stats.memory.label"),
|
header: t("field.stats.memory.label"),
|
||||||
@@ -106,14 +122,20 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
id: "actions",
|
||||||
accessorKey: "actions",
|
accessorKey: "actions",
|
||||||
size: 80,
|
size: 80,
|
||||||
header: t("action.title"),
|
header: t("action.title"),
|
||||||
|
enableSorting: false,
|
||||||
Cell({ row }) {
|
Cell({ row }) {
|
||||||
const utils = clientApi.useUtils();
|
const utils = clientApi.useUtils();
|
||||||
const { mutateAsync: startContainer } = clientApi.docker.startAll.useMutation();
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
const { mutateAsync: stopContainer } = clientApi.docker.stopAll.useMutation();
|
const onSettled = async () => {
|
||||||
const { mutateAsync: restartContainer } = clientApi.docker.restartAll.useMutation();
|
await utils.docker.getContainers.invalidate();
|
||||||
|
};
|
||||||
|
const { mutateAsync: startContainer } = clientApi.docker.startAll.useMutation({ onSettled });
|
||||||
|
const { mutateAsync: stopContainer } = clientApi.docker.stopAll.useMutation({ onSettled });
|
||||||
|
const { mutateAsync: restartContainer } = clientApi.docker.restartAll.useMutation({ onSettled });
|
||||||
|
|
||||||
const handleActionAsync = async (action: "start" | "stop" | "restart") => {
|
const handleActionAsync = async (action: "start" | "stop" | "restart") => {
|
||||||
const mutation = action === "start" ? startContainer : action === "stop" ? stopContainer : restartContainer;
|
const mutation = action === "start" ? startContainer : action === "stop" ? stopContainer : restartContainer;
|
||||||
@@ -121,9 +143,6 @@ const createColumns = (
|
|||||||
await mutation(
|
await mutation(
|
||||||
{ ids: [row.original.id] },
|
{ ids: [row.original.id] },
|
||||||
{
|
{
|
||||||
async onSettled() {
|
|
||||||
await utils.docker.getContainers.invalidate();
|
|
||||||
},
|
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
showSuccessNotification({
|
showSuccessNotification({
|
||||||
title: t(`action.${action}.notification.success.title`),
|
title: t(`action.${action}.notification.success.title`),
|
||||||
@@ -167,7 +186,7 @@ const createColumns = (
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function DockerWidget({ width }: WidgetComponentProps<"dockerContainers">) {
|
export default function DockerWidget({ options, width, isEditMode }: WidgetComponentProps<"dockerContainers">) {
|
||||||
const t = useScopedI18n("docker");
|
const t = useScopedI18n("docker");
|
||||||
const isTiny = width <= 256;
|
const isTiny = width <= 256;
|
||||||
|
|
||||||
@@ -191,8 +210,8 @@ export default function DockerWidget({ width }: WidgetComponentProps<"dockerCont
|
|||||||
enablePagination: false,
|
enablePagination: false,
|
||||||
enableTopToolbar: false,
|
enableTopToolbar: false,
|
||||||
enableBottomToolbar: false,
|
enableBottomToolbar: false,
|
||||||
enableSorting: false,
|
|
||||||
enableColumnActions: false,
|
enableColumnActions: false,
|
||||||
|
enableSorting: options.enableRowSorting && !isEditMode,
|
||||||
enableStickyHeader: false,
|
enableStickyHeader: false,
|
||||||
enableColumnOrdering: false,
|
enableColumnOrdering: false,
|
||||||
enableRowSelection: false,
|
enableRowSelection: false,
|
||||||
@@ -202,6 +221,7 @@ export default function DockerWidget({ width }: WidgetComponentProps<"dockerCont
|
|||||||
enableFilters: false,
|
enableFilters: false,
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
initialState: {
|
initialState: {
|
||||||
|
sorting: [{ id: options.defaultSort, desc: options.descendingDefaultSort }],
|
||||||
density: "xs",
|
density: "xs",
|
||||||
},
|
},
|
||||||
mantinePaperProps: {
|
mantinePaperProps: {
|
||||||
|
|||||||
@@ -1,12 +1,35 @@
|
|||||||
import { IconBrandDocker, IconServerOff } from "@tabler/icons-react";
|
import { IconBrandDocker, IconServerOff } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
import type { RouterOutputs } from "@homarr/api";
|
||||||
|
|
||||||
import { createWidgetDefinition } from "../definition";
|
import { createWidgetDefinition } from "../definition";
|
||||||
import { optionsBuilder } from "../options";
|
import { optionsBuilder } from "../options";
|
||||||
|
|
||||||
|
const columnsList = [
|
||||||
|
"name",
|
||||||
|
"state",
|
||||||
|
"cpuUsage",
|
||||||
|
"memoryUsage",
|
||||||
|
] as const satisfies (keyof RouterOutputs["docker"]["getContainers"]["containers"][number])[];
|
||||||
|
|
||||||
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
|
export const { definition, componentLoader } = createWidgetDefinition("dockerContainers", {
|
||||||
icon: IconBrandDocker,
|
icon: IconBrandDocker,
|
||||||
createOptions() {
|
createOptions() {
|
||||||
return optionsBuilder.from(() => ({}));
|
return optionsBuilder.from((factory) => ({
|
||||||
|
enableRowSorting: factory.switch({
|
||||||
|
defaultValue: false,
|
||||||
|
}),
|
||||||
|
defaultSort: factory.select({
|
||||||
|
defaultValue: "name",
|
||||||
|
options: columnsList.map((value) => ({
|
||||||
|
value,
|
||||||
|
label: (t) => t(`widget.dockerContainers.option.defaultSort.option.${value}`),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
descendingDefaultSort: factory.switch({
|
||||||
|
defaultValue: false,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
INTERNAL_SERVER_ERROR: {
|
INTERNAL_SERVER_ERROR: {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
import type { MRT_ColumnDef, MRT_VisibilityState } from "mantine-react-table";
|
import type { MRT_ColumnDef, MRT_VisibilityState } from "mantine-react-table";
|
||||||
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
|
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ import { useScopedI18n } from "@homarr/translation/client";
|
|||||||
|
|
||||||
import type { WidgetComponentProps } from "../definition";
|
import type { WidgetComponentProps } from "../definition";
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
interface QuickFilter {
|
interface QuickFilter {
|
||||||
integrationKinds: string[];
|
integrationKinds: string[];
|
||||||
statuses: ExtendedDownloadClientItem["state"][];
|
statuses: ExtendedDownloadClientItem["state"][];
|
||||||
@@ -188,14 +191,14 @@ export default function DownloadClientsWidget({
|
|||||||
)
|
)
|
||||||
//Add extrapolated data and actions if user is allowed interaction
|
//Add extrapolated data and actions if user is allowed interaction
|
||||||
.map((item): ExtendedDownloadClientItem => {
|
.map((item): ExtendedDownloadClientItem => {
|
||||||
const received = Math.floor(item.size * item.progress);
|
const received = item.received ?? Math.floor(item.size * item.progress);
|
||||||
const integrationIds = [pair.integration.id];
|
const integrationIds = [pair.integration.id];
|
||||||
return {
|
return {
|
||||||
integration: pair.integration,
|
integration: pair.integration,
|
||||||
...item,
|
...item,
|
||||||
category: item.category !== undefined && item.category.length > 0 ? item.category : undefined,
|
category: item.category !== undefined && item.category.length > 0 ? item.category : undefined,
|
||||||
received,
|
received,
|
||||||
ratio: item.sent !== undefined ? item.sent / (received || 1) : undefined,
|
ratio: item.sent !== undefined ? item.sent / item.size : undefined,
|
||||||
//Only add if permission to use mutations
|
//Only add if permission to use mutations
|
||||||
actions: integrationsWithInteractions.includes(pair.integration.id)
|
actions: integrationsWithInteractions.includes(pair.integration.id)
|
||||||
? {
|
? {
|
||||||
@@ -714,7 +717,10 @@ const ItemInfoModal = ({ items, currentIndex, opened, onClose }: ItemInfoModalPr
|
|||||||
/>
|
/>
|
||||||
{item.type !== "miscellaneous" && <NormalizedLine itemKey="ratio" values={item.ratio} />}
|
{item.type !== "miscellaneous" && <NormalizedLine itemKey="ratio" values={item.ratio} />}
|
||||||
<NormalizedLine itemKey="added" values={item.added === undefined ? "unknown" : dayjs(item.added).format()} />
|
<NormalizedLine itemKey="added" values={item.added === undefined ? "unknown" : dayjs(item.added).format()} />
|
||||||
<NormalizedLine itemKey="time" values={item.time !== 0 ? dayjs().add(item.time).format() : "∞"} />
|
<NormalizedLine
|
||||||
|
itemKey="time"
|
||||||
|
values={item.time !== 0 ? dayjs().add(item.time, "milliseconds").fromNow() : "∞"}
|
||||||
|
/>
|
||||||
<NormalizedLine itemKey="category" values={item.category} />
|
<NormalizedLine itemKey="category" values={item.category} />
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -41,21 +41,21 @@ import {
|
|||||||
IconX,
|
IconX,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import { Color } from "@tiptap/extension-color";
|
import { Color } from "@tiptap/extension-color";
|
||||||
import Highlight from "@tiptap/extension-highlight";
|
import { Highlight } from "@tiptap/extension-highlight";
|
||||||
import Image from "@tiptap/extension-image";
|
import { Image } from "@tiptap/extension-image";
|
||||||
import Placeholder from "@tiptap/extension-placeholder";
|
import { Placeholder } from "@tiptap/extension-placeholder";
|
||||||
import Table from "@tiptap/extension-table";
|
import { Table } from "@tiptap/extension-table";
|
||||||
import TableCell from "@tiptap/extension-table-cell";
|
import { TableCell } from "@tiptap/extension-table-cell";
|
||||||
import TableHeader from "@tiptap/extension-table-header";
|
import { TableHeader } from "@tiptap/extension-table-header";
|
||||||
import TableRow from "@tiptap/extension-table-row";
|
import { TableRow } from "@tiptap/extension-table-row";
|
||||||
import TaskItem from "@tiptap/extension-task-item";
|
import { TaskItem } from "@tiptap/extension-task-item";
|
||||||
import TaskList from "@tiptap/extension-task-list";
|
import { TaskList } from "@tiptap/extension-task-list";
|
||||||
import TextAlign from "@tiptap/extension-text-align";
|
import { TextAlign } from "@tiptap/extension-text-align";
|
||||||
import TextStyle from "@tiptap/extension-text-style";
|
import { TextStyle } from "@tiptap/extension-text-style";
|
||||||
import Underline from "@tiptap/extension-underline";
|
|
||||||
import type { Editor } from "@tiptap/react";
|
import type { Editor } from "@tiptap/react";
|
||||||
import { BubbleMenu, useEditor } from "@tiptap/react";
|
import { useEditor } from "@tiptap/react";
|
||||||
import StarterKit from "@tiptap/starter-kit";
|
import { BubbleMenu } from "@tiptap/react/menus";
|
||||||
|
import { StarterKit } from "@tiptap/starter-kit";
|
||||||
import type { Node } from "prosemirror-model";
|
import type { Node } from "prosemirror-model";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
@@ -133,7 +133,8 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
StarterKit,
|
// we use a custom link implementation from mantine
|
||||||
|
StarterKit.configure({ link: false }),
|
||||||
Table.configure({
|
Table.configure({
|
||||||
resizable: true,
|
resizable: true,
|
||||||
lastColumnResizable: false,
|
lastColumnResizable: false,
|
||||||
@@ -170,8 +171,9 @@ export function Notebook({ options, setOptions, isEditMode, boardId, itemId }: W
|
|||||||
TaskList.configure({ itemTypeName: "taskItem" }),
|
TaskList.configure({ itemTypeName: "taskItem" }),
|
||||||
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
TextAlign.configure({ types: ["heading", "paragraph"] }),
|
||||||
TextStyle,
|
TextStyle,
|
||||||
Underline,
|
|
||||||
],
|
],
|
||||||
|
shouldRerenderOnTransaction: true,
|
||||||
|
immediatelyRender: false,
|
||||||
content,
|
content,
|
||||||
onUpdate: ({ editor }) => {
|
onUpdate: ({ editor }) => {
|
||||||
setContent(editor.getHTML());
|
setContent(editor.getHTML());
|
||||||
|
|||||||
@@ -18,14 +18,17 @@ interface TextInput extends CommonInput<string> {
|
|||||||
validate?: z.ZodType<string>;
|
validate?: z.ZodType<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MultiSelectInput<TOptions extends SelectOption[]>
|
interface MultiSelectInput<TOptions extends SelectOption[]> extends CommonInput<
|
||||||
extends CommonInput<inferSelectOptionValue<TOptions[number]>[]> {
|
inferSelectOptionValue<TOptions[number]>[]
|
||||||
|
> {
|
||||||
options: TOptions;
|
options: TOptions;
|
||||||
searchable?: boolean;
|
searchable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SortableItemListInput<TItem, TOptionValue extends UniqueIdentifier>
|
export interface SortableItemListInput<TItem, TOptionValue extends UniqueIdentifier> extends Omit<
|
||||||
extends Omit<CommonInput<TOptionValue[]>, "withDescription"> {
|
CommonInput<TOptionValue[]>,
|
||||||
|
"withDescription"
|
||||||
|
> {
|
||||||
AddButton: (props: { addItem: (item: TItem) => void; values: TOptionValue[] }) => React.ReactNode;
|
AddButton: (props: { addItem: (item: TItem) => void; values: TOptionValue[] }) => React.ReactNode;
|
||||||
ItemComponent: (props: {
|
ItemComponent: (props: {
|
||||||
item: TItem;
|
item: TItem;
|
||||||
@@ -37,8 +40,9 @@ export interface SortableItemListInput<TItem, TOptionValue extends UniqueIdentif
|
|||||||
useData: (values: TOptionValue[]) => { data: TItem[] | undefined; isLoading: boolean; error: unknown };
|
useData: (values: TOptionValue[]) => { data: TItem[] | undefined; isLoading: boolean; error: unknown };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectInput<TOptions extends readonly SelectOption[]>
|
interface SelectInput<TOptions extends readonly SelectOption[]> extends CommonInput<
|
||||||
extends CommonInput<inferSelectOptionValue<TOptions[number]>> {
|
inferSelectOptionValue<TOptions[number]>
|
||||||
|
> {
|
||||||
options: TOptions;
|
options: TOptions;
|
||||||
searchable?: boolean;
|
searchable?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+1462
-1520
File diff suppressed because it is too large.
Load diff
+3
-1
@@ -2,5 +2,7 @@ packages:
|
|||||||
- apps/*
|
- apps/*
|
||||||
- packages/*
|
- packages/*
|
||||||
- tooling/*
|
- tooling/*
|
||||||
|
|
||||||
minimumReleaseAge: 4320 # Only download deps if they are at least 3 days old (in minutes)
|
minimumReleaseAge: 4320 # Only download deps if they are at least 3 days old (in minutes)
|
||||||
|
minimumReleaseAgeExclude:
|
||||||
|
- next
|
||||||
|
- "@next/*"
|
||||||
+12
-6
@@ -1,10 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Create sub directories in volume
|
# Create sub directories in volume
|
||||||
mkdir -p /appdata/db
|
mkdir -p /appdata/db
|
||||||
mkdir -p /appdata/redis
|
mkdir -p /appdata/redis
|
||||||
mkdir -p /appdata/trusted-certificates
|
mkdir -p /appdata/trusted-certificates
|
||||||
|
|
||||||
# Run migrations
|
# Run migrations
|
||||||
if [ $DB_MIGRATIONS_DISABLED = "true" ]; then
|
if [ "$DB_MIGRATIONS_DISABLED" = "true" ]; then
|
||||||
echo "DB migrations are disabled, skipping"
|
echo "DB migrations are disabled, skipping"
|
||||||
else
|
else
|
||||||
echo "Running DB migrations"
|
echo "Running DB migrations"
|
||||||
@@ -20,13 +22,15 @@ export CRON_JOB_API_KEY=$(openssl rand -base64 32)
|
|||||||
# 1. Replace the HOSTNAME in the nginx template file
|
# 1. Replace the HOSTNAME in the nginx template file
|
||||||
# 2. Create the nginx configuration file from the template
|
# 2. Create the nginx configuration file from the template
|
||||||
# 3. Start the nginx server
|
# 3. Start the nginx server
|
||||||
|
export HOSTNAME
|
||||||
envsubst '${HOSTNAME}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
envsubst '${HOSTNAME}' < /etc/nginx/templates/nginx.conf > /etc/nginx/nginx.conf
|
||||||
# Start services in the background and store their PIDs
|
# Start services in the background and store their PIDs
|
||||||
nginx -g 'daemon off;' &
|
nginx -g 'daemon off;' &
|
||||||
NGINX_PID=$!
|
NGINX_PID=$!
|
||||||
|
|
||||||
if [ $REDIS_IS_EXTERNAL = "true" ]; then
|
if [ "$REDIS_IS_EXTERNAL" = "true" ]; then
|
||||||
echo "Using external Redis server at redis://$REDIS_HOST:$REDIS_PORT"
|
echo "Using external Redis server at redis://$REDIS_HOST:$REDIS_PORT"
|
||||||
|
REDIS_PID=""
|
||||||
else
|
else
|
||||||
echo "Starting internal Redis server"
|
echo "Starting internal Redis server"
|
||||||
redis-server /app/redis.conf &
|
redis-server /app/redis.conf &
|
||||||
@@ -49,9 +53,11 @@ terminate() {
|
|||||||
echo "Received SIGTERM. Shutting down..."
|
echo "Received SIGTERM. Shutting down..."
|
||||||
kill -TERM $NGINX_PID $TASKS_PID $WSS_PID $NEXTJS_PID 2>/dev/null
|
kill -TERM $NGINX_PID $TASKS_PID $WSS_PID $NEXTJS_PID 2>/dev/null
|
||||||
wait
|
wait
|
||||||
# kill redis-server last because of logging of other services
|
# kill redis-server last because of logging of other services and only if $REDIS_PID is set
|
||||||
kill -TERM $REDIS_PID 2>/dev/null
|
if [ -n "$REDIS_PID" ]; then
|
||||||
wait
|
kill -TERM $REDIS_PID 2>/dev/null
|
||||||
|
wait
|
||||||
|
fi
|
||||||
echo "Shutdown complete."
|
echo "Shutdown complete."
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@@ -61,4 +67,4 @@ trap terminate TERM INT
|
|||||||
|
|
||||||
# Wait for all processes
|
# Wait for all processes
|
||||||
wait $NEXTJS_PID
|
wait $NEXTJS_PID
|
||||||
terminate
|
terminate
|
||||||
@@ -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
|
||||||
@@ -1 +1 @@
|
|||||||
[{"username":"carlchina","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png"},{"username":"zielmann","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png"},{"username":"Thalyn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png"},{"username":"magnushj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png"},{"username":"almontegil","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png"},{"username":"Skick","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12619811/medium/0331f1de413a645b4516bc4e037f31bb.jpg"},{"username":"andibing","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg"},{"username":"gronare","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png"},{"username":"SmartPhoneLover","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg"},{"username":"marcelotk_15","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png"},{"username":"S3OD177","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png"},{"username":"marcg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png"},{"username":"BeersTeddy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png"},{"username":"jamesmcmahon0","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg"},{"username":"b1nar10","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/249b02e3368752cb175446082015737c_default.png"},{"username":"vannCN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg"},{"username":"binswm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png"},{"username":"SkewRam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg"},{"username":"raphcatarino","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg"},{"username":"shillos5","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg"},{"username":"wolong98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg"},{"username":"spair0039","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png"},{"username":"MajorMarcin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg"},{"username":"KosmoMoustache","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png"},{"username":"Soochaehwa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png"},{"username":"garryfield","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg"},{"username":"droidenko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg"},{"username":"maathis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg"},{"username":"bukvam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg"},{"username":"gm.cinalli","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg"},{"username":"antoine2tt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png"},{"username":"cretzen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg"},{"username":"ktKongTong","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg"},{"username":"marinkaberg","avatarUrl":"https://crowLine truncated
|
[{"username":"carlchina","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png"},{"username":"zielmann","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png"},{"username":"Thalyn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png"},{"username":"magnushj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png"},{"username":"almontegil","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png"},{"username":"Skick","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12619811/medium/0331f1de413a645b4516bc4e037f31bb.jpg"},{"username":"andibing","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg"},{"username":"gronare","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png"},{"username":"SmartPhoneLover","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg"},{"username":"marcelotk_15","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png"},{"username":"S3OD177","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png"},{"username":"marcg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png"},{"username":"BeersTeddy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png"},{"username":"jamesmcmahon0","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg"},{"username":"b1nar10","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/249b02e3368752cb175446082015737c_default.png"},{"username":"vannCN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg"},{"username":"binswm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png"},{"username":"SkewRam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg"},{"username":"raphcatarino","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg"},{"username":"shillos5","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg"},{"username":"wolong98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg"},{"username":"spair0039","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png"},{"username":"MajorMarcin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg"},{"username":"KosmoMoustache","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png"},{"username":"Soochaehwa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png"},{"username":"garryfield","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg"},{"username":"droidenko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg"},{"username":"maathis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg"},{"username":"bukvam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg"},{"username":"gm.cinalli","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg"},{"username":"antoine2tt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png"},{"username":"cretzen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg"},{"username":"ktKongTong","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg"},{"username":"marinkaberg","avatarUrl":"https://crowLine truncated
|
||||||
@@ -17,14 +17,14 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/eslint-plugin-next": "16.0.3",
|
"@next/eslint-plugin-next": "16.0.10",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-config-turbo": "^2.6.1",
|
"eslint-config-turbo": "^2.6.3",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-hooks": "^6.1.1",
|
"eslint-plugin-react-hooks": "^6.1.1",
|
||||||
"typescript-eslint": "^8.46.2"
|
"typescript-eslint": "^8.48.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
"prettier": "@homarr/prettier-config",
|
"prettier": "@homarr/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
"@ianvs/prettier-plugin-sort-imports": "^4.7.0",
|
||||||
"prettier": "^3.6.2"
|
"prettier": "^3.7.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||||
"prettier-plugin-packagejson": "^2.5.19",
|
"prettier-plugin-packagejson": "^2.5.20",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user